When a snapshot is added, mark all HEAD image objects that exist as clean.
When a snapshot is removed, mark all clean objects that were dirty in the
deleted snapshot as dirty.
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
snap_ids.insert(pair<string, snap_t>(in_snap_name, id));
}
+ void ImageCtx::rm_snap(string in_snap_name, snap_t id)
+ {
+ assert(snap_lock.is_wlocked());
+ snaps.erase(std::remove(snaps.begin(), snaps.end(), id), snaps.end());
+ snap_info.erase(id);
+ snap_ids.erase(in_snap_name);
+ }
+
uint64_t ImageCtx::get_image_size(snap_t in_snap_id) const
{
assert(snap_lock.is_locked());
void add_snap(std::string in_snap_name, librados::snap_t id,
uint64_t in_size, parent_info parent,
uint8_t protection_status, uint64_t flags);
+ void rm_snap(std::string in_snap_name, librados::snap_t id);
uint64_t get_image_size(librados::snap_t in_snap_id) const;
bool test_features(uint64_t test_features) const;
int get_flags(librados::snap_t in_snap_id, uint64_t *flags) const;
return true;
}
uint8_t state = (*this)[object_no];
- bool exists = (state == OBJECT_EXISTS || state == OBJECT_PENDING);
+ bool exists = (state != OBJECT_NONEXISTENT);
ldout(m_image_ctx.cct, 20) << &m_image_ctx << " object_may_exist: "
<< "object_no=" << object_no << " r=" << exists
<< dendl;
lderr(cct) << "unable to load object map: " << cpp_strerror(r)
<< dendl;
invalidate(CEPH_NOSNAP);
+ return;
}
std::string snap_oid(object_map_name(m_image_ctx.id, snap_id));
lderr(cct) << "unable to snapshot object map '" << snap_oid << "': "
<< cpp_strerror(r) << dendl;
invalidate(snap_id);
+ return;
+ }
+
+ if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) {
+ librados::ObjectWriteOperation op;
+ rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "", "");
+ cls_client::object_map_snap_add(&op);
+ r = m_image_ctx.md_ctx.operate(oid, &op);
+ if (r < 0) {
+ lderr(cct) << "unable to snapshot object map: " << cpp_strerror(r)
+ << dendl;
+ invalidate(CEPH_NOSNAP);
+ return;
+ }
+
+ for (uint64_t i = 0; i < m_object_map.size(); ++i) {
+ if (m_object_map[i] == OBJECT_EXISTS) {
+ m_object_map[i] = OBJECT_EXISTS_CLEAN;
+ }
+ }
}
}
int ObjectMap::snapshot_remove(uint64_t snap_id) {
+ assert(m_image_ctx.snap_lock.is_wlocked());
+ assert(snap_id != CEPH_NOSNAP);
+ CephContext *cct = m_image_ctx.cct;
+
+ int r;
+ if ((m_image_ctx.features & RBD_FEATURE_FAST_DIFF) != 0) {
+ RWLock::WLocker l(m_image_ctx.object_map_lock);
+
+ uint64_t next_snap_id = CEPH_NOSNAP;
+ std::map<librados::snap_t, SnapInfo>::const_iterator it =
+ m_image_ctx.snap_info.find(snap_id);
+ assert(it != m_image_ctx.snap_info.end());
+
+ ++it;
+ if (it != m_image_ctx.snap_info.end()) {
+ next_snap_id = it->first;
+ }
+
+ ceph::BitVector<2> snap_object_map;
+ std::string snap_oid(object_map_name(m_image_ctx.id, snap_id));
+ r = cls_client::object_map_load(&m_image_ctx.md_ctx, snap_oid,
+ &snap_object_map);
+ if (r < 0) {
+ lderr(cct) << "error loading snapshot object map: " << cpp_strerror(r)
+ << dendl;
+ }
+
+ if (r == 0) {
+ uint64_t flags;
+ m_image_ctx.get_flags(snap_id, &flags);
+ if ((flags & RBD_FLAG_OBJECT_MAP_INVALID) != 0) {
+ invalidate(next_snap_id);
+ r = -EINVAL;
+ }
+ }
+
+ if (r == 0) {
+ std::string oid(object_map_name(m_image_ctx.id, next_snap_id));
+ librados::ObjectWriteOperation op;
+ if (next_snap_id == CEPH_NOSNAP) {
+ rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME, LOCK_EXCLUSIVE, "",
+ "");
+ }
+ cls_client::object_map_snap_remove(&op, snap_object_map);
+
+ r = m_image_ctx.md_ctx.operate(oid, &op);
+ if (r < 0) {
+ lderr(cct) << "unable to remove object map snapshot: "
+ << cpp_strerror(r) << dendl;
+ invalidate(next_snap_id);
+ }
+ }
+
+ if (r == 0 && next_snap_id == CEPH_NOSNAP) {
+ for (uint64_t i = 0; i < m_object_map.size(); ++i) {
+ if (m_object_map[i] == OBJECT_EXISTS_CLEAN &&
+ (i >= snap_object_map.size() ||
+ snap_object_map[i] == OBJECT_EXISTS)) {
+ m_object_map[i] = OBJECT_EXISTS;
+ }
+ }
+ }
+ }
+
std::string oid(object_map_name(m_image_ctx.id, snap_id));
- int r = m_image_ctx.md_ctx.remove(oid);
+ r = m_image_ctx.md_ctx.remove(oid);
if (r < 0 && r != -ENOENT) {
return r;
}
RWLock::RLocker md_locker(ictx->md_lock);
snap_t snap_id;
{
- // block for purposes of auto-destruction of snap_locker on early return
- RWLock::RLocker snap_locker(ictx->snap_lock);
+ RWLock::WLocker snap_locker(ictx->snap_lock);
snap_id = ictx->get_snap_id(snap_name);
- if (snap_id == CEPH_NOSNAP)
- return -ENOENT;
+ if (snap_id == CEPH_NOSNAP) {
+ return -ENOENT;
+ }
- parent_spec our_pspec;
- RWLock::RLocker parent_locker(ictx->parent_lock);
- r = ictx->get_parent_spec(snap_id, &our_pspec);
+ r = ictx->object_map.snapshot_remove(snap_id);
if (r < 0) {
- lderr(ictx->cct) << "snap_remove: can't get parent spec" << dendl;
- return r;
+ lderr(ictx->cct) << "snap_remove: failed to remove snapshot object map"
+ << dendl;
+ return r;
}
- if (ictx->parent_md.spec != our_pspec &&
- (scan_for_parents(ictx, our_pspec, snap_id) == -ENOENT)) {
- r = cls_client::remove_child(&ictx->md_ctx, RBD_CHILDREN,
- our_pspec, ictx->id);
- if (r < 0 && r != -ENOENT) {
- lderr(ictx->cct) << "snap_remove: failed to deregister from parent "
- << "image" << dendl;
+ {
+ parent_spec our_pspec;
+ RWLock::RLocker parent_locker(ictx->parent_lock);
+ r = ictx->get_parent_spec(snap_id, &our_pspec);
+ if (r < 0) {
+ lderr(ictx->cct) << "snap_remove: can't get parent spec" << dendl;
return r;
}
- }
- }
- r = ictx->object_map.snapshot_remove(snap_id);
- if (r < 0) {
- lderr(ictx->cct) << "snap_remove: failed to remove snapshot object map"
- << dendl;
- return 0;
- }
+ if (ictx->parent_md.spec != our_pspec &&
+ (scan_for_parents(ictx, our_pspec, snap_id) == -ENOENT)) {
+ r = cls_client::remove_child(&ictx->md_ctx, RBD_CHILDREN,
+ our_pspec, ictx->id);
+ if (r < 0 && r != -ENOENT) {
+ lderr(ictx->cct) << "snap_remove: failed to deregister from parent "
+ << "image" << dendl;
+ return r;
+ }
+ }
+ }
- r = rm_snap(ictx, snap_name);
- if (r < 0) {
- return r;
+ r = rm_snap(ictx, snap_name, snap_id);
+ if (r < 0) {
+ return r;
+ }
}
r = ictx->data_ctx.selfmanaged_snap_remove(snap_id);
if (r < 0) {
+ lderr(ictx->cct) << "snap_remove: failed to remove RADOS snapshot"
+ << dendl;
return r;
}
return 0;
}
- int rm_snap(ImageCtx *ictx, const char *snap_name)
+ int rm_snap(ImageCtx *ictx, const char *snap_name, uint64_t snap_id)
{
+ assert(ictx->snap_lock.is_wlocked());
+
int r;
if (ictx->old_format) {
r = cls_client::old_snapshot_remove(&ictx->md_ctx,
ictx->header_oid, snap_name);
} else {
- RWLock::RLocker l(ictx->snap_lock);
- r = cls_client::snapshot_remove(&ictx->md_ctx,
- ictx->header_oid,
- ictx->get_snap_id(snap_name));
+ r = cls_client::snapshot_remove(&ictx->md_ctx, ictx->header_oid, snap_id);
+ if (r == 0) {
+ ictx->rm_snap(snap_name, snap_id);
+ }
}
if (r < 0) {
int snap_is_protected(ImageCtx *ictx, const char *snap_name,
bool *is_protected);
int add_snap(ImageCtx *ictx, const char *snap_name);
- int rm_snap(ImageCtx *ictx, const char *snap_name);
+ int rm_snap(ImageCtx *ictx, const char *snap_name, uint64_t snap_id);
int refresh_parent(ImageCtx *ictx);
int ictx_check(ImageCtx *ictx);
int ictx_refresh(ImageCtx *ictx);