diff options
author | Neil Brown <neilb@suse.de> | 2007-10-16 07:48:46 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2007-10-16 07:48:46 -0400 |
commit | 644bd2f048972d75eb1979b1fdca257d528ce687 (patch) | |
tree | 1a6c067c285ba8497e433f8545c550dc4ffc7135 /drivers/md/dm-crypt.c | |
parent | 3eed13fd933dbb81db12f7cdec6de9268c4443b5 (diff) |
Fix memory leak in dm-crypt
dm-crypt used the ->bi_size member in the bio endio handling to
free the appropriate pages, but it frees all of it from both call
paths. With the ->bi_end_io() changes, ->bi_size was always 0 since
we don't do partial completes. This caused dm-crypt to leak memory.
Fix this by removing the size argument from crypt_free_buffer_pages().
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'drivers/md/dm-crypt.c')
-rw-r--r-- | drivers/md/dm-crypt.c | 31 |
1 files changed, 5 insertions, 26 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 8216a6f75be5..64fee90bb68b 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -441,33 +441,12 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size) | |||
441 | return clone; | 441 | return clone; |
442 | } | 442 | } |
443 | 443 | ||
444 | static void crypt_free_buffer_pages(struct crypt_config *cc, | 444 | static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone) |
445 | struct bio *clone, unsigned int bytes) | ||
446 | { | 445 | { |
447 | unsigned int i, start, end; | 446 | unsigned int i; |
448 | struct bio_vec *bv; | 447 | struct bio_vec *bv; |
449 | 448 | ||
450 | /* | 449 | for (i = 0; i < clone->bi_vcnt; i++) { |
451 | * This is ugly, but Jens Axboe thinks that using bi_idx in the | ||
452 | * endio function is too dangerous at the moment, so I calculate the | ||
453 | * correct position using bi_vcnt and bi_size. | ||
454 | * The bv_offset and bv_len fields might already be modified but we | ||
455 | * know that we always allocated whole pages. | ||
456 | * A fix to the bi_idx issue in the kernel is in the works, so | ||
457 | * we will hopefully be able to revert to the cleaner solution soon. | ||
458 | */ | ||
459 | i = clone->bi_vcnt - 1; | ||
460 | bv = bio_iovec_idx(clone, i); | ||
461 | end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - clone->bi_size; | ||
462 | start = end - bytes; | ||
463 | |||
464 | start >>= PAGE_SHIFT; | ||
465 | if (!clone->bi_size) | ||
466 | end = clone->bi_vcnt; | ||
467 | else | ||
468 | end >>= PAGE_SHIFT; | ||
469 | |||
470 | for (i = start; i < end; i++) { | ||
471 | bv = bio_iovec_idx(clone, i); | 450 | bv = bio_iovec_idx(clone, i); |
472 | BUG_ON(!bv->bv_page); | 451 | BUG_ON(!bv->bv_page); |
473 | mempool_free(bv->bv_page, cc->page_pool); | 452 | mempool_free(bv->bv_page, cc->page_pool); |
@@ -519,7 +498,7 @@ static void crypt_endio(struct bio *clone, int error) | |||
519 | * free the processed pages | 498 | * free the processed pages |
520 | */ | 499 | */ |
521 | if (!read_io) { | 500 | if (!read_io) { |
522 | crypt_free_buffer_pages(cc, clone, clone->bi_size); | 501 | crypt_free_buffer_pages(cc, clone); |
523 | goto out; | 502 | goto out; |
524 | } | 503 | } |
525 | 504 | ||
@@ -608,7 +587,7 @@ static void process_write(struct dm_crypt_io *io) | |||
608 | ctx.idx_out = 0; | 587 | ctx.idx_out = 0; |
609 | 588 | ||
610 | if (unlikely(crypt_convert(cc, &ctx) < 0)) { | 589 | if (unlikely(crypt_convert(cc, &ctx) < 0)) { |
611 | crypt_free_buffer_pages(cc, clone, clone->bi_size); | 590 | crypt_free_buffer_pages(cc, clone); |
612 | bio_put(clone); | 591 | bio_put(clone); |
613 | dec_pending(io, -EIO); | 592 | dec_pending(io, -EIO); |
614 | return; | 593 | return; |