int get_features(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
{
uint64_t features, snap_id;
+ bool read_only = false;
bufferlist::iterator iter = in->begin();
try {
::decode(snap_id, iter);
+ if (!iter.end()) {
+ ::decode(read_only, iter);
+ }
} catch (const buffer::error &err) {
return -EINVAL;
}
features = snap.features;
}
- uint64_t incompatible = features & RBD_FEATURES_INCOMPATIBLE;
+ uint64_t incompatible = (read_only ? features & RBD_FEATURES_INCOMPATIBLE :
+ features & RBD_FEATURES_RW_INCOMPATIBLE);
::encode(features, *out);
::encode(incompatible, *out);
}
int get_mutable_metadata(librados::IoCtx *ioctx, const std::string &oid,
- uint64_t *size, uint64_t *features,
+ bool read_only, uint64_t *size, uint64_t *features,
uint64_t *incompatible_features,
map<rados::cls::lock::locker_id_t,
rados::cls::lock::locker_info_t> *lockers,
bufferlist sizebl, featuresbl, parentbl, empty;
snapid_t snap = CEPH_NOSNAP;
::encode(snap, sizebl);
- ::encode(snap, featuresbl);
- ::encode(snap, parentbl);
op.exec("rbd", "get_size", sizebl);
+
+ ::encode(snap, featuresbl);
+ ::encode(read_only, featuresbl);
op.exec("rbd", "get_features", featuresbl);
+
op.exec("rbd", "get_snapcontext", empty);
+
+ ::encode(snap, parentbl);
op.exec("rbd", "get_parent", parentbl);
rados::cls::lock::get_lock_info_start(&op, RBD_LOCK_NAME);
int get_immutable_metadata(librados::IoCtx *ioctx, const std::string &oid,
std::string *object_prefix, uint8_t *order);
int get_mutable_metadata(librados::IoCtx *ioctx, const std::string &oid,
- uint64_t *size, uint64_t *features,
+ bool read_only, uint64_t *size, uint64_t *features,
uint64_t *incompatible_features,
map<rados::cls::lock::locker_id_t,
rados::cls::lock::locker_info_t> *lockers,
#define RBD_FEATURE_STRIPINGV2 (1<<1)
#define RBD_FEATURE_EXCLUSIVE_LOCK (1<<2)
-#define RBD_FEATURES_INCOMPATIBLE (RBD_FEATURE_LAYERING|RBD_FEATURE_STRIPINGV2|\
- RBD_FEATURE_EXCLUSIVE_LOCK)
-#define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING|RBD_FEATURE_STRIPINGV2|\
- RBD_FEATURE_EXCLUSIVE_LOCK)
+#define RBD_FEATURES_INCOMPATIBLE (RBD_FEATURE_LAYERING | \
+ RBD_FEATURE_STRIPINGV2)
+
+#define RBD_FEATURES_RW_INCOMPATIBLE (RBD_FEATURES_INCOMPATIBLE | \
+ RBD_FEATURE_EXCLUSIVE_LOCK)
+
+#define RBD_FEATURES_ALL (RBD_FEATURE_LAYERING | \
+ RBD_FEATURE_STRIPINGV2 | \
+ RBD_FEATURE_EXCLUSIVE_LOCK)
#endif
} else {
do {
uint64_t incompatible_features;
+ bool read_only = ictx->read_only || ictx->snap_id != CEPH_NOSNAP;
r = cls_client::get_mutable_metadata(&ictx->md_ctx, ictx->header_oid,
+ read_only,
&ictx->size, &ictx->features,
&incompatible_features,
&ictx->lockers,
using ::librbd::cls_client::get_stripe_unit_count;
using ::librbd::cls_client::set_stripe_unit_count;
using ::librbd::cls_client::old_snapshot_add;
+using ::librbd::cls_client::get_mutable_metadata;
static char *random_buf(size_t len)
{
ioctx.close();
}
+
+TEST_F(TestClsRbd, get_mutable_metadata_features)
+{
+ librados::IoCtx ioctx;
+ ASSERT_EQ(0, _rados.ioctx_create(_pool_name.c_str(), ioctx));
+
+ string oid = get_temp_image_name();
+ ASSERT_EQ(0, create_image(&ioctx, oid, 10, 22, RBD_FEATURE_EXCLUSIVE_LOCK,
+ oid));
+
+ uint64_t size, features, incompatible_features;
+ std::map<rados::cls::lock::locker_id_t,
+ rados::cls::lock::locker_info_t> lockers;
+ bool exclusive_lock;
+ std::string lock_tag;
+ ::SnapContext snapc;
+ parent_info parent;
+
+ ASSERT_EQ(0, get_mutable_metadata(&ioctx, oid, true, &size, &features,
+ &incompatible_features, &lockers,
+ &exclusive_lock, &lock_tag, &snapc,
+ &parent));
+ ASSERT_EQ(static_cast<uint64_t>(RBD_FEATURE_EXCLUSIVE_LOCK), features);
+ ASSERT_EQ(0U, incompatible_features);
+
+ ASSERT_EQ(0, get_mutable_metadata(&ioctx, oid, false, &size, &features,
+ &incompatible_features, &lockers,
+ &exclusive_lock, &lock_tag, &snapc,
+ &parent));
+ ASSERT_EQ(static_cast<uint64_t>(RBD_FEATURE_EXCLUSIVE_LOCK), features);
+ ASSERT_EQ(static_cast<uint64_t>(RBD_FEATURE_EXCLUSIVE_LOCK),
+ incompatible_features);
+
+ ioctx.close();
+}