[RFC v2 2/6] scsi_debug: add doublestore option

Douglas Gilbert
2020-01-09T08:30:46Z

The scsi_debug driver has always been restricted to using one
(or none) ramdisk image for its storage. This means that thousands
of scsi_debug devices can be created without exhausting the host
machine's RAM. The downside is that all scsi_debug devices share
the same ramdisk image. This option doubles the amount of ramdisk
storage space with the first, third, fifth (etc) created
scsi_debug devices using the first ramdisk image while the second,
fourth, sixth (etc) created scsi_debug devices using the second
ramdisk image.

The reason for doing this is to check that (partial) disk to disk
copies based on scsi_debug devices have actually worked properly.
As an example: assume /dev/sdb and /dev/sg1 are the same
scsi_debug device, while /dev/sdc and /dev/sg2 are also the
same scsi_debug device. With doublestore=1 they will have
different ramdisk images. Then the following pseudocode could
be executed to check the if sgh_dd copy worked:
dd if=/dev/urandom of=/dev/sdb
sgh_dd if=/dev/sg1 of=/dev/sg2 [plus option(s) to test]
cmp /dev/sdb /dev/sdc

If the cmp fails then the copy has failed (or some other
mechanism wrote to /dev/sdb or /dev/sdc in the interim).

Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
drivers/scsi/scsi_debug.c | 261 ++++++++++++++++++++++++++------------
1 file changed, 182 insertions(+), 79 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 18c07e9ace15..7ca6c6c43c93 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -108,6 +108,7 @@ static const char *sdebug_version_date = "20190125";
#define DEF_DEV_SIZE_MB 8
#define DEF_DIF 0
#define DEF_DIX 0
+#define DEF_DOUBLESTORE false
#define DEF_D_SENSE 0
#define DEF_EVERY_NTH 0
#define DEF_FAKE_RW 0
@@ -255,6 +256,7 @@ struct sdebug_dev_info {
unsigned long uas_bm[1];
atomic_t num_in_q;
atomic_t stopped;
+ int sdg_devnum;
bool used;
};

@@ -633,6 +635,7 @@ static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
+static atomic_t a_sdg_devnum;
static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
static int sdebug_no_lun_0 = DEF_NO_LUN_0;
static int sdebug_no_uld;
@@ -658,6 +661,7 @@ static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
static int sdebug_uuid_ctl = DEF_UUID_CTL;
static bool sdebug_random = DEF_RANDOM;
+static bool sdebug_doublestore = DEF_DOUBLESTORE;
static bool sdebug_removable = DEF_REMOVABLE;
static bool sdebug_clustering;
static bool sdebug_host_lock = DEF_HOST_LOCK;
@@ -681,7 +685,7 @@ static int sdebug_sectors_per; /* sectors per cylinder */
static LIST_HEAD(sdebug_host_list);
static DEFINE_SPINLOCK(sdebug_host_list_lock);

-static unsigned char *fake_storep; /* ramdisk storage */
+static u8 *fake_store_a[2]; /* ramdisk storage */
static struct t10_pi_tuple *dif_storep; /* protection info */
static void *map_storep; /* provisioning map */

@@ -699,6 +703,9 @@ static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */

static DEFINE_RWLOCK(atomic_rw);
+static DEFINE_RWLOCK(atomic_rw2);
+
+static rwlock_t *ramdisk_lck_a[2];

static char sdebug_proc_name[] = MY_NAME;
static const char *my_name = MY_NAME;
@@ -730,11 +737,11 @@ static inline bool scsi_debug_lbp(void)
(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
}

-static void *lba2fake_store(unsigned long long lba)
+static void *lba2fake_store(unsigned long long lba, int acc_num)
{
lba = do_div(lba, sdebug_store_sectors);

- return fake_storep + lba * sdebug_sector_size;
+ return fake_store_a[acc_num % 2] + lba * sdebug_sector_size;
}

static struct t10_pi_tuple *dif_store(sector_t sector)
@@ -1043,7 +1050,7 @@ static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
__func__, off_dst, scsi_bufflen(scp), act_len,
scsi_get_resid(scp));
n = scsi_bufflen(scp) - (off_dst + act_len);
- scsi_set_resid(scp, min(scsi_get_resid(scp), n));
+ scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
return 0;
}

