From patchwork Thu Jan 9 08:30:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Gilbert X-Patchwork-Id: 11325175 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 678AB109A for ; Thu, 9 Jan 2020 08:30:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5014C20673 for ; Thu, 9 Jan 2020 08:30:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728474AbgAIIan (ORCPT ); Thu, 9 Jan 2020 03:30:43 -0500 Received: from smtp.infotech.no ([82.134.31.41]:33877 "EHLO smtp.infotech.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728405AbgAIIan (ORCPT ); Thu, 9 Jan 2020 03:30:43 -0500 Received: from localhost (localhost [127.0.0.1]) by smtp.infotech.no (Postfix) with ESMTP id 81CBB204148; Thu, 9 Jan 2020 09:30:40 +0100 (CET) X-Virus-Scanned: by amavisd-new-2.6.6 (20110518) (Debian) at infotech.no Received: from smtp.infotech.no ([127.0.0.1]) by localhost (smtp.infotech.no [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id QnZ7ohr7oY7b; Thu, 9 Jan 2020 09:30:40 +0100 (CET) Received: from xtwo70.infotech.no (unknown [82.134.31.177]) by smtp.infotech.no (Postfix) with ESMTPA id 542DD204191; Thu, 9 Jan 2020 09:30:40 +0100 (CET) From: Douglas Gilbert To: linux-scsi@vger.kernel.org Cc: martin.petersen@oracle.com, jejb@linux.vnet.ibm.com, hare@suse.de Subject: [RFC v2 1/6] scsi_debug: randomize command completion time Date: Thu, 9 Jan 2020 09:30:34 +0100 Message-Id: <20200109083039.16582-2-dgilbert@interlog.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200109083039.16582-1-dgilbert@interlog.com> References: <20200109083039.16582-1-dgilbert@interlog.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Add a new command line option (e.g. random=1) and sysfs attribute that causes subsequent command completion times to be between the current command delay setting and 0. A unformily distributed 32 bit, kernel provided integer is used for this purpose. Since the existing 'delay' whose units are jiffies (typically milliseconds) and 'ndelay' (units: nanoseconds) options (and sysfs attributes) span a range greater than 32 bits, some scaling is required. The purpose of this patch is to widen the range of testing cases that are visited in long running tests. Put simply: rarely struct race conditions are more likely to be found when this facility is used. The default is the previous case in which all command completions were roughly equal to (if not, slightly longer) than the value given by the 'delay' or 'ndelay' settings (or their defaults). This option's default is equivalent to setting 'random=0' . Signed-off-by: Douglas Gilbert --- drivers/scsi/scsi_debug.c | 42 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 44cb054d5e66..18c07e9ace15 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -125,6 +126,7 @@ static const char *sdebug_version_date = "20190125"; #define DEF_PHYSBLK_EXP 0 #define DEF_OPT_XFERLEN_EXP 0 #define DEF_PTYPE TYPE_DISK +#define DEF_RANDOM false #define DEF_REMOVABLE false #define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ #define DEF_SECTOR_SIZE 512 @@ -655,6 +657,7 @@ static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 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_removable = DEF_REMOVABLE; static bool sdebug_clustering; static bool sdebug_host_lock = DEF_HOST_LOCK; @@ -4354,9 +4357,21 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, ktime_t kt; if (delta_jiff > 0) { - kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ)); - } else - kt = ndelay; + u64 ns = jiffies_to_nsecs(delta_jiff); + + if (sdebug_random && ns < U32_MAX) { + ns = prandom_u32_max((u32)ns); + } else if (sdebug_random) { + ns >>= 12; /* scale to 4 usec precision */ + if (ns < U32_MAX) /* over 4 hours max */ + ns = prandom_u32_max((u32)ns); + ns <<= 12; + } + kt = ns_to_ktime(ns); + } else { /* ndelay has a 4.2 second max */ + kt = sdebug_random ? prandom_u32_max((u32)ndelay) : + (u32)ndelay; + } if (!sd_dp->init_hrt) { sd_dp->init_hrt = true; sqcp->sd_dp = sd_dp; @@ -4451,6 +4466,7 @@ module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); +module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); @@ -4511,6 +4527,7 @@ MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); +MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); @@ -5101,6 +5118,24 @@ static ssize_t map_show(struct device_driver *ddp, char *buf) } static DRIVER_ATTR_RO(map); +static ssize_t random_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_random); +} + +static ssize_t random_store(struct device_driver *ddp, const char *buf, + size_t count) +{ + int n; + + if (count > 0 && kstrtoint(buf, 10, &n) == 0 && n >= 0) { + sdebug_random = (n > 0); + return count; + } + return -EINVAL; +} +static DRIVER_ATTR_RW(random); + static ssize_t removable_show(struct device_driver *ddp, char *buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); @@ -5211,6 +5246,7 @@ static struct attribute *sdebug_drv_attrs[] = { &driver_attr_guard.attr, &driver_attr_ato.attr, &driver_attr_map.attr, + &driver_attr_random.attr, &driver_attr_removable.attr, &driver_attr_host_lock.attr, &driver_attr_ndelay.attr, From patchwork Thu Jan 9 08:30:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Gilbert X-Patchwork-Id: 11325185 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BEDC4139A for ; Thu, 9 Jan 2020 08:30:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 89F2520661 for ; Thu, 9 Jan 2020 08:30:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728494AbgAIIaq (ORCPT ); Thu, 9 Jan 2020 03:30:46 -0500 Received: from smtp.infotech.no ([82.134.31.41]:33889 "EHLO smtp.infotech.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728437AbgAIIao (ORCPT ); Thu, 9 Jan 2020 03:30:44 -0500 Received: from localhost (localhost [127.0.0.1]) by smtp.infotech.no (Postfix) with ESMTP id B0984204199; Thu, 9 Jan 2020 09:30:40 +0100 (CET) X-Virus-Scanned: by amavisd-new-2.6.6 (20110518) (Debian) at infotech.no Received: from smtp.infotech.no ([127.0.0.1]) by localhost (smtp.infotech.no [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 7udjhd23m+uE; Thu, 9 Jan 2020 09:30:40 +0100 (CET) Received: from xtwo70.infotech.no (unknown [82.134.31.177]) by smtp.infotech.no (Postfix) with ESMTPA id 63162204193; Thu, 9 Jan 2020 09:30:40 +0100 (CET) From: Douglas Gilbert To: linux-scsi@vger.kernel.org Cc: martin.petersen@oracle.com, jejb@linux.vnet.ibm.com, hare@suse.de Subject: [RFC v2 2/6] scsi_debug: add doublestore option Date: Thu, 9 Jan 2020 09:30:35 +0100 Message-Id: <20200109083039.16582-3-dgilbert@interlog.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200109083039.16582-1-dgilbert@interlog.com> References: <20200109083039.16582-1-dgilbert@interlog.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org 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 --- 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); } From patchwork Thu Jan 9 08:30:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Gilbert X-Patchwork-Id: 11325181 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A318A1871 for ; Thu, 9 Jan 2020 08:30:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8B89E2073A for ; Thu, 9 Jan 2020 08:30:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728480AbgAIIao (ORCPT ); Thu, 9 Jan 2020 03:30:44 -0500 Received: from smtp.infotech.no ([82.134.31.41]:33886 "EHLO smtp.infotech.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728431AbgAIIan (ORCPT ); Thu, 9 Jan 2020 03:30:43 -0500 Received: from localhost (localhost [127.0.0.1]) by smtp.infotech.no (Postfix) with ESMTP id AA475204197; Thu, 9 Jan 2020 09:30:40 +0100 (CET) X-Virus-Scanned: by amavisd-new-2.6.6 (20110518) (Debian) at infotech.no Received: from smtp.infotech.no ([127.0.0.1]) by localhost (smtp.infotech.no [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VmwVjfy58yUX; Thu, 9 Jan 2020 09:30:40 +0100 (CET) Received: from xtwo70.infotech.no (unknown [82.134.31.177]) by smtp.infotech.no (Postfix) with ESMTPA id 77C7B204194; Thu, 9 Jan 2020 09:30:40 +0100 (CET) From: Douglas Gilbert To: linux-scsi@vger.kernel.org Cc: martin.petersen@oracle.com, jejb@linux.vnet.ibm.com, hare@suse.de Subject: [RFC v2 3/6] scsi_debug: implement verify(10), add verify(16) Date: Thu, 9 Jan 2020 09:30:36 +0100 Message-Id: <20200109083039.16582-4-dgilbert@interlog.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200109083039.16582-1-dgilbert@interlog.com> References: <20200109083039.16582-1-dgilbert@interlog.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org With the addition of the doublestore option, the ability to check whether the two different ramdisk images are the same or not becomes useful. Prior to this patch VERIFY(10) always returned true (i.e. the SCSI GOOD status) without checking. This option adds support for BYTCHK equal to 1 and 3 . If the comparison fails then a sense key of MISCOMPARE is returned as per the T10 standards. Add support for the VERIFY(16). Signed-off-by: Douglas Gilbert --- drivers/scsi/scsi_debug.c | 103 +++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 7ca6c6c43c93..b94a453ea0f7 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -342,7 +342,7 @@ enum sdeb_opcode_index { SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */ SDEB_I_MAINT_IN = 14, SDEB_I_MAINT_OUT = 15, - SDEB_I_VERIFY = 16, /* 10 only */ + SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */ SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */ SDEB_I_RESERVE = 18, /* 6, 10 */ SDEB_I_RELEASE = 19, /* 6, 10 */ @@ -385,7 +385,8 @@ static const unsigned char opcode_ind_arr[256] = { 0, SDEB_I_VARIABLE_LEN, /* 0x80; 0x80->0x9f: 16 byte cdbs */ 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, - SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0, + SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, + 0, 0, 0, SDEB_I_VERIFY, 0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ @@ -427,6 +428,7 @@ static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); +static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); @@ -471,6 +473,12 @@ static const struct opcode_info_t write_iarr[] = { 0xbf, 0xc7, 0, 0, 0, 0} }, }; +static const struct opcode_info_t verify_iarr[] = { + {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ + NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, + 0, 0, 0, 0, 0, 0} }, +}; + static const struct opcode_info_t sa_in_16_iarr[] = { {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -571,9 +579,10 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { /* 15 */ {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */ - {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, - 0, 0, 0, 0, 0, 0} }, + {ARRAY_SIZE(verify_iarr), 0x8f, 0, + F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ + verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, @@ -2556,7 +2565,8 @@ static int do_dout_fetch(struct scsi_cmnd *scmd, u32 num, u8 *doutp) /* 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, int acc_num) +static bool comp_write_worker(u64 lba, u32 num, const u8 *arr, int acc_num, + bool compare_only) { bool res; u64 block, rest = 0; @@ -2578,6 +2588,8 @@ static bool comp_write_worker(u64 lba, u32 num, const u8 *arr, int acc_num) rest * lb_size); if (!res) return res; + if (compare_only) + return true; arr += num * lb_size; memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); if (rest) @@ -3491,7 +3503,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, scp2acc_num(scp))) { + if (!comp_write_worker(lba, num, arr, acc_num, false)) { mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); retval = check_condition_result; goto cleanup; @@ -3555,7 +3567,7 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) if (ret) goto out; - unmap_region(lba, num, scp2acc_num(scp)); + unmap_region(lba, num, acc_num); } ret = 0; @@ -3736,6 +3748,81 @@ static int resp_report_luns(struct scsi_cmnd *scp, return res; } +static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) +{ + bool is_bytchk3 = false; + u8 bytchk; + int ret, j; + int acc_num = scp2acc_num(scp); + u32 vnum, a_num, off; + const u32 lb_size = sdebug_sector_size; + unsigned long iflags; + u64 lba; + u8 *arr; + u8 *cmd = scp->cmnd; + + bytchk = (cmd[1] >> 1) & 0x3; + if (bytchk == 0) { + return 0; /* always claim internal verify okay */ + } else if (bytchk == 2) { + mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); + return check_condition_result; + } else if (bytchk == 3) { + is_bytchk3 = true; /* 1 block sent, compared repeatedly */ + } + switch (cmd[0]) { + case VERIFY_16: + lba = get_unaligned_be64(cmd + 2); + vnum = get_unaligned_be32(cmd + 10); + break; + case VERIFY: /* is VERIFY(10) */ + lba = get_unaligned_be32(cmd + 2); + vnum = get_unaligned_be16(cmd + 7); + break; + default: + mk_sense_invalid_opcode(scp); + return check_condition_result; + } + a_num = is_bytchk3 ? 1 : vnum; + /* Treat following check like one for read (i.e. no write) access */ + ret = check_device_access_params(scp, lba, a_num, false); + if (ret) + return ret; + + arr = kcalloc(lb_size, vnum, GFP_ATOMIC); + if (!arr) { + mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, + INSUFF_RES_ASCQ); + return check_condition_result; + } + /* Not changing store, so only need read access */ + read_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags); + + ret = do_dout_fetch(scp, a_num, arr); + if (ret == -1) { + ret = DID_ERROR << 16; + goto cleanup; + } else if (sdebug_verbose && (ret < (a_num * lb_size))) { + sdev_printk(KERN_INFO, scp->device, + "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", + my_name, __func__, a_num * lb_size, ret); + } + if (is_bytchk3) { + for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) + memcpy(arr + off, arr, lb_size); + } + ret = 0; + if (!comp_write_worker(lba, vnum, arr, acc_num, true)) { + mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); + ret = check_condition_result; + goto cleanup; + } +cleanup: + read_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags); + kfree(arr); + return ret; +} + static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) { u32 tag = blk_mq_unique_tag(cmnd->request); From patchwork Thu Jan 9 08:30:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Gilbert X-Patchwork-Id: 11325179 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 817E1139A for ; Thu, 9 Jan 2020 08:30:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6A3A82072A for ; Thu, 9 Jan 2020 08:30:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728478AbgAIIao (ORCPT ); Thu, 9 Jan 2020 03:30:44 -0500 Received: from smtp.infotech.no ([82.134.31.41]:33896 "EHLO smtp.infotech.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728444AbgAIIan (ORCPT ); Thu, 9 Jan 2020 03:30:43 -0500 Received: from localhost (localhost [127.0.0.1]) by smtp.infotech.no (Postfix) with ESMTP id CF10B204193; Thu, 9 Jan 2020 09:30:40 +0100 (CET) X-Virus-Scanned: by amavisd-new-2.6.6 (20110518) (Debian) at infotech.no Received: from smtp.infotech.no ([127.0.0.1]) by localhost (smtp.infotech.no [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 1KkrYIROSjlo; Thu, 9 Jan 2020 09:30:40 +0100 (CET) Received: from xtwo70.infotech.no (unknown [82.134.31.177]) by smtp.infotech.no (Postfix) with ESMTPA id 887CA204195; Thu, 9 Jan 2020 09:30:40 +0100 (CET) From: Douglas Gilbert To: linux-scsi@vger.kernel.org Cc: martin.petersen@oracle.com, jejb@linux.vnet.ibm.com, hare@suse.de Subject: [RFC v2 4/6] scsi_debug: weaken rwlock around ramdisk access Date: Thu, 9 Jan 2020 09:30:37 +0100 Message-Id: <20200109083039.16582-5-dgilbert@interlog.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200109083039.16582-1-dgilbert@interlog.com> References: <20200109083039.16582-1-dgilbert@interlog.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org The design of this driver is to do any ramdisk access on the same thread that invoked the queuecommand() call. That is assumed to be user space context. The command duration is implemented by setting the delay with a high resolution timer. The hr timer's callback may well be in interrupt context, but it doesn't touch the ramdisk. So try removing the _irqsave()/_irqrestore() portion on the read- write lock that protects ramdisk access. Signed-off-by: Douglas Gilbert --- drivers/scsi/scsi_debug.c | 59 +++++++++++++++------------------------ 1 file changed, 22 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index b94a453ea0f7..7cafbf4aefe8 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -2716,7 +2716,6 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) u32 num; u32 ei_lba; int acc_num = scp2acc_num(scp); - unsigned long iflags; u64 lba; int ret; bool check_prot; @@ -2801,22 +2800,21 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) return check_condition_result; } - read_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags); + read_lock(ramdisk_lck_a[acc_num % 2]); /* 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(ramdisk_lck_a[acc_num % 2], - iflags); + read_unlock(ramdisk_lck_a[acc_num % 2]); 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(ramdisk_lck_a[acc_num % 2], iflags); + read_unlock(ramdisk_lck_a[acc_num % 2]); if (unlikely(ret == -1)) return DID_ERROR << 16; @@ -3023,7 +3021,6 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) u32 ei_lba; int acc_num = scp2acc_num(scp); int ret; - unsigned long iflags; u64 lba; u8 *cmd = scp->cmnd; @@ -3081,15 +3078,14 @@ 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(ramdisk_lck_a[acc_num % 2], iflags); + write_lock(ramdisk_lck_a[acc_num % 2]); /* 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(ramdisk_lck_a[acc_num % 2], - iflags); + write_unlock(ramdisk_lck_a[acc_num % 2]); mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); return illegal_condition_result; } @@ -3098,7 +3094,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(ramdisk_lck_a[acc_num % 2], iflags); + write_unlock(ramdisk_lck_a[acc_num % 2]); if (unlikely(-1 == ret)) return DID_ERROR << 16; else if (unlikely(sdebug_verbose && @@ -3146,7 +3142,6 @@ static int resp_write_scat(struct scsi_cmnd *scp, u32 ei_lba; int acc_num = scp2acc_num(scp); u64 lba; - unsigned long iflags; int ret, res; bool is_16; static const u32 lrd_size = 32; /* + parameter list header size */ @@ -3208,7 +3203,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, goto err_out; } - write_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags); + write_lock(ramdisk_lck_a[acc_num % 2]); sg_off = lbdof_blen; /* Spec says Buffer xfer Length field in number of LBs in dout */ cum_lb = 0; @@ -3291,7 +3286,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, } ret = 0; err_out_unlock: - write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags); + write_unlock(ramdisk_lck_a[acc_num % 2]); err_out: kfree(lrdp); return ret; @@ -3300,7 +3295,6 @@ 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) { - unsigned long iflags; unsigned long long i; u64 block, lbaa; u32 lb_size = sdebug_sector_size; @@ -3313,7 +3307,7 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, if (ret) return ret; - write_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags); + write_lock(ramdisk_lck_a[acc_num % 2]); if (unmap && scsi_debug_lbp()) { unmap_region(lba, num, acc_num); @@ -3331,7 +3325,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(ramdisk_lck_a[acc_num % 2], iflags); + write_unlock(ramdisk_lck_a[acc_num % 2]); return DID_ERROR << 16; } else if (sdebug_verbose && !ndob && (ret < lb_size)) sdev_printk(KERN_INFO, scp->device, @@ -3347,7 +3341,7 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, if (scsi_debug_lbp()) map_region(lba, num); out: - write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags); + write_unlock(ramdisk_lck_a[acc_num % 2]); return 0; } @@ -3463,7 +3457,6 @@ static int resp_comp_write(struct scsi_cmnd *scp, u32 dnum; u32 lb_size = sdebug_sector_size; u8 num; - unsigned long iflags; int ret; int retval = 0; int acc_num = scp2acc_num(scp); @@ -3493,7 +3486,7 @@ static int resp_comp_write(struct scsi_cmnd *scp, return check_condition_result; } - write_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags); + write_lock(ramdisk_lck_a[acc_num % 2]); ret = do_dout_fetch(scp, dnum, arr); if (ret == -1) { @@ -3511,7 +3504,7 @@ static int resp_comp_write(struct scsi_cmnd *scp, if (scsi_debug_lbp()) map_region(lba, num); cleanup: - write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags); + write_unlock(ramdisk_lck_a[acc_num % 2]); kfree(arr); return retval; } @@ -3529,8 +3522,6 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) unsigned int i, payload_len, descriptors; int ret; int acc_num = scp2acc_num(scp); - unsigned long iflags; - if (!scsi_debug_lbp()) return 0; /* fib and say its done */ @@ -3557,7 +3548,7 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) desc = (void *)&buf[8]; - write_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags); + write_lock(ramdisk_lck_a[acc_num % 2]); for (i = 0 ; i < descriptors ; i++) { unsigned long long lba = get_unaligned_be64(&desc[i].lba); @@ -3573,7 +3564,7 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) ret = 0; out: - write_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags); + write_unlock(ramdisk_lck_a[acc_num % 2]); kfree(buf); return ret; @@ -3756,7 +3747,6 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) int acc_num = scp2acc_num(scp); u32 vnum, a_num, off; const u32 lb_size = sdebug_sector_size; - unsigned long iflags; u64 lba; u8 *arr; u8 *cmd = scp->cmnd; @@ -3796,7 +3786,7 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) return check_condition_result; } /* Not changing store, so only need read access */ - read_lock_irqsave(ramdisk_lck_a[acc_num % 2], iflags); + read_lock(ramdisk_lck_a[acc_num % 2]); ret = do_dout_fetch(scp, a_num, arr); if (ret == -1) { @@ -3818,7 +3808,7 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) goto cleanup; } cleanup: - read_unlock_irqrestore(ramdisk_lck_a[acc_num % 2], iflags); + read_unlock(ramdisk_lck_a[acc_num % 2]); kfree(arr); return ret; } @@ -4467,9 +4457,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; if (cmnd->result & SDEG_RES_IMMED_MASK) { - /* - * This is the F_DELAY_OVERR case. No delay. - */ cmnd->result &= ~SDEG_RES_IMMED_MASK; delta_jiff = ndelay = 0; } @@ -4994,16 +4981,14 @@ static ssize_t doublestore_store(struct device_driver *ddp, const char *buf, 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); + write_lock(ramdisk_lck_a[1]); sdebug_doublestore = false; vfree(fake_store_a[1]); fake_store_a[1] = NULL; - write_unlock_irqrestore(ramdisk_lck_a[1], iflags); + write_unlock(ramdisk_lck_a[1]); } else { unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; @@ -5013,10 +4998,10 @@ static ssize_t doublestore_store(struct device_driver *ddp, const char *buf, return -ENOMEM; if (sdebug_num_parts > 0) sdebug_build_parts(fsp, sz); - write_lock_irqsave(ramdisk_lck_a[1], iflags); + write_lock(ramdisk_lck_a[1]); fake_store_a[1] = fsp; sdebug_doublestore = true; - write_unlock_irqrestore(ramdisk_lck_a[1], iflags); + write_unlock(ramdisk_lck_a[1]); } return count; } @@ -5949,7 +5934,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost, pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ fini: - if (F_DELAY_OVERR & flags) + if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ return schedule_resp(scp, devip, errsts, pfp, 0, 0); else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || sdebug_ndelay > 10000)) { From patchwork Thu Jan 9 08:30:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Gilbert X-Patchwork-Id: 11325183 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 45EDF921 for ; Thu, 9 Jan 2020 08:30:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2DEEA2064C for ; Thu, 9 Jan 2020 08:30:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728493AbgAIIap (ORCPT ); Thu, 9 Jan 2020 03:30:45 -0500 Received: from smtp.infotech.no ([82.134.31.41]:33899 "EHLO smtp.infotech.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728435AbgAIIao (ORCPT ); Thu, 9 Jan 2020 03:30:44 -0500 Received: from localhost (localhost [127.0.0.1]) by smtp.infotech.no (Postfix) with ESMTP id D3B72204194; Thu, 9 Jan 2020 09:30:40 +0100 (CET) X-Virus-Scanned: by amavisd-new-2.6.6 (20110518) (Debian) at infotech.no Received: from smtp.infotech.no ([127.0.0.1]) by localhost (smtp.infotech.no [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id aoAZytWZMXuG; Thu, 9 Jan 2020 09:30:40 +0100 (CET) Received: from xtwo70.infotech.no (unknown [82.134.31.177]) by smtp.infotech.no (Postfix) with ESMTPA id 97806204191; Thu, 9 Jan 2020 09:30:40 +0100 (CET) From: Douglas Gilbert To: linux-scsi@vger.kernel.org Cc: martin.petersen@oracle.com, jejb@linux.vnet.ibm.com, hare@suse.de Subject: [RFC v2 5/6] scsi_debug: improve command duration calculation Date: Thu, 9 Jan 2020 09:30:38 +0100 Message-Id: <20200109083039.16582-6-dgilbert@interlog.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200109083039.16582-1-dgilbert@interlog.com> References: <20200109083039.16582-1-dgilbert@interlog.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Previously the code did the work implied by the given SCSI command and after that it waited for a timer based on the user specified command duration to be exhausted before informing the mid-level that the command was complete. For short command durations the time to complete the work implied by the SCSI command could be significant compared to the user specified command duration. For example a WRITE of 128 blocks (say 512 bytes each) on a machine that can copy from main memory to main memory at a rate of 10 GB/sec will take around 6.4 microseconds to do that copy. If the user specified a command duration of 5 microseconds (ndelay=5000) should the driver do a further delay of 5 microseconds after the copy or return immediately because 6.4 > 5 ? The action prior to this patch was to always do the timer based delay. After this patch, for ndelay values less than 1 millisecond, this driver will complete the command immediately. And in the case where the user specified delay was 7 microseconds, a timer delay of 600 nanoseconds will be set ((7 - 6.4) * 1000). Signed-off-by: Douglas Gilbert --- drivers/scsi/scsi_debug.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 7cafbf4aefe8..e140e764dfba 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -4366,6 +4366,8 @@ static void setup_inject(struct sdebug_queue *sqp, sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts); } +#define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ + /* Complete the processing of the thread that queued a SCSI command to this * driver. It either completes the command by calling cmnd_done() or * schedules a hr timer or work queue then returns 0. Returns @@ -4377,8 +4379,10 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, struct sdebug_dev_info *), int delta_jiff, int ndelay) { - unsigned long iflags; + bool new_sd_dp; int k, num_in_q, qdepth, inject; + unsigned long iflags; + u64 ns_from_boot = 0; struct sdebug_queue *sqp; struct sdebug_queued_cmd *sqcp; struct scsi_device *sdp; @@ -4394,7 +4398,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, if (delta_jiff == 0) goto respond_in_thread; - /* schedule the response at a later time if resources permit */ sqp = get_queue(cmnd); spin_lock_irqsave(&sqp->qc_lock, iflags); if (unlikely(atomic_read(&sqp->blocked))) { @@ -4453,8 +4456,15 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); if (sd_dp == NULL) return SCSI_MLQUEUE_HOST_BUSY; + new_sd_dp = true; + } else { + new_sd_dp = false; } + if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS) + ns_from_boot = ktime_get_boottime_ns(); + + /* one of the resp_*() response functions is called here */ cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; if (cmnd->result & SDEG_RES_IMMED_MASK) { cmnd->result &= ~SDEG_RES_IMMED_MASK; @@ -4485,6 +4495,22 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, } else { /* ndelay has a 4.2 second max */ kt = sdebug_random ? prandom_u32_max((u32)ndelay) : (u32)ndelay; + if (ndelay < INCLUSIVE_TIMING_MAX_NS) { + u64 d = ktime_get_boottime_ns() - ns_from_boot; + + if (kt <= d) { /* elapsed duration >= kt */ + sqcp->a_cmnd = NULL; + atomic_dec(&devip->num_in_q); + clear_bit(k, sqp->in_use_bm); + if (new_sd_dp) + kfree(sd_dp); + /* call scsi_done() from this thread */ + cmnd->scsi_done(cmnd); + return 0; + } + /* otherwise reduce kt by elapsed time */ + kt -= d; + } } if (!sd_dp->init_hrt) { sd_dp->init_hrt = true; @@ -4498,6 +4524,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, if (sdebug_statistics) sd_dp->issuing_cpu = raw_smp_processor_id(); sd_dp->defer_t = SDEB_DEFER_HRT; + /* schedule the invocation of scsi_done() for a later time */ hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); } else { /* jdelay < 0, use work queue */ if (!sd_dp->init_wq) { From patchwork Thu Jan 9 08:30:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Douglas Gilbert X-Patchwork-Id: 11325177 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3B12A921 for ; Thu, 9 Jan 2020 08:30:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 19D9020673 for ; Thu, 9 Jan 2020 08:30:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728490AbgAIIao (ORCPT ); Thu, 9 Jan 2020 03:30:44 -0500 Received: from smtp.infotech.no ([82.134.31.41]:33900 "EHLO smtp.infotech.no" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728459AbgAIIao (ORCPT ); Thu, 9 Jan 2020 03:30:44 -0500 Received: from localhost (localhost [127.0.0.1]) by smtp.infotech.no (Postfix) with ESMTP id EC632204191; Thu, 9 Jan 2020 09:30:40 +0100 (CET) X-Virus-Scanned: by amavisd-new-2.6.6 (20110518) (Debian) at infotech.no Received: from smtp.infotech.no ([127.0.0.1]) by localhost (smtp.infotech.no [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id prn6E5iWnJr3; Thu, 9 Jan 2020 09:30:40 +0100 (CET) Received: from xtwo70.infotech.no (unknown [82.134.31.177]) by smtp.infotech.no (Postfix) with ESMTPA id A5B58204196; Thu, 9 Jan 2020 09:30:40 +0100 (CET) From: Douglas Gilbert To: linux-scsi@vger.kernel.org Cc: martin.petersen@oracle.com, jejb@linux.vnet.ibm.com, hare@suse.de Subject: [RFC v2 6/6] scsi_debug: bump to version 1.89 Date: Thu, 9 Jan 2020 09:30:39 +0100 Message-Id: <20200109083039.16582-7-dgilbert@interlog.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200109083039.16582-1-dgilbert@interlog.com> References: <20200109083039.16582-1-dgilbert@interlog.com> MIME-Version: 1.0 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org The scsi_debug driver version is visible in: /sys/modules/scsi_debug/version and can thus be used by user space programs to alter the features they try to use. Since the doublestore option is a significant addition, bump the version number which will appear as 0189 when the above file is read. Signed-off-by: Douglas Gilbert --- drivers/scsi/scsi_debug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index e140e764dfba..5601d800e7a3 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -7,7 +7,7 @@ * anything out of the ordinary is seen. * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * - * Copyright (C) 2001 - 2018 Douglas Gilbert + * Copyright (C) 2001 - 2019 Douglas Gilbert * * For documentation see http://sg.danny.cz/sg/sdebug26.html */ @@ -57,8 +57,8 @@ #include "scsi_logging.h" /* make sure inq_product_rev string corresponds to this version */ -#define SDEBUG_VERSION "0188" /* format to fit INQUIRY revision field */ -static const char *sdebug_version_date = "20190125"; +#define SDEBUG_VERSION "0189" /* format to fit INQUIRY revision field */ +static const char *sdebug_version_date = "20191229"; #define MY_NAME "scsi_debug"