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