@@ -1535,7 +1542,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
}
put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
ret = fill_from_dev_buffer(scp, arr,
- min(alloc_len, SDEBUG_LONG_INQ_SZ));
+ min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
kfree(arr);
return ret;
}
@@ -1690,7 +1697,7 @@ static int resp_readcap16(struct scsi_cmnd *scp,
}

return fill_from_dev_buffer(scp, arr,
- min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
+ min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
}

#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
@@ -1764,9 +1771,9 @@ static int resp_report_tgtpgs(struct scsi_cmnd *scp,
* - The constructed command length
* - The maximum array size
*/
- rlen = min(alen,n);
+ rlen = min_t(int, alen, n);
ret = fill_from_dev_buffer(scp, arr,
- min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
+ min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
kfree(arr);
return ret;
}
@@ -2268,7 +2275,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
arr[0] = offset - 1;
else
put_unaligned_be16((offset - 2), arr + 0);
- return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
+ return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
}

#define SDEBUG_MAX_MSELECT_SZ 512
@@ -2453,9 +2460,9 @@ static int resp_log_sense(struct scsi_cmnd *scp,
mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
return check_condition_result;
}
- len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
+ len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
return fill_from_dev_buffer(scp, arr,
- min(len, SDEBUG_MAX_INQ_ARR_SZ));
+ min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
}

static inline int check_device_access_params(struct scsi_cmnd *scp,
@@ -2478,6 +2485,18 @@ static inline int check_device_access_params(struct scsi_cmnd *scp,
return 0;
}

+static int scp2acc_num(struct scsi_cmnd *scp)
+{
+ if (sdebug_doublestore) {
+ struct scsi_device *sdp = scp->device;
+ struct sdebug_dev_info *devip =
+ (struct sdebug_dev_info *)sdp->hostdata;
+
+ return devip->sdg_devnum;
+ }
+ return 0;
+}
+
/* Returns number of bytes copied or -1 if error. */
static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
u32 num, bool do_write)
@@ -2486,6 +2505,7 @@ static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
u64 block, rest = 0;
struct scsi_data_buffer *sdb = &scmd->sdb;
enum dma_data_direction dir;
+ u8 *fsp;

if (do_write) {
dir = DMA_TO_DEVICE;
@@ -2498,20 +2518,21 @@ static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
return 0;
if (scmd->sc_data_direction != dir)
return -1;
+ fsp = fake_store_a[scp2acc_num(scmd) % 2];

block = do_div(lba, sdebug_store_sectors);
if (block + num > sdebug_store_sectors)
rest = block + num - sdebug_store_sectors;

ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
- fake_storep + (block * sdebug_sector_size),
+ fsp + (block * sdebug_sector_size),
(num - rest) * sdebug_sector_size, sg_skip, do_write);
if (ret != (num - rest) * sdebug_sector_size)
return ret;

if (rest) {
ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
- fake_storep, rest * sdebug_sector_size,
+ fsp, rest * sdebug_sector_size,
sg_skip + ((num - rest) * sdebug_sector_size),
do_write);
}
@@ -2519,34 +2540,48 @@ static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
return ret;
}

+/* Returns number of bytes copied or -1 if error. */
+static int do_dout_fetch(struct scsi_cmnd *scmd, u32 num, u8 *doutp)
+{
+ struct scsi_data_buffer *sdb = &scmd->sdb;
+
+ if (!sdb->length)
+ return 0;
+ if (scmd->sc_data_direction != DMA_TO_DEVICE)
+ return -1;
+ return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
+ num * sdebug_sector_size, 0, true);
+}
+
/* If lba2fake_store(lba,num) compares equal to arr(num), then copy top half of
* arr into lba2fake_store(lba,num) and return true. If comparison fails then
* return false. */
-static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
+static bool comp_write_worker(u64 lba, u32 num, const u8 *arr, int acc_num)
{
bool res;
u64 block, rest = 0;
u32 store_blks = sdebug_store_sectors;
u32 lb_size = sdebug_sector_size;
+ u8 *fsp;

block = do_div(lba, store_blks);
if (block + num > store_blks)
rest = block + num - store_blks;

- res = !memcmp(fake_storep + (block * lb_size), arr,
- (num - rest) * lb_size);
+ fsp = fake_store_a[acc_num % 2];
+
+ res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
if (!res)
return res;
if (rest)
- res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
+ res = memcmp(fsp, arr + ((num - rest) * lb_size),
rest * lb_size);
if (!res)
return res;
arr += num * lb_size;
- memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
+ memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
if (rest)
- memcpy(fake_storep, arr + ((num - rest) * lb_size),
- rest * lb_size);
+ memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
return res;
}

