mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-15 11:44:11 +00:00
rbd: prevent busy loop when requesting exclusive lock
commit9d01e07fd1
upstream. 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: stable@vger.kernel.org #588159009d
: rbd: retrieve and check lock owner twice before blocklisting Cc: stable@vger.kernel.org Signed-off-by: Ilya Dryomov <idryomov@gmail.com> Reviewed-by: Dongsheng Yang <dongsheng.yang@easystack.cn> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
3cb2060049
commit
c2ae3f7e0b
1 changed files with 15 additions and 13 deletions
|
@ -3677,7 +3677,7 @@ static int rbd_lock(struct rbd_device *rbd_dev)
|
|||
ret = ceph_cls_lock(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc,
|
||||
RBD_LOCK_NAME, CEPH_CLS_LOCK_EXCLUSIVE, cookie,
|
||||
RBD_LOCK_TAG, "", 0);
|
||||
if (ret)
|
||||
if (ret && ret != -EEXIST)
|
||||
return ret;
|
||||
|
||||
__rbd_lock(rbd_dev, cookie);
|
||||
|
@ -3880,7 +3880,7 @@ static struct ceph_locker *get_lock_owner_info(struct rbd_device *rbd_dev)
|
|||
&rbd_dev->header_oloc, RBD_LOCK_NAME,
|
||||
&lock_type, &lock_tag, &lockers, &num_lockers);
|
||||
if (ret) {
|
||||
rbd_warn(rbd_dev, "failed to retrieve lockers: %d", ret);
|
||||
rbd_warn(rbd_dev, "failed to get header lockers: %d", ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
@ -3942,8 +3942,10 @@ static int find_watcher(struct rbd_device *rbd_dev,
|
|||
ret = ceph_osdc_list_watchers(osdc, &rbd_dev->header_oid,
|
||||
&rbd_dev->header_oloc, &watchers,
|
||||
&num_watchers);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
rbd_warn(rbd_dev, "failed to get watchers: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sscanf(locker->id.cookie, RBD_LOCK_COOKIE_PREFIX " %llu", &cookie);
|
||||
for (i = 0; i < num_watchers; i++) {
|
||||
|
@ -3987,8 +3989,12 @@ static int rbd_try_lock(struct rbd_device *rbd_dev)
|
|||
locker = refreshed_locker = NULL;
|
||||
|
||||
ret = rbd_lock(rbd_dev);
|
||||
if (ret != -EBUSY)
|
||||
if (!ret)
|
||||
goto out;
|
||||
if (ret != -EBUSY) {
|
||||
rbd_warn(rbd_dev, "failed to lock header: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* determine if the current lock holder is still alive */
|
||||
locker = get_lock_owner_info(rbd_dev);
|
||||
|
@ -4091,11 +4097,8 @@ static int rbd_try_acquire_lock(struct rbd_device *rbd_dev)
|
|||
|
||||
ret = rbd_try_lock(rbd_dev);
|
||||
if (ret < 0) {
|
||||
rbd_warn(rbd_dev, "failed to lock header: %d", ret);
|
||||
if (ret == -EBLOCKLISTED)
|
||||
goto out;
|
||||
|
||||
ret = 1; /* request lock anyway */
|
||||
rbd_warn(rbd_dev, "failed to acquire lock: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
if (ret > 0) {
|
||||
up_write(&rbd_dev->lock_rwsem);
|
||||
|
@ -6631,12 +6634,11 @@ static int rbd_add_acquire_lock(struct rbd_device *rbd_dev)
|
|||
cancel_delayed_work_sync(&rbd_dev->lock_dwork);
|
||||
if (!ret)
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
rbd_warn(rbd_dev, "failed to acquire exclusive lock: %ld", ret);
|
||||
return ret;
|
||||
rbd_warn(rbd_dev, "failed to acquire lock: %ld", ret);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The lock may have been released by now, unless automatic lock
|
||||
|
|
Loading…
Add table
Reference in a new issue