]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "librbd/object_map/SnapshotRemoveRequest.h" | |
5 | #include "common/dout.h" | |
6 | #include "common/errno.h" | |
7 | #include "librbd/ImageCtx.h" | |
8 | #include "librbd/ObjectMap.h" | |
9 | #include "librbd/object_map/InvalidateRequest.h" | |
10 | #include "cls/lock/cls_lock_client.h" | |
11 | ||
12 | #define dout_subsys ceph_subsys_rbd | |
13 | #undef dout_prefix | |
14 | #define dout_prefix *_dout << "librbd::object_map::SnapshotRemoveRequest: " | |
15 | ||
16 | namespace librbd { | |
17 | namespace object_map { | |
18 | ||
19 | namespace { | |
20 | ||
21 | std::ostream& operator<<(std::ostream& os, | |
22 | const SnapshotRemoveRequest::State& state) { | |
23 | switch(state) { | |
24 | case SnapshotRemoveRequest::STATE_LOAD_MAP: | |
25 | os << "LOAD_MAP"; | |
26 | break; | |
27 | case SnapshotRemoveRequest::STATE_REMOVE_SNAPSHOT: | |
28 | os << "REMOVE_SNAPSHOT"; | |
29 | break; | |
30 | case SnapshotRemoveRequest::STATE_INVALIDATE_NEXT_MAP: | |
31 | os << "INVALIDATE_NEXT_MAP"; | |
32 | break; | |
33 | case SnapshotRemoveRequest::STATE_REMOVE_MAP: | |
34 | os << "REMOVE_MAP"; | |
35 | break; | |
36 | default: | |
37 | os << "UNKNOWN (" << static_cast<uint32_t>(state) << ")"; | |
38 | break; | |
39 | } | |
40 | return os; | |
41 | } | |
42 | ||
43 | } // anonymous namespace | |
44 | ||
45 | void SnapshotRemoveRequest::send() { | |
46 | assert(m_image_ctx.owner_lock.is_locked()); | |
47 | assert(m_image_ctx.snap_lock.is_wlocked()); | |
48 | ||
49 | if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) { | |
50 | compute_next_snap_id(); | |
51 | ||
52 | uint64_t flags; | |
53 | int r = m_image_ctx.get_flags(m_snap_id, &flags); | |
54 | assert(r == 0); | |
55 | ||
56 | if ((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0) { | |
57 | send_invalidate_next_map(); | |
58 | } else { | |
59 | send_load_map(); | |
60 | } | |
61 | } else { | |
62 | send_remove_map(); | |
63 | } | |
64 | } | |
65 | ||
66 | bool SnapshotRemoveRequest::should_complete(int r) { | |
67 | CephContext *cct = m_image_ctx.cct; | |
68 | ldout(cct, 5) << this << " " << __func__ << ": state=" << m_state << ", " | |
69 | << "r=" << r << dendl; | |
70 | ||
71 | RWLock::RLocker owner_locker(m_image_ctx.owner_lock); | |
72 | bool finished = false; | |
73 | switch (m_state) { | |
74 | case STATE_LOAD_MAP: | |
75 | if (r == -ENOENT) { | |
76 | finished = true; | |
77 | break; | |
78 | } | |
79 | ||
80 | if (r == 0) { | |
81 | bufferlist::iterator it = m_out_bl.begin(); | |
82 | r = cls_client::object_map_load_finish(&it, &m_snap_object_map); | |
83 | } | |
84 | if (r < 0) { | |
85 | RWLock::WLocker snap_locker(m_image_ctx.snap_lock); | |
86 | send_invalidate_next_map(); | |
87 | } else { | |
88 | send_remove_snapshot(); | |
89 | } | |
90 | break; | |
91 | case STATE_REMOVE_SNAPSHOT: | |
92 | if (r < 0 && r != -ENOENT) { | |
93 | RWLock::WLocker snap_locker(m_image_ctx.snap_lock); | |
94 | send_invalidate_next_map(); | |
95 | } else { | |
96 | update_object_map(); | |
97 | send_remove_map(); | |
98 | } | |
99 | break; | |
100 | case STATE_INVALIDATE_NEXT_MAP: | |
101 | send_remove_map(); | |
102 | break; | |
103 | case STATE_REMOVE_MAP: | |
104 | finished = true; | |
105 | break; | |
106 | default: | |
107 | assert(false); | |
108 | break; | |
109 | } | |
110 | return finished; | |
111 | } | |
112 | ||
113 | void SnapshotRemoveRequest::send_load_map() { | |
114 | CephContext *cct = m_image_ctx.cct; | |
115 | std::string snap_oid(ObjectMap<>::object_map_name(m_image_ctx.id, m_snap_id)); | |
116 | ldout(cct, 5) << this << " " << __func__ << ": snap_oid=" << snap_oid | |
117 | << dendl; | |
118 | m_state = STATE_LOAD_MAP; | |
119 | ||
120 | librados::ObjectReadOperation op; | |
121 | cls_client::object_map_load_start(&op); | |
122 | ||
123 | librados::AioCompletion *rados_completion = create_callback_completion(); | |
124 | int r = m_image_ctx.md_ctx.aio_operate(snap_oid, rados_completion, &op, | |
125 | &m_out_bl); | |
126 | assert(r == 0); | |
127 | rados_completion->release(); | |
128 | } | |
129 | ||
130 | void SnapshotRemoveRequest::send_remove_snapshot() { | |
131 | CephContext *cct = m_image_ctx.cct; | |
132 | std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, m_next_snap_id)); | |
133 | ldout(cct, 5) << this << " " << __func__ << ": oid=" << oid << dendl; | |
134 | m_state = STATE_REMOVE_SNAPSHOT; | |
135 | ||
136 | librados::ObjectWriteOperation op; | |
137 | if (m_next_snap_id == CEPH_NOSNAP) { | |
138 | rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", ""); | |
139 | } | |
140 | cls_client::object_map_snap_remove(&op, m_snap_object_map); | |
141 | ||
142 | librados::AioCompletion *rados_completion = create_callback_completion(); | |
143 | int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op); | |
144 | assert(r == 0); | |
145 | rados_completion->release(); | |
146 | } | |
147 | ||
148 | void SnapshotRemoveRequest::send_invalidate_next_map() { | |
149 | assert(m_image_ctx.owner_lock.is_locked()); | |
150 | assert(m_image_ctx.snap_lock.is_wlocked()); | |
151 | ||
152 | CephContext *cct = m_image_ctx.cct; | |
153 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
154 | m_state = STATE_INVALIDATE_NEXT_MAP; | |
155 | ||
156 | InvalidateRequest<> *req = new InvalidateRequest<>(m_image_ctx, | |
157 | m_next_snap_id, true, | |
158 | create_callback_context()); | |
159 | req->send(); | |
160 | } | |
161 | ||
162 | void SnapshotRemoveRequest::send_remove_map() { | |
163 | CephContext *cct = m_image_ctx.cct; | |
164 | std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, m_snap_id)); | |
165 | ldout(cct, 5) << this << " " << __func__ << ": oid=" << oid << dendl; | |
166 | m_state = STATE_REMOVE_MAP; | |
167 | ||
168 | librados::ObjectWriteOperation op; | |
169 | op.remove(); | |
170 | ||
171 | librados::AioCompletion *rados_completion = create_callback_completion(); | |
172 | int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op); | |
173 | assert(r == 0); | |
174 | rados_completion->release(); | |
175 | } | |
176 | ||
177 | void SnapshotRemoveRequest::compute_next_snap_id() { | |
178 | assert(m_image_ctx.snap_lock.is_locked()); | |
179 | ||
180 | m_next_snap_id = CEPH_NOSNAP; | |
181 | std::map<librados::snap_t, SnapInfo>::const_iterator it = | |
182 | m_image_ctx.snap_info.find(m_snap_id); | |
183 | assert(it != m_image_ctx.snap_info.end()); | |
184 | ||
185 | ++it; | |
186 | if (it != m_image_ctx.snap_info.end()) { | |
187 | m_next_snap_id = it->first; | |
188 | } | |
189 | } | |
190 | ||
191 | void SnapshotRemoveRequest::update_object_map() { | |
192 | RWLock::RLocker snap_locker(m_image_ctx.snap_lock); | |
193 | RWLock::WLocker object_map_locker(m_image_ctx.object_map_lock); | |
194 | if (m_next_snap_id == m_image_ctx.snap_id && m_next_snap_id == CEPH_NOSNAP) { | |
195 | CephContext *cct = m_image_ctx.cct; | |
196 | ldout(cct, 5) << this << " " << __func__ << dendl; | |
b32b8144 FG |
197 | |
198 | auto it = m_object_map.begin(); | |
199 | auto end_it = m_object_map.end(); | |
200 | auto snap_it = m_snap_object_map.begin(); | |
201 | uint64_t i = 0; | |
202 | for (; it != end_it; ++it) { | |
203 | if (*it == OBJECT_EXISTS_CLEAN && | |
7c673cae | 204 | (i >= m_snap_object_map.size() || |
b32b8144 FG |
205 | *snap_it == OBJECT_EXISTS)) { |
206 | *it = OBJECT_EXISTS; | |
207 | } | |
208 | if (i < m_snap_object_map.size()) { | |
209 | ++snap_it; | |
7c673cae | 210 | } |
b32b8144 | 211 | ++i; |
7c673cae FG |
212 | } |
213 | } | |
214 | } | |
215 | ||
216 | } // namespace object_map | |
217 | } // namespace librbd |