namespace librbd {
-namespace {
-
-struct C_ApplyRefresh : public Context {
- object_map::RefreshRequest<> *request;
- C_ApplyRefresh(object_map::RefreshRequest<> *request) : request(request) {
- }
- virtual void finish(int r) {
- if (r < 0) {
- request->apply();
- } else {
- request->discard();
- }
- }
-};
-
-} // anonymous namespace
-
-ObjectMap::ObjectMap(ImageCtx &image_ctx)
- : m_image_ctx(image_ctx), m_snap_id(CEPH_NOSNAP)
+ObjectMap::ObjectMap(ImageCtx &image_ctx, uint64_t snap_id)
+ : m_image_ctx(image_ctx), m_snap_id(snap_id)
{
}
return m_object_map[object_no];
}
-int ObjectMap::lock()
-{
- if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
- return 0;
- }
-
- bool broke_lock = false;
- CephContext *cct = m_image_ctx.cct;
- std::string oid(object_map_name(m_image_ctx.id, CEPH_NOSNAP));
- while (true) {
- int r;
- ldout(cct, 10) << &m_image_ctx << " locking object map: "
- << oid << dendl;
- r = rados::cls::lock::lock(&m_image_ctx.md_ctx, oid,
- RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "", "",
- utime_t(), 0);
- if (r == 0) {
- break;
- } else if (broke_lock || r != -EBUSY) {
- lderr(cct) << "failed to lock object map: " << cpp_strerror(r) << dendl;
- return r;
- }
-
- typedef std::map<rados::cls::lock::locker_id_t,
- rados::cls::lock::locker_info_t> lockers_t;
- lockers_t lockers;
- ClsLockType lock_type;
- std::string lock_tag;
- r = rados::cls::lock::get_lock_info(&m_image_ctx.md_ctx, oid,
- RBD_LOCK_NAME, &lockers,
- &lock_type, &lock_tag);
- if (r == -ENOENT) {
- continue;
- } else if (r < 0) {
- lderr(cct) << "failed to list object map locks: " << cpp_strerror(r)
- << dendl;
- return r;
- }
-
- ldout(cct, 10) << "breaking current object map lock" << dendl;
- for (lockers_t::iterator it = lockers.begin();
- it != lockers.end(); ++it) {
- const rados::cls::lock::locker_id_t &locker = it->first;
- r = rados::cls::lock::break_lock(&m_image_ctx.md_ctx, oid,
- RBD_LOCK_NAME, locker.cookie,
- locker.locker);
- if (r < 0 && r != -ENOENT) {
- lderr(cct) << "failed to break object map lock: " << cpp_strerror(r)
- << dendl;
- return r;
- }
- }
-
-
-
- broke_lock = true;
- }
- return 0;
-}
-
-void ObjectMap::lock(Context *on_finish) {
- object_map::LockRequest<> *req = new object_map::LockRequest<>(
- m_image_ctx, on_finish);
- req->send();
-}
-
-int ObjectMap::unlock()
-{
- if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP)) {
- return 0;
- }
-
- std::string oid = object_map_name(m_image_ctx.id, CEPH_NOSNAP);
- ldout(m_image_ctx.cct, 10) << &m_image_ctx << " unlocking object map: "
- << oid << dendl;
- int r = rados::cls::lock::unlock(&m_image_ctx.md_ctx, oid,
- RBD_LOCK_NAME, "");
- if (r < 0 && r != -ENOENT) {
- lderr(m_image_ctx.cct) << "failed to release object map lock: "
- << cpp_strerror(r) << dendl;
- }
- return r;
-}
-
-void ObjectMap::unlock(Context *on_finish) {
- object_map::UnlockRequest<> *req = new object_map::UnlockRequest<>(
- m_image_ctx, on_finish);
- req->send();
-}
-
bool ObjectMap::object_may_exist(uint64_t object_no) const
{
+ assert(m_image_ctx.snap_lock.is_locked());
+
// Fall back to default logic if object map is disabled or invalid
- if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP) ||
- m_image_ctx.test_flags(RBD_FLAG_OBJECT_MAP_INVALID)) {
+ if (!m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
+ m_image_ctx.snap_lock) ||
+ m_image_ctx.test_flags(RBD_FLAG_OBJECT_MAP_INVALID,
+ m_image_ctx.snap_lock)) {
return true;
}
return exists;
}
-void ObjectMap::refresh(uint64_t snap_id)
-{
- assert(m_image_ctx.snap_lock.is_wlocked());
- RWLock::WLocker l(m_image_ctx.object_map_lock);
- m_snap_id = snap_id;
-
- CephContext *cct = m_image_ctx.cct;
- std::string oid(object_map_name(m_image_ctx.id, snap_id));
- ldout(cct, 10) << &m_image_ctx << " refreshing object map: "
- << oid << dendl;
-
- uint64_t num_objs = Striper::get_num_objects(
- m_image_ctx.layout, m_image_ctx.get_image_size(snap_id));
-
- int r = cls_client::object_map_load(&m_image_ctx.md_ctx, oid,
- &m_object_map);
- if (r == -EINVAL) {
- // object map is corrupt on-disk -- clear it and properly size it
- // so future IO can keep the object map in sync
- invalidate(snap_id, false);
-
- librados::ObjectWriteOperation op;
- if (snap_id == CEPH_NOSNAP) {
- rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "",
- "");
- }
- op.truncate(0);
- cls_client::object_map_resize(&op, num_objs, OBJECT_NONEXISTENT);
-
- r = m_image_ctx.md_ctx.operate(oid, &op);
- if (r == 0) {
- m_object_map.clear();
- object_map::ResizeRequest::resize(&m_object_map, num_objs,
- OBJECT_NONEXISTENT);
- }
- }
- if (r < 0) {
- lderr(cct) << "error refreshing object map: " << cpp_strerror(r)
- << dendl;
- invalidate(snap_id, false);
- m_object_map.clear();
- return;
- }
-
- ldout(cct, 20) << "refreshed object map: num_objs=" << m_object_map.size()
- << dendl;
-
- if (m_object_map.size() < num_objs) {
- lderr(cct) << "object map smaller than current object count: "
- << m_object_map.size() << " != " << num_objs << dendl;
- invalidate(snap_id, false);
-
- // correct the size issue so future IO can keep the object map in sync
- librados::ObjectWriteOperation op;
- if (snap_id == CEPH_NOSNAP) {
- rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "",
- "");
- }
- cls_client::object_map_resize(&op, num_objs, OBJECT_NONEXISTENT);
+void ObjectMap::open(Context *on_finish) {
+ object_map::RefreshRequest<> *req = new object_map::RefreshRequest<>(
+ m_image_ctx, &m_object_map, m_snap_id, on_finish);
+ req->send();
+}
- r = m_image_ctx.md_ctx.operate(oid, &op);
- if (r == 0) {
- object_map::ResizeRequest::resize(&m_object_map, num_objs,
- OBJECT_NONEXISTENT);
- }
- } else if (m_object_map.size() > num_objs) {
- // resize op might have been interrupted
- ldout(cct, 1) << "object map larger than current object count: "
- << m_object_map.size() << " != " << num_objs << dendl;
- }
+void ObjectMap::lock(Context *on_finish) {
+ assert(m_snap_id == CEPH_NOSNAP);
+ object_map::LockRequest<> *req = new object_map::LockRequest<>(
+ m_image_ctx, on_finish);
+ req->send();
}
-Context* ObjectMap::refresh(uint64_t snap_id, Context *on_finish) {
- object_map::RefreshRequest<> *req = new object_map::RefreshRequest<>(
- m_image_ctx, &m_object_map, snap_id, on_finish);
+void ObjectMap::unlock(Context *on_finish) {
+ assert(m_snap_id == CEPH_NOSNAP);
+ object_map::UnlockRequest<> *req = new object_map::UnlockRequest<>(
+ m_image_ctx, on_finish);
req->send();
- return new C_ApplyRefresh(req);
}
void ObjectMap::rollback(uint64_t snap_id, Context *on_finish) {
void ObjectMap::snapshot_add(uint64_t snap_id, Context *on_finish) {
assert(m_image_ctx.snap_lock.is_locked());
assert((m_image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0);
+ assert(snap_id != CEPH_NOSNAP);
object_map::SnapshotCreateRequest *req =
new object_map::SnapshotCreateRequest(m_image_ctx, &m_object_map, snap_id,
req->send();
}
-void ObjectMap::aio_save(Context *on_finish)
-{
- assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP));
+void ObjectMap::aio_save(Context *on_finish) {
assert(m_image_ctx.owner_lock.is_locked());
+ assert(m_image_ctx.snap_lock.is_locked());
+ assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
+ m_image_ctx.snap_lock));
RWLock::RLocker object_map_locker(m_image_ctx.object_map_lock);
librados::ObjectWriteOperation op;
void ObjectMap::aio_resize(uint64_t new_size, uint8_t default_object_state,
Context *on_finish) {
- assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP));
assert(m_image_ctx.owner_lock.is_locked());
+ assert(m_image_ctx.snap_lock.is_locked());
+ assert(m_image_ctx.test_features(RBD_FEATURE_OBJECT_MAP,
+ m_image_ctx.snap_lock));
assert(m_image_ctx.image_watcher != NULL);
assert(m_image_ctx.exclusive_lock == nullptr ||
m_image_ctx.exclusive_lock->is_lock_owner());
req->send();
}
-void ObjectMap::invalidate(uint64_t snap_id, bool force) {
- assert(m_image_ctx.snap_lock.is_wlocked());
- assert(m_image_ctx.object_map_lock.is_wlocked());
- uint64_t flags;
- m_image_ctx.get_flags(snap_id, &flags);
- if ((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0) {
- return;
- }
-
- // TODO remove once all methods are async
- C_SaferCond cond_ctx;
- object_map::InvalidateRequest<> *req = new object_map::InvalidateRequest<>(
- m_image_ctx, m_snap_id, force, &cond_ctx);
- req->send();
-
- cond_ctx.wait();
-}
-
} // namespace librbd