1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/object_map/RefreshRequest.h"
5 #include "cls/lock/cls_lock_client.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ObjectMap.h"
10 #include "librbd/object_map/InvalidateRequest.h"
11 #include "librbd/object_map/LockRequest.h"
12 #include "librbd/object_map/ResizeRequest.h"
13 #include "librbd/Utils.h"
14 #include "osdc/Striper.h"
16 #define dout_subsys ceph_subsys_rbd
18 #define dout_prefix *_dout << "librbd::object_map::RefreshRequest: "
22 using util::create_context_callback;
23 using util::create_rados_callback;
25 namespace object_map {
28 RefreshRequest<I>::RefreshRequest(I &image_ctx, ceph::BitVector<2> *object_map,
29 uint64_t snap_id, Context *on_finish)
30 : m_image_ctx(image_ctx), m_object_map(object_map), m_snap_id(snap_id),
31 m_on_finish(on_finish), m_object_count(0),
32 m_truncate_on_disk_object_map(false) {
36 void RefreshRequest<I>::send() {
38 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
39 m_object_count = Striper::get_num_objects(
40 m_image_ctx.layout, m_image_ctx.get_image_size(m_snap_id));
44 CephContext *cct = m_image_ctx.cct;
45 ldout(cct, 20) << this << " " << __func__ << ": "
46 << "object_count=" << m_object_count << dendl;
51 void RefreshRequest<I>::apply() {
54 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
55 num_objs = Striper::get_num_objects(
56 m_image_ctx.layout, m_image_ctx.get_image_size(m_snap_id));
58 assert(m_on_disk_object_map.size() >= num_objs);
60 *m_object_map = m_on_disk_object_map;
64 void RefreshRequest<I>::send_lock() {
65 CephContext *cct = m_image_ctx.cct;
66 if (m_object_count > cls::rbd::MAX_OBJECT_MAP_OBJECT_COUNT) {
67 send_invalidate_and_close();
69 } else if (m_snap_id != CEPH_NOSNAP) {
74 std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, m_snap_id));
75 ldout(cct, 10) << this << " " << __func__ << ": oid=" << oid << dendl;
77 using klass = RefreshRequest<I>;
78 Context *ctx = create_context_callback<
79 klass, &klass::handle_lock>(this);
81 LockRequest<I> *req = LockRequest<I>::create(m_image_ctx, ctx);
86 Context *RefreshRequest<I>::handle_lock(int *ret_val) {
87 CephContext *cct = m_image_ctx.cct;
88 ldout(cct, 10) << this << " " << __func__ << dendl;
90 assert(*ret_val == 0);
96 void RefreshRequest<I>::send_load() {
97 CephContext *cct = m_image_ctx.cct;
98 std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, m_snap_id));
99 ldout(cct, 10) << this << " " << __func__ << ": oid=" << oid << dendl;
101 librados::ObjectReadOperation op;
102 cls_client::object_map_load_start(&op);
104 using klass = RefreshRequest<I>;
106 librados::AioCompletion *rados_completion =
107 create_rados_callback<klass, &klass::handle_load>(this);
108 int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op, &m_out_bl);
110 rados_completion->release();
113 template <typename I>
114 Context *RefreshRequest<I>::handle_load(int *ret_val) {
115 CephContext *cct = m_image_ctx.cct;
116 ldout(cct, 10) << this << " " << __func__ << ": r=" << *ret_val << dendl;
119 bufferlist::iterator bl_it = m_out_bl.begin();
120 *ret_val = cls_client::object_map_load_finish(&bl_it,
121 &m_on_disk_object_map);
124 std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, m_snap_id));
125 if (*ret_val == -EINVAL) {
126 // object map is corrupt on-disk -- clear it and properly size it
127 // so future IO can keep the object map in sync
128 lderr(cct) << "object map corrupt on-disk: " << oid << dendl;
129 m_truncate_on_disk_object_map = true;
130 send_resize_invalidate();
132 } else if (*ret_val < 0) {
133 lderr(cct) << "failed to load object map: " << oid << dendl;
138 if (m_on_disk_object_map.size() < m_object_count) {
139 lderr(cct) << "object map smaller than current object count: "
140 << m_on_disk_object_map.size() << " != "
141 << m_object_count << dendl;
142 send_resize_invalidate();
146 ldout(cct, 20) << "refreshed object map: num_objs="
147 << m_on_disk_object_map.size() << dendl;
148 if (m_on_disk_object_map.size() > m_object_count) {
149 // resize op might have been interrupted
150 ldout(cct, 1) << "object map larger than current object count: "
151 << m_on_disk_object_map.size() << " != "
152 << m_object_count << dendl;
159 template <typename I>
160 void RefreshRequest<I>::send_invalidate() {
161 CephContext *cct = m_image_ctx.cct;
162 ldout(cct, 10) << this << " " << __func__ << dendl;
164 m_on_disk_object_map.clear();
165 object_map::ResizeRequest::resize(&m_on_disk_object_map, m_object_count,
168 using klass = RefreshRequest<I>;
169 Context *ctx = create_context_callback<
170 klass, &klass::handle_invalidate>(this);
171 InvalidateRequest<I> *req = InvalidateRequest<I>::create(
172 m_image_ctx, m_snap_id, false, ctx);
174 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
175 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
179 template <typename I>
180 Context *RefreshRequest<I>::handle_invalidate(int *ret_val) {
181 CephContext *cct = m_image_ctx.cct;
182 ldout(cct, 10) << this << " " << __func__ << ": r=" << *ret_val << dendl;
184 assert(*ret_val == 0);
189 template <typename I>
190 void RefreshRequest<I>::send_resize_invalidate() {
191 CephContext *cct = m_image_ctx.cct;
192 ldout(cct, 10) << this << " " << __func__ << dendl;
194 m_on_disk_object_map.clear();
195 object_map::ResizeRequest::resize(&m_on_disk_object_map, m_object_count,
198 using klass = RefreshRequest<I>;
199 Context *ctx = create_context_callback<
200 klass, &klass::handle_resize_invalidate>(this);
201 InvalidateRequest<I> *req = InvalidateRequest<I>::create(
202 m_image_ctx, m_snap_id, false, ctx);
204 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
205 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
209 template <typename I>
210 Context *RefreshRequest<I>::handle_resize_invalidate(int *ret_val) {
211 CephContext *cct = m_image_ctx.cct;
212 ldout(cct, 10) << this << " " << __func__ << ": r=" << *ret_val << dendl;
214 assert(*ret_val == 0);
219 template <typename I>
220 void RefreshRequest<I>::send_resize() {
221 CephContext *cct = m_image_ctx.cct;
222 std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, m_snap_id));
223 ldout(cct, 10) << this << " " << __func__ << ": oid=" << oid << dendl;
225 librados::ObjectWriteOperation op;
226 if (m_snap_id == CEPH_NOSNAP) {
227 rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "");
229 if (m_truncate_on_disk_object_map) {
232 cls_client::object_map_resize(&op, m_object_count, OBJECT_NONEXISTENT);
234 using klass = RefreshRequest<I>;
235 librados::AioCompletion *rados_completion =
236 create_rados_callback<klass, &klass::handle_resize>(this);
237 int r = m_image_ctx.md_ctx.aio_operate(oid, rados_completion, &op);
239 rados_completion->release();
242 template <typename I>
243 Context *RefreshRequest<I>::handle_resize(int *ret_val) {
244 CephContext *cct = m_image_ctx.cct;
245 ldout(cct, 10) << this << " " << __func__ << ": r=" << *ret_val << dendl;
248 lderr(cct) << "failed to adjust object map size: " << cpp_strerror(*ret_val)
256 template <typename I>
257 void RefreshRequest<I>::send_invalidate_and_close() {
258 CephContext *cct = m_image_ctx.cct;
259 ldout(cct, 10) << this << " " << __func__ << dendl;
261 using klass = RefreshRequest<I>;
262 Context *ctx = create_context_callback<
263 klass, &klass::handle_invalidate_and_close>(this);
264 InvalidateRequest<I> *req = InvalidateRequest<I>::create(
265 m_image_ctx, m_snap_id, false, ctx);
267 lderr(cct) << "object map too large: " << m_object_count << dendl;
268 RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
269 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
273 template <typename I>
274 Context *RefreshRequest<I>::handle_invalidate_and_close(int *ret_val) {
275 CephContext *cct = m_image_ctx.cct;
276 ldout(cct, 10) << this << " " << __func__ << ": r=" << *ret_val << dendl;
278 assert(*ret_val == 0);
281 m_object_map->clear();
285 } // namespace object_map
286 } // namespace librbd
288 template class librbd::object_map::RefreshRequest<librbd::ImageCtx>;