diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 938a57bf73c187d194f62668859242e1e8287657..c0326f54d3ab92883ff8e76937075cac348c5473 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -212,6 +212,16 @@ static void drbd_remove_request_interval(struct rb_root *root, wake_up(&mdev->misc_wait); } +static void maybe_wakeup_conflicting_requests(struct drbd_request *req) +{ + const unsigned long s = req->rq_state; + if (s & RQ_LOCAL_PENDING && !(s & RQ_LOCAL_ABORTED)) + return; + if (req->i.waiting) + /* Retry all conflicting peer requests. */ + wake_up(&req->w.mdev->misc_wait); +} + /* Helper for __req_mod(). * Set m->bio to the master bio, if it is fit to be completed, * or leave it alone (it is initialized to NULL in __req_mod), @@ -235,10 +245,6 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) */ if (s & RQ_LOCAL_PENDING && !(s & RQ_LOCAL_ABORTED)) return; - if (req->i.waiting) { - /* Retry all conflicting peer requests. */ - wake_up(&mdev->misc_wait); - } if (s & RQ_NET_QUEUED) return; if (s & RQ_NET_PENDING) @@ -388,6 +394,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= (RQ_LOCAL_COMPLETED|RQ_LOCAL_OK); req->rq_state &= ~RQ_LOCAL_PENDING; + maybe_wakeup_conflicting_requests(req); _req_may_be_done_not_susp(req, m); put_ldev(mdev); break; @@ -405,6 +412,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state &= ~RQ_LOCAL_PENDING; __drbd_chk_io_error(mdev, false); + maybe_wakeup_conflicting_requests(req); _req_may_be_done_not_susp(req, m); put_ldev(mdev); break; @@ -615,6 +623,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, dec_ap_pending(mdev); atomic_sub(req->i.size >> 9, &mdev->ap_in_flight); req->rq_state &= ~RQ_NET_PENDING; + maybe_wakeup_conflicting_requests(req); _req_may_be_done_not_susp(req, m); break; @@ -626,6 +635,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, */ D_ASSERT(req->rq_state & RQ_NET_PENDING); req->rq_state |= RQ_POSTPONED; + maybe_wakeup_conflicting_requests(req); _req_may_be_done_not_susp(req, m); break; @@ -643,6 +653,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, if (!(req->rq_state & RQ_WRITE)) goto goto_read_retry_local; + maybe_wakeup_conflicting_requests(req); _req_may_be_done_not_susp(req, m); /* else: done by HANDED_OVER_TO_NETWORK */ break;