From: Josh Durgin Date: Thu, 24 Jul 2014 22:29:40 +0000 (-0700) Subject: librbd: fix crash using clone of flattened image X-Git-Tag: v0.80.6~6 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a67f9152f128d693d160e5b08f2ac8b8bc83e8e0;p=ceph.git librbd: fix crash using clone of flattened image The crash occurs due to ImageCtx->parent->parent being uninitialized, since the inital open_parent() -> open_image(parent) -> ictx_refresh(parent) occurs before ImageCtx->parent->snap_id is set, so refresh_parent() is not called to open an ImageCtx for the parent of the parent. This leaves the ImageCtx->parent->parent NULL, but the rest of ImageCtx->parent updated to point at the correct parent snapshot. Setting the parent->snap_id earlier has some unintended side effects currently, so for now just call refresh_parent() during open_parent(). This is the easily backportable version of the fix. Further patches can clean up this whole initialization process. Fixes: #8845 Backport: firefly, dumpling Signed-off-by: Josh Durgin (cherry picked from commit 2545e80d274b23b6715f4d8b1f4c6b96182996fb) --- diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 9fc1cc3671c..afa46602532 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -1275,6 +1275,19 @@ reprotect_and_return_err: return r; } ictx->parent->snap_set(ictx->parent->snap_name); + ictx->parent->parent_lock.get_write(); + r = refresh_parent(ictx->parent); + if (r < 0) { + lderr(ictx->cct) << "error refreshing parent snapshot " + << ictx->parent->id << " " + << ictx->parent->snap_name << dendl; + ictx->parent->parent_lock.put_write(); + ictx->parent->snap_lock.put_write(); + close_image(ictx->parent); + ictx->parent = NULL; + return r; + } + ictx->parent->parent_lock.put_write(); ictx->parent->snap_lock.put_write(); return 0; diff --git a/src/librbd/internal.h b/src/librbd/internal.h index 6fb1af46175..1e9fd9a67a0 100644 --- a/src/librbd/internal.h +++ b/src/librbd/internal.h @@ -114,6 +114,7 @@ namespace librbd { bool *is_protected); int add_snap(ImageCtx *ictx, const char *snap_name); int rm_snap(ImageCtx *ictx, const char *snap_name); + int refresh_parent(ImageCtx *ictx); int ictx_check(ImageCtx *ictx); int ictx_refresh(ImageCtx *ictx); int copy(ImageCtx *ictx, IoCtx& dest_md_ctx, const char *destname, diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index bb53081d794..2525732671f 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -815,3 +815,31 @@ class TestClone(object): after_flatten = clone2.read(IMG_SIZE / 2, 256) eq(data, after_flatten) self.rbd.remove(ioctx, 'clone2') + + def test_flatten_multi_level(self): + self.clone.create_snap('snap2') + self.clone.protect_snap('snap2') + self.rbd.clone(ioctx, 'clone', 'snap2', ioctx, 'clone3', features) + self.clone.flatten() + with Image(ioctx, 'clone3') as clone3: + clone3.flatten() + self.clone.unprotect_snap('snap2') + self.clone.remove_snap('snap2') + self.rbd.remove(ioctx, 'clone3') + + def test_resize_flatten_multi_level(self): + self.clone.create_snap('snap2') + self.clone.protect_snap('snap2') + self.rbd.clone(ioctx, 'clone', 'snap2', ioctx, 'clone3', features) + self.clone.resize(1) + orig_data = self.image.read(0, 256) + with Image(ioctx, 'clone3') as clone3: + clone3_data = clone3.read(0, 256) + eq(orig_data, clone3_data) + self.clone.flatten() + with Image(ioctx, 'clone3') as clone3: + clone3_data = clone3.read(0, 256) + eq(orig_data, clone3_data) + self.rbd.remove(ioctx, 'clone3') + self.clone.unprotect_snap('snap2') + self.clone.remove_snap('snap2')