| From 445559cdcb98a141f5de415b94fd6eaccab87e6d Mon Sep 17 00:00:00 2001 |
| From: "Darrick J. Wong" <darrick.wong@oracle.com> |
| Date: Tue, 25 Nov 2014 17:45:15 -0800 |
| Subject: dm bufio: fix memleak when using a dm_buffer's inline bio |
| |
| From: "Darrick J. Wong" <darrick.wong@oracle.com> |
| |
| commit 445559cdcb98a141f5de415b94fd6eaccab87e6d upstream. |
| |
| When dm-bufio sets out to use the bio built into a struct dm_buffer to |
| issue an IO, it needs to call bio_reset after it's done with the bio |
| so that we can free things attached to the bio such as the integrity |
| payload. Therefore, inject our own endio callback to take care of |
| the bio_reset after calling submit_io's end_io callback. |
| |
| Test case: |
| 1. modprobe scsi_debug delay=0 dif=1 dix=199 ato=1 dev_size_mb=300 |
| 2. Set up a dm-bufio client, e.g. dm-verity, on the scsi_debug device |
| 3. Repeatedly read metadata and watch kmalloc-192 leak! |
| |
| Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> |
| Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> |
| Signed-off-by: Mike Snitzer <snitzer@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/md/dm-bufio.c | 20 +++++++++++++++++++- |
| 1 file changed, 19 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/md/dm-bufio.c |
| +++ b/drivers/md/dm-bufio.c |
| @@ -529,6 +529,19 @@ static void use_dmio(struct dm_buffer *b |
| end_io(&b->bio, r); |
| } |
| |
| +static void inline_endio(struct bio *bio, int error) |
| +{ |
| + bio_end_io_t *end_fn = bio->bi_private; |
| + |
| + /* |
| + * Reset the bio to free any attached resources |
| + * (e.g. bio integrity profiles). |
| + */ |
| + bio_reset(bio); |
| + |
| + end_fn(bio, error); |
| +} |
| + |
| static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, |
| bio_end_io_t *end_io) |
| { |
| @@ -540,7 +553,12 @@ static void use_inline_bio(struct dm_buf |
| b->bio.bi_max_vecs = DM_BUFIO_INLINE_VECS; |
| b->bio.bi_sector = block << b->c->sectors_per_block_bits; |
| b->bio.bi_bdev = b->c->bdev; |
| - b->bio.bi_end_io = end_io; |
| + b->bio.bi_end_io = inline_endio; |
| + /* |
| + * Use of .bi_private isn't a problem here because |
| + * the dm_buffer's inline bio is local to bufio. |
| + */ |
| + b->bio.bi_private = end_io; |
| |
| /* |
| * We assume that if len >= PAGE_SIZE ptr is page-aligned. |