From: Josh Durgin Date: Tue, 26 Jun 2012 20:47:53 +0000 (-0700) Subject: cls_rbd: add {get,set}_id methods X-Git-Tag: v0.50~104^2~12 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=5ae6e71fcb7720dd0509bf170789a9d6172477f3;p=ceph.git cls_rbd: add {get,set}_id methods These will be used on a new rbd id object to provide a level of indirection so that header objects don't need to move when an image is renamed. Signed-off-by: Josh Durgin --- diff --git a/src/cls_rbd.cc b/src/cls_rbd.cc index ae178e14cb63..64d783ae6be0 100644 --- a/src/cls_rbd.cc +++ b/src/cls_rbd.cc @@ -64,6 +64,8 @@ cls_method_handle_t h_lock_image_shared; cls_method_handle_t h_unlock_image; cls_method_handle_t h_break_lock; cls_method_handle_t h_list_locks; +cls_method_handle_t h_get_id; +cls_method_handle_t h_set_id; cls_method_handle_t h_old_snapshots_list; cls_method_handle_t h_old_snapshot_add; cls_method_handle_t h_old_snapshot_remove; @@ -150,6 +152,17 @@ static int read_key(cls_method_context_t hctx, const string &key, T *out) return 0; } +static bool is_valid_id(const string &id) { + if (!id.size()) + return false; + for (size_t i = 0; i < id.size(); ++i) { + if (!isalnum(id[i])) { + return false; + } + } + return true; +} + /** * Initialize the header with basic metadata. * Extra features may initialize more fields in the future. @@ -1107,6 +1120,88 @@ int get_all_features(cls_method_context_t hctx, bufferlist *in, bufferlist *out) return 0; } +/************************ rbd_id object methods **************************/ + +/** + * Input: + * @param in ignored + * + * Output: + * @param id the id stored in the object + * @returns 0 on success, negative error code on failure + */ +int get_id(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + uint64_t size; + int r = cls_cxx_stat(hctx, &size, NULL); + if (r < 0) + return r; + + if (size == 0) + return -ENOENT; + + bufferlist read_bl; + r = cls_cxx_read(hctx, 0, size, &read_bl); + if (r < 0) { + CLS_ERR("get_id: could not read id: %d", r); + return r; + } + + string id; + try { + bufferlist::iterator iter = read_bl.begin(); + ::decode(id, iter); + } catch (const buffer::error &err) { + return -EIO; + } + + ::encode(id, *out); + return 0; +}; + +/** + * Set the id of an image. The object must already exist. + * + * Input: + * @param id the id of the image, as an alpha-numeric string + * + * Output: + * @returns 0 on success, -EEXIST if the atomic create fails, + * negative error code on other error + */ +int set_id(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + int r = check_exists(hctx); + if (r < 0) + return r; + + string id; + try { + bufferlist::iterator iter = in->begin(); + ::decode(id, iter); + } catch (const buffer::error &err) { + return -EINVAL; + } + + if (!is_valid_id(id)) { + CLS_ERR("set_id: invalid id '%s'", id.c_str()); + return -EINVAL; + } + + uint64_t size; + r = cls_cxx_stat(hctx, &size, NULL); + if (r < 0) + return r; + if (size != 0) + return -EEXIST; + + CLS_LOG(20, "set_id: id=%s", id.c_str()); + + bufferlist write_bl; + ::encode(id, write_bl); + return cls_cxx_write(hctx, 0, write_bl.length(), &write_bl); +} + /****************************** Old format *******************************/ int old_snapshots_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out) @@ -1406,6 +1501,15 @@ void __cls_init() CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, remove_parent, &h_remove_parent); + /* methods for the rbd_id.$image_name objects */ + cls_register_cxx_method(h_class, "get_id", + CLS_METHOD_RD | CLS_METHOD_PUBLIC, + get_id, &h_get_id); + cls_register_cxx_method(h_class, "set_id", + CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC, + set_id, &h_set_id); + + /* methods for the old format */ cls_register_cxx_method(h_class, "snap_list", CLS_METHOD_RD | CLS_METHOD_PUBLIC, diff --git a/src/librbd/cls_rbd_client.cc b/src/librbd/cls_rbd_client.cc index e098719641de..0778ddf29fb7 100644 --- a/src/librbd/cls_rbd_client.cc +++ b/src/librbd/cls_rbd_client.cc @@ -416,5 +416,31 @@ namespace librbd { return ioctx->exec(oid, "rbd", "break_lock", in, out); } + /************************ rbd_id object methods ************************/ + + int get_id(librados::IoCtx *ioctx, const std::string &oid, std::string *id) + { + bufferlist in, out; + int r = ioctx->exec(oid, "rbd", "get_id", in, out); + if (r < 0) + return r; + + bufferlist::iterator iter = out.begin(); + try { + ::decode(*id, iter); + } catch (const buffer::error &err) { + return -EBADMSG; + } + + return 0; + } + + int set_id(librados::IoCtx *ioctx, const std::string &oid, std::string id) + { + bufferlist in, out; + ::encode(*id, in); + return ioctx->exec(oid, "rbd", "set_id", in, out); + } + } // namespace cls_client } // namespace librbd diff --git a/src/librbd/cls_rbd_client.h b/src/librbd/cls_rbd_client.h index 45194af5911e..e606002cfdba 100644 --- a/src/librbd/cls_rbd_client.h +++ b/src/librbd/cls_rbd_client.h @@ -44,8 +44,8 @@ namespace librbd { std::string *parent_image, snapid_t *parent_snap_id, uint64_t *parent_overlap); int set_parent(librados::IoCtx *ioctx, const std::string &oid, - int64_t parent_pool, const std::string& parent_image, snapid_t parent_snap_id, - uint64_t parent_overlap); + int64_t parent_pool, const std::string& parent_image, + snapid_t parent_snap_id, uint64_t parent_overlap); int remove_parent(librados::IoCtx *ioctx, const std::string &oid); int snapshot_add(librados::IoCtx *ioctx, const std::string &oid, snapid_t snap_id, const std::string &snap_name); @@ -73,6 +73,10 @@ namespace librbd { int break_lock(librados::IoCtx *ioctx, const std::string& oid, const std::string &locker, const std::string &cookie); + // operations on rbd_id objects + int get_id(librados::IoCtx *ioctx, const std::string &oid, std::string *id); + int set_id(librados::IoCtx *ioctx, const std::string &oid, std::string id); + // class operations on the old format, kept for // backwards compatability int old_snapshot_add(librados::IoCtx *ioctx, const std::string &oid, diff --git a/src/test/rbd/test_cls_rbd.cc b/src/test/rbd/test_cls_rbd.cc index 2cf91f316a8e..83965448e166 100644 --- a/src/test/rbd/test_cls_rbd.cc +++ b/src/test/rbd/test_cls_rbd.cc @@ -33,6 +33,41 @@ using ::librbd::cls_client::lock_image_exclusive; using ::librbd::cls_client::lock_image_shared; using ::librbd::cls_client::unlock_image; using ::librbd::cls_client::break_lock; +using ::librbd::cls_client::get_id; +using ::librbd::cls_client::set_id; + +TEST(cls_rbd, get_and_set_id) +{ + 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)); + + string oid = "rbd_id_test"; + string id; + string valid_id = "0123abcxyzZYXCBA"; + string invalid_id = ".abc"; + string empty_id; + + ASSERT_EQ(-ENOENT, get_id(&ioctx, oid, &id)); + ASSERT_EQ(-ENOENT, set_id(&ioctx, oid, valid_id)); + + ASSERT_EQ(0, ioctx.create(oid, true)); + ASSERT_EQ(-EINVAL, set_id(&ioctx, oid, invalid_id)); + ASSERT_EQ(-EINVAL, set_id(&ioctx, oid, empty_id)); + ASSERT_EQ(-ENOENT, get_id(&ioctx, oid, &id)); + + ASSERT_EQ(0, set_id(&ioctx, oid, valid_id)); + ASSERT_EQ(-EEXIST, set_id(&ioctx, oid, valid_id)); + ASSERT_EQ(-EEXIST, set_id(&ioctx, oid, valid_id + valid_id)); + ASSERT_EQ(0, get_id(&ioctx, oid, &id)); + ASSERT_EQ(id, valid_id); + + ioctx.close(); + ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); +} TEST(cls_rbd, create) {