diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2017-05-11 04:21:46 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2017-05-11 12:04:30 -0400 |
commit | a00ebd1cf12c378a1d4f7a1d6daf1d76c1eaad82 (patch) | |
tree | 98edd7dd6a0d901d705fe94374c983eda5524798 /drivers/block | |
parent | ed6565e734249ef021d5c13ba34c167eb4e42f62 (diff) |
drbd: fix request leak introduced by locking/atomic, kref: Kill kref_sub()
When killing kref_sub(), the unconditional additional kref_get()
was not properly paired with the necessary kref_put(), causing
a leak of struct drbd_requests (~ 224 Bytes) per submitted bio,
and breaking DRBD in general, as the destructor of those "drbd_requests"
does more than just the mempoll_free().
Fixes: bdfafc4ffdd2 ("locking/atomic, kref: Kill kref_sub()")
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Cc: stable@vger.kernel.org # v4.11
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index b5730e17b455..656624314f0d 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c | |||
@@ -315,24 +315,32 @@ void drbd_req_complete(struct drbd_request *req, struct bio_and_error *m) | |||
315 | } | 315 | } |
316 | 316 | ||
317 | /* still holds resource->req_lock */ | 317 | /* still holds resource->req_lock */ |
318 | static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_error *m, int put) | 318 | static void drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_error *m, int put) |
319 | { | 319 | { |
320 | struct drbd_device *device = req->device; | 320 | struct drbd_device *device = req->device; |
321 | D_ASSERT(device, m || (req->rq_state & RQ_POSTPONED)); | 321 | D_ASSERT(device, m || (req->rq_state & RQ_POSTPONED)); |
322 | 322 | ||
323 | if (!put) | ||
324 | return; | ||
325 | |||
323 | if (!atomic_sub_and_test(put, &req->completion_ref)) | 326 | if (!atomic_sub_and_test(put, &req->completion_ref)) |
324 | return 0; | 327 | return; |
325 | 328 | ||
326 | drbd_req_complete(req, m); | 329 | drbd_req_complete(req, m); |
327 | 330 | ||
331 | /* local completion may still come in later, | ||
332 | * we need to keep the req object around. */ | ||
333 | if (req->rq_state & RQ_LOCAL_ABORTED) | ||
334 | return; | ||
335 | |||
328 | if (req->rq_state & RQ_POSTPONED) { | 336 | if (req->rq_state & RQ_POSTPONED) { |
329 | /* don't destroy the req object just yet, | 337 | /* don't destroy the req object just yet, |
330 | * but queue it for retry */ | 338 | * but queue it for retry */ |
331 | drbd_restart_request(req); | 339 | drbd_restart_request(req); |
332 | return 0; | 340 | return; |
333 | } | 341 | } |
334 | 342 | ||
335 | return 1; | 343 | kref_put(&req->kref, drbd_req_destroy); |
336 | } | 344 | } |
337 | 345 | ||
338 | static void set_if_null_req_next(struct drbd_peer_device *peer_device, struct drbd_request *req) | 346 | static void set_if_null_req_next(struct drbd_peer_device *peer_device, struct drbd_request *req) |
@@ -519,12 +527,8 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m, | |||
519 | if (req->i.waiting) | 527 | if (req->i.waiting) |
520 | wake_up(&device->misc_wait); | 528 | wake_up(&device->misc_wait); |
521 | 529 | ||
522 | if (c_put) { | 530 | drbd_req_put_completion_ref(req, m, c_put); |
523 | if (drbd_req_put_completion_ref(req, m, c_put)) | 531 | kref_put(&req->kref, drbd_req_destroy); |
524 | kref_put(&req->kref, drbd_req_destroy); | ||
525 | } else { | ||
526 | kref_put(&req->kref, drbd_req_destroy); | ||
527 | } | ||
528 | } | 532 | } |
529 | 533 | ||
530 | static void drbd_report_io_error(struct drbd_device *device, struct drbd_request *req) | 534 | static void drbd_report_io_error(struct drbd_device *device, struct drbd_request *req) |
@@ -1366,8 +1370,7 @@ nodata: | |||
1366 | } | 1370 | } |
1367 | 1371 | ||
1368 | out: | 1372 | out: |
1369 | if (drbd_req_put_completion_ref(req, &m, 1)) | 1373 | drbd_req_put_completion_ref(req, &m, 1); |
1370 | kref_put(&req->kref, drbd_req_destroy); | ||
1371 | spin_unlock_irq(&resource->req_lock); | 1374 | spin_unlock_irq(&resource->req_lock); |
1372 | 1375 | ||
1373 | /* Even though above is a kref_put(), this is safe. | 1376 | /* Even though above is a kref_put(), this is safe. |