[PATCH] bio_uncopy_user mem leak

From: Kurt Garloff
Date: Tue Aug 17 2004 - 11:02:37 EST


Hi Andrew,

When using bounce buffers for SG_IO commands with unaligned
buffers in blk_rq_map_user(), we should free the pages from
blk_rq_unmap_user() which calls bio_uncopy_user() for the
non-BIO_USER_MAPPED case. That function failed to free the
pages for write requests.

So we leaked pages and you machine would go OOM. Rebooting
helped ;-)

This bug was triggered by writing audio CDs (but not on data
CDs), as the audio frames are not aligned well (2352 bytes),
so the user pages don't just get mapped.

Bug was reported by Mathias Homan and debugged by Chris Mason + me.
(Jens is away.)

Signed-off-by: Kurt Garloff <garloff@xxxxxxx>

bio.c | 21 +++++++++------------
1 files changed, 9 insertions(+), 12 deletions(-)

--- linux-2.6.8.x86/fs/bio.c.orig 2004-08-14 07:37:15.000000000 +0200
+++ linux-2.6.8.x86/fs/bio.c 2004-08-17 17:41:52.022012902 +0200
@@ -388,20 +388,17 @@ int bio_uncopy_user(struct bio *bio)
struct bio_vec *bvec;
int i, ret = 0;

- if (bio_data_dir(bio) == READ) {
- char *uaddr = bio->bi_private;
-
- __bio_for_each_segment(bvec, bio, i, 0) {
- char *addr = page_address(bvec->bv_page);
-
- if (!ret && copy_to_user(uaddr, addr, bvec->bv_len))
- ret = -EFAULT;
+ char *uaddr = bio->bi_private;
+
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ char *addr = page_address(bvec->bv_page);
+ if (bio_data_dir(bio) == READ && !ret &&
+ copy_to_user(uaddr, addr, bvec->bv_len))
+ ret = -EFAULT;

- __free_page(bvec->bv_page);
- uaddr += bvec->bv_len;
- }
+ __free_page(bvec->bv_page);
+ uaddr += bvec->bv_len;
}
-
bio_put(bio);
return ret;
}

--
Kurt Garloff, Director SUSE Labs, Novell

Attachment: pgp00000.pgp
Description: PGP signature