Skip to content

Commit 9d01e07

Browse files
committed
rbd: prevent busy loop when requesting exclusive lock
Due to rbd_try_acquire_lock() effectively swallowing all but EBLOCKLISTED error from rbd_try_lock() ("request lock anyway") and rbd_request_lock() returning ETIMEDOUT error not only for an actual notify timeout but also when the lock owner doesn't respond, a busy loop inside of rbd_acquire_lock() between rbd_try_acquire_lock() and rbd_request_lock() is possible. Requesting the lock on EBUSY error (returned by get_lock_owner_info() if an incompatible lock or invalid lock owner is detected) makes very little sense. The same goes for ETIMEDOUT error (might pop up pretty much anywhere if osd_request_timeout option is set) and many others. Just fail I/O requests on rbd_dev->acquiring_list immediately on any error from rbd_try_lock(). Cc: [email protected] # 5881590: rbd: retrieve and check lock owner twice before blocklisting Cc: [email protected] Signed-off-by: Ilya Dryomov <[email protected]> Reviewed-by: Dongsheng Yang <[email protected]>
1 parent e7e607b commit 9d01e07

File tree

1 file changed

+15
-13
lines changed

1 file changed

+15
-13
lines changed

drivers/block/rbd.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3675,7 +3675,7 @@ static int rbd_lock(struct rbd_device *rbd_dev)
36753675
ret = ceph_cls_lock(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
36763676
RBD_LOCK_NAME, CEPH_CLS_LOCK_EXCLUSIVE, cookie,
36773677
RBD_LOCK_TAG, "", 0);
3678-
if (ret)
3678+
if (ret && ret != -EEXIST)
36793679
return ret;
36803680

36813681
__rbd_lock(rbd_dev, cookie);
@@ -3878,7 +3878,7 @@ static struct ceph_locker *get_lock_owner_info(struct rbd_device *rbd_dev)
38783878
&rbd_dev->header_oloc, RBD_LOCK_NAME,
38793879
&lock_type, &lock_tag, &lockers, &num_lockers);
38803880
if (ret) {
3881-
rbd_warn(rbd_dev, "failed to retrieve lockers: %d", ret);
3881+
rbd_warn(rbd_dev, "failed to get header lockers: %d", ret);
38823882
return ERR_PTR(ret);
38833883
}
38843884

@@ -3940,8 +3940,10 @@ static int find_watcher(struct rbd_device *rbd_dev,
39403940
ret = ceph_osdc_list_watchers(osdc, &rbd_dev->header_oid,
39413941
&rbd_dev->header_oloc, &watchers,
39423942
&num_watchers);
3943-
if (ret)
3943+
if (ret) {
3944+
rbd_warn(rbd_dev, "failed to get watchers: %d", ret);
39443945
return ret;
3946+
}
39453947

39463948
sscanf(locker->id.cookie, RBD_LOCK_COOKIE_PREFIX " %llu", &cookie);
39473949
for (i = 0; i < num_watchers; i++) {
@@ -3985,8 +3987,12 @@ static int rbd_try_lock(struct rbd_device *rbd_dev)
39853987
locker = refreshed_locker = NULL;
39863988

39873989
ret = rbd_lock(rbd_dev);
3988-
if (ret != -EBUSY)
3990+
if (!ret)
3991+
goto out;
3992+
if (ret != -EBUSY) {
3993+
rbd_warn(rbd_dev, "failed to lock header: %d", ret);
39893994
goto out;
3995+
}
39903996

39913997
/* determine if the current lock holder is still alive */
39923998
locker = get_lock_owner_info(rbd_dev);
@@ -4089,11 +4095,8 @@ static int rbd_try_acquire_lock(struct rbd_device *rbd_dev)
40894095

40904096
ret = rbd_try_lock(rbd_dev);
40914097
if (ret < 0) {
4092-
rbd_warn(rbd_dev, "failed to lock header: %d", ret);
4093-
if (ret == -EBLOCKLISTED)
4094-
goto out;
4095-
4096-
ret = 1; /* request lock anyway */
4098+
rbd_warn(rbd_dev, "failed to acquire lock: %d", ret);
4099+
goto out;
40974100
}
40984101
if (ret > 0) {
40994102
up_write(&rbd_dev->lock_rwsem);
@@ -6627,12 +6630,11 @@ static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
66276630
cancel_delayed_work_sync(&rbd_dev->lock_dwork);
66286631
if (!ret)
66296632
ret = -ETIMEDOUT;
6630-
}
66316633

6632-
if (ret) {
6633-
rbd_warn(rbd_dev, "failed to acquire exclusive lock: %ld", ret);
6634-
return ret;
6634+
rbd_warn(rbd_dev, "failed to acquire lock: %ld", ret);
66356635
}
6636+
if (ret)
6637+
return ret;
66366638

66376639
/*
66386640
* The lock may have been released by now, unless automatic lock

0 commit comments

Comments
 (0)