From 49dbada8b0c0859274a6af35821851d803593539 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 6 Jul 2010 16:47:28 -0400 Subject: [RHEL6 PATCH 3/6] scsi: add sd_unprep_fn to free discard page BZ 610054 commit 4d854b5cb0f9966066fa9a2ecfe18cae5a0b7aa9 Author: FUJITA Tomonori Date: Thu Jul 1 19:49:18 2010 +0900 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 Signed-off-by: Jens Axboe commit 9fc8101934ce1a15552d5509c2fbc9a209d9b5ab Author: FUJITA Tomonori Date: Sat Jul 3 08:07:04 2010 -0600 scsi: need to reset unprep_rq_fn in sd_remove We need to reset q->unprep_rq_fn in sd_remove. Otherwise we hit kernel oops if we access to a scsi disk device via sg after removing scsi disk module. Signed-off-by: FUJITA Tomonori Signed-off-by: Jens Axboe diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f208e72..adc99d2 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -423,6 +423,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) sector_t sector = bio->bi_sector; unsigned int nr_sectors = bio_sectors(bio); unsigned int len; + int ret; struct page *page; if (sdkp->device->sector_size == 4096) { @@ -463,7 +464,15 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) } blk_add_request_payload(rq, page, len); - return scsi_setup_blk_pc_cmnd(sdp, rq); + ret = scsi_setup_blk_pc_cmnd(sdp, rq); + rq->buffer = page_address(page); + return ret; +} + +static void sd_unprep_fn(struct request_queue *q, struct request *rq) +{ + if (rq->cmd_flags & REQ_DISCARD) + __free_page(virt_to_page(rq->buffer)); } /** @@ -2197,6 +2206,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) sd_revalidate_disk(gd); blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); + blk_queue_unprep_rq(sdp->request_queue, sd_unprep_fn); gd->driverfs_dev = &sdp->sdev_gendev; gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS; @@ -2332,6 +2342,7 @@ static int sd_remove(struct device *dev) async_synchronize_full(); sdkp = dev_get_drvdata(dev); blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); + blk_queue_unprep_rq(sdkp->device->request_queue, NULL); device_del(&sdkp->dev); del_gendisk(sdkp->disk); sd_shutdown(dev); -- 1.6.6.1