mirror of
https://github.com/ceph/ceph
synced 2025-02-23 11:07:35 +00:00
cls_rbd: remove locking methods
These are unnecessary now that librbd is using the generic cls_lock. Fixes: #2951 Signed-off-by: Josh Durgin <josh.durgin@inktank.com>
This commit is contained in:
parent
8f2a0d91ab
commit
855dff62ae
275
src/cls_rbd.cc
275
src/cls_rbd.cc
@ -65,11 +65,6 @@ cls_method_handle_t h_snapshot_add;
|
||||
cls_method_handle_t h_snapshot_remove;
|
||||
cls_method_handle_t h_get_all_features;
|
||||
cls_method_handle_t h_copyup;
|
||||
cls_method_handle_t h_lock_image_exclusive;
|
||||
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_dir_get_id;
|
||||
@ -85,11 +80,6 @@ cls_method_handle_t h_assign_bid;
|
||||
|
||||
#define RBD_MAX_KEYS_READ 64
|
||||
#define RBD_SNAP_KEY_PREFIX "snapshot_"
|
||||
#define RBD_LOCK_PREFIX "lock_"
|
||||
#define RBD_LOCK_TYPE_KEY RBD_LOCK_PREFIX "type"
|
||||
#define RBD_LOCKS_KEY RBD_LOCK_PREFIX "lockers"
|
||||
#define RBD_LOCK_EXCLUSIVE "exclusive"
|
||||
#define RBD_LOCK_SHARED "shared"
|
||||
#define RBD_DIR_ID_KEY_PREFIX "id_"
|
||||
#define RBD_DIR_NAME_KEY_PREFIX "name_"
|
||||
|
||||
@ -441,256 +431,6 @@ int set_size(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* helper function to add a lock and update disk state.
|
||||
*
|
||||
* Input:
|
||||
* @param lock_type The type of lock, either RBD_LOCK_EXCLUSIVE or RBD_LOCK_SHARED
|
||||
* @param cookie The cookie to set in the lock
|
||||
*
|
||||
* @return 0 on success, or -errno on failure
|
||||
*/
|
||||
int lock_image(cls_method_context_t hctx, string lock_type,
|
||||
const string &cookie)
|
||||
{
|
||||
bool exclusive = lock_type == RBD_LOCK_EXCLUSIVE;
|
||||
|
||||
// see if there's already a locker
|
||||
set<pair<string, string> > lockers;
|
||||
string existing_lock_type;
|
||||
int r = read_key(hctx, RBD_LOCKS_KEY, &lockers);
|
||||
if (r != 0 && r != -ENOENT) {
|
||||
CLS_ERR("Could not read list of current lockers: %s", strerror(r));
|
||||
return r;
|
||||
}
|
||||
if (exclusive && r != -ENOENT && lockers.size()) {
|
||||
CLS_LOG(20, "could not exclusive-lock image, already locked");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (lockers.size() && !exclusive) {
|
||||
// make sure existing lock is a shared lock
|
||||
r = read_key(hctx, RBD_LOCK_TYPE_KEY, &existing_lock_type);
|
||||
if (r != 0) {
|
||||
CLS_ERR("Could not read type of current locks off disk: %s", strerror(r));
|
||||
return r;
|
||||
}
|
||||
if (existing_lock_type != lock_type) {
|
||||
CLS_LOG(20, "cannot take shared lock on image, existing exclusive lock");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
// lock the image
|
||||
entity_inst_t locker;
|
||||
r = cls_get_request_origin(hctx, &locker);
|
||||
assert(r == 0);
|
||||
stringstream locker_stringstream;
|
||||
locker_stringstream << locker;
|
||||
pair<set<pair<string, string> >::iterator, bool> result;
|
||||
result = lockers.insert(make_pair(locker_stringstream.str(), cookie));
|
||||
if (!result.second) { // we didn't insert, because it already existed
|
||||
CLS_LOG(20, "could not insert locker -- already present");
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
map<string, bufferlist> lock_keys;
|
||||
::encode(lockers, lock_keys[RBD_LOCKS_KEY]);
|
||||
::encode(lock_type, lock_keys[RBD_LOCK_TYPE_KEY]);
|
||||
|
||||
r = cls_cxx_map_set_vals(hctx, &lock_keys);
|
||||
if (r != 0) {
|
||||
CLS_ERR("error writing new lock state");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an exclusive lock on an image for the activating client, if possible.
|
||||
*
|
||||
* Input:
|
||||
* @param lock_cookie A string cookie, defined by the locker.
|
||||
*
|
||||
* @returns 0 on success, -EINVAL if it can't decode the lock_cookie,
|
||||
* -EBUSY if the image is already locked, or -errno on (unexpected) failure.
|
||||
*/
|
||||
int lock_image_exclusive(cls_method_context_t hctx,
|
||||
bufferlist *in, bufferlist *out)
|
||||
{
|
||||
CLS_LOG(20, "lock_image_exclusive");
|
||||
string lock_cookie;
|
||||
try {
|
||||
bufferlist::iterator iter = in->begin();
|
||||
::decode(lock_cookie, iter);
|
||||
} catch (const buffer::error &err) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return lock_image(hctx, RBD_LOCK_EXCLUSIVE, lock_cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an exclusive lock on an image, if possible.
|
||||
*
|
||||
* Input:
|
||||
* @param lock_cookie A string cookie, defined by the locker.
|
||||
*
|
||||
* @returns 0 on success, -EINVAL if it can't decode the lock_cookie,
|
||||
* -EBUSY if the image is exclusive locked, or -errno on (unexpected) failure.
|
||||
*/
|
||||
int lock_image_shared(cls_method_context_t hctx,
|
||||
bufferlist *in, bufferlist *out)
|
||||
{
|
||||
CLS_LOG(20, "lock_image_shared");
|
||||
string lock_cookie;
|
||||
try {
|
||||
bufferlist::iterator iter = in->begin();
|
||||
::decode(lock_cookie, iter);
|
||||
} catch (const buffer::error &err) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return lock_image(hctx, RBD_LOCK_SHARED, lock_cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* helper function to remove a lock from on disk and clean up state.
|
||||
*
|
||||
* @param inst The string representation of the locker's entity.
|
||||
* @param cookie The user-defined cookie associated with the lock.
|
||||
*
|
||||
* @return 0 on success, -ENOENT if there is no such lock (either
|
||||
* entity or cookie is wrong), or -errno on other error.
|
||||
*/
|
||||
int remove_lock(cls_method_context_t hctx, const string& inst,
|
||||
const string& cookie)
|
||||
{
|
||||
// get current lockers
|
||||
set<pair<string, string> > lockers;
|
||||
string location = RBD_LOCKS_KEY;
|
||||
int r = read_key(hctx, location, &lockers);
|
||||
if (r != 0) {
|
||||
CLS_ERR("Could not read list of current lockers off disk: %s", strerror(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
// remove named locker from set
|
||||
pair<string, string> locker(inst, cookie);
|
||||
set<pair<string, string> >::iterator iter = lockers.find(locker);
|
||||
if (iter == lockers.end()) { // no such key
|
||||
return -ENOENT;
|
||||
}
|
||||
lockers.erase(iter);
|
||||
|
||||
// encode and write new set to disk
|
||||
bufferlist locker_bufferlist;
|
||||
::encode(lockers, locker_bufferlist);
|
||||
cls_cxx_map_set_val(hctx, location, &locker_bufferlist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock an image which the activating client currently has locked.
|
||||
*
|
||||
* Input:
|
||||
* @param lock_cookie The user-defined cookie associated with the lock.
|
||||
*
|
||||
* @return 0 on success, -EINVAL if it can't decode the cookie, -ENOENT
|
||||
* if there is no such lock (either entity or cookie is wrong), or
|
||||
* -errno on other (unexpected) error.
|
||||
*/
|
||||
int unlock_image(cls_method_context_t hctx,
|
||||
bufferlist *in, bufferlist *out)
|
||||
{
|
||||
CLS_LOG(20, "unlock_image");
|
||||
string lock_cookie;
|
||||
try {
|
||||
bufferlist::iterator iter = in->begin();
|
||||
::decode(lock_cookie, iter);
|
||||
} catch (const buffer::error& err) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entity_inst_t inst;
|
||||
int r = cls_get_request_origin(hctx, &inst);
|
||||
assert(r == 0);
|
||||
stringstream inst_stringstream;
|
||||
inst_stringstream << inst;
|
||||
return remove_lock(hctx, inst_stringstream.str(), lock_cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break the lock on an image held by any client.
|
||||
*
|
||||
* Input:
|
||||
* @param locker The string representation of the locking client's entity.
|
||||
* @param lock_cookie The user-defined cookie associated with the lock.
|
||||
*
|
||||
* @return 0 on success, -EINVAL if it can't decode the locker and
|
||||
* cookie, -ENOENT if there is no such lock (either entity or cookie
|
||||
* is wrong), or -errno on other (unexpected) error.
|
||||
*/
|
||||
int break_lock(cls_method_context_t hctx,
|
||||
bufferlist *in, bufferlist *out)
|
||||
{
|
||||
CLS_LOG(20, "break_lock");
|
||||
string locker;
|
||||
string lock_cookie;
|
||||
try {
|
||||
bufferlist::iterator iter = in->begin();
|
||||
::decode(locker, iter);
|
||||
::decode(lock_cookie, iter);
|
||||
} catch (const buffer::error& err) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return remove_lock(hctx, locker, lock_cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of clients locking this object (presumably an rbd header),
|
||||
* as well as whether the lock is shared or exclusive.
|
||||
*
|
||||
* Input:
|
||||
* @param in is ignored.
|
||||
*
|
||||
* Output:
|
||||
* @param set<pair<string, string> > lockers The set of clients holding locks,
|
||||
* as <client, cookie> pairs.
|
||||
* @param exclusive_lock A bool, true if the lock is exclusive. If there are no
|
||||
* lockers, this is meaningless.
|
||||
*
|
||||
* @return 0 on success, -errno on failure.
|
||||
*/
|
||||
int list_locks(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
|
||||
{
|
||||
CLS_LOG(20, "list_locks");
|
||||
string key = RBD_LOCKS_KEY;
|
||||
string exclusive_string;
|
||||
bool have_locks = true;
|
||||
int r = cls_cxx_map_get_val(hctx, key, out);
|
||||
if (r != 0 && r != -ENOENT) {
|
||||
CLS_ERR("Failure in reading list of current lockers: %s", strerror(r));
|
||||
return r;
|
||||
}
|
||||
if (r == -ENOENT) { // none listed
|
||||
set<pair<string, string> > empty_lockers;
|
||||
::encode(empty_lockers, *out);
|
||||
have_locks = false;
|
||||
r = 0;
|
||||
}
|
||||
if (have_locks) {
|
||||
key = RBD_LOCK_TYPE_KEY;
|
||||
r = read_key(hctx, key, &exclusive_string);
|
||||
if (r < 0) {
|
||||
CLS_ERR("Failed to read lock type off disk: %s", strerror(r));
|
||||
}
|
||||
}
|
||||
::encode((exclusive_string == RBD_LOCK_EXCLUSIVE), *out);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* verify that the header object exists
|
||||
*
|
||||
@ -2180,21 +1920,6 @@ void __cls_init()
|
||||
cls_register_cxx_method(h_class, "copyup",
|
||||
CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC,
|
||||
copyup, &h_copyup);
|
||||
cls_register_cxx_method(h_class, "lock_exclusive",
|
||||
CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC,
|
||||
lock_image_exclusive, &h_lock_image_exclusive);
|
||||
cls_register_cxx_method(h_class, "lock_shared",
|
||||
CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC,
|
||||
lock_image_shared, &h_lock_image_shared);
|
||||
cls_register_cxx_method(h_class, "unlock_image",
|
||||
CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC,
|
||||
unlock_image, &h_unlock_image);
|
||||
cls_register_cxx_method(h_class, "break_lock",
|
||||
CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PUBLIC,
|
||||
break_lock, &h_break_lock);
|
||||
cls_register_cxx_method(h_class, "list_locks",
|
||||
CLS_METHOD_RD | CLS_METHOD_PUBLIC,
|
||||
list_locks, &h_list_locks);
|
||||
cls_register_cxx_method(h_class, "get_parent",
|
||||
CLS_METHOD_RD | CLS_METHOD_PUBLIC,
|
||||
get_parent, &h_get_parent);
|
||||
|
@ -441,64 +441,12 @@ namespace librbd {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int list_locks(librados::IoCtx *ioctx, const std::string &oid,
|
||||
std::set<std::pair<std::string, std::string> > &locks,
|
||||
bool &exclusive)
|
||||
{
|
||||
bufferlist in, out;
|
||||
int r = ioctx->exec(oid, "rbd", "list_locks", in, out);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
bufferlist::iterator iter = out.begin();
|
||||
try {
|
||||
::decode(locks, iter);
|
||||
::decode(exclusive, iter);
|
||||
} catch (const buffer::error &err) {
|
||||
return -EBADMSG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int copyup(librados::IoCtx *ioctx, const std::string &oid,
|
||||
bufferlist data) {
|
||||
bufferlist out;
|
||||
return ioctx->exec(oid, "rbd", "copyup", data, out);
|
||||
}
|
||||
|
||||
int lock_image_exclusive(librados::IoCtx *ioctx, const std::string &oid,
|
||||
const std::string &cookie)
|
||||
{
|
||||
bufferlist in, out;
|
||||
::encode(cookie, in);
|
||||
return ioctx->exec(oid, "rbd", "lock_exclusive", in, out);
|
||||
}
|
||||
|
||||
int lock_image_shared(librados::IoCtx *ioctx, const std::string &oid,
|
||||
const std::string &cookie)
|
||||
{
|
||||
bufferlist in, out;
|
||||
::encode(cookie, in);
|
||||
return ioctx->exec(oid, "rbd", "lock_shared", in, out);
|
||||
}
|
||||
|
||||
int unlock_image(librados::IoCtx *ioctx, const std::string& oid,
|
||||
const std::string &cookie)
|
||||
{
|
||||
bufferlist in, out;
|
||||
::encode(cookie, in);
|
||||
return ioctx->exec(oid, "rbd", "unlock_image", in, out);
|
||||
}
|
||||
int break_lock(librados::IoCtx *ioctx, const std::string& oid,
|
||||
const std::string &locker, const std::string &cookie)
|
||||
{
|
||||
bufferlist in, out;
|
||||
::encode(locker, in);
|
||||
::encode(cookie, in);
|
||||
return ioctx->exec(oid, "rbd", "break_lock", in, out);
|
||||
}
|
||||
|
||||
int get_protection_status(librados::IoCtx *ioctx, const std::string &oid,
|
||||
snapid_t snap_id, uint8_t *protection_status)
|
||||
{
|
||||
|
@ -68,19 +68,8 @@ namespace librbd {
|
||||
std::vector<uint64_t> *features,
|
||||
std::vector<parent_info> *parents,
|
||||
std::vector<uint8_t> *protection_statuses);
|
||||
int list_locks(librados::IoCtx *ioctx, const std::string &oid,
|
||||
std::set<std::pair<std::string, std::string> > &locks,
|
||||
bool &exclusive);
|
||||
int copyup(librados::IoCtx *ioctx, const std::string &oid,
|
||||
bufferlist data);
|
||||
int lock_image_exclusive(librados::IoCtx *ioctx, const std::string &oid,
|
||||
const std::string &cookie);
|
||||
int lock_image_shared(librados::IoCtx *ioctx, const std::string &oid,
|
||||
const std::string &cookie);
|
||||
int unlock_image(librados::IoCtx *ioctx, const std::string& oid,
|
||||
const std::string &cookie);
|
||||
int break_lock(librados::IoCtx *ioctx, const std::string& oid,
|
||||
const std::string &locker, const std::string &cookie);
|
||||
int get_protection_status(librados::IoCtx *ioctx, const std::string &oid,
|
||||
snapid_t snap_id, uint8_t *protection_status);
|
||||
int set_protection_status(librados::IoCtx *ioctx, const std::string &oid,
|
||||
|
@ -32,11 +32,6 @@ using ::librbd::cls_client::remove_child;
|
||||
using ::librbd::cls_client::get_children;
|
||||
using ::librbd::cls_client::get_snapcontext;
|
||||
using ::librbd::cls_client::snapshot_list;
|
||||
using ::librbd::cls_client::list_locks;
|
||||
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::copyup;
|
||||
using ::librbd::cls_client::get_id;
|
||||
using ::librbd::cls_client::set_id;
|
||||
@ -365,98 +360,6 @@ TEST(cls_rbd, get_features)
|
||||
ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados));
|
||||
}
|
||||
|
||||
TEST(cls_rbd, image_locking)
|
||||
{
|
||||
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 = "test_locking_image";
|
||||
uint64_t size = 20 << 30;
|
||||
uint64_t features = 0;
|
||||
uint8_t order = 22;
|
||||
string object_prefix = "foo";
|
||||
string cookies[4];
|
||||
cookies[0] = "cookie0";
|
||||
cookies[1] = "cookie1";
|
||||
cookies[2] = "cookie2";
|
||||
cookies[3] = "cookie3";
|
||||
|
||||
ASSERT_EQ(0, create_image(&ioctx, oid, size, order,
|
||||
features, object_prefix));
|
||||
|
||||
// test that we can lock
|
||||
ASSERT_EQ(0, lock_image_exclusive(&ioctx, oid, cookies[0]));
|
||||
// and that we can't lock again
|
||||
ASSERT_EQ(-EBUSY, lock_image_exclusive(&ioctx, oid, cookies[1]));
|
||||
// and that unlock works
|
||||
ASSERT_EQ(0, unlock_image(&ioctx, oid, cookies[0]));
|
||||
// and that we can do shared locking
|
||||
ASSERT_EQ(0, lock_image_shared(&ioctx, oid, cookies[2]));
|
||||
ASSERT_EQ(0, lock_image_shared(&ioctx, oid, cookies[3]));
|
||||
// and that you can't exclusive lock with shared lockers
|
||||
ASSERT_EQ(-EBUSY, lock_image_exclusive(&ioctx, oid, cookies[1]));
|
||||
// but that you can after unlocking the shared lockers
|
||||
ASSERT_EQ(0, unlock_image(&ioctx, oid, cookies[2]));
|
||||
ASSERT_EQ(0, unlock_image(&ioctx, oid, cookies[3]));
|
||||
ASSERT_EQ(0, lock_image_exclusive(&ioctx, oid, cookies[1]));
|
||||
ASSERT_EQ(0, unlock_image(&ioctx, oid, cookies[1]));
|
||||
|
||||
// test that we can list locks
|
||||
std::set<std::pair<std::string, std::string> > lockers;
|
||||
bool exclusive;
|
||||
ASSERT_EQ(0, list_locks(&ioctx, oid, lockers, exclusive));
|
||||
// and that no locks makes for an empty set
|
||||
int lockers_size = lockers.size();
|
||||
ASSERT_EQ(0, lockers_size);
|
||||
|
||||
// test that two shared lockers compare properly
|
||||
ASSERT_EQ(0, lock_image_shared(&ioctx, oid, cookies[2]));
|
||||
ASSERT_EQ(0, lock_image_shared(&ioctx, oid, cookies[3]));
|
||||
ASSERT_EQ(0, list_locks(&ioctx, oid, lockers, exclusive));
|
||||
ASSERT_FALSE(exclusive);
|
||||
lockers_size = lockers.size();
|
||||
ASSERT_EQ(2, lockers_size);
|
||||
std::set<std::pair<std::string, std::string> >::iterator first, second;
|
||||
second = lockers.begin();
|
||||
first = second++;
|
||||
ASSERT_EQ(0, first->first.compare(second->first));
|
||||
std::string our_entity = first->first; // saved for later
|
||||
ASSERT_EQ(0, unlock_image(&ioctx, oid, cookies[2]));
|
||||
ASSERT_EQ(0, unlock_image(&ioctx, oid, cookies[3]));
|
||||
|
||||
// and that a single exclusive looks right
|
||||
ASSERT_EQ(0, lock_image_exclusive(&ioctx, oid, cookies[0]));
|
||||
ASSERT_EQ(0, list_locks(&ioctx, oid, lockers, exclusive));
|
||||
lockers_size = lockers.size();
|
||||
ASSERT_EQ(1, lockers_size);
|
||||
ASSERT_TRUE(exclusive);
|
||||
|
||||
// and do our best to test lock breaking
|
||||
ASSERT_EQ(0, break_lock(&ioctx, oid, our_entity, cookies[0]));
|
||||
// and that it actually removes the lock
|
||||
ASSERT_EQ(0, list_locks(&ioctx, oid, lockers, exclusive));
|
||||
lockers_size = lockers.size();
|
||||
ASSERT_EQ(0, lockers_size);
|
||||
|
||||
// test that non-existent locks return errors correctly
|
||||
ASSERT_EQ(-ENOENT, unlock_image(&ioctx, oid, cookies[1]));
|
||||
ASSERT_EQ(-ENOENT, unlock_image(&ioctx, oid, cookies[0]));
|
||||
ASSERT_EQ(-ENOENT, break_lock(&ioctx, oid, our_entity, cookies[0]));
|
||||
// and make sure they still do that when somebody else does hold a lock
|
||||
ASSERT_EQ(0, lock_image_shared(&ioctx, oid, cookies[2]));
|
||||
ASSERT_EQ(-ENOENT, unlock_image(&ioctx, oid, cookies[1]));
|
||||
ASSERT_EQ(-ENOENT, unlock_image(&ioctx, oid, cookies[0]));
|
||||
ASSERT_EQ(-ENOENT, break_lock(&ioctx, oid, our_entity, cookies[0]));
|
||||
ASSERT_EQ(0, unlock_image(&ioctx, oid, cookies[2]));
|
||||
|
||||
ioctx.close();
|
||||
ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados));
|
||||
}
|
||||
|
||||
TEST(cls_rbd, get_object_prefix)
|
||||
{
|
||||
librados::Rados rados;
|
||||
|
Loading…
Reference in New Issue
Block a user