From: Greg Kroah-Hartman Date: Mon, 15 May 2023 12:48:36 +0000 (+0200) Subject: 5.4-stable patches X-Git-Tag: v4.14.315~27 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=eb07c7773af8076fd32d15b519a836fe7ebabc03;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: drbd-correctly-submit-flush-bio-on-barrier.patch pci-pciehp-fix-ab-ba-deadlock-between-reset_lock-and-device_lock.patch pci-pciehp-use-down_read-write_nested-reset_lock-to-fix-lockdep-errors.patch serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch --- diff --git a/queue-5.4/drbd-correctly-submit-flush-bio-on-barrier.patch b/queue-5.4/drbd-correctly-submit-flush-bio-on-barrier.patch new file mode 100644 index 00000000000..81b1a3a0b64 --- /dev/null +++ b/queue-5.4/drbd-correctly-submit-flush-bio-on-barrier.patch @@ -0,0 +1,49 @@ +From 3899d94e3831ee07ea6821c032dc297aec80586a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christoph=20B=C3=B6hmwalder?= + +Date: Wed, 3 May 2023 14:19:37 +0200 +Subject: drbd: correctly submit flush bio on barrier +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Christoph Böhmwalder + +commit 3899d94e3831ee07ea6821c032dc297aec80586a upstream. + +When we receive a flush command (or "barrier" in DRBD), we currently use +a REQ_OP_FLUSH with the REQ_PREFLUSH flag set. + +The correct way to submit a flush bio is by using a REQ_OP_WRITE without +any data, and set the REQ_PREFLUSH flag. + +Since commit b4a6bb3a67aa ("block: add a sanity check for non-write +flush/fua bios"), this triggers a warning in the block layer, but this +has been broken for quite some time before that. + +So use the correct set of flags to actually make the flush happen. + +Cc: Christoph Hellwig +Cc: stable@vger.kernel.org +Fixes: f9ff0da56437 ("drbd: allow parallel flushes for multi-volume resources") +Reported-by: Thomas Voegtle +Signed-off-by: Christoph Böhmwalder +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/20230503121937.17232-1-christoph.boehmwalder@linbit.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + drivers/block/drbd/drbd_receiver.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/block/drbd/drbd_receiver.c ++++ b/drivers/block/drbd/drbd_receiver.c +@@ -1298,7 +1298,7 @@ static void submit_one_flush(struct drbd + bio_set_dev(bio, device->ldev->backing_bdev); + bio->bi_private = octx; + bio->bi_end_io = one_flush_endio; +- bio->bi_opf = REQ_OP_FLUSH | REQ_PREFLUSH; ++ bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH; + + device->flush_jif = jiffies; + set_bit(FLUSH_PENDING, &device->flags); diff --git a/queue-5.4/pci-pciehp-fix-ab-ba-deadlock-between-reset_lock-and-device_lock.patch b/queue-5.4/pci-pciehp-fix-ab-ba-deadlock-between-reset_lock-and-device_lock.patch new file mode 100644 index 00000000000..e677860ab4a --- /dev/null +++ b/queue-5.4/pci-pciehp-fix-ab-ba-deadlock-between-reset_lock-and-device_lock.patch @@ -0,0 +1,181 @@ +From stable-owner@vger.kernel.org Tue May 9 12:51:50 2023 +From: Lukas Wunner +Date: Tue, 9 May 2023 12:41:10 +0200 +Subject: PCI: pciehp: Fix AB-BA deadlock between reset_lock and device_lock +To: stable@vger.kernel.org +Cc: Anatoli.Antonovitch@amd.com, alex.williamson@redhat.com, amichon@kalrayinc.com, andrey2805@gmail.com, ashok.raj@intel.com, bhelgaas@google.com, dstein@hpe.com, ian.may@canonical.com, michael.haeuptle@hpe.com, mika.westerberg@linux.intel.com, rahul.kumar1@amd.com, sathyanarayanan.kuppuswamy@linux.intel.com, wangxiongfeng2@huawei.com, zhangjialin11@huawei.com +Message-ID: <8811bdb978f819b519ef33e9f536422453311bea.1683628574.git.lukas@wunner.de> + +From: Lukas Wunner + +commit f5eff5591b8f9c5effd25c92c758a127765f74c1 upstream. + +In 2013, commits + + 2e35afaefe64 ("PCI: pciehp: Add reset_slot() method") + 608c388122c7 ("PCI: Add slot reset option to pci_dev_reset()") + +amended PCIe hotplug to mask Presence Detect Changed events during a +Secondary Bus Reset. The reset thus no longer causes gratuitous slot +bringdown and bringup. + +However the commits neglected to serialize reset with code paths reading +slot registers. For instance, a slot bringup due to an earlier hotplug +event may see the Presence Detect State bit cleared during a concurrent +Secondary Bus Reset. + +In 2018, commit + + 5b3f7b7d062b ("PCI: pciehp: Avoid slot access during reset") + +retrofitted the missing locking. It introduced a reset_lock which +serializes a Secondary Bus Reset with other parts of pciehp. + +Unfortunately the locking turns out to be overzealous: reset_lock is +held for the entire enumeration and de-enumeration of hotplugged devices, +including driver binding and unbinding. + +Driver binding and unbinding acquires device_lock while the reset_lock +of the ancestral hotplug port is held. A concurrent Secondary Bus Reset +acquires the ancestral reset_lock while already holding the device_lock. +The asymmetric locking order in the two code paths can lead to AB-BA +deadlocks. + +Michael Haeuptle reports such deadlocks on simultaneous hot-removal and +vfio release (the latter implies a Secondary Bus Reset): + + pciehp_ist() # down_read(reset_lock) + pciehp_handle_presence_or_link_change() + pciehp_disable_slot() + __pciehp_disable_slot() + remove_board() + pciehp_unconfigure_device() + pci_stop_and_remove_bus_device() + pci_stop_bus_device() + pci_stop_dev() + device_release_driver() + device_release_driver_internal() + __device_driver_lock() # device_lock() + + SYS_munmap() + vfio_device_fops_release() + vfio_device_group_close() + vfio_device_close() + vfio_device_last_close() + vfio_pci_core_close_device() + vfio_pci_core_disable() # device_lock() + __pci_reset_function_locked() + pci_reset_bus_function() + pci_dev_reset_slot_function() + pci_reset_hotplug_slot() + pciehp_reset_slot() # down_write(reset_lock) + +Ian May reports the same deadlock on simultaneous hot-removal and an +AER-induced Secondary Bus Reset: + + aer_recover_work_func() + pcie_do_recovery() + aer_root_reset() + pci_bus_error_reset() + pci_slot_reset() + pci_slot_lock() # device_lock() + pci_reset_hotplug_slot() + pciehp_reset_slot() # down_write(reset_lock) + +Fix by releasing the reset_lock during driver binding and unbinding, +thereby splitting and shrinking the critical section. + +Driver binding and unbinding is protected by the device_lock() and thus +serialized with a Secondary Bus Reset. There's no need to additionally +protect it with the reset_lock. However, pciehp does not bind and +unbind devices directly, but rather invokes PCI core functions which +also perform certain enumeration and de-enumeration steps. + +The reset_lock's purpose is to protect slot registers, not enumeration +and de-enumeration of hotplugged devices. That would arguably be the +job of the PCI core, not the PCIe hotplug driver. After all, an +AER-induced Secondary Bus Reset may as well happen during boot-time +enumeration of the PCI hierarchy and there's no locking to prevent that +either. + +Exempting *de-enumeration* from the reset_lock is relatively harmless: +A concurrent Secondary Bus Reset may foil config space accesses such as +PME interrupt disablement. But if the device is physically gone, those +accesses are pointless anyway. If the device is physically present and +only logically removed through an Attention Button press or the sysfs +"power" attribute, PME interrupts as well as DMA cannot come through +because pciehp_unconfigure_device() disables INTx and Bus Master bits. +That's still protected by the reset_lock in the present commit. + +Exempting *enumeration* from the reset_lock also has limited impact: +The exempted call to pci_bus_add_device() may perform device accesses +through pcibios_bus_add_device() and pci_fixup_device() which are now +no longer protected from a concurrent Secondary Bus Reset. Otherwise +there should be no impact. + +In essence, the present commit seeks to fix the AB-BA deadlocks while +still retaining a best-effort reset protection for enumeration and +de-enumeration of hotplugged devices -- until a general solution is +implemented in the PCI core. + +Link: https://lore.kernel.org/linux-pci/CS1PR8401MB0728FC6FDAB8A35C22BD90EC95F10@CS1PR8401MB0728.NAMPRD84.PROD.OUTLOOK.COM +Link: https://lore.kernel.org/linux-pci/20200615143250.438252-1-ian.may@canonical.com +Link: https://lore.kernel.org/linux-pci/ce878dab-c0c4-5bd0-a725-9805a075682d@amd.com +Link: https://lore.kernel.org/linux-pci/ed831249-384a-6d35-0831-70af191e9bce@huawei.com +Link: https://bugzilla.kernel.org/show_bug.cgi?id=215590 +Fixes: 5b3f7b7d062b ("PCI: pciehp: Avoid slot access during reset") +Link: https://lore.kernel.org/r/fef2b2e9edf245c049a8c5b94743c0f74ff5008a.1681191902.git.lukas@wunner.de +Reported-by: Michael Haeuptle +Reported-by: Ian May +Reported-by: Andrey Grodzovsky +Reported-by: Rahul Kumar +Reported-by: Jialin Zhang +Tested-by: Anatoli Antonovitch +Signed-off-by: Lukas Wunner +Signed-off-by: Bjorn Helgaas +Cc: stable@vger.kernel.org # v4.19+ +Cc: Dan Stein +Cc: Ashok Raj +Cc: Alex Michon +Cc: Xiongfeng Wang +Cc: Alex Williamson +Cc: Mika Westerberg +Cc: Sathyanarayanan Kuppuswamy +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/hotplug/pciehp_pci.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/pci/hotplug/pciehp_pci.c ++++ b/drivers/pci/hotplug/pciehp_pci.c +@@ -63,7 +63,14 @@ int pciehp_configure_device(struct contr + + pci_assign_unassigned_bridge_resources(bridge); + pcie_bus_configure_settings(parent); ++ ++ /* ++ * Release reset_lock during driver binding ++ * to avoid AB-BA deadlock with device_lock. ++ */ ++ up_read(&ctrl->reset_lock); + pci_bus_add_devices(parent); ++ down_read_nested(&ctrl->reset_lock, ctrl->depth); + + out: + pci_unlock_rescan_remove(); +@@ -104,7 +111,15 @@ void pciehp_unconfigure_device(struct co + list_for_each_entry_safe_reverse(dev, temp, &parent->devices, + bus_list) { + pci_dev_get(dev); ++ ++ /* ++ * Release reset_lock during driver unbinding ++ * to avoid AB-BA deadlock with device_lock. ++ */ ++ up_read(&ctrl->reset_lock); + pci_stop_and_remove_bus_device(dev); ++ down_read_nested(&ctrl->reset_lock, ctrl->depth); ++ + /* + * Ensure that no new Requests will be generated from + * the device. diff --git a/queue-5.4/pci-pciehp-use-down_read-write_nested-reset_lock-to-fix-lockdep-errors.patch b/queue-5.4/pci-pciehp-use-down_read-write_nested-reset_lock-to-fix-lockdep-errors.patch new file mode 100644 index 00000000000..04763a651bd --- /dev/null +++ b/queue-5.4/pci-pciehp-use-down_read-write_nested-reset_lock-to-fix-lockdep-errors.patch @@ -0,0 +1,186 @@ +From stable-owner@vger.kernel.org Tue May 9 12:50:59 2023 +From: Lukas Wunner +Date: Tue, 9 May 2023 12:41:09 +0200 +Subject: PCI: pciehp: Use down_read/write_nested(reset_lock) to fix lockdep errors +To: stable@vger.kernel.org +Cc: Anatoli.Antonovitch@amd.com, alex.williamson@redhat.com, amichon@kalrayinc.com, andrey2805@gmail.com, ashok.raj@intel.com, bhelgaas@google.com, dstein@hpe.com, ian.may@canonical.com, michael.haeuptle@hpe.com, mika.westerberg@linux.intel.com, rahul.kumar1@amd.com, sathyanarayanan.kuppuswamy@linux.intel.com, wangxiongfeng2@huawei.com, zhangjialin11@huawei.com +Message-ID: <0296a234ed04adfec0f256b24fae929f6a268509.1683628574.git.lukas@wunner.de> + +From: Hans de Goede + +commit 085a9f43433f30cbe8a1ade62d9d7827c3217f4d upstream. + +Use down_read_nested() and down_write_nested() when taking the +ctrl->reset_lock rw-sem, passing the number of PCIe hotplug controllers in +the path to the PCI root bus as lock subclass parameter. + +This fixes the following false-positive lockdep report when unplugging a +Lenovo X1C8 from a Lenovo 2nd gen TB3 dock: + + pcieport 0000:06:01.0: pciehp: Slot(1): Link Down + pcieport 0000:06:01.0: pciehp: Slot(1): Card not present + ============================================ + WARNING: possible recursive locking detected + 5.16.0-rc2+ #621 Not tainted + -------------------------------------------- + irq/124-pciehp/86 is trying to acquire lock: + ffff8e5ac4299ef8 (&ctrl->reset_lock){.+.+}-{3:3}, at: pciehp_check_presence+0x23/0x80 + + but task is already holding lock: + ffff8e5ac4298af8 (&ctrl->reset_lock){.+.+}-{3:3}, at: pciehp_ist+0xf3/0x180 + + other info that might help us debug this: + Possible unsafe locking scenario: + + CPU0 + ---- + lock(&ctrl->reset_lock); + lock(&ctrl->reset_lock); + + *** DEADLOCK *** + + May be due to missing lock nesting notation + + 3 locks held by irq/124-pciehp/86: + #0: ffff8e5ac4298af8 (&ctrl->reset_lock){.+.+}-{3:3}, at: pciehp_ist+0xf3/0x180 + #1: ffffffffa3b024e8 (pci_rescan_remove_lock){+.+.}-{3:3}, at: pciehp_unconfigure_device+0x31/0x110 + #2: ffff8e5ac1ee2248 (&dev->mutex){....}-{3:3}, at: device_release_driver+0x1c/0x40 + + stack backtrace: + CPU: 4 PID: 86 Comm: irq/124-pciehp Not tainted 5.16.0-rc2+ #621 + Hardware name: LENOVO 20U90SIT19/20U90SIT19, BIOS N2WET30W (1.20 ) 08/26/2021 + Call Trace: + + dump_stack_lvl+0x59/0x73 + __lock_acquire.cold+0xc5/0x2c6 + lock_acquire+0xb5/0x2b0 + down_read+0x3e/0x50 + pciehp_check_presence+0x23/0x80 + pciehp_runtime_resume+0x5c/0xa0 + device_for_each_child+0x45/0x70 + pcie_port_device_runtime_resume+0x20/0x30 + pci_pm_runtime_resume+0xa7/0xc0 + __rpm_callback+0x41/0x110 + rpm_callback+0x59/0x70 + rpm_resume+0x512/0x7b0 + __pm_runtime_resume+0x4a/0x90 + __device_release_driver+0x28/0x240 + device_release_driver+0x26/0x40 + pci_stop_bus_device+0x68/0x90 + pci_stop_bus_device+0x2c/0x90 + pci_stop_and_remove_bus_device+0xe/0x20 + pciehp_unconfigure_device+0x6c/0x110 + pciehp_disable_slot+0x5b/0xe0 + pciehp_handle_presence_or_link_change+0xc3/0x2f0 + pciehp_ist+0x179/0x180 + +This lockdep warning is triggered because with Thunderbolt, hotplug ports +are nested. When removing multiple devices in a daisy-chain, each hotplug +port's reset_lock may be acquired recursively. It's never the same lock, so +the lockdep splat is a false positive. + +Because locks at the same hierarchy level are never acquired recursively, a +per-level lockdep class is sufficient to fix the lockdep warning. + +The choice to use one lockdep subclass per pcie-hotplug controller in the +path to the root-bus was made to conserve class keys because their number +is limited and the complexity grows quadratically with number of keys +according to Documentation/locking/lockdep-design.rst. + +Link: https://lore.kernel.org/linux-pci/20190402021933.GA2966@mit.edu/ +Link: https://lore.kernel.org/linux-pci/de684a28-9038-8fc6-27ca-3f6f2f6400d7@redhat.com/ +Link: https://lore.kernel.org/r/20211217141709.379663-1-hdegoede@redhat.com +Link: https://bugzilla.kernel.org/show_bug.cgi?id=208855 +Reported-by: "Theodore Ts'o" +Signed-off-by: Hans de Goede +Signed-off-by: Bjorn Helgaas +Reviewed-by: Lukas Wunner +Cc: stable@vger.kernel.org +[lukas: backport to v5.4-stable] +Signed-off-by: Lukas Wunner +Signed-off-by: Greg Kroah-Hartman +--- + drivers/pci/hotplug/pciehp.h | 3 +++ + drivers/pci/hotplug/pciehp_core.c | 2 +- + drivers/pci/hotplug/pciehp_hpc.c | 19 +++++++++++++++++-- + 3 files changed, 21 insertions(+), 3 deletions(-) + +--- a/drivers/pci/hotplug/pciehp.h ++++ b/drivers/pci/hotplug/pciehp.h +@@ -72,6 +72,8 @@ extern int pciehp_poll_time; + * @reset_lock: prevents access to the Data Link Layer Link Active bit in the + * Link Status register and to the Presence Detect State bit in the Slot + * Status register during a slot reset which may cause them to flap ++ * @depth: Number of additional hotplug ports in the path to the root bus, ++ * used as lock subclass for @reset_lock + * @ist_running: flag to keep user request waiting while IRQ thread is running + * @request_result: result of last user request submitted to the IRQ thread + * @requester: wait queue to wake up on completion of user request, +@@ -102,6 +104,7 @@ struct controller { + + struct hotplug_slot hotplug_slot; /* hotplug core interface */ + struct rw_semaphore reset_lock; ++ unsigned int depth; + unsigned int ist_running; + int request_result; + wait_queue_head_t requester; +--- a/drivers/pci/hotplug/pciehp_core.c ++++ b/drivers/pci/hotplug/pciehp_core.c +@@ -165,7 +165,7 @@ static void pciehp_check_presence(struct + { + int occupied; + +- down_read(&ctrl->reset_lock); ++ down_read_nested(&ctrl->reset_lock, ctrl->depth); + mutex_lock(&ctrl->state_lock); + + occupied = pciehp_card_present_or_link_active(ctrl); +--- a/drivers/pci/hotplug/pciehp_hpc.c ++++ b/drivers/pci/hotplug/pciehp_hpc.c +@@ -674,7 +674,7 @@ static irqreturn_t pciehp_ist(int irq, v + * Disable requests have higher priority than Presence Detect Changed + * or Data Link Layer State Changed events. + */ +- down_read(&ctrl->reset_lock); ++ down_read_nested(&ctrl->reset_lock, ctrl->depth); + if (events & DISABLE_SLOT) + pciehp_handle_disable_request(ctrl); + else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) +@@ -808,7 +808,7 @@ int pciehp_reset_slot(struct hotplug_slo + if (probe) + return 0; + +- down_write(&ctrl->reset_lock); ++ down_write_nested(&ctrl->reset_lock, ctrl->depth); + + if (!ATTN_BUTTN(ctrl)) { + ctrl_mask |= PCI_EXP_SLTCTL_PDCE; +@@ -864,6 +864,20 @@ static inline void dbg_ctrl(struct contr + + #define FLAG(x, y) (((x) & (y)) ? '+' : '-') + ++static inline int pcie_hotplug_depth(struct pci_dev *dev) ++{ ++ struct pci_bus *bus = dev->bus; ++ int depth = 0; ++ ++ while (bus->parent) { ++ bus = bus->parent; ++ if (bus->self && bus->self->is_hotplug_bridge) ++ depth++; ++ } ++ ++ return depth; ++} ++ + struct controller *pcie_init(struct pcie_device *dev) + { + struct controller *ctrl; +@@ -877,6 +891,7 @@ struct controller *pcie_init(struct pcie + return NULL; + + ctrl->pcie = dev; ++ ctrl->depth = pcie_hotplug_depth(dev->port); + pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap); + + if (pdev->hotplug_user_indicators) diff --git a/queue-5.4/serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch b/queue-5.4/serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch new file mode 100644 index 00000000000..d6f21235d2d --- /dev/null +++ b/queue-5.4/serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch @@ -0,0 +1,98 @@ +From stable-owner@vger.kernel.org Thu May 11 14:33:08 2023 +From: "Ilpo Järvinen" +Date: Thu, 11 May 2023 15:32:44 +0300 +Subject: serial: 8250: Fix serial8250_tx_empty() race with DMA Tx +To: stable@vger.kernel.org +Cc: "Ilpo Järvinen" , "Greg Kroah-Hartman" +Message-ID: <20230511123244.38514-2-ilpo.jarvinen@linux.intel.com> + +From: "Ilpo Järvinen" + +There's a potential race before THRE/TEMT deasserts when DMA Tx is +starting up (or the next batch of continuous Tx is being submitted). +This can lead to misdetecting Tx empty condition. + +It is entirely normal for THRE/TEMT to be set for some time after the +DMA Tx had been setup in serial8250_tx_dma(). As Tx side is definitely +not empty at that point, it seems incorrect for serial8250_tx_empty() +claim Tx is empty. + +Fix the race by also checking in serial8250_tx_empty() whether there's +DMA Tx active. + +Note: This fix only addresses in-kernel race mainly to make using +TCSADRAIN/FLUSH robust. Userspace can still cause other races but they +seem userspace concurrency control problems. + +Fixes: 9ee4b83e51f74 ("serial: 8250: Add support for dmaengine") +Cc: stable@vger.kernel.org +Signed-off-by: Ilpo Järvinen +Link: https://lore.kernel.org/r/20230317113318.31327-3-ilpo.jarvinen@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +(cherry picked from commit 146a37e05d620cef4ad430e5d1c9c077fe6fa76f) +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/8250/8250.h | 12 ++++++++++++ + drivers/tty/serial/8250/8250_port.c | 12 +++++++++--- + 2 files changed, 21 insertions(+), 3 deletions(-) + +--- a/drivers/tty/serial/8250/8250.h ++++ b/drivers/tty/serial/8250/8250.h +@@ -305,6 +305,13 @@ extern int serial8250_rx_dma(struct uart + extern void serial8250_rx_dma_flush(struct uart_8250_port *); + extern int serial8250_request_dma(struct uart_8250_port *); + extern void serial8250_release_dma(struct uart_8250_port *); ++ ++static inline bool serial8250_tx_dma_running(struct uart_8250_port *p) ++{ ++ struct uart_8250_dma *dma = p->dma; ++ ++ return dma && dma->tx_running; ++} + #else + static inline int serial8250_tx_dma(struct uart_8250_port *p) + { +@@ -320,6 +327,11 @@ static inline int serial8250_request_dma + return -1; + } + static inline void serial8250_release_dma(struct uart_8250_port *p) { } ++ ++static inline bool serial8250_tx_dma_running(struct uart_8250_port *p) ++{ ++ return false; ++} + #endif + + static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) +--- a/drivers/tty/serial/8250/8250_port.c ++++ b/drivers/tty/serial/8250/8250_port.c +@@ -1922,19 +1922,25 @@ static int serial8250_tx_threshold_handl + static unsigned int serial8250_tx_empty(struct uart_port *port) + { + struct uart_8250_port *up = up_to_u8250p(port); ++ unsigned int result = 0; + unsigned long flags; + unsigned int lsr; + + serial8250_rpm_get(up); + + spin_lock_irqsave(&port->lock, flags); +- lsr = serial_port_in(port, UART_LSR); +- up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; ++ if (!serial8250_tx_dma_running(up)) { ++ lsr = serial_port_in(port, UART_LSR); ++ up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; ++ ++ if ((lsr & BOTH_EMPTY) == BOTH_EMPTY) ++ result = TIOCSER_TEMT; ++ } + spin_unlock_irqrestore(&port->lock, flags); + + serial8250_rpm_put(up); + +- return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; ++ return result; + } + + unsigned int serial8250_do_get_mctrl(struct uart_port *port) diff --git a/queue-5.4/series b/queue-5.4/series index a72337bc69d..d3cda07113e 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -266,3 +266,8 @@ ext4-add-bounds-checking-in-get_max_inline_xattr_value_size.patch ext4-bail-out-of-ext4_xattr_ibody_get-fails-for-any-reason.patch ext4-remove-a-bug_on-in-ext4_mb_release_group_pa.patch ext4-fix-invalid-free-tracking-in-ext4_xattr_move_to_block.patch +tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch +serial-8250-fix-serial8250_tx_empty-race-with-dma-tx.patch +drbd-correctly-submit-flush-bio-on-barrier.patch +pci-pciehp-use-down_read-write_nested-reset_lock-to-fix-lockdep-errors.patch +pci-pciehp-fix-ab-ba-deadlock-between-reset_lock-and-device_lock.patch diff --git a/queue-5.4/tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch b/queue-5.4/tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch new file mode 100644 index 00000000000..3b37956c7c3 --- /dev/null +++ b/queue-5.4/tty-prevent-writing-chars-during-tcsetattr-tcsadrain-flush.patch @@ -0,0 +1,127 @@ +From stable-owner@vger.kernel.org Thu May 11 14:33:03 2023 +From: "Ilpo Järvinen" +Date: Thu, 11 May 2023 15:32:43 +0300 +Subject: tty: Prevent writing chars during tcsetattr TCSADRAIN/FLUSH +To: stable@vger.kernel.org +Cc: "Ilpo Järvinen" , "Greg Kroah-Hartman" +Message-ID: <20230511123244.38514-1-ilpo.jarvinen@linux.intel.com> + +From: "Ilpo Järvinen" + +If userspace races tcsetattr() with a write, the drained condition +might not be guaranteed by the kernel. There is a race window after +checking Tx is empty before tty_set_termios() takes termios_rwsem for +write. During that race window, more characters can be queued by a +racing writer. + +Any ongoing transmission might produce garbage during HW's +->set_termios() call. The intent of TCSADRAIN/FLUSH seems to be +preventing such a character corruption. If those flags are set, take +tty's write lock to stop any writer before performing the lower layer +Tx empty check and wait for the pending characters to be sent (if any). + +The initial wait for all-writers-done must be placed outside of tty's +write lock to avoid deadlock which makes it impossible to use +tty_wait_until_sent(). The write lock is retried if a racing write is +detected. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Cc: stable@vger.kernel.org +Signed-off-by: Ilpo Järvinen +Link: https://lore.kernel.org/r/20230317113318.31327-2-ilpo.jarvinen@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +(cherry picked from commit 094fb49a2d0d6827c86d2e0840873e6db0c491d2) +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/tty_io.c | 4 ++-- + drivers/tty/tty_ioctl.c | 45 +++++++++++++++++++++++++++++++++------------ + include/linux/tty.h | 2 ++ + 3 files changed, 37 insertions(+), 14 deletions(-) + +--- a/drivers/tty/tty_io.c ++++ b/drivers/tty/tty_io.c +@@ -876,13 +876,13 @@ static ssize_t tty_read(struct file *fil + return i; + } + +-static void tty_write_unlock(struct tty_struct *tty) ++void tty_write_unlock(struct tty_struct *tty) + { + mutex_unlock(&tty->atomic_write_lock); + wake_up_interruptible_poll(&tty->write_wait, EPOLLOUT); + } + +-static int tty_write_lock(struct tty_struct *tty, int ndelay) ++int tty_write_lock(struct tty_struct *tty, int ndelay) + { + if (!mutex_trylock(&tty->atomic_write_lock)) { + if (ndelay) +--- a/drivers/tty/tty_ioctl.c ++++ b/drivers/tty/tty_ioctl.c +@@ -397,21 +397,42 @@ static int set_termios(struct tty_struct + tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); + tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); + +- ld = tty_ldisc_ref(tty); ++ if (opt & (TERMIOS_FLUSH|TERMIOS_WAIT)) { ++retry_write_wait: ++ retval = wait_event_interruptible(tty->write_wait, !tty_chars_in_buffer(tty)); ++ if (retval < 0) ++ return retval; + +- if (ld != NULL) { +- if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) +- ld->ops->flush_buffer(tty); +- tty_ldisc_deref(ld); +- } ++ if (tty_write_lock(tty, 0) < 0) ++ goto retry_write_wait; + +- if (opt & TERMIOS_WAIT) { +- tty_wait_until_sent(tty, 0); +- if (signal_pending(current)) +- return -ERESTARTSYS; +- } ++ /* Racing writer? */ ++ if (tty_chars_in_buffer(tty)) { ++ tty_write_unlock(tty); ++ goto retry_write_wait; ++ } ++ ++ ld = tty_ldisc_ref(tty); ++ if (ld != NULL) { ++ if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) ++ ld->ops->flush_buffer(tty); ++ tty_ldisc_deref(ld); ++ } + +- tty_set_termios(tty, &tmp_termios); ++ if ((opt & TERMIOS_WAIT) && tty->ops->wait_until_sent) { ++ tty->ops->wait_until_sent(tty, 0); ++ if (signal_pending(current)) { ++ tty_write_unlock(tty); ++ return -ERESTARTSYS; ++ } ++ } ++ ++ tty_set_termios(tty, &tmp_termios); ++ ++ tty_write_unlock(tty); ++ } else { ++ tty_set_termios(tty, &tmp_termios); ++ } + + /* FIXME: Arguably if tmp_termios == tty->termios AND the + actual requested termios was not tmp_termios then we may +--- a/include/linux/tty.h ++++ b/include/linux/tty.h +@@ -480,6 +480,8 @@ extern void __stop_tty(struct tty_struct + extern void stop_tty(struct tty_struct *tty); + extern void __start_tty(struct tty_struct *tty); + extern void start_tty(struct tty_struct *tty); ++void tty_write_unlock(struct tty_struct *tty); ++int tty_write_lock(struct tty_struct *tty, int ndelay); + extern int tty_register_driver(struct tty_driver *driver); + extern int tty_unregister_driver(struct tty_driver *driver); + extern struct device *tty_register_device(struct tty_driver *driver,