aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2007-10-16 07:48:46 -0400
committerJens Axboe <jens.axboe@oracle.com>2007-10-16 07:48:46 -0400
commit644bd2f048972d75eb1979b1fdca257d528ce687 (patch)
tree1a6c067c285ba8497e433f8545c550dc4ffc7135 /drivers/md
parent3eed13fd933dbb81db12f7cdec6de9268c4443b5 (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')
-rw-r--r--drivers/md/dm-crypt.c31
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
444static void crypt_free_buffer_pages(struct crypt_config *cc, 444static 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;