From: Jason Dillaman Date: Fri, 5 Jan 2018 02:50:02 +0000 (-0500) Subject: librbd: track new operation features within image X-Git-Tag: wip-pdonnell-testing-20180317.202121~574^2~2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=209f6fc5a44e2d068ce0dd8b3e9a25ee700ad0e0;p=ceph-ci.git librbd: track new operation features within image This will initially be utilized to restrict older clients from performing operations against an image if (1) it doesn't support the new feature bit, or (2) doesn't support the specific enabled op feature. Signed-off-by: Jason Dillaman --- diff --git a/src/cls/rbd/cls_rbd.cc b/src/cls/rbd/cls_rbd.cc index e95c31c2f65..0bb3778fbac 100644 --- a/src/cls/rbd/cls_rbd.cc +++ b/src/cls/rbd/cls_rbd.cc @@ -350,6 +350,12 @@ int set_features(cls_method_context_t hctx, bufferlist *in, bufferlist *out) return r; } + if ((mask & RBD_FEATURES_INTERNAL) != 0ULL) { + CLS_ERR("Attempting to set internal feature: %" PRIu64, + static_cast(mask & RBD_FEATURES_INTERNAL)); + return -EINVAL; + } + // newer clients might attempt to mask off features we don't support mask &= RBD_FEATURES_ALL; @@ -920,6 +926,112 @@ int set_flags(cls_method_context_t hctx, bufferlist *in, bufferlist *out) return 0; } +/** + * Get the operation-based image features + * + * Input: + * + * Output: + * @param bitmask of enabled op features (uint64_t) + * @returns 0 on success, negative error code on failure + */ +int op_features_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + CLS_LOG(20, "op_features_get"); + + uint64_t op_features = 0; + int r = read_key(hctx, "op_features", &op_features); + if (r < 0 && r != -ENOENT) { + CLS_ERR("failed to read op features off disk: %s", cpp_strerror(r).c_str()); + return r; + } + + encode(op_features, *out); + return 0; +} + +/** + * Set the operation-based image features + * + * Input: + * @param op_features image op features + * @param mask image op feature mask + * + * Output: + * none + * + * @returns 0 on success, negative error code upon failure + */ +int op_features_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + uint64_t op_features; + uint64_t mask; + bufferlist::iterator iter = in->begin(); + try { + decode(op_features, iter); + decode(mask, iter); + } catch (const buffer::error &err) { + return -EINVAL; + } + + uint64_t unsupported_op_features = (mask & ~RBD_OPERATION_FEATURES_ALL); + if (unsupported_op_features != 0ULL) { + CLS_ERR("unsupported op features: %" PRIu64, unsupported_op_features); + return -EINVAL; + } + + uint64_t orig_features; + int r = read_key(hctx, "features", &orig_features); + if (r < 0) { + CLS_ERR("failed to read features off disk: %s", cpp_strerror(r).c_str()); + return r; + } + + uint64_t orig_op_features = 0; + r = read_key(hctx, "op_features", &orig_op_features); + if (r < 0 && r != -ENOENT) { + CLS_ERR("Could not read op features off disk: %s", cpp_strerror(r).c_str()); + return r; + } + + op_features = (orig_op_features & ~mask) | (op_features & mask); + CLS_LOG(10, "set_features op_features=%" PRIu64 " orig_op_features=%" PRIu64, + op_features, orig_op_features); + + uint64_t features = orig_features; + if (op_features == 0ULL) { + features &= ~RBD_FEATURE_OPERATIONS; + + r = cls_cxx_map_remove_key(hctx, "op_features"); + if (r == -ENOENT) { + r = 0; + } + } else { + features |= RBD_FEATURE_OPERATIONS; + + bufferlist bl; + encode(op_features, bl); + r = cls_cxx_map_set_val(hctx, "op_features", &bl); + } + + if (r < 0) { + CLS_ERR("error updating op features: %s", cpp_strerror(r).c_str()); + return r; + } + + if (features != orig_features) { + bufferlist bl; + encode(features, bl); + r = cls_cxx_map_set_val(hctx, "features", &bl); + if (r < 0) { + CLS_ERR("error updating features: %s", cpp_strerror(r).c_str()); + return r; + } + } + + return 0; +} + /** * get the current parent, if any * @@ -5536,6 +5648,8 @@ CLS_INIT(rbd) cls_method_handle_t h_get_create_timestamp; cls_method_handle_t h_get_flags; cls_method_handle_t h_set_flags; + cls_method_handle_t h_op_features_get; + cls_method_handle_t h_op_features_set; cls_method_handle_t h_remove_parent; cls_method_handle_t h_add_child; cls_method_handle_t h_remove_child; @@ -5697,6 +5811,11 @@ CLS_INIT(rbd) cls_register_cxx_method(h_class, "set_flags", CLS_METHOD_RD | CLS_METHOD_WR, set_flags, &h_set_flags); + cls_register_cxx_method(h_class, "op_features_get", CLS_METHOD_RD, + op_features_get, &h_op_features_get); + cls_register_cxx_method(h_class, "op_features_set", + CLS_METHOD_RD | CLS_METHOD_WR, + op_features_set, &h_op_features_set); cls_register_cxx_method(h_class, "metadata_list", CLS_METHOD_RD, metadata_list, &h_metadata_list); diff --git a/src/cls/rbd/cls_rbd_client.cc b/src/cls/rbd/cls_rbd_client.cc index 68a1d3dab19..16b9d552152 100644 --- a/src/cls/rbd/cls_rbd_client.cc +++ b/src/cls/rbd/cls_rbd_client.cc @@ -403,6 +403,56 @@ namespace librbd { op->exec("rbd", "set_flags", inbl); } + void op_features_get_start(librados::ObjectReadOperation *op) + { + bufferlist in_bl; + op->exec("rbd", "op_features_get", in_bl); + } + + int op_features_get_finish(bufferlist::iterator *it, uint64_t *op_features) + { + try { + decode(*op_features, *it); + } catch (const buffer::error &err) { + return -EBADMSG; + } + return 0; + } + + int op_features_get(librados::IoCtx *ioctx, const std::string &oid, + uint64_t *op_features) + { + librados::ObjectReadOperation op; + op_features_get_start(&op); + + bufferlist out_bl; + int r = ioctx->operate(oid, &op, &out_bl); + if (r < 0) { + return r; + } + + bufferlist::iterator it = out_bl.begin(); + return op_features_get_finish(&it, op_features); + } + + void op_features_set(librados::ObjectWriteOperation *op, + uint64_t op_features, uint64_t mask) + { + bufferlist inbl; + encode(op_features, inbl); + encode(mask, inbl); + op->exec("rbd", "op_features_set", inbl); + } + + int op_features_set(librados::IoCtx *ioctx, const std::string &oid, + uint64_t op_features, uint64_t mask) + { + librados::ObjectWriteOperation op; + op_features_set(&op, op_features, mask); + + return ioctx->operate(oid, &op); + } + int remove_parent(librados::IoCtx *ioctx, const std::string &oid) { librados::ObjectWriteOperation op; diff --git a/src/cls/rbd/cls_rbd_client.h b/src/cls/rbd/cls_rbd_client.h index 14ce01c437f..4b3fbf9874c 100644 --- a/src/cls/rbd/cls_rbd_client.h +++ b/src/cls/rbd/cls_rbd_client.h @@ -89,6 +89,14 @@ namespace librbd { vector *snap_flags); void set_flags(librados::ObjectWriteOperation *op, snapid_t snap_id, uint64_t flags, uint64_t mask); + void op_features_get_start(librados::ObjectReadOperation *op); + int op_features_get_finish(bufferlist::iterator *it, uint64_t *op_features); + int op_features_get(librados::IoCtx *ioctx, const std::string &oid, + uint64_t *op_features); + void op_features_set(librados::ObjectWriteOperation *op, + uint64_t op_features, uint64_t mask); + int op_features_set(librados::IoCtx *ioctx, const std::string &oid, + uint64_t op_features, uint64_t mask); int remove_parent(librados::IoCtx *ioctx, const std::string &oid); void remove_parent(librados::ObjectWriteOperation *op); int add_child(librados::IoCtx *ioctx, const std::string &oid, diff --git a/src/common/options.cc b/src/common/options.cc index e7d767bb9ea..9efd3d8ee16 100644 --- a/src/common/options.cc +++ b/src/common/options.cc @@ -5732,7 +5732,7 @@ static std::vector