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:
Josh Durgin 2012-09-07 18:45:22 -07:00
parent 8f2a0d91ab
commit 855dff62ae
4 changed files with 0 additions and 435 deletions

View File

@ -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);

View File

@ -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)
{

View File

@ -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,

View File

@ -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;