@@ -2605,7 +2640,7 @@ static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));

while (sg_miter_next(&miter) && resid > 0) {
- size_t len = min(miter.length, resid);
+ size_t len = min_t(size_t, miter.length, resid);
void *start = dif_store(sector);
size_t rest = 0;

@@ -2632,12 +2667,12 @@ static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
sg_miter_stop(&miter);
}

-static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
+static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
unsigned int sectors, u32 ei_lba)
{
unsigned int i;
- struct t10_pi_tuple *sdt;
sector_t sector;
+ struct t10_pi_tuple *sdt;

for (i = 0; i < sectors; i++, ei_lba++) {
int ret;
@@ -2648,14 +2683,15 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
if (sdt->app_tag == cpu_to_be16(0xffff))
continue;

- ret = dif_verify(sdt, lba2fake_store(sector), sector, ei_lba);
+ ret = dif_verify(sdt, lba2fake_store(sector, scp2acc_num(scp)),
+ sector, ei_lba);
if (ret) {
dif_errors++;
return ret;
}
}

- dif_copy_prot(SCpnt, start_sec, sectors, true);
+ dif_copy_prot(scp, start_sec, sectors, true);
dix_reads++;

return 0;
@@ -2665,10 +2701,11 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
u8 *cmd = scp->cmnd;
struct sdebug_queued_cmd *sqcp;
- u64 lba;
u32 num;
u32 ei_lba;
+ int acc_num = scp2acc_num(scp);
unsigned long iflags;
+ u64 lba;
int ret;
bool check_prot;

@@ -2752,21 +2789,22 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
return check_condition_result;
}

- read_lock_irqsave(&atomic_rw, iflags);
+ read_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags);

/* DIX + T10 DIF */
if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
int prot_ret = prot_verify_read(scp, lba, num, ei_lba);

if (prot_ret) {
- read_unlock_irqrestore(&atomic_rw, iflags);
+ read_unlock_irqrestore(ramdisk_lck_a[acc_num % 2],
+ iflags);
mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
return illegal_condition_result;
}
}

ret = do_device_access(scp, 0, lba, num, false);
- read_unlock_irqrestore(&atomic_rw, iflags);
+ read_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags);
if (unlikely(ret == -1))
return DID_ERROR << 16;

@@ -2938,9 +2976,10 @@ static void map_region(sector_t lba, unsigned int len)
}
}

