diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2012-03-26 20:12:24 +0200 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 16:58:25 +0100 |
commit | 648e46b531006b069c66f171151819d10b423c26 (patch) | |
tree | e0550b7e6972b46bb580637c02895a6a2d87dc67 /drivers/block/drbd/drbd_req.c | |
parent | 4439c400ab278378a82efb543bb3bb91b184d8db (diff) |
drbd: complete_conflicting_writes() should not care about connections
complete_conflicting_writes() should not cause -EIO.
It should not timeout either, or care for connection states.
Connection timeout is detected elsewhere, and it's cleanup path is
supposed to remove any pending requests or peer_requests from the
write_requests tree.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_req.c')
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 46 |
1 files changed, 26 insertions, 20 deletions
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 1249672519ca..c76402c3f64c 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -800,21 +800,33 @@ static bool remote_due_to_read_balancing(struct drbd_conf *mdev, sector_t sector * The write_requests tree contains all active write requests which we * currently know about. Wait for any requests to complete which conflict with * the new one. + * + * Only way out: remove the conflicting intervals from the tree. */ -static int complete_conflicting_writes(struct drbd_conf *mdev, - sector_t sector, int size) +static void complete_conflicting_writes(struct drbd_request *req) { - for(;;) { - struct drbd_interval *i; - int err; + DEFINE_WAIT(wait); + struct drbd_conf *mdev = req->w.mdev; + struct drbd_interval *i; + sector_t sector = req->i.sector; + int size = req->i.size; + i = drbd_find_overlap(&mdev->write_requests, sector, size); + if (!i) + return; + + for (;;) { + prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE); i = drbd_find_overlap(&mdev->write_requests, sector, size); if (!i) - return 0; - err = drbd_wait_misc(mdev, i); - if (err) - return err; + break; + /* Indicate to wake up device->misc_wait on progress. */ + i->waiting = true; + spin_unlock_irq(&mdev->tconn->req_lock); + schedule(); + spin_lock_irq(&mdev->tconn->req_lock); } + finish_wait(&mdev->misc_wait, &wait); } int __drbd_make_request(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) @@ -826,7 +838,7 @@ int __drbd_make_request(struct drbd_conf *mdev, struct bio *bio, unsigned long s struct drbd_request *req; struct net_conf *nc; int local, remote, send_oos = 0; - int err; + int err = 0; int ret = 0; union drbd_dev_state s; @@ -925,16 +937,10 @@ allocate_barrier: spin_lock_irq(&mdev->tconn->req_lock); if (rw == WRITE) { - err = complete_conflicting_writes(mdev, sector, size); - if (err) { - if (err != -ERESTARTSYS) - _conn_request_state(mdev->tconn, - NS(conn, C_TIMEOUT), - CS_HARD); - spin_unlock_irq(&mdev->tconn->req_lock); - err = -EIO; - goto fail_free_complete; - } + /* This may temporarily give up the req_lock, + * but will re-aquire it before it returns here. + * Needs to be before the check on drbd_suspended() */ + complete_conflicting_writes(req); } if (drbd_suspended(mdev)) { |