From f87c441f6891e5e72d5e712d9a19e45a1b9a97eb Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 15 Jun 2012 10:42:49 -0700 Subject: [PATCH] cls_rbd: check for LAYERING feature for parent methods You need to set the feature on the image before you can use these methods. We *could* allow get_parent, but that just means they'll get ENOENT instead of ENOEXEC, and the latter is more informative. Signed-off-by: Sage Weil --- src/cls_rbd.cc | 34 ++++++++++++++++++++++++++++++++++ src/include/rbd_types.h | 6 ++++-- src/test/rbd/test_cls_rbd.cc | 11 +++++++++-- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/cls_rbd.cc b/src/cls_rbd.cc index 8685ae8516320..8f0099b514ea0 100644 --- a/src/cls_rbd.cc +++ b/src/cls_rbd.cc @@ -348,6 +348,28 @@ int get_features(cls_method_context_t hctx, bufferlist *in, bufferlist *out) return 0; } +/** + * check that given feature(s) are set + * + * @param hctx context + * @param need features needed + * @return 0 if features are set, negative error (like ENOEXEC) otherwise + */ +int require_feature(cls_method_context_t hctx, uint64_t need) +{ + uint64_t features; + int r = read_key(hctx, "features", &features); + if (r == -ENOENT) // this implies it's an old-style image with no features + return -ENOEXEC; + if (r < 0) + return r; + if ((features & need) != need) { + CLS_LOG(10, "require_feature missing feature %llx, have %llx", need, features); + return -ENOEXEC; + } + return 0; +} + /** * Input: * @param snap_id which snapshot to query, or CEPH_NOSNAP (uint64_t) @@ -717,6 +739,10 @@ int get_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) CLS_LOG(20, "get_parent snap_id=%llu", snap_id); + r = require_feature(hctx, RBD_FEATURE_LAYERING); + if (r < 0) + return r; + cls_rbd_parent parent; if (snap_id == CEPH_NOSNAP) { r = read_key(hctx, "parent", &parent); @@ -772,6 +798,10 @@ int set_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) if (r < 0) return r; + r = require_feature(hctx, RBD_FEATURE_LAYERING); + if (r < 0) + return r; + CLS_LOG(20, "set_parent pool=%lld id=%s snapid=%llu size=%llu", pool, id.c_str(), snapid.val, size); @@ -818,6 +848,10 @@ int remove_parent(cls_method_context_t hctx, bufferlist *in, bufferlist *out) if (r < 0) return r; + r = require_feature(hctx, RBD_FEATURE_LAYERING); + if (r < 0) + return r; + cls_rbd_parent parent; r = read_key(hctx, "parent", &parent); if (r < 0) diff --git a/src/include/rbd_types.h b/src/include/rbd_types.h index a91ca84a3074d..2cd5fedf5aed6 100644 --- a/src/include/rbd_types.h +++ b/src/include/rbd_types.h @@ -31,8 +31,10 @@ #define RBD_HEADER_PREFIX "rbd_header." #define RBD_DATA_PREFIX "rbd_data." -#define RBD_FEATURES_INCOMPATIBLE 0 -#define RBD_FEATURES_ALL 0 +#define RBD_FEATURE_LAYERING 1 + +#define RBD_FEATURES_INCOMPATIBLE (RBD_FEATURE_LAYERING) +#define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING) /* * old-style rbd image 'foo' consists of objects diff --git a/src/test/rbd/test_cls_rbd.cc b/src/test/rbd/test_cls_rbd.cc index d94bda8ccb68c..5fc5fee4900f5 100644 --- a/src/test/rbd/test_cls_rbd.cc +++ b/src/test/rbd/test_cls_rbd.cc @@ -285,8 +285,15 @@ TEST(cls_rbd, parents) uint64_t size; ASSERT_EQ(-ENOENT, get_parent(&ioctx, "doesnotexist", CEPH_NOSNAP, &pool, &parent, &snapid, &size)); - - ASSERT_EQ(0, create_image(&ioctx, "foo", 1000, 22, 0, "foo.")); + + // old image should fail + ASSERT_EQ(0, create_image(&ioctx, "old", 1000, 22, 0, "old_blk.")); + ASSERT_EQ(-ENOEXEC, get_parent(&ioctx, "old", CEPH_NOSNAP, &pool, &parent, &snapid, &size)); + ASSERT_EQ(-ENOEXEC, set_parent(&ioctx, "old", -1, "parent", 3, 10<<20)); + ASSERT_EQ(-ENOEXEC, remove_parent(&ioctx, "old")); + + // new image will work + ASSERT_EQ(0, create_image(&ioctx, "foo", 1000, 22, RBD_FEATURE_LAYERING, "foo.")); ASSERT_EQ(-ENOENT, get_parent(&ioctx, "foo", CEPH_NOSNAP, &pool, &parent, &snapid, &size)); ASSERT_EQ(-ENOENT, get_parent(&ioctx, "foo", 123, &pool, &parent, &snapid, &size)); -- 2.39.5