2023-08-13 16:35:49

by Sasha Levin

[permalink] [raw]
Subject: [PATCH AUTOSEL 5.10 22/25] rbd: make get_lock_owner_info() return a single locker or NULL

From: Ilya Dryomov <[email protected]>

[ Upstream commit f38cb9d9c2045dad16eead4a2e1aedfddd94603b ]

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: Ilya Dryomov <[email protected]>
Reviewed-by: Dongsheng Yang <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
---
drivers/block/rbd.c | 84 +++++++++++++++++++++++++++------------------
1 file changed, 51 insertions(+), 33 deletions(-)

diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 63491748dc8d7..81ebb86836c5b 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -3914,10 +3914,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;
@@ -3926,39 +3933,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,
@@ -4008,51 +4021,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;
}

--
2.40.1



2023-08-14 14:08:37

by Ilya Dryomov

[permalink] [raw]
Subject: Re: [PATCH AUTOSEL 5.10 22/25] rbd: make get_lock_owner_info() return a single locker or NULL

On Sun, Aug 13, 2023 at 6:11 PM Sasha Levin <[email protected]> wrote:
>
> From: Ilya Dryomov <[email protected]>
>
> [ Upstream commit f38cb9d9c2045dad16eead4a2e1aedfddd94603b ]
>
> 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: Ilya Dryomov <[email protected]>
> Reviewed-by: Dongsheng Yang <[email protected]>
> Signed-off-by: Sasha Levin <[email protected]>

Hi Sasha,

This is a prerequisite patch, it doesn't make sense to backport it
without also backporting "rbd: harden get_lock_owner_info() a bit" and
"rbd: retrieve and check lock owner twice before blocklisting".

Please drop it.

Thanks,

Ilya