diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2012-08-14 05:28:52 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-09 08:05:50 -0500 |
commit | 5af2e8ce2b463c2cc8e4a074f9d8f660ae7c1d8f (patch) | |
tree | 17e450ce313e0fa63096c61acf57536f4e40f533 | |
parent | 715306f69d85f7ea21eaef4efe75b8364cfea1d5 (diff) |
drbd: Fix completion of requests while the device is suspended
In various places (E.g. CONNECTION_LOST_WHILE_PENDING) the
RQ_COMPLETION_SUSP mask is passed in the clear set to mod_rq_state().
The issue was that it tried to clear the RQ_COMPLETION_SUSP bit
out of the state mask first, and eventuelly set it afterwards,
in the drbd_req_put_completion_ref() function.
Fixed that by moving the reference getting out of
drbd_req_put_completion_ref() into the mod_rq_state(), before the place
where the extra reference might be put.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 18 |
1 files changed, 6 insertions, 12 deletions
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 266ef24b3c74..5ddb01edd933 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c | |||
@@ -304,18 +304,6 @@ static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_ | |||
304 | if (!atomic_sub_and_test(put, &req->completion_ref)) | 304 | if (!atomic_sub_and_test(put, &req->completion_ref)) |
305 | return 0; | 305 | return 0; |
306 | 306 | ||
307 | if (drbd_suspended(mdev)) { | ||
308 | /* We do not allow completion while suspended. Re-get a | ||
309 | * reference, so whatever happens when this is resumed | ||
310 | * may put and complete. */ | ||
311 | |||
312 | D_ASSERT(!(req->rq_state & RQ_COMPLETION_SUSP)); | ||
313 | req->rq_state |= RQ_COMPLETION_SUSP; | ||
314 | atomic_inc(&req->completion_ref); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* else */ | ||
319 | drbd_req_complete(req, m); | 307 | drbd_req_complete(req, m); |
320 | 308 | ||
321 | if (req->rq_state & RQ_POSTPONED) { | 309 | if (req->rq_state & RQ_POSTPONED) { |
@@ -338,6 +326,9 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m, | |||
338 | int c_put = 0; | 326 | int c_put = 0; |
339 | int k_put = 0; | 327 | int k_put = 0; |
340 | 328 | ||
329 | if (drbd_suspended(mdev) && !((s | clear) & RQ_COMPLETION_SUSP)) | ||
330 | set |= RQ_COMPLETION_SUSP; | ||
331 | |||
341 | /* apply */ | 332 | /* apply */ |
342 | 333 | ||
343 | req->rq_state &= ~clear; | 334 | req->rq_state &= ~clear; |
@@ -366,6 +357,9 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m, | |||
366 | if (!(s & RQ_NET_SENT) && (set & RQ_NET_SENT)) | 357 | if (!(s & RQ_NET_SENT) && (set & RQ_NET_SENT)) |
367 | atomic_add(req->i.size >> 9, &mdev->ap_in_flight); | 358 | atomic_add(req->i.size >> 9, &mdev->ap_in_flight); |
368 | 359 | ||
360 | if (!(s & RQ_COMPLETION_SUSP) && (set & RQ_COMPLETION_SUSP)) | ||
361 | atomic_inc(&req->completion_ref); | ||
362 | |||
369 | /* progress: put references */ | 363 | /* progress: put references */ |
370 | 364 | ||
371 | if ((s & RQ_COMPLETION_SUSP) && (clear & RQ_COMPLETION_SUSP)) | 365 | if ((s & RQ_COMPLETION_SUSP) && (clear & RQ_COMPLETION_SUSP)) |