From 3f020443c8d92e61d8593049147a79a6696c9c93 Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Thu, 24 Jul 2014 15:29:40 -0700 Subject: [PATCH] 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) --- src/librbd/internal.cc | 13 +++++++++++++ src/librbd/internal.h | 1 + src/test/pybind/test_rbd.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index 138ed42164bdf..7394a9ac7d0b8 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -1269,6 +1269,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 723a688cfb5b6..6cf2ca96f4a32 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 6a57ff13c21b7..c9efdff6c31c1 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -808,3 +808,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') -- 2.39.5