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>
This commit is contained in:
@@ -441,33 +441,12 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
|
|||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void crypt_free_buffer_pages(struct crypt_config *cc,
|
static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone)
|
||||||
struct bio *clone, unsigned int bytes)
|
|
||||||
{
|
{
|
||||||
unsigned int i, start, end;
|
unsigned int i;
|
||||||
struct bio_vec *bv;
|
struct bio_vec *bv;
|
||||||
|
|
||||||
/*
|
for (i = 0; i < clone->bi_vcnt; i++) {
|
||||||
* This is ugly, but Jens Axboe thinks that using bi_idx in the
|
|
||||||
* endio function is too dangerous at the moment, so I calculate the
|
|
||||||
* correct position using bi_vcnt and bi_size.
|
|
||||||
* The bv_offset and bv_len fields might already be modified but we
|
|
||||||
* know that we always allocated whole pages.
|
|
||||||
* A fix to the bi_idx issue in the kernel is in the works, so
|
|
||||||
* we will hopefully be able to revert to the cleaner solution soon.
|
|
||||||
*/
|
|
||||||
i = clone->bi_vcnt - 1;
|
|
||||||
bv = bio_iovec_idx(clone, i);
|
|
||||||
end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - clone->bi_size;
|
|
||||||
start = end - bytes;
|
|
||||||
|
|
||||||
start >>= PAGE_SHIFT;
|
|
||||||
if (!clone->bi_size)
|
|
||||||
end = clone->bi_vcnt;
|
|
||||||
else
|
|
||||||
end >>= PAGE_SHIFT;
|
|
||||||
|
|
||||||
for (i = start; i < end; i++) {
|
|
||||||
bv = bio_iovec_idx(clone, i);
|
bv = bio_iovec_idx(clone, i);
|
||||||
BUG_ON(!bv->bv_page);
|
BUG_ON(!bv->bv_page);
|
||||||
mempool_free(bv->bv_page, cc->page_pool);
|
mempool_free(bv->bv_page, cc->page_pool);
|
||||||
@@ -519,7 +498,7 @@ static void crypt_endio(struct bio *clone, int error)
|
|||||||
* free the processed pages
|
* free the processed pages
|
||||||
*/
|
*/
|
||||||
if (!read_io) {
|
if (!read_io) {
|
||||||
crypt_free_buffer_pages(cc, clone, clone->bi_size);
|
crypt_free_buffer_pages(cc, clone);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,7 +587,7 @@ static void process_write(struct dm_crypt_io *io)
|
|||||||
ctx.idx_out = 0;
|
ctx.idx_out = 0;
|
||||||
|
|
||||||
if (unlikely(crypt_convert(cc, &ctx) < 0)) {
|
if (unlikely(crypt_convert(cc, &ctx) < 0)) {
|
||||||
crypt_free_buffer_pages(cc, clone, clone->bi_size);
|
crypt_free_buffer_pages(cc, clone);
|
||||||
bio_put(clone);
|
bio_put(clone);
|
||||||
dec_pending(io, -EIO);
|
dec_pending(io, -EIO);
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user