From e2ea625469e02dac293070a7fe8f5daa5b36e292 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Sun, 10 Apr 2022 19:44:53 -0400 Subject: [PATCH] Drop scsi-scsi_debug-address-races-following-module-load.patch Signed-off-by: Sasha Levin --- ...-address-races-following-module-load.patch | 491 ------------------ queue-5.16/series | 1 - ...-address-races-following-module-load.patch | 491 ------------------ queue-5.17/series | 1 - 4 files changed, 984 deletions(-) delete mode 100644 queue-5.16/scsi-scsi_debug-address-races-following-module-load.patch delete mode 100644 queue-5.17/scsi-scsi_debug-address-races-following-module-load.patch diff --git a/queue-5.16/scsi-scsi_debug-address-races-following-module-load.patch b/queue-5.16/scsi-scsi_debug-address-races-following-module-load.patch deleted file mode 100644 index 322b5975283..00000000000 --- a/queue-5.16/scsi-scsi_debug-address-races-following-module-load.patch +++ /dev/null @@ -1,491 +0,0 @@ -From a6ba076acf7ee934d0c622f62a753027e0c1b6c8 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Sat, 8 Jan 2022 20:28:45 -0500 -Subject: scsi: scsi_debug: Address races following module load - -From: Douglas Gilbert - -[ Upstream commit 2aad3cd8537033cd34f70294a23f54623ffe9c1b ] - -When scsi_debug is loaded as a module with many (simulated) hosts, targets, -and devices (LUs), modprobe can take a long time to return. Only a small -amount of this time is spent in the scsi_debug_init(); the rest is other -parts of the kernel reacting to to the appearance of new storage -devices. As soon as scsi_debug_init() has completed the user space may call -'rmmod scsi_debug' and this was found to cause race problems as outlined -here: - - https://bugzilla.kernel.org/show_bug.cgi?id=212337 - -To reliably generate this race a sysfs parameter called rm_all_hosts was -added and the code was strengthened in this area. The main change was to -make the count of scsi_debug hosts present an atomic. Then it was found -that the handling of the existing add_host parameter needed the same -strengthening. Further: 'echo -9999 > -/sys/bus/pseudo/drivers/scsi_debug/add_host has the same effect as -rm_all_hosts so rm_all_hosts was not needed. - -To inhibit a race between two invocations of writes to add_host, a mutex -was added. Also address a possible race when rmmod is called but LUs are -still being added. - -The logic to remove (all) hosts is rather crude: it works backwards down a -linked lists of hosts. Any pending requests are terminated with -DID_NO_CONNECT as are any new requests. In the case where not all hosts are -being removed, the ones that remain may have lost requests as just -outlined. The lowest numbered host (id) hosts will remain. - -Cc: Bart Van Assche -Link: https://lore.kernel.org/r/20220109012853.301953-2-dgilbert@interlog.com -Signed-off-by: Douglas Gilbert -Signed-off-by: Martin K. Petersen -Signed-off-by: Sasha Levin ---- - drivers/scsi/scsi_debug.c | 197 ++++++++++++++++++++++++++++---------- - 1 file changed, 146 insertions(+), 51 deletions(-) - -diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c -index 2104973a35cd..24f3905f054f 100644 ---- a/drivers/scsi/scsi_debug.c -+++ b/drivers/scsi/scsi_debug.c -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -730,7 +731,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - }; - --static int sdebug_num_hosts; -+static atomic_t sdebug_num_hosts; -+static DEFINE_MUTEX(add_host_mutex); -+ - static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ - static int sdebug_ato = DEF_ATO; - static int sdebug_cdb_len = DEF_CDB_LEN; -@@ -777,6 +780,7 @@ static int sdebug_uuid_ctl = DEF_UUID_CTL; - static bool sdebug_random = DEF_RANDOM; - static bool sdebug_per_host_store = DEF_PER_HOST_STORE; - static bool sdebug_removable = DEF_REMOVABLE; -+static bool sdebug_deflect_incoming; - static bool sdebug_clustering; - static bool sdebug_host_lock = DEF_HOST_LOCK; - static bool sdebug_strict = DEF_STRICT; -@@ -5026,6 +5030,10 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp) - sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) - sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; -+ if (smp_load_acquire(&sdebug_deflect_incoming)) { -+ pr_info("Exit early due to deflect_incoming\n"); -+ return 1; -+ } - if (devip == NULL) { - devip = find_build_dev_info(sdp); - if (devip == NULL) -@@ -5111,7 +5119,7 @@ static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) - } - - /* Deletes (stops) timers or work queues of all queued commands */ --static void stop_all_queued(void) -+static void stop_all_queued(bool done_with_no_conn) - { - unsigned long iflags; - int j, k; -@@ -5120,13 +5128,15 @@ static void stop_all_queued(void) - struct sdebug_queued_cmd *sqcp; - struct sdebug_dev_info *devip; - struct sdebug_defer *sd_dp; -+ struct scsi_cmnd *scp; - - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { - spin_lock_irqsave(&sqp->qc_lock, iflags); - for (k = 0; k < SDEBUG_CANQUEUE; ++k) { - if (test_bit(k, sqp->in_use_bm)) { - sqcp = &sqp->qc_arr[k]; -- if (sqcp->a_cmnd == NULL) -+ scp = sqcp->a_cmnd; -+ if (!scp) - continue; - devip = (struct sdebug_dev_info *) - sqcp->a_cmnd->device->hostdata; -@@ -5141,6 +5151,10 @@ static void stop_all_queued(void) - l_defer_t = SDEB_DEFER_NONE; - spin_unlock_irqrestore(&sqp->qc_lock, iflags); - stop_qc_helper(sd_dp, l_defer_t); -+ if (done_with_no_conn && l_defer_t != SDEB_DEFER_NONE) { -+ scp->result = DID_NO_CONNECT << 16; -+ scsi_done(scp); -+ } - clear_bit(k, sqp->in_use_bm); - spin_lock_irqsave(&sqp->qc_lock, iflags); - } -@@ -5283,7 +5297,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) - } - } - spin_unlock(&sdebug_host_list_lock); -- stop_all_queued(); -+ stop_all_queued(false); - if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, SCpnt->device, - "%s: %d device(s) found\n", __func__, k); -@@ -5343,13 +5357,50 @@ static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) - } - } - --static void block_unblock_all_queues(bool block) -+static void sdeb_block_all_queues(void) -+{ -+ int j; -+ struct sdebug_queue *sqp; -+ -+ for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) -+ atomic_set(&sqp->blocked, (int)true); -+} -+ -+static void sdeb_unblock_all_queues(void) - { - int j; - struct sdebug_queue *sqp; - - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) -- atomic_set(&sqp->blocked, (int)block); -+ atomic_set(&sqp->blocked, (int)false); -+} -+ -+static void -+sdeb_add_n_hosts(int num_hosts) -+{ -+ if (num_hosts < 1) -+ return; -+ do { -+ bool found; -+ unsigned long idx; -+ struct sdeb_store_info *sip; -+ bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; -+ -+ found = false; -+ if (want_phs) { -+ xa_for_each_marked(per_store_ap, idx, sip, SDEB_XA_NOT_IN_USE) { -+ sdeb_most_recent_idx = (int)idx; -+ found = true; -+ break; -+ } -+ if (found) /* re-use case */ -+ sdebug_add_host_helper((int)idx); -+ else -+ sdebug_do_add_host(true /* make new store */); -+ } else { -+ sdebug_do_add_host(false); -+ } -+ } while (--num_hosts); - } - - /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 -@@ -5362,10 +5413,10 @@ static void tweak_cmnd_count(void) - modulo = abs(sdebug_every_nth); - if (modulo < 2) - return; -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - count = atomic_read(&sdebug_cmnd_count); - atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - } - - static void clear_queue_stats(void) -@@ -5383,6 +5434,15 @@ static bool inject_on_this_cmd(void) - return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; - } - -+static int process_deflect_incoming(struct scsi_cmnd *scp) -+{ -+ u8 opcode = scp->cmnd[0]; -+ -+ if (opcode == SYNCHRONIZE_CACHE || opcode == SYNCHRONIZE_CACHE_16) -+ return 0; -+ return DID_NO_CONNECT << 16; -+} -+ - #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ - - /* Complete the processing of the thread that queued a SCSI command to this -@@ -5392,8 +5452,7 @@ static bool inject_on_this_cmd(void) - */ - static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, - int scsi_result, -- int (*pfp)(struct scsi_cmnd *, -- struct sdebug_dev_info *), -+ int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *), - int delta_jiff, int ndelay) - { - bool new_sd_dp; -@@ -5414,13 +5473,27 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, - } - sdp = cmnd->device; - -- if (delta_jiff == 0) -+ if (delta_jiff == 0) { -+ sqp = get_queue(cmnd); -+ if (atomic_read(&sqp->blocked)) { -+ if (smp_load_acquire(&sdebug_deflect_incoming)) -+ return process_deflect_incoming(cmnd); -+ else -+ return SCSI_MLQUEUE_HOST_BUSY; -+ } - goto respond_in_thread; -+ } - - sqp = get_queue(cmnd); - spin_lock_irqsave(&sqp->qc_lock, iflags); - if (unlikely(atomic_read(&sqp->blocked))) { - spin_unlock_irqrestore(&sqp->qc_lock, iflags); -+ if (smp_load_acquire(&sdebug_deflect_incoming)) { -+ scsi_result = process_deflect_incoming(cmnd); -+ goto respond_in_thread; -+ } -+ if (sdebug_verbose) -+ pr_info("blocked --> SCSI_MLQUEUE_HOST_BUSY\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - num_in_q = atomic_read(&devip->num_in_q); -@@ -5616,8 +5689,12 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, - respond_in_thread: /* call back to mid-layer using invocation thread */ - cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; - cmnd->result &= ~SDEG_RES_IMMED_MASK; -- if (cmnd->result == 0 && scsi_result != 0) -+ if (cmnd->result == 0 && scsi_result != 0) { - cmnd->result = scsi_result; -+ if (sdebug_verbose) -+ pr_info("respond_in_thread: tag=0x%x, scp->result=0x%x\n", -+ blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)), scsi_result); -+ } - scsi_done(cmnd); - return 0; - } -@@ -5900,7 +5977,7 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf, - int j, k; - struct sdebug_queue *sqp; - -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; - ++j, ++sqp) { - k = find_first_bit(sqp->in_use_bm, -@@ -5914,7 +5991,7 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf, - sdebug_jdelay = jdelay; - sdebug_ndelay = 0; - } -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - } - return res; - } -@@ -5940,7 +6017,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, - int j, k; - struct sdebug_queue *sqp; - -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; - ++j, ++sqp) { - k = find_first_bit(sqp->in_use_bm, -@@ -5955,7 +6032,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, - sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN - : DEF_JDELAY; - } -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - } - return res; - } -@@ -6269,7 +6346,7 @@ static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && - (n <= SDEBUG_CANQUEUE) && - (sdebug_host_max_queue == 0)) { -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - k = 0; - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; - ++j, ++sqp) { -@@ -6284,7 +6361,7 @@ static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, - atomic_set(&retired_max_queue, k + 1); - else - atomic_set(&retired_max_queue, 0); -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - return count; - } - return -EINVAL; -@@ -6356,43 +6433,48 @@ static DRIVER_ATTR_RW(virtual_gb); - static ssize_t add_host_show(struct device_driver *ddp, char *buf) - { - /* absolute number of hosts currently active is what is shown */ -- return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts); -+ return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&sdebug_num_hosts)); - } - -+/* -+ * Accept positive and negative values. Hex values (only positive) may be prefixed by '0x'. -+ * To remove all hosts use a large negative number (e.g. -9999). The value 0 does nothing. -+ * Returns -EBUSY if another add_host sysfs invocation is active. -+ */ - static ssize_t add_host_store(struct device_driver *ddp, const char *buf, - size_t count) - { -- bool found; -- unsigned long idx; -- struct sdeb_store_info *sip; -- bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; - int delta_hosts; - -- if (sscanf(buf, "%d", &delta_hosts) != 1) -+ if (count == 0 || kstrtoint(buf, 0, &delta_hosts)) - return -EINVAL; -+ if (sdebug_verbose) -+ pr_info("prior num_hosts=%d, num_to_add=%d\n", -+ atomic_read(&sdebug_num_hosts), delta_hosts); -+ if (delta_hosts == 0) -+ return count; -+ if (mutex_trylock(&add_host_mutex) == 0) -+ return -EBUSY; - if (delta_hosts > 0) { -- do { -- found = false; -- if (want_phs) { -- xa_for_each_marked(per_store_ap, idx, sip, -- SDEB_XA_NOT_IN_USE) { -- sdeb_most_recent_idx = (int)idx; -- found = true; -- break; -- } -- if (found) /* re-use case */ -- sdebug_add_host_helper((int)idx); -- else -- sdebug_do_add_host(true); -- } else { -- sdebug_do_add_host(false); -- } -- } while (--delta_hosts); -+ sdeb_add_n_hosts(delta_hosts); - } else if (delta_hosts < 0) { -+ smp_store_release(&sdebug_deflect_incoming, true); -+ sdeb_block_all_queues(); -+ if (delta_hosts >= atomic_read(&sdebug_num_hosts)) -+ stop_all_queued(true); - do { -+ if (atomic_read(&sdebug_num_hosts) < 1) { -+ free_all_queued(); -+ break; -+ } - sdebug_do_remove_host(false); - } while (++delta_hosts); -+ sdeb_unblock_all_queues(); -+ smp_store_release(&sdebug_deflect_incoming, false); - } -+ mutex_unlock(&add_host_mutex); -+ if (sdebug_verbose) -+ pr_info("post num_hosts=%d\n", atomic_read(&sdebug_num_hosts)); - return count; - } - static DRIVER_ATTR_RW(add_host); -@@ -6902,6 +6984,10 @@ static int __init scsi_debug_init(void) - sdebug_add_host = 0; - - for (k = 0; k < hosts_to_add; k++) { -+ if (smp_load_acquire(&sdebug_deflect_incoming)) { -+ pr_info("exit early as sdebug_deflect_incoming is set\n"); -+ return 0; -+ } - if (want_store && k == 0) { - ret = sdebug_add_host_helper(idx); - if (ret < 0) { -@@ -6919,8 +7005,12 @@ static int __init scsi_debug_init(void) - } - } - if (sdebug_verbose) -- pr_info("built %d host(s)\n", sdebug_num_hosts); -+ pr_info("built %d host(s)\n", atomic_read(&sdebug_num_hosts)); - -+ /* -+ * Even though all the hosts have been established, due to async device (LU) scanning -+ * by the scsi mid-level, there may still be devices (LUs) being set up. -+ */ - return 0; - - bus_unreg: -@@ -6936,12 +7026,17 @@ static int __init scsi_debug_init(void) - - static void __exit scsi_debug_exit(void) - { -- int k = sdebug_num_hosts; -+ int k; - -- stop_all_queued(); -- for (; k; k--) -+ /* Possible race with LUs still being set up; stop them asap */ -+ sdeb_block_all_queues(); -+ smp_store_release(&sdebug_deflect_incoming, true); -+ stop_all_queued(false); -+ for (k = 0; atomic_read(&sdebug_num_hosts) > 0; k++) - sdebug_do_remove_host(true); - free_all_queued(); -+ if (sdebug_verbose) -+ pr_info("removed %d hosts\n", k); - driver_unregister(&sdebug_driverfs_driver); - bus_unregister(&pseudo_lld_bus); - root_device_unregister(pseudo_primary); -@@ -7111,13 +7206,13 @@ static int sdebug_add_host_helper(int per_host_idx) - sdbg_host->dev.bus = &pseudo_lld_bus; - sdbg_host->dev.parent = pseudo_primary; - sdbg_host->dev.release = &sdebug_release_adapter; -- dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts); -+ dev_set_name(&sdbg_host->dev, "adapter%d", atomic_read(&sdebug_num_hosts)); - - error = device_register(&sdbg_host->dev); - if (error) - goto clean; - -- ++sdebug_num_hosts; -+ atomic_inc(&sdebug_num_hosts); - return 0; - - clean: -@@ -7181,7 +7276,7 @@ static void sdebug_do_remove_host(bool the_end) - return; - - device_unregister(&sdbg_host->dev); -- --sdebug_num_hosts; -+ atomic_dec(&sdebug_num_hosts); - } - - static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) -@@ -7189,10 +7284,10 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) - int num_in_q = 0; - struct sdebug_dev_info *devip; - -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - devip = (struct sdebug_dev_info *)sdev->hostdata; - if (NULL == devip) { -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - return -ENODEV; - } - num_in_q = atomic_read(&devip->num_in_q); -@@ -7211,7 +7306,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) - sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", - __func__, qdepth, num_in_q); - } -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - return sdev->queue_depth; - } - --- -2.35.1 - diff --git a/queue-5.16/series b/queue-5.16/series index abd983d1c97..d96a7fa65c5 100644 --- a/queue-5.16/series +++ b/queue-5.16/series @@ -11,7 +11,6 @@ ath5k-fix-oob-in-ath5k_eeprom_read_pcal_info_5111.patch drm-amd-display-add-signal-type-check-when-verify-st.patch drm-edid-remove-non_desktop-quirk-for-hpn-3515-and-l.patch drm-edid-improve-non-desktop-quirk-logging.patch -scsi-scsi_debug-address-races-following-module-load.patch drm-amd-amdgpu-amdgpu_cs-fix-refcount-leak-of-a-dma_.patch drm-amd-display-fix-memory-leak.patch drm-amd-display-use-psr-version-selected-during-set_.patch diff --git a/queue-5.17/scsi-scsi_debug-address-races-following-module-load.patch b/queue-5.17/scsi-scsi_debug-address-races-following-module-load.patch deleted file mode 100644 index b515f0e2338..00000000000 --- a/queue-5.17/scsi-scsi_debug-address-races-following-module-load.patch +++ /dev/null @@ -1,491 +0,0 @@ -From be5e65338a564a1cb149ff10be808b2103c1df9a Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Sat, 8 Jan 2022 20:28:45 -0500 -Subject: scsi: scsi_debug: Address races following module load - -From: Douglas Gilbert - -[ Upstream commit 2aad3cd8537033cd34f70294a23f54623ffe9c1b ] - -When scsi_debug is loaded as a module with many (simulated) hosts, targets, -and devices (LUs), modprobe can take a long time to return. Only a small -amount of this time is spent in the scsi_debug_init(); the rest is other -parts of the kernel reacting to to the appearance of new storage -devices. As soon as scsi_debug_init() has completed the user space may call -'rmmod scsi_debug' and this was found to cause race problems as outlined -here: - - https://bugzilla.kernel.org/show_bug.cgi?id=212337 - -To reliably generate this race a sysfs parameter called rm_all_hosts was -added and the code was strengthened in this area. The main change was to -make the count of scsi_debug hosts present an atomic. Then it was found -that the handling of the existing add_host parameter needed the same -strengthening. Further: 'echo -9999 > -/sys/bus/pseudo/drivers/scsi_debug/add_host has the same effect as -rm_all_hosts so rm_all_hosts was not needed. - -To inhibit a race between two invocations of writes to add_host, a mutex -was added. Also address a possible race when rmmod is called but LUs are -still being added. - -The logic to remove (all) hosts is rather crude: it works backwards down a -linked lists of hosts. Any pending requests are terminated with -DID_NO_CONNECT as are any new requests. In the case where not all hosts are -being removed, the ones that remain may have lost requests as just -outlined. The lowest numbered host (id) hosts will remain. - -Cc: Bart Van Assche -Link: https://lore.kernel.org/r/20220109012853.301953-2-dgilbert@interlog.com -Signed-off-by: Douglas Gilbert -Signed-off-by: Martin K. Petersen -Signed-off-by: Sasha Levin ---- - drivers/scsi/scsi_debug.c | 197 ++++++++++++++++++++++++++++---------- - 1 file changed, 146 insertions(+), 51 deletions(-) - -diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c -index 2104973a35cd..24f3905f054f 100644 ---- a/drivers/scsi/scsi_debug.c -+++ b/drivers/scsi/scsi_debug.c -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -730,7 +731,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - }; - --static int sdebug_num_hosts; -+static atomic_t sdebug_num_hosts; -+static DEFINE_MUTEX(add_host_mutex); -+ - static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ - static int sdebug_ato = DEF_ATO; - static int sdebug_cdb_len = DEF_CDB_LEN; -@@ -777,6 +780,7 @@ static int sdebug_uuid_ctl = DEF_UUID_CTL; - static bool sdebug_random = DEF_RANDOM; - static bool sdebug_per_host_store = DEF_PER_HOST_STORE; - static bool sdebug_removable = DEF_REMOVABLE; -+static bool sdebug_deflect_incoming; - static bool sdebug_clustering; - static bool sdebug_host_lock = DEF_HOST_LOCK; - static bool sdebug_strict = DEF_STRICT; -@@ -5026,6 +5030,10 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp) - sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) - sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; -+ if (smp_load_acquire(&sdebug_deflect_incoming)) { -+ pr_info("Exit early due to deflect_incoming\n"); -+ return 1; -+ } - if (devip == NULL) { - devip = find_build_dev_info(sdp); - if (devip == NULL) -@@ -5111,7 +5119,7 @@ static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) - } - - /* Deletes (stops) timers or work queues of all queued commands */ --static void stop_all_queued(void) -+static void stop_all_queued(bool done_with_no_conn) - { - unsigned long iflags; - int j, k; -@@ -5120,13 +5128,15 @@ static void stop_all_queued(void) - struct sdebug_queued_cmd *sqcp; - struct sdebug_dev_info *devip; - struct sdebug_defer *sd_dp; -+ struct scsi_cmnd *scp; - - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { - spin_lock_irqsave(&sqp->qc_lock, iflags); - for (k = 0; k < SDEBUG_CANQUEUE; ++k) { - if (test_bit(k, sqp->in_use_bm)) { - sqcp = &sqp->qc_arr[k]; -- if (sqcp->a_cmnd == NULL) -+ scp = sqcp->a_cmnd; -+ if (!scp) - continue; - devip = (struct sdebug_dev_info *) - sqcp->a_cmnd->device->hostdata; -@@ -5141,6 +5151,10 @@ static void stop_all_queued(void) - l_defer_t = SDEB_DEFER_NONE; - spin_unlock_irqrestore(&sqp->qc_lock, iflags); - stop_qc_helper(sd_dp, l_defer_t); -+ if (done_with_no_conn && l_defer_t != SDEB_DEFER_NONE) { -+ scp->result = DID_NO_CONNECT << 16; -+ scsi_done(scp); -+ } - clear_bit(k, sqp->in_use_bm); - spin_lock_irqsave(&sqp->qc_lock, iflags); - } -@@ -5283,7 +5297,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) - } - } - spin_unlock(&sdebug_host_list_lock); -- stop_all_queued(); -+ stop_all_queued(false); - if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, SCpnt->device, - "%s: %d device(s) found\n", __func__, k); -@@ -5343,13 +5357,50 @@ static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) - } - } - --static void block_unblock_all_queues(bool block) -+static void sdeb_block_all_queues(void) -+{ -+ int j; -+ struct sdebug_queue *sqp; -+ -+ for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) -+ atomic_set(&sqp->blocked, (int)true); -+} -+ -+static void sdeb_unblock_all_queues(void) - { - int j; - struct sdebug_queue *sqp; - - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) -- atomic_set(&sqp->blocked, (int)block); -+ atomic_set(&sqp->blocked, (int)false); -+} -+ -+static void -+sdeb_add_n_hosts(int num_hosts) -+{ -+ if (num_hosts < 1) -+ return; -+ do { -+ bool found; -+ unsigned long idx; -+ struct sdeb_store_info *sip; -+ bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; -+ -+ found = false; -+ if (want_phs) { -+ xa_for_each_marked(per_store_ap, idx, sip, SDEB_XA_NOT_IN_USE) { -+ sdeb_most_recent_idx = (int)idx; -+ found = true; -+ break; -+ } -+ if (found) /* re-use case */ -+ sdebug_add_host_helper((int)idx); -+ else -+ sdebug_do_add_host(true /* make new store */); -+ } else { -+ sdebug_do_add_host(false); -+ } -+ } while (--num_hosts); - } - - /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 -@@ -5362,10 +5413,10 @@ static void tweak_cmnd_count(void) - modulo = abs(sdebug_every_nth); - if (modulo < 2) - return; -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - count = atomic_read(&sdebug_cmnd_count); - atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - } - - static void clear_queue_stats(void) -@@ -5383,6 +5434,15 @@ static bool inject_on_this_cmd(void) - return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; - } - -+static int process_deflect_incoming(struct scsi_cmnd *scp) -+{ -+ u8 opcode = scp->cmnd[0]; -+ -+ if (opcode == SYNCHRONIZE_CACHE || opcode == SYNCHRONIZE_CACHE_16) -+ return 0; -+ return DID_NO_CONNECT << 16; -+} -+ - #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ - - /* Complete the processing of the thread that queued a SCSI command to this -@@ -5392,8 +5452,7 @@ static bool inject_on_this_cmd(void) - */ - static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, - int scsi_result, -- int (*pfp)(struct scsi_cmnd *, -- struct sdebug_dev_info *), -+ int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *), - int delta_jiff, int ndelay) - { - bool new_sd_dp; -@@ -5414,13 +5473,27 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, - } - sdp = cmnd->device; - -- if (delta_jiff == 0) -+ if (delta_jiff == 0) { -+ sqp = get_queue(cmnd); -+ if (atomic_read(&sqp->blocked)) { -+ if (smp_load_acquire(&sdebug_deflect_incoming)) -+ return process_deflect_incoming(cmnd); -+ else -+ return SCSI_MLQUEUE_HOST_BUSY; -+ } - goto respond_in_thread; -+ } - - sqp = get_queue(cmnd); - spin_lock_irqsave(&sqp->qc_lock, iflags); - if (unlikely(atomic_read(&sqp->blocked))) { - spin_unlock_irqrestore(&sqp->qc_lock, iflags); -+ if (smp_load_acquire(&sdebug_deflect_incoming)) { -+ scsi_result = process_deflect_incoming(cmnd); -+ goto respond_in_thread; -+ } -+ if (sdebug_verbose) -+ pr_info("blocked --> SCSI_MLQUEUE_HOST_BUSY\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - num_in_q = atomic_read(&devip->num_in_q); -@@ -5616,8 +5689,12 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, - respond_in_thread: /* call back to mid-layer using invocation thread */ - cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; - cmnd->result &= ~SDEG_RES_IMMED_MASK; -- if (cmnd->result == 0 && scsi_result != 0) -+ if (cmnd->result == 0 && scsi_result != 0) { - cmnd->result = scsi_result; -+ if (sdebug_verbose) -+ pr_info("respond_in_thread: tag=0x%x, scp->result=0x%x\n", -+ blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)), scsi_result); -+ } - scsi_done(cmnd); - return 0; - } -@@ -5900,7 +5977,7 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf, - int j, k; - struct sdebug_queue *sqp; - -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; - ++j, ++sqp) { - k = find_first_bit(sqp->in_use_bm, -@@ -5914,7 +5991,7 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf, - sdebug_jdelay = jdelay; - sdebug_ndelay = 0; - } -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - } - return res; - } -@@ -5940,7 +6017,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, - int j, k; - struct sdebug_queue *sqp; - -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; - ++j, ++sqp) { - k = find_first_bit(sqp->in_use_bm, -@@ -5955,7 +6032,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, - sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN - : DEF_JDELAY; - } -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - } - return res; - } -@@ -6269,7 +6346,7 @@ static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && - (n <= SDEBUG_CANQUEUE) && - (sdebug_host_max_queue == 0)) { -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - k = 0; - for (j = 0, sqp = sdebug_q_arr; j < submit_queues; - ++j, ++sqp) { -@@ -6284,7 +6361,7 @@ static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, - atomic_set(&retired_max_queue, k + 1); - else - atomic_set(&retired_max_queue, 0); -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - return count; - } - return -EINVAL; -@@ -6356,43 +6433,48 @@ static DRIVER_ATTR_RW(virtual_gb); - static ssize_t add_host_show(struct device_driver *ddp, char *buf) - { - /* absolute number of hosts currently active is what is shown */ -- return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts); -+ return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&sdebug_num_hosts)); - } - -+/* -+ * Accept positive and negative values. Hex values (only positive) may be prefixed by '0x'. -+ * To remove all hosts use a large negative number (e.g. -9999). The value 0 does nothing. -+ * Returns -EBUSY if another add_host sysfs invocation is active. -+ */ - static ssize_t add_host_store(struct device_driver *ddp, const char *buf, - size_t count) - { -- bool found; -- unsigned long idx; -- struct sdeb_store_info *sip; -- bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; - int delta_hosts; - -- if (sscanf(buf, "%d", &delta_hosts) != 1) -+ if (count == 0 || kstrtoint(buf, 0, &delta_hosts)) - return -EINVAL; -+ if (sdebug_verbose) -+ pr_info("prior num_hosts=%d, num_to_add=%d\n", -+ atomic_read(&sdebug_num_hosts), delta_hosts); -+ if (delta_hosts == 0) -+ return count; -+ if (mutex_trylock(&add_host_mutex) == 0) -+ return -EBUSY; - if (delta_hosts > 0) { -- do { -- found = false; -- if (want_phs) { -- xa_for_each_marked(per_store_ap, idx, sip, -- SDEB_XA_NOT_IN_USE) { -- sdeb_most_recent_idx = (int)idx; -- found = true; -- break; -- } -- if (found) /* re-use case */ -- sdebug_add_host_helper((int)idx); -- else -- sdebug_do_add_host(true); -- } else { -- sdebug_do_add_host(false); -- } -- } while (--delta_hosts); -+ sdeb_add_n_hosts(delta_hosts); - } else if (delta_hosts < 0) { -+ smp_store_release(&sdebug_deflect_incoming, true); -+ sdeb_block_all_queues(); -+ if (delta_hosts >= atomic_read(&sdebug_num_hosts)) -+ stop_all_queued(true); - do { -+ if (atomic_read(&sdebug_num_hosts) < 1) { -+ free_all_queued(); -+ break; -+ } - sdebug_do_remove_host(false); - } while (++delta_hosts); -+ sdeb_unblock_all_queues(); -+ smp_store_release(&sdebug_deflect_incoming, false); - } -+ mutex_unlock(&add_host_mutex); -+ if (sdebug_verbose) -+ pr_info("post num_hosts=%d\n", atomic_read(&sdebug_num_hosts)); - return count; - } - static DRIVER_ATTR_RW(add_host); -@@ -6902,6 +6984,10 @@ static int __init scsi_debug_init(void) - sdebug_add_host = 0; - - for (k = 0; k < hosts_to_add; k++) { -+ if (smp_load_acquire(&sdebug_deflect_incoming)) { -+ pr_info("exit early as sdebug_deflect_incoming is set\n"); -+ return 0; -+ } - if (want_store && k == 0) { - ret = sdebug_add_host_helper(idx); - if (ret < 0) { -@@ -6919,8 +7005,12 @@ static int __init scsi_debug_init(void) - } - } - if (sdebug_verbose) -- pr_info("built %d host(s)\n", sdebug_num_hosts); -+ pr_info("built %d host(s)\n", atomic_read(&sdebug_num_hosts)); - -+ /* -+ * Even though all the hosts have been established, due to async device (LU) scanning -+ * by the scsi mid-level, there may still be devices (LUs) being set up. -+ */ - return 0; - - bus_unreg: -@@ -6936,12 +7026,17 @@ static int __init scsi_debug_init(void) - - static void __exit scsi_debug_exit(void) - { -- int k = sdebug_num_hosts; -+ int k; - -- stop_all_queued(); -- for (; k; k--) -+ /* Possible race with LUs still being set up; stop them asap */ -+ sdeb_block_all_queues(); -+ smp_store_release(&sdebug_deflect_incoming, true); -+ stop_all_queued(false); -+ for (k = 0; atomic_read(&sdebug_num_hosts) > 0; k++) - sdebug_do_remove_host(true); - free_all_queued(); -+ if (sdebug_verbose) -+ pr_info("removed %d hosts\n", k); - driver_unregister(&sdebug_driverfs_driver); - bus_unregister(&pseudo_lld_bus); - root_device_unregister(pseudo_primary); -@@ -7111,13 +7206,13 @@ static int sdebug_add_host_helper(int per_host_idx) - sdbg_host->dev.bus = &pseudo_lld_bus; - sdbg_host->dev.parent = pseudo_primary; - sdbg_host->dev.release = &sdebug_release_adapter; -- dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts); -+ dev_set_name(&sdbg_host->dev, "adapter%d", atomic_read(&sdebug_num_hosts)); - - error = device_register(&sdbg_host->dev); - if (error) - goto clean; - -- ++sdebug_num_hosts; -+ atomic_inc(&sdebug_num_hosts); - return 0; - - clean: -@@ -7181,7 +7276,7 @@ static void sdebug_do_remove_host(bool the_end) - return; - - device_unregister(&sdbg_host->dev); -- --sdebug_num_hosts; -+ atomic_dec(&sdebug_num_hosts); - } - - static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) -@@ -7189,10 +7284,10 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) - int num_in_q = 0; - struct sdebug_dev_info *devip; - -- block_unblock_all_queues(true); -+ sdeb_block_all_queues(); - devip = (struct sdebug_dev_info *)sdev->hostdata; - if (NULL == devip) { -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - return -ENODEV; - } - num_in_q = atomic_read(&devip->num_in_q); -@@ -7211,7 +7306,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) - sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", - __func__, qdepth, num_in_q); - } -- block_unblock_all_queues(false); -+ sdeb_unblock_all_queues(); - return sdev->queue_depth; - } - --- -2.35.1 - diff --git a/queue-5.17/series b/queue-5.17/series index 98da1837dd1..c48ef36b181 100644 --- a/queue-5.17/series +++ b/queue-5.17/series @@ -17,7 +17,6 @@ drm-amdkfd-enable-heavy-weight-tlb-flush-on-arcturus.patch drm-edid-remove-non_desktop-quirk-for-hpn-3515-and-l.patch drm-edid-improve-non-desktop-quirk-logging.patch bluetooth-hci_event-ignore-multiple-conn-complete-ev.patch -scsi-scsi_debug-address-races-following-module-load.patch drm-amd-amdgpu-amdgpu_cs-fix-refcount-leak-of-a-dma_.patch drm-amd-display-fix-memory-leak.patch drm-amd-display-use-psr-version-selected-during-set_.patch -- 2.47.3