From: Josh Durgin Date: Sat, 9 Mar 2013 02:57:24 +0000 (-0800) Subject: librbd: invalidate cache when flattening X-Git-Tag: v0.59~17^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=46e8fc00b2dc8eb17d8777b6ef5ad1cfcc389cea;p=ceph.git librbd: invalidate cache when flattening The cache stores which objects don't exist. Flatten bypasses the cache when doing its copyups, so when it is done the -ENOENT from the cache is treated as zeroes instead of 'need to read from parent'. Clients that have the image open need to forgot about the cached non-existent objects as well. Do this during ictx_refresh, while the parent_lock is held exclusively so no new reads from the parent can happen until the updated parent metadata is visible, so no new reads from the parent will occur. Signed-off-by: Josh Durgin --- diff --git a/src/librbd/ImageCtx.cc b/src/librbd/ImageCtx.cc index 99641ad54b46..983aae251576 100644 --- a/src/librbd/ImageCtx.cc +++ b/src/librbd/ImageCtx.cc @@ -533,6 +533,14 @@ namespace librbd { lderr(cct) << "could not release all objects from cache" << dendl; } + void ImageCtx::clear_nonexistence_cache() { + if (!object_cacher) + return; + cache_lock.Lock(); + object_cacher->clear_nonexistence(object_set); + cache_lock.Unlock(); + } + int ImageCtx::register_watch() { assert(!wctx); wctx = new WatchCtx(this); diff --git a/src/librbd/ImageCtx.h b/src/librbd/ImageCtx.h index 53f6f95e5bef..42910c86364c 100644 --- a/src/librbd/ImageCtx.h +++ b/src/librbd/ImageCtx.h @@ -132,6 +132,7 @@ namespace librbd { int flush_cache(); void shutdown_cache(); void invalidate_cache(); + void clear_nonexistence_cache(); int register_watch(); void unregister_watch(); size_t parent_io_len(uint64_t offset, size_t length, diff --git a/src/librbd/internal.cc b/src/librbd/internal.cc index f9509435f885..450e5d9bfe66 100644 --- a/src/librbd/internal.cc +++ b/src/librbd/internal.cc @@ -1546,6 +1546,7 @@ reprotect_and_return_err: ictx->get_parent_pool_id(ictx->snap_id) || ictx->parent->id != ictx->get_parent_image_id(ictx->snap_id) || ictx->parent->snap_id != ictx->get_parent_snap_id(ictx->snap_id)) { + ictx->clear_nonexistence_cache(); close_image(ictx->parent); ictx->parent = NULL; } diff --git a/src/test/pybind/test_rbd.py b/src/test/pybind/test_rbd.py index c8b399bbb24c..821d721ebf17 100644 --- a/src/test/pybind/test_rbd.py +++ b/src/test/pybind/test_rbd.py @@ -655,3 +655,23 @@ class TestClone(object): def test_flatten_larger_order(self): self.check_flatten_with_order(IMG_ORDER + 2) + + def test_flatten_drops_cache(self): + global ioctx + global features + self.rbd.clone(ioctx, IMG_NAME, 'snap1', ioctx, 'clone2', + features, IMG_ORDER) + with Image(ioctx, 'clone2') as clone: + with Image(ioctx, 'clone2') as clone2: + # cache object non-existence + data = clone.read(IMG_SIZE / 2, 256) + clone2_data = clone2.read(IMG_SIZE / 2, 256) + eq(data, clone2_data) + clone.flatten() + assert_raises(ImageNotFound, clone.parent_info) + assert_raises(ImageNotFound, clone2.parent_info) + after_flatten = clone.read(IMG_SIZE / 2, 256) + eq(data, after_flatten) + after_flatten = clone2.read(IMG_SIZE / 2, 256) + eq(data, after_flatten) + self.rbd.remove(ioctx, 'clone2')