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

[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.
parent 2f04ba94
...@@ -1821,13 +1821,14 @@ EXPORT_SYMBOL(blk_rq_map_user); ...@@ -1821,13 +1821,14 @@ EXPORT_SYMBOL(blk_rq_map_user);
* Description: * Description:
* Unmap a request previously mapped by blk_rq_map_user(). * 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; const int read = rq_data_dir(rq) == READ;
int ret = 0; int ret = 0;
if (rq->biotail) if (bio)
bio_unmap_user(rq->biotail, read); bio_unmap_user(bio, read);
if (rq->buffer) { if (rq->buffer) {
if (read && copy_to_user(ubuf, rq->buffer, ulen)) if (read && copy_to_user(ubuf, rq->buffer, ulen))
ret = -EFAULT; ret = -EFAULT;
......
...@@ -111,6 +111,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk, ...@@ -111,6 +111,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk,
unsigned long start_time; unsigned long start_time;
int reading, writing; int reading, writing;
struct request *rq; struct request *rq;
struct bio *bio;
char sense[SCSI_SENSE_BUFFERSIZE]; char sense[SCSI_SENSE_BUFFERSIZE];
if (hdr->interface_id != 'S') if (hdr->interface_id != 'S')
...@@ -164,6 +165,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk, ...@@ -164,6 +165,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk,
rq->sense_len = 0; rq->sense_len = 0;
rq->flags |= REQ_BLOCK_PC; rq->flags |= REQ_BLOCK_PC;
bio = rq->bio;
rq->timeout = (hdr->timeout * HZ) / 1000; rq->timeout = (hdr->timeout * HZ) / 1000;
if (!rq->timeout) if (!rq->timeout)
...@@ -199,7 +201,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk, ...@@ -199,7 +201,7 @@ static int sg_io(request_queue_t *q, struct gendisk *bd_disk,
hdr->sb_len_wr = len; 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; return -EFAULT;
/* may not have succeeded, but output values written to control /* may not have succeeded, but output values written to control
......
...@@ -1946,6 +1946,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, ...@@ -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; request_queue_t *q = cdi->disk->queue;
struct request *rq; struct request *rq;
struct bio *bio;
unsigned int len; unsigned int len;
int nr, ret = 0; int nr, ret = 0;
...@@ -1980,6 +1981,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, ...@@ -1980,6 +1981,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
rq->cmd_len = 12; rq->cmd_len = 12;
rq->flags |= REQ_BLOCK_PC; rq->flags |= REQ_BLOCK_PC;
rq->timeout = 60 * HZ; rq->timeout = 60 * HZ;
bio = 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;
...@@ -1987,7 +1989,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, ...@@ -1987,7 +1989,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
cdi->last_sense = s->sense_key; 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; ret = -EFAULT;
if (ret) if (ret)
......
...@@ -522,7 +522,7 @@ extern void __blk_stop_queue(request_queue_t *q); ...@@ -522,7 +522,7 @@ extern void __blk_stop_queue(request_queue_t *q);
extern void blk_run_queue(request_queue_t *); extern void blk_run_queue(request_queue_t *);
extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); 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 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 *); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *);
static inline request_queue_t *bdev_get_queue(struct block_device *bdev) static inline request_queue_t *bdev_get_queue(struct block_device *bdev)
......
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