mirror of
https://github.com/torvalds/linux.git
synced 2026-09-14 16:10:02 +02:00
scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails
sd_set_special_bvec() allocates a special payload page for UNMAP and
WRITE SAME commands. If scsi_alloc_sgtables() fails afterward in
sd_setup_unmap_cmnd() or sd_setup_write_same{10,16}_cmnd(), the SCSI
midlayer does not call uninit_command() because RQF_DONTPREP is not set
yet, leaking the page.
Call sd_uninit_command() on error, and clear RQF_SPECIAL_PAYLOAD after
freeing the page.
Fixes: 81d926e8b5 ("sd: split sd_setup_discard_cmnd")
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Reviewed-by: John Garry <john.g.garry@oracle.com>
Link: https://patch.msgid.link/20260707030333.22245-3-yangxiuwei@kylinos.cn
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
parent
e3cc6ea1a7
commit
bb31844d88
|
|
@ -958,6 +958,21 @@ static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,
|
|||
return protect;
|
||||
}
|
||||
|
||||
static void sd_uninit_command(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct request *rq = scsi_cmd_to_rq(cmd);
|
||||
struct scsi_device *sdp = cmd->device;
|
||||
|
||||
if (!(rq->rq_flags & RQF_SPECIAL_PAYLOAD))
|
||||
return;
|
||||
|
||||
if (sdp->sector_size > PAGE_SIZE)
|
||||
mempool_free(rq->special_vec.bv_page, sd_large_page_pool);
|
||||
else
|
||||
mempool_free(rq->special_vec.bv_page, sd_page_pool);
|
||||
rq->rq_flags &= ~RQF_SPECIAL_PAYLOAD;
|
||||
}
|
||||
|
||||
static void *sd_set_special_bvec(struct scsi_cmnd *cmd, unsigned int data_len)
|
||||
{
|
||||
struct page *page;
|
||||
|
|
@ -990,6 +1005,7 @@ static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd)
|
|||
u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq));
|
||||
unsigned int data_len = 24;
|
||||
char *buf;
|
||||
blk_status_t ret;
|
||||
|
||||
buf = sd_set_special_bvec(cmd, data_len);
|
||||
if (!buf)
|
||||
|
|
@ -1008,7 +1024,10 @@ static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd)
|
|||
cmd->transfersize = data_len;
|
||||
rq->timeout = SD_TIMEOUT;
|
||||
|
||||
return scsi_alloc_sgtables(cmd);
|
||||
ret = scsi_alloc_sgtables(cmd);
|
||||
if (ret != BLK_STS_OK)
|
||||
sd_uninit_command(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sd_config_atomic(struct scsi_disk *sdkp, struct queue_limits *lim)
|
||||
|
|
@ -1079,6 +1098,7 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd,
|
|||
u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq));
|
||||
u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq));
|
||||
u32 data_len = sdp->sector_size;
|
||||
blk_status_t ret;
|
||||
|
||||
if (!sd_set_special_bvec(cmd, data_len))
|
||||
return BLK_STS_RESOURCE;
|
||||
|
|
@ -1094,7 +1114,10 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd,
|
|||
cmd->transfersize = data_len;
|
||||
rq->timeout = unmap ? SD_TIMEOUT : SD_WRITE_SAME_TIMEOUT;
|
||||
|
||||
return scsi_alloc_sgtables(cmd);
|
||||
ret = scsi_alloc_sgtables(cmd);
|
||||
if (ret != BLK_STS_OK)
|
||||
sd_uninit_command(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,
|
||||
|
|
@ -1106,6 +1129,7 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,
|
|||
u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq));
|
||||
u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq));
|
||||
u32 data_len = sdp->sector_size;
|
||||
blk_status_t ret;
|
||||
|
||||
if (!sd_set_special_bvec(cmd, data_len))
|
||||
return BLK_STS_RESOURCE;
|
||||
|
|
@ -1121,7 +1145,10 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,
|
|||
cmd->transfersize = data_len;
|
||||
rq->timeout = unmap ? SD_TIMEOUT : SD_WRITE_SAME_TIMEOUT;
|
||||
|
||||
return scsi_alloc_sgtables(cmd);
|
||||
ret = scsi_alloc_sgtables(cmd);
|
||||
if (ret != BLK_STS_OK)
|
||||
sd_uninit_command(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static blk_status_t sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd)
|
||||
|
|
@ -1550,20 +1577,6 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
static void sd_uninit_command(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
struct request *rq = scsi_cmd_to_rq(SCpnt);
|
||||
struct scsi_device *sdp = SCpnt->device;
|
||||
unsigned sector_size = sdp->sector_size;
|
||||
|
||||
if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) {
|
||||
if (sector_size > PAGE_SIZE)
|
||||
mempool_free(rq->special_vec.bv_page, sd_large_page_pool);
|
||||
else
|
||||
mempool_free(rq->special_vec.bv_page, sd_page_pool);
|
||||
}
|
||||
}
|
||||
|
||||
static bool sd_need_revalidate(struct gendisk *disk, struct scsi_disk *sdkp)
|
||||
{
|
||||
if (sdkp->device->removable || sdkp->write_prot) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user