-static void unmap_region(sector_t lba, unsigned int len)
+static void unmap_region(sector_t lba, unsigned int len, int acc_num)
{
sector_t end = lba + len;
+ u8 *fsp = fake_store_a[acc_num % 2];

while (lba < end) {
unsigned long index = lba_to_map_index(lba);
@@ -2950,8 +2989,7 @@ static void unmap_region(sector_t lba, unsigned int len)
index < map_size) {
clear_bit(index, map_storep);
if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
- memset(fake_storep +
- lba * sdebug_sector_size,
+ memset(fsp + lba * sdebug_sector_size,
(sdebug_lbprz & 1) ? 0 : 0xff,
sdebug_sector_size *
sdebug_unmap_granularity);
@@ -2968,13 +3006,14 @@ static void unmap_region(sector_t lba, unsigned int len)

static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
- u8 *cmd = scp->cmnd;
- u64 lba;
+ bool check_prot;
u32 num;
u32 ei_lba;
- unsigned long iflags;
+ int acc_num = scp2acc_num(scp);
int ret;
- bool check_prot;
+ unsigned long iflags;
+ u64 lba;
+ u8 *cmd = scp->cmnd;

switch (cmd[0]) {
case WRITE_16:
@@ -3030,14 +3069,15 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
ret = check_device_access_params(scp, lba, num, true);
if (ret)
return ret;
- write_lock_irqsave(&atomic_rw, iflags);
+ write_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags);

/* DIX + T10 DIF */
if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
int prot_ret = prot_verify_write(scp, lba, num, ei_lba);

if (prot_ret) {
- write_unlock_irqrestore(&atomic_rw, iflags);
+ write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2],
+ iflags);
mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
return illegal_condition_result;
}
@@ -3046,7 +3086,7 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
ret = do_device_access(scp, 0, lba, num, true);
if (unlikely(scsi_debug_lbp()))
map_region(lba, num);
- write_unlock_irqrestore(&atomic_rw, iflags);
+ write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags);
if (unlikely(-1 == ret))
return DID_ERROR << 16;
else if (unlikely(sdebug_verbose &&
@@ -3092,6 +3132,7 @@ static int resp_write_scat(struct scsi_cmnd *scp,
u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
u32 lb_size = sdebug_sector_size;
u32 ei_lba;
+ int acc_num = scp2acc_num(scp);
u64 lba;
unsigned long iflags;
int ret, res;
@@ -3155,7 +3196,7 @@ static int resp_write_scat(struct scsi_cmnd *scp,
goto err_out;
}

- write_lock_irqsave(&atomic_rw, iflags);
+ write_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags);
sg_off = lbdof_blen;
/* Spec says Buffer xfer Length field in number of LBs in dout */
cum_lb = 0;
@@ -3238,7 +3279,7 @@ static int resp_write_scat(struct scsi_cmnd *scp,
}
ret = 0;
err_out_unlock:
- write_unlock_irqrestore(&atomic_rw, iflags);
+ write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags);
err_out:
kfree(lrdp);
return ret;
@@ -3247,27 +3288,30 @@ static int resp_write_scat(struct scsi_cmnd *scp,
static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
u32 ei_lba, bool unmap, bool ndob)
{
- int ret;
unsigned long iflags;
unsigned long long i;
- u32 lb_size = sdebug_sector_size;
u64 block, lbaa;
+ u32 lb_size = sdebug_sector_size;
+ int ret;
+ int acc_num = scp2acc_num(scp);
u8 *fs1p;
+ u8 *fsp;

ret = check_device_access_params(scp, lba, num, true);
if (ret)
return ret;

- write_lock_irqsave(&atomic_rw, iflags);
+ write_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags);

if (unmap && scsi_debug_lbp()) {
- unmap_region(lba, num);
+ unmap_region(lba, num, acc_num);
goto out;
}
lbaa = lba;
block = do_div(lbaa, sdebug_store_sectors);
/* if ndob then zero 1 logical block, else fetch 1 logical block */
- fs1p = fake_storep + (block * lb_size);
+ fsp = fake_store_a[acc_num % 2];
+ fs1p = fsp + (block * lb_size);
if (ndob) {
memset(fs1p, 0, lb_size);
ret = 0;
@@ -3275,7 +3319,7 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
ret = fetch_to_dev_buffer(scp, fs1p, lb_size);

if (-1 == ret) {
- write_unlock_irqrestore(&atomic_rw, iflags);
+ write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags);
return DID_ERROR << 16;
} else if (sdebug_verbose && !ndob && (ret < lb_size))
sdev_printk(KERN_INFO, scp->device,
@@ -3286,12 +3330,12 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
for (i = 1 ; i < num ; i++) {
lbaa = lba + i;
block = do_div(lbaa, sdebug_store_sectors);
- memmove(fake_storep + (block * lb_size), fs1p, lb_size);
+ memmove(fsp + (block * lb_size), fs1p, lb_size);
}
if (scsi_debug_lbp())
map_region(lba, num);
out:
- write_unlock_irqrestore(&atomic_rw, iflags);
+ write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags);

return 0;
}
@@ -3403,7 +3447,6 @@ static int resp_comp_write(struct scsi_cmnd *scp,
{
u8 *cmd = scp->cmnd;
u8 *arr;
- u8 *fake_storep_hold;
u64 lba;
u32 dnum;
u32 lb_size = sdebug_sector_size;
@@ -3411,6 +3454,7 @@ static int resp_comp_write(struct scsi_cmnd *scp,
unsigned long iflags;
int ret;
int retval = 0;
+ int acc_num = scp2acc_num(scp);

lba = get_unaligned_be64(cmd + 2);
num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
@@ -3437,14 +3481,9 @@ static int resp_comp_write(struct scsi_cmnd *scp,
return check_condition_result;
}

- write_lock_irqsave(&atomic_rw, iflags);
+ write_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags);

- /* trick do_device_access() to fetch both compare and write buffers
- * from data-in into arr. Safe (atomic) since write_lock held. */
- fake_storep_hold = fake_storep;
- fake_storep = arr;
- ret = do_device_access(scp, 0, 0, dnum, true);
- fake_storep = fake_storep_hold;
+ ret = do_dout_fetch(scp, dnum, arr);
if (ret == -1) {
retval = DID_ERROR << 16;
goto cleanup;
@@ -3452,7 +3491,7 @@ static int resp_comp_write(struct scsi_cmnd *scp,
sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
"indicated=%u, IO sent=%d bytes\n", my_name,
dnum * lb_size, ret);
- if (!comp_write_worker(lba, num, arr)) {
+ if (!comp_write_worker(lba, num, arr, scp2acc_num(scp))) {
mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
retval = check_condition_result;
goto cleanup;
@@ -3460,7 +3499,7 @@ static int resp_comp_write(struct scsi_cmnd *scp,
if (scsi_debug_lbp())
map_region(lba, num);
cleanup:
- write_unlock_irqrestore(&atomic_rw, iflags);
+ write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags);
kfree(arr);
return retval;
}
@@ -3477,6 +3516,7 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
struct unmap_block_desc *desc;
unsigned int i, payload_len, descriptors;
int ret;
+ int acc_num = scp2acc_num(scp);
unsigned long iflags;

@@ -3505,7 +3545,7 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)

desc = (void *)&buf[8];

- write_lock_irqsave(&atomic_rw, iflags);
+ write_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags);

for (i = 0 ; i < descriptors ; i++) {
unsigned long long lba = get_unaligned_be64(&desc[i].lba);
@@ -3515,13 +3555,13 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
if (ret)
goto out;

- unmap_region(lba, num);
+ unmap_region(lba, num, scp2acc_num(scp));
}

ret = 0;

out:
- write_unlock_irqrestore(&atomic_rw, iflags);
+ write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags);
kfree(buf);

return ret;
@@ -3891,6 +3931,7 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp)
if (sdebug_no_uld)
sdp->no_uld_attach = 1;
config_cdb_len(sdp);
+ devip->sdg_devnum = atomic_inc_return(&a_sdg_devnum);
return 0;
}

