Commit dac25d20 authored by Jens Axboe's avatar Jens Axboe Committed by Linus Torvalds

[PATCH] BIO page refcounting fix

Hopefully fixes the free-of-a-freed-page BUG caused during CDRW writing.

This also fixes a problem in the bouncing for io errors (it needs to free
the pages and clear the BIO_UPTODATE flag, not set it.  it's already set.
passing -EIO to bio_endio() takes care of that).
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 09e77fca
...@@ -1813,6 +1813,12 @@ EXPORT_SYMBOL(blk_insert_request); ...@@ -1813,6 +1813,12 @@ EXPORT_SYMBOL(blk_insert_request);
* *
* A matching blk_rq_unmap_user() must be issued at the end of io, while * A matching blk_rq_unmap_user() must be issued at the end of io, while
* still in process context. * still in process context.
*
* Note: The mapped bio may need to be bounced through blk_queue_bounce()
* before being submitted to the device, as pages mapped may be out of
* reach. It's the callers responsibility to make sure this happens. The
* original bio must be passed back in to blk_rq_unmap_user() for proper
* unmapping.
*/ */
struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf, struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf,
unsigned int len) unsigned int len)
......
...@@ -170,6 +170,13 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk, ...@@ -170,6 +170,13 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk,
rq->flags |= REQ_BLOCK_PC; rq->flags |= REQ_BLOCK_PC;
bio = rq->bio; bio = rq->bio;
/*
* bounce this after holding a reference to the original bio, it's
* needed for proper unmapping
*/
if (rq->bio)
blk_queue_bounce(q, &rq->bio);
rq->timeout = (hdr->timeout * HZ) / 1000; rq->timeout = (hdr->timeout * HZ) / 1000;
if (!rq->timeout) if (!rq->timeout)
rq->timeout = q->sg_timeout; rq->timeout = q->sg_timeout;
......
...@@ -2002,6 +2002,9 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, ...@@ -2002,6 +2002,9 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
rq->timeout = 60 * HZ; rq->timeout = 60 * HZ;
bio = rq->bio; bio = rq->bio;
if (rq->bio)
blk_queue_bounce(q, &rq->bio);
if (blk_execute_rq(q, cdi->disk, rq)) { if (blk_execute_rq(q, cdi->disk, rq)) {
struct request_sense *s = rq->sense; struct request_sense *s = rq->sense;
ret = -EIO; ret = -EIO;
......
...@@ -446,7 +446,6 @@ static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev, ...@@ -446,7 +446,6 @@ static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev,
if (!write_to_vm) if (!write_to_vm)
bio->bi_rw |= (1 << BIO_RW); bio->bi_rw |= (1 << BIO_RW);
blk_queue_bounce(q, &bio);
return bio; return bio;
out: out:
kfree(pages); kfree(pages);
......
...@@ -308,12 +308,10 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool) ...@@ -308,12 +308,10 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool)
{ {
struct bio *bio_orig = bio->bi_private; struct bio *bio_orig = bio->bi_private;
struct bio_vec *bvec, *org_vec; struct bio_vec *bvec, *org_vec;
int i; int i, err = 0;
if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
goto out_eio; err = -EIO;
set_bit(BIO_UPTODATE, &bio_orig->bi_flags);
/* /*
* free up bounce indirect pages used * free up bounce indirect pages used
...@@ -326,8 +324,7 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool) ...@@ -326,8 +324,7 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool)
mempool_free(bvec->bv_page, pool); mempool_free(bvec->bv_page, pool);
} }
out_eio: bio_endio(bio_orig, bio_orig->bi_size, err);
bio_endio(bio_orig, bio_orig->bi_size, 0);
bio_put(bio); bio_put(bio);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment