From 2e403ef2c98bb64220060c06b435fb1ffe08294e Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 5 Oct 2012 16:56:33 -0700 Subject: [PATCH] cls_rbd: add stripe_unit, stripe_count metadata * add STRIPINGV2 feature * add stripe_unit, stripe_count keys * add accessor methods Signed-off-by: Sage Weil --- src/cls_rbd.cc | 138 +++++++++++++++++++++++++++++++++++ src/include/rbd/features.h | 7 +- src/librbd/cls_rbd_client.cc | 36 +++++++++ src/librbd/cls_rbd_client.h | 4 + src/test/rbd/test_cls_rbd.cc | 35 ++++++++- 5 files changed, 216 insertions(+), 4 deletions(-) diff --git a/src/cls_rbd.cc b/src/cls_rbd.cc index c4584f9075b..a16c0fb22bb 100644 --- a/src/cls_rbd.cc +++ b/src/cls_rbd.cc @@ -42,6 +42,19 @@ #include "librbd/cls_rbd.h" +/* + * Object keys: + * + * + * + * stripe_unit: size in bytes of the stripe unit. if not present, + * the stripe unit is assumed to match the object size (1 << order). + * + * stripe_count: number of objects to stripe over before looping back. + * if not present or 1, striping is disabled. this is the default. + * + */ + CLS_VER(2,0) CLS_NAME(rbd) @@ -54,6 +67,8 @@ cls_method_handle_t h_get_parent; cls_method_handle_t h_set_parent; cls_method_handle_t h_get_protection_status; cls_method_handle_t h_set_protection_status; +cls_method_handle_t h_get_stripe_unit_count; +cls_method_handle_t h_set_stripe_unit_count; cls_method_handle_t h_remove_parent; cls_method_handle_t h_add_child; cls_method_handle_t h_remove_child; @@ -566,6 +581,123 @@ int set_protection_status(cls_method_context_t hctx, bufferlist *in, return 0; } +/** + * get striping parameters + * + * Input: + * none + * + * Output: + * @param stripe unit (bytes) + * @param stripe count (num objects) + * + * @returns 0 on success + */ +int get_stripe_unit_count(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + int r = check_exists(hctx); + if (r < 0) + return r; + + CLS_LOG(20, "get_stripe_unit_count"); + + r = require_feature(hctx, RBD_FEATURE_STRIPINGV2); + if (r < 0) + return r; + + uint64_t stripe_unit = 0, stripe_count = 0; + r = read_key(hctx, "stripe_unit", &stripe_unit); + if (r == -ENOENT) { + // default to object size + uint8_t order; + r = read_key(hctx, "order", &order); + if (r < 0) { + CLS_ERR("failed to read the order off of disk: %s", strerror(r)); + return -EIO; + } + stripe_unit = 1ull << order; + } + if (r < 0) + return r; + r = read_key(hctx, "stripe_count", &stripe_count); + if (r == -ENOENT) { + // default to 1 + stripe_count = 1; + r = 0; + } + if (r < 0) + return r; + + ::encode(stripe_unit, *out); + ::encode(stripe_count, *out); + return 0; +} + +/** + * set striping parameters + * + * Input: + * @param stripe unit (bytes) + * @param stripe count (num objects) + * + * @returns 0 on success + */ +int set_stripe_unit_count(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + uint64_t stripe_unit, stripe_count; + + bufferlist::iterator iter = in->begin(); + try { + ::decode(stripe_unit, iter); + ::decode(stripe_count, iter); + } catch (const buffer::error &err) { + CLS_LOG(20, "set_stripe_unit_count: invalid decode"); + return -EINVAL; + } + + if (!stripe_count || !stripe_unit) + return -EINVAL; + + int r = check_exists(hctx); + if (r < 0) + return r; + + CLS_LOG(20, "set_stripe_unit_count"); + + r = require_feature(hctx, RBD_FEATURE_STRIPINGV2); + if (r < 0) + return r; + + uint8_t order; + r = read_key(hctx, "order", &order); + if (r < 0) { + CLS_ERR("failed to read the order off of disk: %s", strerror(r)); + return r; + } + if ((1ull << order) % stripe_unit) { + CLS_ERR("stripe unit %lld is not a factor of the object size %lld", stripe_unit, 1ull << order); + return -EINVAL; + } + + bufferlist bl, bl2; + ::encode(stripe_unit, bl); + r = cls_cxx_map_set_val(hctx, "stripe_unit", &bl); + if (r < 0) { + CLS_ERR("error writing stripe_unit metadata: %d", r); + return r; + } + + ::encode(stripe_count, bl2); + r = cls_cxx_map_set_val(hctx, "stripe_count", &bl2); + if (r < 0) { + CLS_ERR("error writing stripe_count metadata: %d", r); + return r; + } + + return 0; +} + + /** * get the current parent, if any * @@ -1935,6 +2067,12 @@ void __cls_init() cls_register_cxx_method(h_class, "get_protection_status", CLS_METHOD_RD, get_protection_status, &h_get_protection_status); + cls_register_cxx_method(h_class, "get_stripe_unit_count", + CLS_METHOD_RD, + get_stripe_unit_count, &h_get_stripe_unit_count); + cls_register_cxx_method(h_class, "set_stripe_unit_count", + CLS_METHOD_RD | CLS_METHOD_WR, + set_stripe_unit_count, &h_set_stripe_unit_count); /* methods for the rbd_children object */ cls_register_cxx_method(h_class, "add_child", diff --git a/src/include/rbd/features.h b/src/include/rbd/features.h index e0bdcde5633..3f1587f3b40 100644 --- a/src/include/rbd/features.h +++ b/src/include/rbd/features.h @@ -1,9 +1,10 @@ #ifndef CEPH_RBD_FEATURES_H #define CEPH_RBD_FEATURES_H -#define RBD_FEATURE_LAYERING 1 +#define RBD_FEATURE_LAYERING (1<<0) +#define RBD_FEATURE_STRIPINGV2 (1<<1) -#define RBD_FEATURES_INCOMPATIBLE (RBD_FEATURE_LAYERING) -#define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING) +#define RBD_FEATURES_INCOMPATIBLE (RBD_FEATURE_LAYERING|RBD_FEATURE_STRIPINGV2) +#define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING|RBD_FEATURE_STRIPINGV2) #endif diff --git a/src/librbd/cls_rbd_client.cc b/src/librbd/cls_rbd_client.cc index 9e02561fca6..060f8a855db 100644 --- a/src/librbd/cls_rbd_client.cc +++ b/src/librbd/cls_rbd_client.cc @@ -476,6 +476,42 @@ namespace librbd { return ioctx->exec(oid, "rbd", "set_protection_status", in, out); } + int get_stripe_unit_count(librados::IoCtx *ioctx, const std::string &oid, + uint64_t *stripe_unit, uint64_t *stripe_count) + { + assert(stripe_unit); + assert(stripe_count); + + librados::ObjectReadOperation op; + bufferlist empty; + op.exec("rbd", "get_stripe_unit_count", empty); + + bufferlist outbl; + int r = ioctx->operate(oid, &op, &outbl); + if (r < 0) + return r; + + try { + bufferlist::iterator iter = outbl.begin(); + ::decode(*stripe_unit, iter); + ::decode(*stripe_count, iter); + } catch (const buffer::error &err) { + return -EBADMSG; + } + + return 0; + } + + int set_stripe_unit_count(librados::IoCtx *ioctx, const std::string &oid, + uint64_t stripe_unit, uint64_t stripe_count) + { + bufferlist in, out; + ::encode(stripe_unit, in); + ::encode(stripe_count, in); + return ioctx->exec(oid, "rbd", "set_stripe_unit_count", in, out); + } + + /************************ rbd_id object methods ************************/ int get_id(librados::IoCtx *ioctx, const std::string &oid, std::string *id) diff --git a/src/librbd/cls_rbd_client.h b/src/librbd/cls_rbd_client.h index e37a485eec3..c1d421a43a8 100644 --- a/src/librbd/cls_rbd_client.h +++ b/src/librbd/cls_rbd_client.h @@ -74,6 +74,10 @@ namespace librbd { snapid_t snap_id, uint8_t *protection_status); int set_protection_status(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, uint8_t protection_status); + int get_stripe_unit_count(librados::IoCtx *ioctx, const std::string &oid, + uint64_t *stripe_unit, uint64_t *stripe_count); + int set_stripe_unit_count(librados::IoCtx *ioctx, const std::string &oid, + uint64_t stripe_unit, uint64_t stripe_count); // operations on rbd_id objects int get_id(librados::IoCtx *ioctx, const std::string &oid, std::string *id); diff --git a/src/test/rbd/test_cls_rbd.cc b/src/test/rbd/test_cls_rbd.cc index b28fd053796..a0ded60ae02 100644 --- a/src/test/rbd/test_cls_rbd.cc +++ b/src/test/rbd/test_cls_rbd.cc @@ -45,6 +45,8 @@ using ::librbd::parent_info; using ::librbd::parent_spec; using ::librbd::cls_client::get_protection_status; using ::librbd::cls_client::set_protection_status; +using ::librbd::cls_client::get_stripe_unit_count; +using ::librbd::cls_client::set_stripe_unit_count; using ::librbd::cls_client::old_snapshot_add; static char *random_buf(size_t len) @@ -855,7 +857,7 @@ TEST(cls_rbd, snapshots) TEST(cls_rbd, snapid_race) { - librados::Rados rados; + librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); @@ -876,3 +878,34 @@ TEST(cls_rbd, snapid_race) ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } + +TEST(cls_rbd, stripingv2) +{ + librados::Rados rados; + librados::IoCtx ioctx; + string pool_name = get_temp_pool_name(); + + ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); + ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); + + ASSERT_EQ(0, create_image(&ioctx, "foo", 10, 22, 0, "foo")); + + uint64_t su = 65536, sc = 12; + ASSERT_EQ(-ENOEXEC, get_stripe_unit_count(&ioctx, "foo", &su, &sc)); + ASSERT_EQ(-ENOEXEC, set_stripe_unit_count(&ioctx, "foo", su, sc)); + + ASSERT_EQ(0, create_image(&ioctx, "bar", 10, 22, RBD_FEATURE_STRIPINGV2, "bar")); + ASSERT_EQ(0, get_stripe_unit_count(&ioctx, "bar", &su, &sc)); + ASSERT_EQ(1ull << 22, su); + ASSERT_EQ(1ull, sc); + su = 8192; + sc = 456; + ASSERT_EQ(0, set_stripe_unit_count(&ioctx, "bar", su, sc)); + su = sc = 0; + ASSERT_EQ(0, get_stripe_unit_count(&ioctx, "bar", &su, &sc)); + ASSERT_EQ(8192ull, su); + ASSERT_EQ(456ull, sc); + + ioctx.close(); + ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); +}