@@ -4146,8 +4187,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
return SUCCESS;
}

-static void __init sdebug_build_parts(unsigned char *ramp,
- unsigned long store_size)
+static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
{
struct partition *pp;
int starts[SDEBUG_MAX_PARTS + 2];
@@ -4436,6 +4476,7 @@ module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
module_param_named(dif, sdebug_dif, int, S_IRUGO);
module_param_named(dix, sdebug_dix, int, S_IRUGO);
+module_param_named(doublestore, sdebug_doublestore, bool, S_IRUGO | S_IWUSR);
module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
@@ -4499,6 +4540,7 @@ MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
+MODULE_PARM_DESC(doublestore, "If set, 2 data buffers allocated, devices alternate between the two");
MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
@@ -4788,16 +4830,22 @@ static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
n = (n > 0);
sdebug_fake_rw = (sdebug_fake_rw > 0);
if (sdebug_fake_rw != n) {
- if ((0 == n) && (NULL == fake_storep)) {
- unsigned long sz =
- (unsigned long)sdebug_dev_size_mb *
- 1048576;
-
- fake_storep = vzalloc(sz);
- if (NULL == fake_storep) {
- pr_err("out of memory, 9\n");
+ unsigned long sz = (unsigned long)sdebug_dev_size_mb *
+ 1048576;
+
+ if (n == 0 && !fake_store_a[0]) {
+ fake_store_a[0] = vzalloc(sz);
+ if (!fake_store_a[0])
return -ENOMEM;
- }
+ if (sdebug_num_parts > 0)
+ sdebug_build_parts(fake_store_a[0], sz);
+ }
+ if (sdebug_doublestore && n == 0 && !fake_store_a[1]) {
+ fake_store_a[1] = vzalloc(sz);
+ if (!fake_store_a[1])
+ return -ENOMEM;
+ if (sdebug_num_parts > 0)
+ sdebug_build_parts(fake_store_a[1], sz);
}
sdebug_fake_rw = n;
}
@@ -4848,6 +4896,47 @@ static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
}
static DRIVER_ATTR_RO(dev_size_mb);

+static ssize_t doublestore_show(struct device_driver *ddp, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_doublestore);
+}
+
+static ssize_t doublestore_store(struct device_driver *ddp, const char *buf,
+ size_t count)
+{
+ int n;
+
+ if (count > 0 && kstrtoint(buf, 10, &n) == 0 && n >= 0) {
+ unsigned long iflags;
+
+ if (sdebug_doublestore == (n > 0))
+ return count; /* no state change */
+ if (n <= 0) {
+ write_lock_irqsave(ramdisk_lck_a[1], iflags);
+ sdebug_doublestore = false;
+ vfree(fake_store_a[1]);
+ fake_store_a[1] = NULL;
+ write_unlock_irqrestore(ramdisk_lck_a[1], iflags);
+ } else {
+ unsigned long sz = (unsigned long)sdebug_dev_size_mb *
+ 1048576;
+ u8 *fsp = vzalloc(sz);
+
+ if (!fsp)
+ return -ENOMEM;
+ if (sdebug_num_parts > 0)
+ sdebug_build_parts(fsp, sz);
+ write_lock_irqsave(ramdisk_lck_a[1], iflags);
+ fake_store_a[1] = fsp;
+ sdebug_doublestore = true;
+ write_unlock_irqrestore(ramdisk_lck_a[1], iflags);
+ }
+ return count;
+ }
+ return -EINVAL;
+}
+static DRIVER_ATTR_RW(doublestore);
+
static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
@@ -5225,6 +5314,7 @@ static struct attribute *sdebug_drv_attrs[] = {
&driver_attr_opts.attr,
&driver_attr_ptype.attr,
&driver_attr_dsense.attr,
+ &driver_attr_doublestore.attr,
&driver_attr_fake_rw.attr,
&driver_attr_no_lun_0.attr,
&driver_attr_num_tgts.attr,
@@ -5266,7 +5356,10 @@ static int __init scsi_debug_init(void)
int k;
int ret;

+ ramdisk_lck_a[0] = &atomic_rw;
+ ramdisk_lck_a[1] = &atomic_rw2;
atomic_set(&retired_max_queue, 0);
+ atomic_set(&a_sdg_devnum, 0);

if (sdebug_ndelay >= 1000 * 1000 * 1000) {
pr_warn("ndelay must be less than 1 second, ignored\n");
@@ -5363,14 +5456,22 @@ static int __init scsi_debug_init(void)
}

if (sdebug_fake_rw == 0) {
- fake_storep = vzalloc(sz);
- if (NULL == fake_storep) {
- pr_err("out of memory, 1\n");
+ fake_store_a[0] = vzalloc(sz);
+ if (!fake_store_a[0]) {
ret = -ENOMEM;
goto free_q_arr;
}
if (sdebug_num_parts > 0)
- sdebug_build_parts(fake_storep, sz);
+ sdebug_build_parts(fake_store_a[0], sz);
+ if (sdebug_doublestore) {
+ fake_store_a[1] = vzalloc(sz);
+ if (!fake_store_a[1]) {
+ ret = -ENOMEM;
+ goto free_q_arr;
+ }
+ if (sdebug_num_parts > 0)
+ sdebug_build_parts(fake_store_a[1], sz);
+ }
}

if (sdebug_dix) {
@@ -5467,7 +5568,8 @@ static int __init scsi_debug_init(void)
free_vm:
vfree(map_storep);
vfree(dif_storep);
- vfree(fake_storep);
+ vfree(fake_store_a[1]);
+ vfree(fake_store_a[0]);
free_q_arr:
kfree(sdebug_q_arr);
return ret;
@@ -5487,7 +5589,8 @@ static void __exit scsi_debug_exit(void)

vfree(map_storep);
vfree(dif_storep);
- vfree(fake_storep);
+ vfree(fake_store_a[1]);
+ vfree(fake_store_a[0]);
kfree(sdebug_q_arr);
}

--
2.24.1