]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/ObjectMap.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / librbd / ObjectMap.cc
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/ObjectMap.h"
5 #include "librbd/BlockGuard.h"
6 #include "librbd/ExclusiveLock.h"
7 #include "librbd/ImageCtx.h"
8 #include "librbd/object_map/RefreshRequest.h"
9 #include "librbd/object_map/ResizeRequest.h"
10 #include "librbd/object_map/SnapshotCreateRequest.h"
11 #include "librbd/object_map/SnapshotRemoveRequest.h"
12 #include "librbd/object_map/SnapshotRollbackRequest.h"
13 #include "librbd/object_map/UnlockRequest.h"
14 #include "librbd/object_map/UpdateRequest.h"
15 #include "librbd/Utils.h"
16 #include "common/dout.h"
17 #include "common/errno.h"
18 #include "common/WorkQueue.h"
19
20 #include "include/rados/librados.hpp"
21
22 #include "cls/lock/cls_lock_client.h"
23 #include "cls/rbd/cls_rbd_types.h"
24 #include "include/stringify.h"
25 #include "osdc/Striper.h"
26 #include <sstream>
27
28 #define dout_subsys ceph_subsys_rbd
29 #undef dout_prefix
30 #define dout_prefix *_dout << "librbd::ObjectMap: " << this << " " << __func__ \
31 << ": "
32
33 namespace librbd {
34
35 template <typename I>
36 ObjectMap<I>::ObjectMap(I &image_ctx, uint64_t snap_id)
37 : m_image_ctx(image_ctx), m_snap_id(snap_id),
38 m_update_guard(new UpdateGuard(m_image_ctx.cct)) {
39 }
40
41 template <typename I>
42 ObjectMap<I>::~ObjectMap() {
43 delete m_update_guard;
44 }
45
46 template <typename I>
47 int ObjectMap<I>::aio_remove(librados::IoCtx &io_ctx, const std::string &image_id,
48 librados::AioCompletion *c) {
49 return io_ctx.aio_remove(object_map_name(image_id, CEPH_NOSNAP), c);
50 }
51
52 template <typename I>
53 std::string ObjectMap<I>::object_map_name(const std::string &image_id,
54 uint64_t snap_id) {
55 std::string oid(RBD_OBJECT_MAP_PREFIX + image_id);
56 if (snap_id != CEPH_NOSNAP) {
57 std::stringstream snap_suffix;
58 snap_suffix << "." << std::setfill('0') << std::setw(16) << std::hex
59 << snap_id;
60 oid += snap_suffix.str();
61 }
62 return oid;
63 }
64
65 template <typename I>
66 bool ObjectMap<I>::is_compatible(const file_layout_t& layout, uint64_t size) {
67 uint64_t object_count = Striper::get_num_objects(layout, size);
68 return (object_count <= cls::rbd::MAX_OBJECT_MAP_OBJECT_COUNT);
69 }
70
71 template <typename I>
72 ceph::BitVector<2u>::Reference ObjectMap<I>::operator[](uint64_t object_no)
73 {
74 ceph_assert(m_image_ctx.object_map_lock.is_wlocked());
75 ceph_assert(object_no < m_object_map.size());
76 return m_object_map[object_no];
77 }
78
79 template <typename I>
80 uint8_t ObjectMap<I>::operator[](uint64_t object_no) const
81 {
82 ceph_assert(m_image_ctx.object_map_lock.is_locked());
83 ceph_assert(object_no < m_object_map.size());
84 return m_object_map[object_no];
85 }
86
87 template <typename I>
88 bool ObjectMap<I>::object_may_exist(uint64_t object_no) const
89 {
90 ceph_assert(m_image_ctx.snap_lock.is_locked());
91
92 // Fall back to default logic if object map is disabled or invalid
93 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
94 m_image_ctx.snap_lock)) {
95 return true;
96 }
97
98 bool flags_set;
99 int r = m_image_ctx.test_flags(m_image_ctx.snap_id,
100 RBD_FLAG_OBJECT_MAP_INVALID,
101 m_image_ctx.snap_lock, &flags_set);
102 if (r < 0 || flags_set) {
103 return true;
104 }
105
106 RWLock::RLocker l(m_image_ctx.object_map_lock);
107 uint8_t state = (*this)[object_no];
108 bool exists = (state != OBJECT_NONEXISTENT);
109 ldout(m_image_ctx.cct, 20) << "object_no=" << object_no << " r=" << exists
110 << dendl;
111 return exists;
112 }
113
114 template <typename I>
115 bool ObjectMap<I>::object_may_not_exist(uint64_t object_no) const
116 {
117 ceph_assert(m_image_ctx.snap_lock.is_locked());
118
119 // Fall back to default logic if object map is disabled or invalid
120 if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
121 m_image_ctx.snap_lock)) {
122 return true;
123 }
124
125 bool flags_set;
126 int r = m_image_ctx.test_flags(m_image_ctx.snap_id,
127 RBD_FLAG_OBJECT_MAP_INVALID,
128 m_image_ctx.snap_lock, &flags_set);
129 if (r < 0 || flags_set) {
130 return true;
131 }
132
133 RWLock::RLocker l(m_image_ctx.object_map_lock);
134 uint8_t state = (*this)[object_no];
135 bool nonexistent = (state != OBJECT_EXISTS && state != OBJECT_EXISTS_CLEAN);
136 ldout(m_image_ctx.cct, 20) << "object_no=" << object_no << " r="
137 << nonexistent << dendl;
138 return nonexistent;
139 }
140
141 template <typename I>
142 bool ObjectMap<I>::update_required(const ceph::BitVector<2>::Iterator& it,
143 uint8_t new_state) {
144 ceph_assert(m_image_ctx.object_map_lock.is_wlocked());
145 uint8_t state = *it;
146 if ((state == new_state) ||
147 (new_state == OBJECT_PENDING && state == OBJECT_NONEXISTENT) ||
148 (new_state == OBJECT_NONEXISTENT && state != OBJECT_PENDING)) {
149 return false;
150 }
151 return true;
152 }
153
154 template <typename I>
155 void ObjectMap<I>::open(Context *on_finish) {
156 auto req = object_map::RefreshRequest<I>::create(
157 m_image_ctx, &m_object_map, m_snap_id, on_finish);
158 req->send();
159 }
160
161 template <typename I>
162 void ObjectMap<I>::close(Context *on_finish) {
163 if (m_snap_id != CEPH_NOSNAP) {
164 m_image_ctx.op_work_queue->queue(on_finish, 0);
165 return;
166 }
167
168 auto req = object_map::UnlockRequest<I>::create(m_image_ctx, on_finish);
169 req->send();
170 }
171
172 template <typename I>
173 bool ObjectMap<I>::set_object_map(ceph::BitVector<2> &target_object_map) {
174 ceph_assert(m_image_ctx.owner_lock.is_locked());
175 ceph_assert(m_image_ctx.snap_lock.is_locked());
176 ceph_assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
177 m_image_ctx.snap_lock));
178 RWLock::RLocker object_map_locker(m_image_ctx.object_map_lock);
179 m_object_map = target_object_map;
180 return true;
181 }
182
183 template <typename I>
184 void ObjectMap<I>::rollback(uint64_t snap_id, Context *on_finish) {
185 ceph_assert(m_image_ctx.snap_lock.is_locked());
186 ceph_assert(m_image_ctx.object_map_lock.is_wlocked());
187
188 object_map::SnapshotRollbackRequest *req =
189 new object_map::SnapshotRollbackRequest(m_image_ctx, snap_id, on_finish);
190 req->send();
191 }
192
193 template <typename I>
194 void ObjectMap<I>::snapshot_add(uint64_t snap_id, Context *on_finish) {
195 ceph_assert(m_image_ctx.snap_lock.is_locked());
196 ceph_assert((m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0);
197 ceph_assert(snap_id != CEPH_NOSNAP);
198
199 object_map::SnapshotCreateRequest *req =
200 new object_map::SnapshotCreateRequest(m_image_ctx, &m_object_map, snap_id,
201 on_finish);
202 req->send();
203 }
204
205 template <typename I>
206 void ObjectMap<I>::snapshot_remove(uint64_t snap_id, Context *on_finish) {
207 ceph_assert(m_image_ctx.snap_lock.is_wlocked());
208 ceph_assert((m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0);
209 ceph_assert(snap_id != CEPH_NOSNAP);
210
211 object_map::SnapshotRemoveRequest *req =
212 new object_map::SnapshotRemoveRequest(m_image_ctx, &m_object_map, snap_id,
213 on_finish);
214 req->send();
215 }
216
217 template <typename I>
218 void ObjectMap<I>::aio_save(Context *on_finish) {
219 ceph_assert(m_image_ctx.owner_lock.is_locked());
220 ceph_assert(m_image_ctx.snap_lock.is_locked());
221 ceph_assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
222 m_image_ctx.snap_lock));
223 RWLock::RLocker object_map_locker(m_image_ctx.object_map_lock);
224
225 librados::ObjectWriteOperation op;
226 if (m_snap_id == CEPH_NOSNAP) {
227 rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "");
228 }
229 cls_client::object_map_save(&op, m_object_map);
230
231 std::string oid(object_map_name(m_image_ctx.id, m_snap_id));
232 librados::AioCompletion *comp = util::create_rados_callback(on_finish);
233
234 int r = m_image_ctx.md_ctx.aio_operate(oid, comp, &op);
235 ceph_assert(r == 0);
236 comp->release();
237 }
238
239 template <typename I>
240 void ObjectMap<I>::aio_resize(uint64_t new_size, uint8_t default_object_state,
241 Context *on_finish) {
242 ceph_assert(m_image_ctx.owner_lock.is_locked());
243 ceph_assert(m_image_ctx.snap_lock.is_locked());
244 ceph_assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
245 m_image_ctx.snap_lock));
246 ceph_assert(m_image_ctx.image_watcher != NULL);
247 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
248 m_image_ctx.exclusive_lock->is_lock_owner());
249
250 object_map::ResizeRequest *req = new object_map::ResizeRequest(
251 m_image_ctx, &m_object_map, m_snap_id, new_size, default_object_state,
252 on_finish);
253 req->send();
254 }
255
256 template <typename I>
257 void ObjectMap<I>::detained_aio_update(UpdateOperation &&op) {
258 CephContext *cct = m_image_ctx.cct;
259 ldout(cct, 20) << dendl;
260
261 ceph_assert(m_image_ctx.snap_lock.is_locked());
262 ceph_assert(m_image_ctx.object_map_lock.is_wlocked());
263
264 BlockGuardCell *cell;
265 int r = m_update_guard->detain({op.start_object_no, op.end_object_no},
266 &op, &cell);
267 if (r < 0) {
268 lderr(cct) << "failed to detain object map update: " << cpp_strerror(r)
269 << dendl;
270 m_image_ctx.op_work_queue->queue(op.on_finish, r);
271 return;
272 } else if (r > 0) {
273 ldout(cct, 20) << "detaining object map update due to in-flight update: "
274 << "start=" << op.start_object_no << ", "
275 << "end=" << op.end_object_no << ", "
276 << (op.current_state ?
277 stringify(static_cast<uint32_t>(*op.current_state)) :
278 "")
279 << "->" << static_cast<uint32_t>(op.new_state) << dendl;
280 return;
281 }
282
283 ldout(cct, 20) << "in-flight update cell: " << cell << dendl;
284 Context *on_finish = op.on_finish;
285 Context *ctx = new FunctionContext([this, cell, on_finish](int r) {
286 handle_detained_aio_update(cell, r, on_finish);
287 });
288 aio_update(CEPH_NOSNAP, op.start_object_no, op.end_object_no, op.new_state,
289 op.current_state, op.parent_trace, op.ignore_enoent, ctx);
290 }
291
292 template <typename I>
293 void ObjectMap<I>::handle_detained_aio_update(BlockGuardCell *cell, int r,
294 Context *on_finish) {
295 CephContext *cct = m_image_ctx.cct;
296 ldout(cct, 20) << "cell=" << cell << ", r=" << r << dendl;
297
298 typename UpdateGuard::BlockOperations block_ops;
299 m_update_guard->release(cell, &block_ops);
300
301 {
302 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
303 RWLock::WLocker object_map_locker(m_image_ctx.object_map_lock);
304 for (auto &op : block_ops) {
305 detained_aio_update(std::move(op));
306 }
307 }
308
309 on_finish->complete(r);
310 }
311
312 template <typename I>
313 void ObjectMap<I>::aio_update(uint64_t snap_id, uint64_t start_object_no,
314 uint64_t end_object_no, uint8_t new_state,
315 const boost::optional<uint8_t> &current_state,
316 const ZTracer::Trace &parent_trace,
317 bool ignore_enoent, Context *on_finish) {
318 ceph_assert(m_image_ctx.snap_lock.is_locked());
319 ceph_assert((m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0);
320 ceph_assert(m_image_ctx.image_watcher != nullptr);
321 ceph_assert(m_image_ctx.exclusive_lock == nullptr ||
322 m_image_ctx.exclusive_lock->is_lock_owner());
323 ceph_assert(snap_id != CEPH_NOSNAP ||
324 m_image_ctx.object_map_lock.is_wlocked());
325 ceph_assert(start_object_no < end_object_no);
326
327 CephContext *cct = m_image_ctx.cct;
328 ldout(cct, 20) << "start=" << start_object_no << ", "
329 << "end=" << end_object_no << ", "
330 << (current_state ?
331 stringify(static_cast<uint32_t>(*current_state)) : "")
332 << "->" << static_cast<uint32_t>(new_state) << dendl;
333 if (snap_id == CEPH_NOSNAP) {
334 end_object_no = std::min(end_object_no, m_object_map.size());
335 if (start_object_no >= end_object_no) {
336 ldout(cct, 20) << "skipping update of invalid object map" << dendl;
337 m_image_ctx.op_work_queue->queue(on_finish, 0);
338 return;
339 }
340
341 auto it = m_object_map.begin() + start_object_no;
342 auto end_it = m_object_map.begin() + end_object_no;
343 for (; it != end_it; ++it) {
344 if (update_required(it, new_state)) {
345 break;
346 }
347 }
348 if (it == end_it) {
349 ldout(cct, 20) << "object map update not required" << dendl;
350 m_image_ctx.op_work_queue->queue(on_finish, 0);
351 return;
352 }
353 }
354
355 auto req = object_map::UpdateRequest<I>::create(
356 m_image_ctx, &m_object_map, snap_id, start_object_no, end_object_no,
357 new_state, current_state, parent_trace, ignore_enoent, on_finish);
358 req->send();
359 }
360
361 } // namespace librbd
362
363 template class librbd::ObjectMap<librbd::ImageCtx>;
364