Re: [PATCH] rbd: don't move requests to the running list on errors

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





在 2024/1/18 星期四 下午 6:24, Ilya Dryomov 写道:
On Thu, Jan 18, 2024 at 4:13 AM Dongsheng Yang
<dongsheng.yang@xxxxxxxxxxxx> wrote:



在 2024/1/18 星期四 上午 2:35, Ilya Dryomov 写道:
The running list is supposed to contain requests that are pinning the
exclusive lock, i.e. those that must be flushed before exclusive lock
is released.  When wake_lock_waiters() is called to handle an error,
requests on the acquiring list are failed with that error and no
flushing takes place.  Briefly moving them to the running list is not
only pointless but also harmful: if exclusive lock gets acquired
before all of their state machines are scheduled and go through
rbd_lock_del_request(), we trigger

      rbd_assert(list_empty(&rbd_dev->running_list));

in rbd_try_acquire_lock().

Cc: stable@xxxxxxxxxxxxxxx
Fixes: 637cd060537d ("rbd: new exclusive lock wait/wake code")
Signed-off-by: Ilya Dryomov <idryomov@xxxxxxxxx>
---
   drivers/block/rbd.c | 22 ++++++++++++++--------
   1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 63897d0d6629..12b5d53ec856 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -3452,14 +3452,15 @@ static bool rbd_lock_add_request(struct rbd_img_request *img_req)
   static void rbd_lock_del_request(struct rbd_img_request *img_req)
   {
       struct rbd_device *rbd_dev = img_req->rbd_dev;
-     bool need_wakeup;
+     bool need_wakeup = false;

       lockdep_assert_held(&rbd_dev->lock_rwsem);
       spin_lock(&rbd_dev->lock_lists_lock);
-     rbd_assert(!list_empty(&img_req->lock_item));
-     list_del_init(&img_req->lock_item);
-     need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING &&
-                    list_empty(&rbd_dev->running_list));
+     if (!list_empty(&img_req->lock_item)) {
+             list_del_init(&img_req->lock_item);
+             need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING &&
+                            list_empty(&rbd_dev->running_list));
+     }
       spin_unlock(&rbd_dev->lock_lists_lock);
       if (need_wakeup)
               complete(&rbd_dev->releasing_wait);
@@ -3842,14 +3843,19 @@ static void wake_lock_waiters(struct rbd_device *rbd_dev, int result)
               return;
       }

-     list_for_each_entry(img_req, &rbd_dev->acquiring_list, lock_item) {
+     while (!list_empty(&rbd_dev->acquiring_list)) {
+             img_req = list_first_entry(&rbd_dev->acquiring_list,
+                                        struct rbd_img_request, lock_item);
               mutex_lock(&img_req->state_mutex);
               rbd_assert(img_req->state == RBD_IMG_EXCLUSIVE_LOCK);
+             if (!result)
+                     list_move_tail(&img_req->lock_item,
+                                    &rbd_dev->running_list);
+             else
+                     list_del_init(&img_req->lock_item);
               rbd_img_schedule(img_req, result);
               mutex_unlock(&img_req->state_mutex);
       }
-
-     list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list);

Hi Ilya,
         If we dont move these requests to ->running_list, then the need_wakeup
is always false for these requests. So who will finally complete the
&rbd_dev->releaseing_wait ?

Hi Dongsheng,

These requests are woken up explicitly in rbd_img_schedule().  Because
img_req->work_result would be set to an error, the state machine would
finish immediately on:

     case RBD_IMG_EXCLUSIVE_LOCK:
             if (*result)
                     return true;

rbd_dev->releasing_wait doesn't need to be completed in this case
because these requests are terminated while still on the acquiring
list.  Waiting for their state machines to get scheduled just to hit
that "if (*result)" check and bail isn't necessary.

Hi Ilya,
	Thanx for your explanation, looks good to me now.

Reviewed-by: Dongsheng Yang <dongsheng.yang@xxxxxxxxxxxx>

Thanx

Thanks,

                 Ilya





[Index of Archives]     [CEPH Users]     [Ceph Large]     [Ceph Dev]     [Information on CEPH]     [Linux BTRFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux