X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcls%2Flock%2Fcls_lock.cc;fp=src%2Fceph%2Fsrc%2Fcls%2Flock%2Fcls_lock.cc;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=6e2ae4bbd1d1699570f0fd2745b640d02c55b835;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/cls/lock/cls_lock.cc b/src/ceph/src/cls/lock/cls_lock.cc deleted file mode 100644 index 6e2ae4b..0000000 --- a/src/ceph/src/cls/lock/cls_lock.cc +++ /dev/null @@ -1,598 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -/** \file - * - * This is an OSD class that implements methods for object - * advisory locking. - * - */ - -#include -#include - -#include "include/types.h" -#include "include/utime.h" -#include "objclass/objclass.h" - -#include "common/errno.h" -#include "common/Clock.h" - -#include "cls/lock/cls_lock_types.h" -#include "cls/lock/cls_lock_ops.h" - -#include "global/global_context.h" - -#include "include/compat.h" - - -using namespace rados::cls::lock; - - -CLS_VER(1,0) -CLS_NAME(lock) - -#define LOCK_PREFIX "lock." - -static int read_lock(cls_method_context_t hctx, const string& name, lock_info_t *lock) -{ - bufferlist bl; - string key = LOCK_PREFIX; - key.append(name); - - int r = cls_cxx_getxattr(hctx, key.c_str(), &bl); - if (r < 0) { - if (r == -ENODATA) { - *lock = lock_info_t(); - return 0; - } - if (r != -ENOENT) { - CLS_ERR("error reading xattr %s: %d", key.c_str(), r); - } - return r; - } - - try { - bufferlist::iterator it = bl.begin(); - ::decode(*lock, it); - } catch (const buffer::error &err) { - CLS_ERR("error decoding %s", key.c_str()); - return -EIO; - } - - /* now trim expired locks */ - - utime_t now = ceph_clock_now(); - - map::iterator iter = lock->lockers.begin(); - - while (iter != lock->lockers.end()) { - map::iterator next = iter; - ++next; - - struct locker_info_t& info = iter->second; - if (!info.expiration.is_zero() && info.expiration < now) { - CLS_LOG(20, "expiring locker"); - lock->lockers.erase(iter); - } - - iter = next; - } - - return 0; -} - -static int write_lock(cls_method_context_t hctx, const string& name, const lock_info_t& lock) -{ - string key = LOCK_PREFIX; - key.append(name); - - bufferlist lock_bl; - ::encode(lock, lock_bl, cls_get_client_features(hctx)); - - int r = cls_cxx_setxattr(hctx, key.c_str(), &lock_bl); - if (r < 0) - return r; - - return 0; -} - -/** - * helper function to add a lock and update disk state. - * - * Input: - * @param name Lock name - * @param lock_type Type of lock (exclusive / shared) - * @param duration Duration of lock (in seconds). Zero means it doesn't expire. - * @param flags lock flags - * @param cookie The cookie to set in the lock - * @param tag The tag to match with the lock (can only lock with matching tags) - * @param lock_description The lock description to set (if not empty) - * @param locker_description The locker description - * - * @return 0 on success, or -errno on failure - */ -static int lock_obj(cls_method_context_t hctx, - const string& name, - ClsLockType lock_type, - utime_t duration, - const string& description, - uint8_t flags, - const string& cookie, - const string& tag) -{ - bool exclusive = lock_type == LOCK_EXCLUSIVE; - lock_info_t linfo; - bool fail_if_exists = (flags & LOCK_FLAG_RENEW) == 0; - - CLS_LOG(20, "requested lock_type=%s fail_if_exists=%d", cls_lock_type_str(lock_type), fail_if_exists); - if (lock_type != LOCK_EXCLUSIVE && - lock_type != LOCK_SHARED) - return -EINVAL; - - if (name.empty()) - return -EINVAL; - - // see if there's already a locker - int r = read_lock(hctx, name, &linfo); - if (r < 0 && r != -ENOENT) { - CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); - return r; - } - map& lockers = linfo.lockers; - map::iterator iter; - - locker_id_t id; - id.cookie = cookie; - entity_inst_t inst; - r = cls_get_request_origin(hctx, &inst); - id.locker = inst.name; - assert(r == 0); - - /* check this early, before we check fail_if_exists, otherwise we might - * remove the locker entry and not check it later */ - if (lockers.size() && tag != linfo.tag) { - CLS_LOG(20, "cannot take lock on object, conflicting tag"); - return -EBUSY; - } - - ClsLockType existing_lock_type = linfo.lock_type; - CLS_LOG(20, "existing_lock_type=%s", cls_lock_type_str(existing_lock_type)); - iter = lockers.find(id); - if (iter != lockers.end()) { - if (fail_if_exists) { - return -EEXIST; - } else { - lockers.erase(iter); // remove old entry - } - } - - if (!lockers.empty()) { - if (exclusive) { - CLS_LOG(20, "could not exclusive-lock object, already locked"); - return -EBUSY; - } - - if (existing_lock_type != lock_type) { - CLS_LOG(20, "cannot take lock on object, conflicting lock type"); - return -EBUSY; - } - } - - linfo.lock_type = lock_type; - linfo.tag = tag; - utime_t expiration; - if (!duration.is_zero()) { - expiration = ceph_clock_now(); - expiration += duration; - - } - struct locker_info_t info(expiration, inst.addr, description); - - linfo.lockers[id] = info; - - r = write_lock(hctx, name, linfo); - if (r < 0) - return r; - - return 0; -} - -/** - * Set an exclusive lock on an object for the activating client, if possible. - * - * Input: - * @param cls_lock_lock_op request input - * - * @returns 0 on success, -EINVAL if it can't decode the lock_cookie, - * -EBUSY if the object is already locked, or -errno on (unexpected) failure. - */ -static int lock_op(cls_method_context_t hctx, - bufferlist *in, bufferlist *out) -{ - CLS_LOG(20, "lock_op"); - cls_lock_lock_op op; - try { - bufferlist::iterator iter = in->begin(); - ::decode(op, iter); - } catch (const buffer::error &err) { - return -EINVAL; - } - - return lock_obj(hctx, - op.name, op.type, op.duration, op.description, - op.flags, op.cookie, op.tag); -} - -/** - * helper function to remove a lock from on disk and clean up state. - * - * @param name The lock name - * @param locker The locker entity name - * @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. - */ -static int remove_lock(cls_method_context_t hctx, - const string& name, - entity_name_t& locker, - const string& cookie) -{ - // get current lockers - lock_info_t linfo; - int r = read_lock(hctx, name, &linfo); - if (r < 0) { - CLS_ERR("Could not read list of current lockers off disk: %s", cpp_strerror(r).c_str()); - return r; - } - - map& lockers = linfo.lockers; - struct locker_id_t id(locker, cookie); - - // remove named locker from set - map::iterator iter = lockers.find(id); - if (iter == lockers.end()) { // no such key - return -ENOENT; - } - lockers.erase(iter); - - r = write_lock(hctx, name, linfo); - - return r; -} - -/** - * Unlock an object which the activating client currently has locked. - * - * Input: - * @param cls_lock_unlock_op request input - * - * @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. - */ -static int unlock_op(cls_method_context_t hctx, - bufferlist *in, bufferlist *out) -{ - CLS_LOG(20, "unlock_op"); - cls_lock_unlock_op op; - try { - bufferlist::iterator iter = in->begin(); - ::decode(op, iter); - } catch (const buffer::error& err) { - return -EINVAL; - } - - entity_inst_t inst; - int r = cls_get_request_origin(hctx, &inst); - assert(r == 0); - return remove_lock(hctx, op.name, inst.name, op.cookie); -} - -/** - * Break the lock on an object held by any client. - * - * Input: - * @param cls_lock_break_op request input - * - * @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. - */ -static int break_lock(cls_method_context_t hctx, - bufferlist *in, bufferlist *out) -{ - CLS_LOG(20, "break_lock"); - cls_lock_break_op op; - try { - bufferlist::iterator iter = in->begin(); - ::decode(op, iter); - } catch (const buffer::error& err) { - return -EINVAL; - } - - return remove_lock(hctx, op.name, op.locker, op.cookie); -} - - -/** - * Retrieve lock info: lockers, tag, exclusive - * - * Input: - * @param cls_lock_list_lockers_op request input - * - * Output: - * @param cls_lock_list_lockers_reply result - * - * @return 0 on success, -errno on failure. - */ -static int get_info(cls_method_context_t hctx, bufferlist *in, bufferlist *out) -{ - CLS_LOG(20, "get_info"); - cls_lock_get_info_op op; - try { - bufferlist::iterator iter = in->begin(); - ::decode(op, iter); - } catch (const buffer::error& err) { - return -EINVAL; - } - - // get current lockers - lock_info_t linfo; - int r = read_lock(hctx, op.name, &linfo); - if (r < 0) { - CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); - return r; - } - - struct cls_lock_get_info_reply ret; - - map::iterator iter; - for (iter = linfo.lockers.begin(); iter != linfo.lockers.end(); ++iter) { - ret.lockers[iter->first] = iter->second; - } - ret.lock_type = linfo.lock_type; - ret.tag = linfo.tag; - - ::encode(ret, *out, cls_get_client_features(hctx)); - - return 0; -} - - -/** - * Retrieve a list of locks for this object - * - * Input: - * @param in is ignored. - * - * Output: - * @param out contains encoded cls_list_locks_reply - * - * @return 0 on success, -errno on failure. - */ -static int list_locks(cls_method_context_t hctx, bufferlist *in, bufferlist *out) -{ - CLS_LOG(20, "list_locks"); - - map attrs; - - int r = cls_cxx_getxattrs(hctx, &attrs); - if (r < 0) - return r; - - cls_lock_list_locks_reply ret; - - map::iterator iter; - size_t pos = sizeof(LOCK_PREFIX) - 1; - for (iter = attrs.begin(); iter != attrs.end(); ++iter) { - const string& attr = iter->first; - if (attr.substr(0, pos).compare(LOCK_PREFIX) == 0) { - ret.locks.push_back(attr.substr(pos)); - } - } - - ::encode(ret, *out); - - return 0; -} - -/** - * Assert that the object is currently locked - * - * Input: - * @param cls_lock_assert_op request input - * - * Output: - * @param none - * - * @return 0 on success, -errno on failure. - */ -int assert_locked(cls_method_context_t hctx, bufferlist *in, bufferlist *out) -{ - CLS_LOG(20, "assert_locked"); - - cls_lock_assert_op op; - try { - bufferlist::iterator iter = in->begin(); - ::decode(op, iter); - } catch (const buffer::error& err) { - return -EINVAL; - } - - if (op.type != LOCK_EXCLUSIVE && op.type != LOCK_SHARED) { - return -EINVAL; - } - - if (op.name.empty()) { - return -EINVAL; - } - - // see if there's already a locker - lock_info_t linfo; - int r = read_lock(hctx, op.name, &linfo); - if (r < 0) { - CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); - return r; - } - - if (linfo.lockers.empty()) { - CLS_LOG(20, "object not locked"); - return -EBUSY; - } - - if (linfo.lock_type != op.type) { - CLS_LOG(20, "lock type mismatch: current=%s, assert=%s", - cls_lock_type_str(linfo.lock_type), cls_lock_type_str(op.type)); - return -EBUSY; - } - - if (linfo.tag != op.tag) { - CLS_LOG(20, "lock tag mismatch: current=%s, assert=%s", linfo.tag.c_str(), - op.tag.c_str()); - return -EBUSY; - } - - entity_inst_t inst; - r = cls_get_request_origin(hctx, &inst); - assert(r == 0); - - locker_id_t id; - id.cookie = op.cookie; - id.locker = inst.name; - - map::iterator iter = linfo.lockers.find(id); - if (iter == linfo.lockers.end()) { - CLS_LOG(20, "not locked by assert client"); - return -EBUSY; - } - return 0; -} - -/** - * Update the cookie associated with an object lock - * - * Input: - * @param cls_lock_set_cookie_op request input - * - * Output: - * @param none - * - * @return 0 on success, -errno on failure. - */ -int set_cookie(cls_method_context_t hctx, bufferlist *in, bufferlist *out) -{ - CLS_LOG(20, "set_cookie"); - - cls_lock_set_cookie_op op; - try { - bufferlist::iterator iter = in->begin(); - ::decode(op, iter); - } catch (const buffer::error& err) { - return -EINVAL; - } - - if (op.type != LOCK_EXCLUSIVE && op.type != LOCK_SHARED) { - return -EINVAL; - } - - if (op.name.empty()) { - return -EINVAL; - } - - // see if there's already a locker - lock_info_t linfo; - int r = read_lock(hctx, op.name, &linfo); - if (r < 0) { - CLS_ERR("Could not read lock info: %s", cpp_strerror(r).c_str()); - return r; - } - - if (linfo.lockers.empty()) { - CLS_LOG(20, "object not locked"); - return -EBUSY; - } - - if (linfo.lock_type != op.type) { - CLS_LOG(20, "lock type mismatch: current=%s, assert=%s", - cls_lock_type_str(linfo.lock_type), cls_lock_type_str(op.type)); - return -EBUSY; - } - - if (linfo.tag != op.tag) { - CLS_LOG(20, "lock tag mismatch: current=%s, assert=%s", linfo.tag.c_str(), - op.tag.c_str()); - return -EBUSY; - } - - entity_inst_t inst; - r = cls_get_request_origin(hctx, &inst); - assert(r == 0); - - locker_id_t id; - id.cookie = op.cookie; - id.locker = inst.name; - - map::iterator iter = linfo.lockers.find(id); - if (iter == linfo.lockers.end()) { - CLS_LOG(20, "not locked by client"); - return -EBUSY; - } - - id.cookie = op.new_cookie; - if (linfo.lockers.count(id) != 0) { - CLS_LOG(20, "lock cookie in-use"); - return -EBUSY; - } - - locker_info_t locker_info(iter->second); - linfo.lockers.erase(iter); - - linfo.lockers[id] = locker_info; - r = write_lock(hctx, op.name, linfo); - if (r < 0) { - CLS_ERR("Could not update lock info: %s", cpp_strerror(r).c_str()); - return r; - } - return 0; -} - -CLS_INIT(lock) -{ - CLS_LOG(20, "Loaded lock class!"); - - cls_handle_t h_class; - cls_method_handle_t h_lock_op; - cls_method_handle_t h_unlock_op; - cls_method_handle_t h_break_lock; - cls_method_handle_t h_get_info; - cls_method_handle_t h_list_locks; - cls_method_handle_t h_assert_locked; - cls_method_handle_t h_set_cookie; - - cls_register("lock", &h_class); - cls_register_cxx_method(h_class, "lock", - CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE, - lock_op, &h_lock_op); - cls_register_cxx_method(h_class, "unlock", - CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE, - unlock_op, &h_unlock_op); - cls_register_cxx_method(h_class, "break_lock", - CLS_METHOD_RD | CLS_METHOD_WR, - break_lock, &h_break_lock); - cls_register_cxx_method(h_class, "get_info", - CLS_METHOD_RD, - get_info, &h_get_info); - cls_register_cxx_method(h_class, "list_locks", - CLS_METHOD_RD, - list_locks, &h_list_locks); - cls_register_cxx_method(h_class, "assert_locked", - CLS_METHOD_RD | CLS_METHOD_PROMOTE, - assert_locked, &h_assert_locked); - cls_register_cxx_method(h_class, "set_cookie", - CLS_METHOD_RD | CLS_METHOD_WR | CLS_METHOD_PROMOTE, - set_cookie, &h_set_cookie); - - return; -}