ceph_assert(m_image_ctx.snap_lock.is_wlocked());
if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) {
- compute_next_snap_id();
-
- uint64_t flags;
- int r = m_image_ctx.get_flags(m_snap_id, &flags);
+ int r = m_image_ctx.get_flags(m_snap_id, &m_flags);
ceph_assert(r == 0);
- if ((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0) {
- invalidate_next_map();
- } else {
- load_map();
- }
+ compute_next_snap_id();
+ load_map();
} else {
remove_map();
}
r = cls_client::object_map_load_finish(&it, &m_snap_object_map);
}
if (r == -ENOENT) {
+ // implies we have already deleted this snapshot and handled the
+ // necessary fast-diff cleanup
complete(0);
return;
} else if (r < 0) {
}
void SnapshotRemoveRequest::remove_snapshot() {
+ if ((m_flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0) {
+ // snapshot object map exists on disk but is invalid. cannot clean fast-diff
+ // on next snapshot if current snapshot was invalid.
+ RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
+ RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
+ invalidate_next_map();
+ return;
+ }
+
CephContext *cct = m_image_ctx.cct;
std::string oid(ObjectMap<>::object_map_name(m_image_ctx.id, m_next_snap_id));
ldout(cct, 5) << "oid=" << oid << dendl;
ASSERT_EQ(0, ictx->state->refresh_if_required());
uint64_t snap_id = ictx->snap_info.rbegin()->first;
+ auto snap_it = ictx->snap_info.find(snap_id);
+ ASSERT_NE(ictx->snap_info.end(), snap_it);
+ snap_it->second.flags |= RBD_FLAG_OBJECT_MAP_INVALID;
+
expect_load_map(ictx, snap_id, -ENOENT);
ceph::BitVector<2> object_map;
}
ASSERT_EQ(0, cond_ctx.wait());
+ {
+ // shouldn't invalidate the HEAD revision when we fail to load
+ // the already deleted snapshot
+ RWLock::RLocker snap_locker(ictx->snap_lock);
+ uint64_t flags;
+ ASSERT_EQ(0, ictx->get_flags(CEPH_NOSNAP, &flags));
+ ASSERT_EQ(0U, flags & RBD_FLAG_OBJECT_MAP_INVALID);
+ }
+
expect_unlock_exclusive_lock(*ictx);
}