]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/ObjectMap.cc
update sources to v12.2.3
[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
35template <typename I>
36ObjectMap<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
41template <typename I>
42ObjectMap<I>::~ObjectMap() {
43 delete m_update_guard;
44}
45
46template <typename I>
47int 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
52template <typename I>
53std::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
65template <typename I>
66bool 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
71template <typename I>
72ceph::BitVector<2u>::Reference ObjectMap<I>::operator[](uint64_t object_no)
73{
74 assert(m_image_ctx.object_map_lock.is_wlocked());
75 assert(object_no < m_object_map.size());
76 return m_object_map[object_no];
77}
78
79template <typename I>
80uint8_t ObjectMap<I>::operator[](uint64_t object_no) const
81{
82 assert(m_image_ctx.object_map_lock.is_locked());
83 assert(object_no < m_object_map.size());
84 return m_object_map[object_no];
85}
86
87template <typename I>
88bool ObjectMap<I>::object_may_exist(uint64_t object_no) const
89{
90 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,
31f18b77
FG
94 m_image_ctx.snap_lock)) {
95 return true;
96 }
97
98 bool flags_set;
99 int r = m_image_ctx.test_flags(RBD_FLAG_OBJECT_MAP_INVALID,
100 m_image_ctx.snap_lock, &flags_set);
101 if (r < 0 || flags_set) {
7c673cae
FG
102 return true;
103 }
104
105 RWLock::RLocker l(m_image_ctx.object_map_lock);
106 uint8_t state = (*this)[object_no];
107 bool exists = (state != OBJECT_NONEXISTENT);
108 ldout(m_image_ctx.cct, 20) << "object_no=" << object_no << " r=" << exists
109 << dendl;
110 return exists;
111}
112
113template <typename I>
3efd9988
FG
114bool ObjectMap<I>::update_required(const ceph::BitVector<2>::Iterator& it,
115 uint8_t new_state) {
7c673cae 116 assert(m_image_ctx.object_map_lock.is_wlocked());
3efd9988 117 uint8_t state = *it;
7c673cae
FG
118 if ((state == new_state) ||
119 (new_state == OBJECT_PENDING && state == OBJECT_NONEXISTENT) ||
120 (new_state == OBJECT_NONEXISTENT && state != OBJECT_PENDING)) {
121 return false;
122 }
123 return true;
124}
125
126template <typename I>
127void ObjectMap<I>::open(Context *on_finish) {
128 auto req = object_map::RefreshRequest<I>::create(
129 m_image_ctx, &m_object_map, m_snap_id, on_finish);
130 req->send();
131}
132
133template <typename I>
134void ObjectMap<I>::close(Context *on_finish) {
135 if (m_snap_id != CEPH_NOSNAP) {
136 m_image_ctx.op_work_queue->queue(on_finish, 0);
137 return;
138 }
139
140 auto req = object_map::UnlockRequest<I>::create(m_image_ctx, on_finish);
141 req->send();
142}
143
b32b8144
FG
144template <typename I>
145bool ObjectMap<I>::set_object_map(ceph::BitVector<2> &target_object_map) {
146 assert(m_image_ctx.owner_lock.is_locked());
147 assert(m_image_ctx.snap_lock.is_locked());
148 assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
149 m_image_ctx.snap_lock));
150 RWLock::RLocker object_map_locker(m_image_ctx.object_map_lock);
151 m_object_map = target_object_map;
152 return true;
153}
154
7c673cae
FG
155template <typename I>
156void ObjectMap<I>::rollback(uint64_t snap_id, Context *on_finish) {
157 assert(m_image_ctx.snap_lock.is_locked());
158 assert(m_image_ctx.object_map_lock.is_wlocked());
159
160 object_map::SnapshotRollbackRequest *req =
161 new object_map::SnapshotRollbackRequest(m_image_ctx, snap_id, on_finish);
162 req->send();
163}
164
165template <typename I>
166void ObjectMap<I>::snapshot_add(uint64_t snap_id, Context *on_finish) {
167 assert(m_image_ctx.snap_lock.is_locked());
168 assert((m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0);
169 assert(snap_id != CEPH_NOSNAP);
170
171 object_map::SnapshotCreateRequest *req =
172 new object_map::SnapshotCreateRequest(m_image_ctx, &m_object_map, snap_id,
173 on_finish);
174 req->send();
175}
176
177template <typename I>
178void ObjectMap<I>::snapshot_remove(uint64_t snap_id, Context *on_finish) {
179 assert(m_image_ctx.snap_lock.is_wlocked());
180 assert((m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0);
181 assert(snap_id != CEPH_NOSNAP);
182
183 object_map::SnapshotRemoveRequest *req =
184 new object_map::SnapshotRemoveRequest(m_image_ctx, &m_object_map, snap_id,
185 on_finish);
186 req->send();
187}
188
189template <typename I>
190void ObjectMap<I>::aio_save(Context *on_finish) {
191 assert(m_image_ctx.owner_lock.is_locked());
192 assert(m_image_ctx.snap_lock.is_locked());
193 assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
194 m_image_ctx.snap_lock));
195 RWLock::RLocker object_map_locker(m_image_ctx.object_map_lock);
196
197 librados::ObjectWriteOperation op;
198 if (m_snap_id == CEPH_NOSNAP) {
199 rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "");
200 }
201 cls_client::object_map_save(&op, m_object_map);
202
203 std::string oid(object_map_name(m_image_ctx.id, m_snap_id));
204 librados::AioCompletion *comp = util::create_rados_callback(on_finish);
205
206 int r = m_image_ctx.md_ctx.aio_operate(oid, comp, &op);
207 assert(r == 0);
208 comp->release();
209}
210
211template <typename I>
212void ObjectMap<I>::aio_resize(uint64_t new_size, uint8_t default_object_state,
213 Context *on_finish) {
214 assert(m_image_ctx.owner_lock.is_locked());
215 assert(m_image_ctx.snap_lock.is_locked());
216 assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
217 m_image_ctx.snap_lock));
218 assert(m_image_ctx.image_watcher != NULL);
219 assert(m_image_ctx.exclusive_lock == nullptr ||
220 m_image_ctx.exclusive_lock->is_lock_owner());
221
222 object_map::ResizeRequest *req = new object_map::ResizeRequest(
223 m_image_ctx, &m_object_map, m_snap_id, new_size, default_object_state,
224 on_finish);
225 req->send();
226}
227
228template <typename I>
229void ObjectMap<I>::detained_aio_update(UpdateOperation &&op) {
230 CephContext *cct = m_image_ctx.cct;
231 ldout(cct, 20) << dendl;
232
233 assert(m_image_ctx.snap_lock.is_locked());
234 assert(m_image_ctx.object_map_lock.is_wlocked());
235
236 BlockGuardCell *cell;
237 int r = m_update_guard->detain({op.start_object_no, op.end_object_no},
3efd9988 238 &op, &cell);
7c673cae
FG
239 if (r < 0) {
240 lderr(cct) << "failed to detain object map update: " << cpp_strerror(r)
241 << dendl;
242 m_image_ctx.op_work_queue->queue(op.on_finish, r);
243 return;
244 } else if (r > 0) {
245 ldout(cct, 20) << "detaining object map update due to in-flight update: "
246 << "start=" << op.start_object_no << ", "
247 << "end=" << op.end_object_no << ", "
248 << (op.current_state ?
249 stringify(static_cast<uint32_t>(*op.current_state)) :
250 "")
251 << "->" << static_cast<uint32_t>(op.new_state) << dendl;
252 return;
253 }
254
255 ldout(cct, 20) << "in-flight update cell: " << cell << dendl;
256 Context *on_finish = op.on_finish;
257 Context *ctx = new FunctionContext([this, cell, on_finish](int r) {
258 handle_detained_aio_update(cell, r, on_finish);
259 });
260 aio_update(CEPH_NOSNAP, op.start_object_no, op.end_object_no, op.new_state,
31f18b77 261 op.current_state, op.parent_trace, ctx);
7c673cae
FG
262}
263
264template <typename I>
265void ObjectMap<I>::handle_detained_aio_update(BlockGuardCell *cell, int r,
266 Context *on_finish) {
267 CephContext *cct = m_image_ctx.cct;
268 ldout(cct, 20) << "cell=" << cell << ", r=" << r << dendl;
269
270 typename UpdateGuard::BlockOperations block_ops;
271 m_update_guard->release(cell, &block_ops);
272
273 {
274 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
275 RWLock::WLocker object_map_locker(m_image_ctx.object_map_lock);
276 for (auto &op : block_ops) {
277 detained_aio_update(std::move(op));
278 }
279 }
280
281 on_finish->complete(r);
282}
283
284template <typename I>
285void ObjectMap<I>::aio_update(uint64_t snap_id, uint64_t start_object_no,
286 uint64_t end_object_no, uint8_t new_state,
287 const boost::optional<uint8_t> &current_state,
31f18b77 288 const ZTracer::Trace &parent_trace,
7c673cae
FG
289 Context *on_finish) {
290 assert(m_image_ctx.snap_lock.is_locked());
291 assert((m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0);
292 assert(m_image_ctx.image_watcher != nullptr);
293 assert(m_image_ctx.exclusive_lock == nullptr ||
294 m_image_ctx.exclusive_lock->is_lock_owner());
295 assert(snap_id != CEPH_NOSNAP || m_image_ctx.object_map_lock.is_wlocked());
296 assert(start_object_no < end_object_no);
297
298 CephContext *cct = m_image_ctx.cct;
299 ldout(cct, 20) << "start=" << start_object_no << ", "
300 << "end=" << end_object_no << ", "
301 << (current_state ?
302 stringify(static_cast<uint32_t>(*current_state)) : "")
303 << "->" << static_cast<uint32_t>(new_state) << dendl;
304 if (snap_id == CEPH_NOSNAP) {
305 if (end_object_no > m_object_map.size()) {
306 ldout(cct, 20) << "skipping update of invalid object map" << dendl;
307 m_image_ctx.op_work_queue->queue(on_finish, 0);
308 return;
309 }
310
3efd9988
FG
311 auto it = m_object_map.begin() + start_object_no;
312 auto end_it = m_object_map.begin() + end_object_no;
313 for (; it != end_it; ++it) {
314 if (update_required(it, new_state)) {
7c673cae
FG
315 break;
316 }
317 }
3efd9988 318 if (it == end_it) {
7c673cae
FG
319 ldout(cct, 20) << "object map update not required" << dendl;
320 m_image_ctx.op_work_queue->queue(on_finish, 0);
321 return;
322 }
323 }
324
325 auto req = object_map::UpdateRequest<I>::create(
326 m_image_ctx, &m_object_map, snap_id, start_object_no, end_object_no,
31f18b77 327 new_state, current_state, parent_trace, on_finish);
7c673cae
FG
328 req->send();
329}
330
331} // namespace librbd
332
333template class librbd::ObjectMap<librbd::ImageCtx>;
334