diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2010-07-01 06:49:18 -0400 |
---|---|---|
committer | Jens Axboe <jaxboe@fusionio.com> | 2010-08-07 12:23:49 -0400 |
commit | f1126e950d28ff875d96ed6a04a9ff96c7bfc357 (patch) | |
tree | 4d7217b91a658c1c8fa31325f39b102377765f21 /drivers/scsi/sd.c | |
parent | 28018c242a4ec7017bbbf81d2d3952f820a27118 (diff) |
scsi: add sd_unprep_fn to free discard page
This fixes discard page leak by using q->unprep_rq_fn facility.
q->unprep_rq_fn is called when all the data buffer (req->bio and
scsi_data_buffer) in the request is freed.
sd_unprep() uses rq->buffer to free discard page allocated in
sd_prepare_discard().
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 86da819c70eb..2d4e3a865f39 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -425,6 +425,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) | |||
425 | sector_t sector = bio->bi_sector; | 425 | sector_t sector = bio->bi_sector; |
426 | unsigned int nr_sectors = bio_sectors(bio); | 426 | unsigned int nr_sectors = bio_sectors(bio); |
427 | unsigned int len; | 427 | unsigned int len; |
428 | int ret; | ||
428 | struct page *page; | 429 | struct page *page; |
429 | 430 | ||
430 | if (sdkp->device->sector_size == 4096) { | 431 | if (sdkp->device->sector_size == 4096) { |
@@ -465,7 +466,15 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) | |||
465 | } | 466 | } |
466 | 467 | ||
467 | blk_add_request_payload(rq, page, len); | 468 | blk_add_request_payload(rq, page, len); |
468 | return scsi_setup_blk_pc_cmnd(sdp, rq); | 469 | ret = scsi_setup_blk_pc_cmnd(sdp, rq); |
470 | rq->buffer = page_address(page); | ||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | static void sd_unprep_fn(struct request_queue *q, struct request *rq) | ||
475 | { | ||
476 | if (rq->cmd_flags & REQ_DISCARD) | ||
477 | __free_page(virt_to_page(rq->buffer)); | ||
469 | } | 478 | } |
470 | 479 | ||
471 | /** | 480 | /** |
@@ -2242,6 +2251,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) | |||
2242 | sd_revalidate_disk(gd); | 2251 | sd_revalidate_disk(gd); |
2243 | 2252 | ||
2244 | blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); | 2253 | blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); |
2254 | blk_queue_unprep_rq(sdp->request_queue, sd_unprep_fn); | ||
2245 | 2255 | ||
2246 | gd->driverfs_dev = &sdp->sdev_gendev; | 2256 | gd->driverfs_dev = &sdp->sdev_gendev; |
2247 | gd->flags = GENHD_FL_EXT_DEVT; | 2257 | gd->flags = GENHD_FL_EXT_DEVT; |