scsi_debug: fix compare and write errors
Kernel build tools pointed out a memory leak so that has been fixed and its error paths strengthened with a goto. Testing showed compare and write was only working for lba=0; correcting the length of the LBA field fixed that. Signed-off-by: Douglas Gilbert <dgilbert@interlog.com> Reviewed-by: Ewan D. Milne <emilne@redhat.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
b9f85b1d32
commit
d467d31f70
|
@ -3044,18 +3044,12 @@ resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
|
||||||
u8 num;
|
u8 num;
|
||||||
unsigned long iflags;
|
unsigned long iflags;
|
||||||
int ret;
|
int ret;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
lba = get_unaligned_be32(cmd + 2);
|
lba = get_unaligned_be64(cmd + 2);
|
||||||
num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
|
num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
|
||||||
if (0 == num)
|
if (0 == num)
|
||||||
return 0; /* degenerate case, not an error */
|
return 0; /* degenerate case, not an error */
|
||||||
dnum = 2 * num;
|
|
||||||
arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
|
|
||||||
if (NULL == arr) {
|
|
||||||
mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
|
|
||||||
INSUFF_RES_ASCQ);
|
|
||||||
return check_condition_result;
|
|
||||||
}
|
|
||||||
if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
|
if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
|
||||||
(cmd[1] & 0xe0)) {
|
(cmd[1] & 0xe0)) {
|
||||||
mk_sense_invalid_opcode(scp);
|
mk_sense_invalid_opcode(scp);
|
||||||
|
@ -3078,6 +3072,13 @@ resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
|
||||||
mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
|
mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
|
||||||
return check_condition_result;
|
return check_condition_result;
|
||||||
}
|
}
|
||||||
|
dnum = 2 * num;
|
||||||
|
arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
|
||||||
|
if (NULL == arr) {
|
||||||
|
mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
|
||||||
|
INSUFF_RES_ASCQ);
|
||||||
|
return check_condition_result;
|
||||||
|
}
|
||||||
|
|
||||||
write_lock_irqsave(&atomic_rw, iflags);
|
write_lock_irqsave(&atomic_rw, iflags);
|
||||||
|
|
||||||
|
@ -3088,24 +3089,24 @@ resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
|
||||||
ret = do_device_access(scp, 0, dnum, true);
|
ret = do_device_access(scp, 0, dnum, true);
|
||||||
fake_storep = fake_storep_hold;
|
fake_storep = fake_storep_hold;
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
write_unlock_irqrestore(&atomic_rw, iflags);
|
retval = DID_ERROR << 16;
|
||||||
kfree(arr);
|
goto cleanup;
|
||||||
return DID_ERROR << 16;
|
|
||||||
} else if ((ret < (dnum * lb_size)) &&
|
} else if ((ret < (dnum * lb_size)) &&
|
||||||
(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
|
(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
|
||||||
sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
|
sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
|
||||||
"indicated=%u, IO sent=%d bytes\n", my_name,
|
"indicated=%u, IO sent=%d bytes\n", my_name,
|
||||||
dnum * lb_size, ret);
|
dnum * lb_size, ret);
|
||||||
if (!comp_write_worker(lba, num, arr)) {
|
if (!comp_write_worker(lba, num, arr)) {
|
||||||
write_unlock_irqrestore(&atomic_rw, iflags);
|
|
||||||
kfree(arr);
|
|
||||||
mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
|
mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
|
||||||
return check_condition_result;
|
retval = check_condition_result;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (scsi_debug_lbp())
|
if (scsi_debug_lbp())
|
||||||
map_region(lba, num);
|
map_region(lba, num);
|
||||||
|
cleanup:
|
||||||
write_unlock_irqrestore(&atomic_rw, iflags);
|
write_unlock_irqrestore(&atomic_rw, iflags);
|
||||||
return 0;
|
kfree(arr);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct unmap_block_desc {
|
struct unmap_block_desc {
|
||||||
|
|
Loading…
Reference in New Issue