aboutsummaryrefslogtreecommitdiff
path: root/drivers/block/drbd/drbd_req.c
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2012-07-24 10:12:36 +0200
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 16:58:37 +0100
commit9a278a7906066a1b4f37fff9b5e27a92af0ca3ce (patch)
tree8dd98edd53bc8e0c17f2681e4418b96ffb7af736 /drivers/block/drbd/drbd_req.c
parent934722a2dbf87b43d39c787441e511157d5add94 (diff)
downloadvexpress-lsk-9a278a7906066a1b4f37fff9b5e27a92af0ca3ce.tar.gz
drbd: allow read requests to be retried after force-detach
Sometimes, a lower level block device turns into a tar-pit, not completing requests at all, not even doing error completion. We can force-detach from such a tar-pit block device, either by disk-timeout, or by drbdadm detach --force. Queueing for retry only from the request destruction path (kref hit 0) makes it impossible to retry affected read requests from the peer, until the local IO completion happened, as the locally submitted bio holds a reference on the drbd request object. If we can only complete READs when the local completion finally happens, we would not need to force-detach in the first place. Instead, queue for retry where we otherwise had done the error completion. 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.c19
1 files changed, 10 insertions, 9 deletions
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index f2ba43e7837..c45479aaff8 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -92,7 +92,7 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
return req;
}
-static void drbd_req_destroy(struct kref *kref)
+void drbd_req_destroy(struct kref *kref)
{
struct drbd_request *req = container_of(kref, struct drbd_request, kref);
struct drbd_conf *mdev = req->w.mdev;
@@ -152,10 +152,7 @@ static void drbd_req_destroy(struct kref *kref)
}
}
- if (s & RQ_POSTPONED)
- drbd_restart_request(req);
- else
- mempool_free(req, drbd_request_mempool);
+ mempool_free(req, drbd_request_mempool);
}
static void wake_all_senders(struct drbd_tconn *tconn) {
@@ -292,10 +289,6 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m)
m->error = ok ? 0 : (error ?: -EIO);
m->bio = req->master_bio;
req->master_bio = NULL;
- } else {
- /* Assert that this will be drbd_req_destroy()ed
- * with this very invokation. */
- D_ASSERT(atomic_read(&req->kref.refcount) == 1);
}
}
@@ -320,6 +313,14 @@ static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_
/* else */
drbd_req_complete(req, m);
+
+ if (req->rq_state & RQ_POSTPONED) {
+ /* don't destroy the req object just yet,
+ * but queue it for retry */
+ drbd_restart_request(req);
+ return 0;
+ }
+
return 1;
}