diff options
| author | Jens Axboe <axboe@suse.de> | 2004-04-26 18:27:53 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-04-26 18:27:53 -0700 |
| commit | a7716627dd19f0ea48f8ed785baadbb2e956a515 (patch) | |
| tree | fcfb1cab653a00d0db1a7ff2c2864d929d17f30f | |
| parent | 2f04ba946810e409f29a8d3a6b0d5ff7a26491f6 (diff) | |
[PATCH] fix SG_IO page leak
We cannot always rely on ->biotail remaining untouched. Currently we
leak all the pinned user pages when doing cdda ripping at least, so I
see no way around keeping the bio pointer seperate and passing it back
in for unmap. Alternatively, we could invent a struct blk_map_data and
put it on the stack for passing to both map and unmap.
| -rw-r--r-- | drivers/block/ll_rw_blk.c | 7 | ||||
| -rw-r--r-- | drivers/block/scsi_ioctl.c | 4 | ||||
| -rw-r--r-- | drivers/cdrom/cdrom.c | 4 | ||||
| -rw-r--r-- | include/linux/blkdev.h | 2 |
4 files changed, 11 insertions, 6 deletions
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 258adaa49652..9d8fabf416cf 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1821,13 +1821,14 @@ EXPORT_SYMBOL(blk_rq_map_user); * Description: * Unmap a request previously mapped by blk_rq_map_user(). */ -int blk_rq_unmap_user(struct request *rq, void __user *ubuf, unsigned int ulen) +int blk_rq_unmap_user(struct request *rq, void __user *ubuf, struct bio *bio, + unsigned int ulen) { const int read = rq_data_dir(rq) == READ; int ret = 0; - if (rq->biotail) - bio_unmap_user(rq->biotail, read); + if (bio) + bio_unmap_user(bio, read); if (rq->buffer) { if (read && copy_to_user(ubuf, rq->buffer, ulen)) ret = -EFAULT; diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index f4dea310fdb7..e88b6eca91a3 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -111,6 +111,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk, unsigned long start_time; int reading, writing; struct request *rq; + struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; if (hdr->interface_id != 'S') @@ -164,6 +165,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk, rq->sense_len = 0; rq->flags |= REQ_BLOCK_PC; + bio = rq->bio; rq->timeout = (hdr->timeout * HZ) / 1000; if (!rq->timeout) @@ -199,7 +201,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk, hdr->sb_len_wr = len; } - if (blk_rq_unmap_user(rq, hdr->dxferp, hdr->dxfer_len)) + if (blk_rq_unmap_user(rq, hdr->dxferp, bio, hdr->dxfer_len)) return -EFAULT; /* may not have succeeded, but output values written to control diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 9784f1945073..1f65c1e72ec1 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1946,6 +1946,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, { request_queue_t *q = cdi->disk->queue; struct request *rq; + struct bio *bio; unsigned int len; int nr, ret = 0; @@ -1980,6 +1981,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, rq->cmd_len = 12; rq->flags |= REQ_BLOCK_PC; rq->timeout = 60 * HZ; + bio = rq->bio; if (blk_execute_rq(q, cdi->disk, rq)) { struct request_sense *s = rq->sense; @@ -1987,7 +1989,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, cdi->last_sense = s->sense_key; } - if (blk_rq_unmap_user(rq, ubuf, len)) + if (blk_rq_unmap_user(rq, ubuf, bio, len)) ret = -EFAULT; if (ret) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 150aa866348b..0fa0011d0a8f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -522,7 +522,7 @@ extern void __blk_stop_queue(request_queue_t *q); extern void blk_run_queue(request_queue_t *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int); -extern int blk_rq_unmap_user(struct request *, void __user *, unsigned int); +extern int blk_rq_unmap_user(struct request *, void __user *, struct bio *, unsigned int); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *); static inline request_queue_t *bdev_get_queue(struct block_device *bdev) |
