Merge patch series "scsi: sd: fix probe error cleanup, special_vec leak and sd_done() sense gate"

Yang Xiuwei <yangxiuwei@kylinos.cn> says:

This series fixes three resource-handling bugs in drivers/scsi/sd.c:
sd_probe() error cleanup, special_vec mempool leak on prep failure,
and sd_done() sense handling.

v1: https://lore.kernel.org/all/20260623100159.4018066-1-yangxiuwei@kylinos.cn/

Link: https://patch.msgid.link/20260707030333.22245-1-yangxiuwei@kylinos.cn
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
Martin K. Petersen (Oracle) 2026-08-07 13:14:49 -04:00
commit 8368367590

View File

@ -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) {
@ -2406,8 +2419,8 @@ static int sd_done(struct scsi_cmnd *SCpnt)
}
sdkp->medium_access_timed_out = 0;
if (!scsi_status_is_check_condition(result) &&
(!sense_valid || sense_deferred))
if (!scsi_status_is_check_condition(result) ||
!sense_valid || sense_deferred)
goto out;
switch (sshdr.sense_key) {
@ -4089,7 +4102,9 @@ static int sd_probe(struct scsi_device *sdp)
if (sdp->sector_size > PAGE_SIZE) {
if (sd_large_pool_create()) {
error = -ENOMEM;
goto out_free_index;
device_unregister(&sdkp->disk_dev);
put_disk(gd);
goto out;
}
}