Commit f38cb9d9 authored by Ilya Dryomov's avatar Ilya Dryomov
Browse files

rbd: make get_lock_owner_info() return a single locker or NULL



Make the "num_lockers can be only 0 or 1" assumption explicit and
simplify the API by getting rid of output parameters in preparation
for calling get_lock_owner_info() twice before blocklisting.

Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
Reviewed-by: default avatarDongsheng Yang <dongsheng.yang@easystack.cn>
parent 50164507
Loading
Loading
Loading
Loading
+51 −33
Original line number Diff line number Diff line
@@ -3849,10 +3849,17 @@ static void wake_lock_waiters(struct rbd_device *rbd_dev, int result)
	list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list);
}

static int get_lock_owner_info(struct rbd_device *rbd_dev,
			       struct ceph_locker **lockers, u32 *num_lockers)
static void free_locker(struct ceph_locker *locker)
{
	if (locker)
		ceph_free_lockers(locker, 1);
}

static struct ceph_locker *get_lock_owner_info(struct rbd_device *rbd_dev)
{
	struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
	struct ceph_locker *lockers;
	u32 num_lockers;
	u8 lock_type;
	char *lock_tag;
	int ret;
@@ -3861,39 +3868,45 @@ static int get_lock_owner_info(struct rbd_device *rbd_dev,

	ret = ceph_cls_lock_info(osdc, &rbd_dev->header_oid,
				 &rbd_dev->header_oloc, RBD_LOCK_NAME,
				 &lock_type, &lock_tag, lockers, num_lockers);
	if (ret)
		return ret;
				 &lock_type, &lock_tag, &lockers, &num_lockers);
	if (ret) {
		rbd_warn(rbd_dev, "failed to retrieve lockers: %d", ret);
		return ERR_PTR(ret);
	}

	if (*num_lockers == 0) {
	if (num_lockers == 0) {
		dout("%s rbd_dev %p no lockers detected\n", __func__, rbd_dev);
		lockers = NULL;
		goto out;
	}

	if (strcmp(lock_tag, RBD_LOCK_TAG)) {
		rbd_warn(rbd_dev, "locked by external mechanism, tag %s",
			 lock_tag);
		ret = -EBUSY;
		goto out;
		goto err_busy;
	}

	if (lock_type == CEPH_CLS_LOCK_SHARED) {
		rbd_warn(rbd_dev, "shared lock type detected");
		ret = -EBUSY;
		goto out;
		goto err_busy;
	}

	if (strncmp((*lockers)[0].id.cookie, RBD_LOCK_COOKIE_PREFIX,
	WARN_ON(num_lockers != 1);
	if (strncmp(lockers[0].id.cookie, RBD_LOCK_COOKIE_PREFIX,
		    strlen(RBD_LOCK_COOKIE_PREFIX))) {
		rbd_warn(rbd_dev, "locked by external mechanism, cookie %s",
			 (*lockers)[0].id.cookie);
		ret = -EBUSY;
		goto out;
			 lockers[0].id.cookie);
		goto err_busy;
	}

out:
	kfree(lock_tag);
	return ret;
	return lockers;

err_busy:
	kfree(lock_tag);
	ceph_free_lockers(lockers, num_lockers);
	return ERR_PTR(-EBUSY);
}

static int find_watcher(struct rbd_device *rbd_dev,
@@ -3947,51 +3960,56 @@ static int find_watcher(struct rbd_device *rbd_dev,
static int rbd_try_lock(struct rbd_device *rbd_dev)
{
	struct ceph_client *client = rbd_dev->rbd_client->client;
	struct ceph_locker *lockers;
	u32 num_lockers;
	struct ceph_locker *locker;
	int ret;

	for (;;) {
		locker = NULL;

		ret = rbd_lock(rbd_dev);
		if (ret != -EBUSY)
			return ret;
			goto out;

		/* determine if the current lock holder is still alive */
		ret = get_lock_owner_info(rbd_dev, &lockers, &num_lockers);
		if (ret)
			return ret;

		if (num_lockers == 0)
		locker = get_lock_owner_info(rbd_dev);
		if (IS_ERR(locker)) {
			ret = PTR_ERR(locker);
			locker = NULL;
			goto out;
		}
		if (!locker)
			goto again;

		ret = find_watcher(rbd_dev, lockers);
		ret = find_watcher(rbd_dev, locker);
		if (ret)
			goto out; /* request lock or error */

		rbd_warn(rbd_dev, "breaking header lock owned by %s%llu",
			 ENTITY_NAME(lockers[0].id.name));
			 ENTITY_NAME(locker->id.name));

		ret = ceph_monc_blocklist_add(&client->monc,
					      &lockers[0].info.addr);
					      &locker->info.addr);
		if (ret) {
			rbd_warn(rbd_dev, "blocklist of %s%llu failed: %d",
				 ENTITY_NAME(lockers[0].id.name), ret);
			rbd_warn(rbd_dev, "failed to blocklist %s%llu: %d",
				 ENTITY_NAME(locker->id.name), ret);
			goto out;
		}

		ret = ceph_cls_break_lock(&client->osdc, &rbd_dev->header_oid,
					  &rbd_dev->header_oloc, RBD_LOCK_NAME,
					  lockers[0].id.cookie,
					  &lockers[0].id.name);
		if (ret && ret != -ENOENT)
					  locker->id.cookie, &locker->id.name);
		if (ret && ret != -ENOENT) {
			rbd_warn(rbd_dev, "failed to break header lock: %d",
				 ret);
			goto out;
		}

again:
		ceph_free_lockers(lockers, num_lockers);
		free_locker(locker);
	}

out:
	ceph_free_lockers(lockers, num_lockers);
	free_locker(locker);
	return ret;
}