From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 7B125158090 for ; Sun, 15 May 2022 22:13:26 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id B6772E08FC; Sun, 15 May 2022 22:13:25 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 882B5E08FC for ; Sun, 15 May 2022 22:13:25 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 7B3553418C2 for ; Sun, 15 May 2022 22:13:24 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 13E77DC for ; Sun, 15 May 2022 22:13:23 +0000 (UTC) From: "Mike Pagano" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Mike Pagano" Message-ID: <1652652786.fb92d09eb8774cb7ac3bc6aadc65db19eeb408a7.mpagano@gentoo> Subject: [gentoo-commits] proj/linux-patches:4.14 commit in: / X-VCS-Repository: proj/linux-patches X-VCS-Files: 0000_README 1278_linux-4.14.279.patch X-VCS-Directories: / X-VCS-Committer: mpagano X-VCS-Committer-Name: Mike Pagano X-VCS-Revision: fb92d09eb8774cb7ac3bc6aadc65db19eeb408a7 X-VCS-Branch: 4.14 Date: Sun, 15 May 2022 22:13:23 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 58118f25-310d-4ce1-884e-aefd1d64c1ec X-Archives-Hash: 702ba6b433309b19b80abaefaf011829 commit: fb92d09eb8774cb7ac3bc6aadc65db19eeb408a7 Author: Mike Pagano gentoo org> AuthorDate: Sun May 15 22:13:06 2022 +0000 Commit: Mike Pagano gentoo org> CommitDate: Sun May 15 22:13:06 2022 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=fb92d09e Linux patch 4.14.279 Signed-off-by: Mike Pagano gentoo.org> 0000_README | 4 + 1278_linux-4.14.279.patch | 688 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 692 insertions(+) diff --git a/0000_README b/0000_README index 108646a6..4b838702 100644 --- a/0000_README +++ b/0000_README @@ -1159,6 +1159,10 @@ Patch: 1277_linux-4.14.278.patch From: https://www.kernel.org Desc: Linux 4.14.278 +Patch: 1278_linux-4.14.279.patch +From: https://www.kernel.org +Desc: Linux 4.14.279 + Patch: 1500_XATTR_USER_PREFIX.patch From: https://bugs.gentoo.org/show_bug.cgi?id=470644 Desc: Support for namespace user.pax.* on tmpfs. diff --git a/1278_linux-4.14.279.patch b/1278_linux-4.14.279.patch new file mode 100644 index 00000000..d958840e --- /dev/null +++ b/1278_linux-4.14.279.patch @@ -0,0 +1,688 @@ +diff --git a/Makefile b/Makefile +index 9e6373f02d6c5..efe93f82073af 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 4 + PATCHLEVEL = 14 +-SUBLEVEL = 278 ++SUBLEVEL = 279 + EXTRAVERSION = + NAME = Petit Gorille + +diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c +index 3b6f687f177cd..32f8c501f6cb1 100644 +--- a/arch/mips/bmips/setup.c ++++ b/arch/mips/bmips/setup.c +@@ -174,7 +174,7 @@ void __init plat_mem_setup(void) + dtb = phys_to_virt(fw_arg2); + else if (fw_passed_dtb) /* UHI interface */ + dtb = (void *)fw_passed_dtb; +- else if (__dtb_start != __dtb_end) ++ else if (&__dtb_start != &__dtb_end) + dtb = (void *)__dtb_start; + else + panic("no dtb found"); +diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c +index 9ff7ccde9de0e..a26322ff57e01 100644 +--- a/arch/mips/lantiq/prom.c ++++ b/arch/mips/lantiq/prom.c +@@ -82,7 +82,7 @@ void __init plat_mem_setup(void) + + if (fw_passed_dtb) /* UHI interface */ + dtb = (void *)fw_passed_dtb; +- else if (__dtb_start != __dtb_end) ++ else if (&__dtb_start != &__dtb_end) + dtb = (void *)__dtb_start; + else + panic("no dtb found"); +diff --git a/arch/mips/pic32/pic32mzda/init.c b/arch/mips/pic32/pic32mzda/init.c +index 51599710472bc..406c6c5cec29b 100644 +--- a/arch/mips/pic32/pic32mzda/init.c ++++ b/arch/mips/pic32/pic32mzda/init.c +@@ -36,7 +36,7 @@ static ulong get_fdtaddr(void) + if (fw_passed_dtb && !fw_arg2 && !fw_arg3) + return (ulong)fw_passed_dtb; + +- if (__dtb_start < __dtb_end) ++ if (&__dtb_start < &__dtb_end) + ftaddr = (ulong)__dtb_start; + + return ftaddr; +diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c +index 92b3d48499967..1f7c686f7218a 100644 +--- a/arch/mips/ralink/of.c ++++ b/arch/mips/ralink/of.c +@@ -79,7 +79,7 @@ void __init plat_mem_setup(void) + */ + if (fw_passed_dtb) + dtb = (void *)fw_passed_dtb; +- else if (__dtb_start != __dtb_end) ++ else if (&__dtb_start != &__dtb_end) + dtb = (void *)__dtb_start; + + __dt_setup_arch(dtb); +diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c +index 5543876ec0e25..bfefa8c4fa166 100644 +--- a/drivers/block/drbd/drbd_nl.c ++++ b/drivers/block/drbd/drbd_nl.c +@@ -774,9 +774,11 @@ int drbd_adm_set_role(struct sk_buff *skb, struct genl_info *info) + mutex_lock(&adm_ctx.resource->adm_mutex); + + if (info->genlhdr->cmd == DRBD_ADM_PRIMARY) +- retcode = drbd_set_role(adm_ctx.device, R_PRIMARY, parms.assume_uptodate); ++ retcode = (enum drbd_ret_code)drbd_set_role(adm_ctx.device, ++ R_PRIMARY, parms.assume_uptodate); + else +- retcode = drbd_set_role(adm_ctx.device, R_SECONDARY, 0); ++ retcode = (enum drbd_ret_code)drbd_set_role(adm_ctx.device, ++ R_SECONDARY, 0); + + mutex_unlock(&adm_ctx.resource->adm_mutex); + genl_lock(); +@@ -1941,7 +1943,7 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) + drbd_flush_workqueue(&connection->sender_work); + + rv = _drbd_request_state(device, NS(disk, D_ATTACHING), CS_VERBOSE); +- retcode = rv; /* FIXME: Type mismatch. */ ++ retcode = (enum drbd_ret_code)rv; + drbd_resume_io(device); + if (rv < SS_SUCCESS) + goto fail; +@@ -2671,7 +2673,8 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info) + } + rcu_read_unlock(); + +- retcode = conn_request_state(connection, NS(conn, C_UNCONNECTED), CS_VERBOSE); ++ retcode = (enum drbd_ret_code)conn_request_state(connection, ++ NS(conn, C_UNCONNECTED), CS_VERBOSE); + + conn_reconfig_done(connection); + mutex_unlock(&adm_ctx.resource->adm_mutex); +@@ -2777,7 +2780,7 @@ int drbd_adm_disconnect(struct sk_buff *skb, struct genl_info *info) + mutex_lock(&adm_ctx.resource->adm_mutex); + rv = conn_try_disconnect(connection, parms.force_disconnect); + if (rv < SS_SUCCESS) +- retcode = rv; /* FIXME: Type mismatch. */ ++ retcode = (enum drbd_ret_code)rv; + else + retcode = NO_ERROR; + mutex_unlock(&adm_ctx.resource->adm_mutex); +diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c +index 9de6a32f0c9fc..0b1d4f2b58624 100644 +--- a/drivers/mmc/host/rtsx_pci_sdmmc.c ++++ b/drivers/mmc/host/rtsx_pci_sdmmc.c +@@ -49,10 +49,7 @@ struct realtek_pci_sdmmc { + bool double_clk; + bool eject; + bool initial_mode; +- int power_state; +-#define SDMMC_POWER_ON 1 +-#define SDMMC_POWER_OFF 0 +- ++ int prev_power_state; + int sg_count; + s32 cookie; + int cookie_sg_count; +@@ -913,14 +910,21 @@ static int sd_set_bus_width(struct realtek_pci_sdmmc *host, + return err; + } + +-static int sd_power_on(struct realtek_pci_sdmmc *host) ++static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode) + { + struct rtsx_pcr *pcr = host->pcr; + int err; + +- if (host->power_state == SDMMC_POWER_ON) ++ if (host->prev_power_state == MMC_POWER_ON) + return 0; + ++ if (host->prev_power_state == MMC_POWER_UP) { ++ rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, 0); ++ goto finish; ++ } ++ ++ msleep(100); ++ + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, +@@ -939,11 +943,17 @@ static int sd_power_on(struct realtek_pci_sdmmc *host) + if (err < 0) + return err; + ++ mdelay(1); ++ + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) + return err; + +- host->power_state = SDMMC_POWER_ON; ++ /* send at least 74 clocks */ ++ rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, SD_CLK_TOGGLE_EN); ++ ++finish: ++ host->prev_power_state = power_mode; + return 0; + } + +@@ -952,7 +962,7 @@ static int sd_power_off(struct realtek_pci_sdmmc *host) + struct rtsx_pcr *pcr = host->pcr; + int err; + +- host->power_state = SDMMC_POWER_OFF; ++ host->prev_power_state = MMC_POWER_OFF; + + rtsx_pci_init_cmd(pcr); + +@@ -978,7 +988,7 @@ static int sd_set_power_mode(struct realtek_pci_sdmmc *host, + if (power_mode == MMC_POWER_OFF) + err = sd_power_off(host); + else +- err = sd_power_on(host); ++ err = sd_power_on(host, power_mode); + + return err; + } +@@ -1416,7 +1426,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) + host->mmc = mmc; + host->pdev = pdev; + host->cookie = -1; +- host->power_state = SDMMC_POWER_OFF; ++ host->prev_power_state = MMC_POWER_OFF; + INIT_WORK(&host->work, sd_request); + platform_set_drvdata(pdev, host); + pcr->slots[RTSX_SD_CARD].p_dev = pdev; +diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c +index 05a59b9946cbe..4eb196d7f4a63 100644 +--- a/drivers/net/can/grcan.c ++++ b/drivers/net/can/grcan.c +@@ -245,7 +245,7 @@ struct grcan_device_config { + .rxsize = GRCAN_DEFAULT_BUFFER_SIZE, \ + } + +-#define GRCAN_TXBUG_SAFE_GRLIB_VERSION 0x4100 ++#define GRCAN_TXBUG_SAFE_GRLIB_VERSION 4100 + #define GRLIB_VERSION_MASK 0xffff + + /* GRCAN private data structure */ +@@ -1141,7 +1141,7 @@ static int grcan_close(struct net_device *dev) + return 0; + } + +-static int grcan_transmit_catch_up(struct net_device *dev, int budget) ++static void grcan_transmit_catch_up(struct net_device *dev) + { + struct grcan_priv *priv = netdev_priv(dev); + unsigned long flags; +@@ -1149,7 +1149,7 @@ static int grcan_transmit_catch_up(struct net_device *dev, int budget) + + spin_lock_irqsave(&priv->lock, flags); + +- work_done = catch_up_echo_skb(dev, budget, true); ++ work_done = catch_up_echo_skb(dev, -1, true); + if (work_done) { + if (!priv->resetting && !priv->closing && + !(priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)) +@@ -1163,8 +1163,6 @@ static int grcan_transmit_catch_up(struct net_device *dev, int budget) + } + + spin_unlock_irqrestore(&priv->lock, flags); +- +- return work_done; + } + + static int grcan_receive(struct net_device *dev, int budget) +@@ -1246,19 +1244,13 @@ static int grcan_poll(struct napi_struct *napi, int budget) + struct net_device *dev = priv->dev; + struct grcan_registers __iomem *regs = priv->regs; + unsigned long flags; +- int tx_work_done, rx_work_done; +- int rx_budget = budget / 2; +- int tx_budget = budget - rx_budget; ++ int work_done; + +- /* Half of the budget for receiveing messages */ +- rx_work_done = grcan_receive(dev, rx_budget); ++ work_done = grcan_receive(dev, budget); + +- /* Half of the budget for transmitting messages as that can trigger echo +- * frames being received +- */ +- tx_work_done = grcan_transmit_catch_up(dev, tx_budget); ++ grcan_transmit_catch_up(dev); + +- if (rx_work_done < rx_budget && tx_work_done < tx_budget) { ++ if (work_done < budget) { + napi_complete(napi); + + /* Guarantee no interference with a running reset that otherwise +@@ -1275,7 +1267,7 @@ static int grcan_poll(struct napi_struct *napi, int budget) + spin_unlock_irqrestore(&priv->lock, flags); + } + +- return rx_work_done + tx_work_done; ++ return work_done; + } + + /* Work tx bug by waiting while for the risky situation to clear. If that fails, +@@ -1665,6 +1657,7 @@ exit_free_candev: + static int grcan_probe(struct platform_device *ofdev) + { + struct device_node *np = ofdev->dev.of_node; ++ struct device_node *sysid_parent; + struct resource *res; + u32 sysid, ambafreq; + int irq, err; +@@ -1674,10 +1667,15 @@ static int grcan_probe(struct platform_device *ofdev) + /* Compare GRLIB version number with the first that does not + * have the tx bug (see start_xmit) + */ +- err = of_property_read_u32(np, "systemid", &sysid); +- if (!err && ((sysid & GRLIB_VERSION_MASK) +- >= GRCAN_TXBUG_SAFE_GRLIB_VERSION)) +- txbug = false; ++ sysid_parent = of_find_node_by_path("/ambapp0"); ++ if (sysid_parent) { ++ of_node_get(sysid_parent); ++ err = of_property_read_u32(sysid_parent, "systemid", &sysid); ++ if (!err && ((sysid & GRLIB_VERSION_MASK) >= ++ GRCAN_TXBUG_SAFE_GRLIB_VERSION)) ++ txbug = false; ++ of_node_put(sysid_parent); ++ } + + err = of_property_read_u32(np, "freq", &ambafreq); + if (err) { +diff --git a/fs/namespace.c b/fs/namespace.c +index 683668a20bed7..a0c549f2721ca 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -2570,9 +2570,12 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags, + return -ENODEV; + + mnt = vfs_kern_mount(type, sb_flags, name, data); +- if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && +- !mnt->mnt_sb->s_subtype) +- mnt = fs_set_subtype(mnt, fstype); ++ if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE)) { ++ down_write(&mnt->mnt_sb->s_umount); ++ if (!mnt->mnt_sb->s_subtype) ++ mnt = fs_set_subtype(mnt, fstype); ++ up_write(&mnt->mnt_sb->s_umount); ++ } + + put_filesystem(type); + if (IS_ERR(mnt)) +diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h +index 51afaaa684087..d42288a06af61 100644 +--- a/include/net/bluetooth/hci_core.h ++++ b/include/net/bluetooth/hci_core.h +@@ -34,6 +34,9 @@ + /* HCI priority */ + #define HCI_PRIO_MAX 7 + ++/* HCI maximum id value */ ++#define HCI_MAX_ID 10000 ++ + /* HCI Core structures */ + struct inquiry_data { + bdaddr_t bdaddr; +diff --git a/include/sound/pcm.h b/include/sound/pcm.h +index 24febf9e177c4..0a4770cc3691c 100644 +--- a/include/sound/pcm.h ++++ b/include/sound/pcm.h +@@ -396,6 +396,8 @@ struct snd_pcm_runtime { + wait_queue_head_t sleep; /* poll sleep */ + wait_queue_head_t tsleep; /* transfer sleep */ + struct fasync_struct *fasync; ++ struct mutex buffer_mutex; /* protect for buffer changes */ ++ atomic_t buffer_accessing; /* >0: in r/w operation, <0: blocked */ + + /* -- private section -- */ + void *private_data; +diff --git a/mm/memory.c b/mm/memory.c +index cec495ecffaed..4154fb45ac0f7 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -4836,6 +4836,8 @@ long copy_huge_page_from_user(struct page *dst_page, + if (rc) + break; + ++ flush_dcache_page(subpage); ++ + cond_resched(); + } + return ret_val; +diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c +index ee8a688630891..3f08453e703d7 100644 +--- a/mm/userfaultfd.c ++++ b/mm/userfaultfd.c +@@ -56,6 +56,8 @@ static int mcopy_atomic_pte(struct mm_struct *dst_mm, + /* don't free the page */ + goto out; + } ++ ++ flush_dcache_page(page); + } else { + page = *pagep; + *pagep = NULL; +@@ -565,6 +567,7 @@ retry: + err = -EFAULT; + goto out; + } ++ flush_dcache_page(page); + goto retry; + } else + BUG_ON(page); +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index 687b4d0e4c673..a6f186a04fe70 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -3100,10 +3100,10 @@ int hci_register_dev(struct hci_dev *hdev) + */ + switch (hdev->dev_type) { + case HCI_PRIMARY: +- id = ida_simple_get(&hci_index_ida, 0, 0, GFP_KERNEL); ++ id = ida_simple_get(&hci_index_ida, 0, HCI_MAX_ID, GFP_KERNEL); + break; + case HCI_AMP: +- id = ida_simple_get(&hci_index_ida, 1, 0, GFP_KERNEL); ++ id = ida_simple_get(&hci_index_ida, 1, HCI_MAX_ID, GFP_KERNEL); + break; + default: + return -EINVAL; +@@ -3112,7 +3112,7 @@ int hci_register_dev(struct hci_dev *hdev) + if (id < 0) + return id; + +- sprintf(hdev->name, "hci%d", id); ++ snprintf(hdev->name, sizeof(hdev->name), "hci%d", id); + hdev->id = id; + + BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); +diff --git a/sound/core/pcm.c b/sound/core/pcm.c +index a228bf9331102..de48803f2be2a 100644 +--- a/sound/core/pcm.c ++++ b/sound/core/pcm.c +@@ -1032,6 +1032,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, + init_waitqueue_head(&runtime->tsleep); + + runtime->status->state = SNDRV_PCM_STATE_OPEN; ++ mutex_init(&runtime->buffer_mutex); ++ atomic_set(&runtime->buffer_accessing, 0); + + substream->runtime = runtime; + substream->private_data = pcm->private_data; +@@ -1063,6 +1065,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) + substream->runtime = NULL; + if (substream->timer) + spin_unlock_irq(&substream->timer->lock); ++ mutex_destroy(&runtime->buffer_mutex); + kfree(runtime); + put_pid(substream->pid); + substream->pid = NULL; +diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c +index 82a7387ba9d24..82d4b72dcb64a 100644 +--- a/sound/core/pcm_lib.c ++++ b/sound/core/pcm_lib.c +@@ -2226,10 +2226,15 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, + snd_pcm_stream_unlock_irq(substream); + return -EINVAL; + } ++ if (!atomic_inc_unless_negative(&runtime->buffer_accessing)) { ++ err = -EBUSY; ++ goto _end_unlock; ++ } + snd_pcm_stream_unlock_irq(substream); + err = writer(substream, appl_ofs, data, offset, frames, + transfer); + snd_pcm_stream_lock_irq(substream); ++ atomic_dec(&runtime->buffer_accessing); + if (err < 0) + goto _end_unlock; + err = pcm_accessible_state(runtime); +diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c +index ae33e456708c2..adc5f3c2379ba 100644 +--- a/sound/core/pcm_memory.c ++++ b/sound/core/pcm_memory.c +@@ -160,19 +160,20 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, + size_t size; + struct snd_dma_buffer new_dmab; + ++ mutex_lock(&substream->pcm->open_mutex); + if (substream->runtime) { + buffer->error = -EBUSY; +- return; ++ goto unlock; + } + if (!snd_info_get_line(buffer, line, sizeof(line))) { + snd_info_get_str(str, line, sizeof(str)); + size = simple_strtoul(str, NULL, 10) * 1024; + if ((size != 0 && size < 8192) || size > substream->dma_max) { + buffer->error = -EINVAL; +- return; ++ goto unlock; + } + if (substream->dma_buffer.bytes == size) +- return; ++ goto unlock; + memset(&new_dmab, 0, sizeof(new_dmab)); + new_dmab.dev = substream->dma_buffer.dev; + if (size > 0) { +@@ -180,7 +181,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, + substream->dma_buffer.dev.dev, + size, &new_dmab) < 0) { + buffer->error = -ENOMEM; +- return; ++ goto unlock; + } + substream->buffer_bytes_max = size; + } else { +@@ -192,6 +193,8 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, + } else { + buffer->error = -EINVAL; + } ++ unlock: ++ mutex_unlock(&substream->pcm->open_mutex); + } + + static inline void preallocate_info_init(struct snd_pcm_substream *substream) +diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c +index c530d008fe01d..c57d82402220d 100644 +--- a/sound/core/pcm_native.c ++++ b/sound/core/pcm_native.c +@@ -634,6 +634,30 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, + return 0; + } + ++/* acquire buffer_mutex; if it's in r/w operation, return -EBUSY, otherwise ++ * block the further r/w operations ++ */ ++static int snd_pcm_buffer_access_lock(struct snd_pcm_runtime *runtime) ++{ ++ if (!atomic_dec_unless_positive(&runtime->buffer_accessing)) ++ return -EBUSY; ++ mutex_lock(&runtime->buffer_mutex); ++ return 0; /* keep buffer_mutex, unlocked by below */ ++} ++ ++/* release buffer_mutex and clear r/w access flag */ ++static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) ++{ ++ mutex_unlock(&runtime->buffer_mutex); ++ atomic_inc(&runtime->buffer_accessing); ++} ++ ++#if IS_ENABLED(CONFIG_SND_PCM_OSS) ++#define is_oss_stream(substream) ((substream)->oss.oss) ++#else ++#define is_oss_stream(substream) false ++#endif ++ + static int snd_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) + { +@@ -645,22 +669,25 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; + runtime = substream->runtime; ++ err = snd_pcm_buffer_access_lock(runtime); ++ if (err < 0) ++ return err; + snd_pcm_stream_lock_irq(substream); + switch (runtime->status->state) { + case SNDRV_PCM_STATE_OPEN: + case SNDRV_PCM_STATE_SETUP: + case SNDRV_PCM_STATE_PREPARED: ++ if (!is_oss_stream(substream) && ++ atomic_read(&substream->mmap_count)) ++ err = -EBADFD; + break; + default: +- snd_pcm_stream_unlock_irq(substream); +- return -EBADFD; ++ err = -EBADFD; ++ break; + } + snd_pcm_stream_unlock_irq(substream); +-#if IS_ENABLED(CONFIG_SND_PCM_OSS) +- if (!substream->oss.oss) +-#endif +- if (atomic_read(&substream->mmap_count)) +- return -EBADFD; ++ if (err) ++ goto unlock; + + params->rmask = ~0U; + err = snd_pcm_hw_refine(substream, params); +@@ -737,14 +764,19 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, + if ((usecs = period_to_usecs(runtime)) >= 0) + pm_qos_add_request(&substream->latency_pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, usecs); +- return 0; ++ err = 0; + _error: +- /* hardware might be unusable from this time, +- so we force application to retry to set +- the correct hardware parameter settings */ +- snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); +- if (substream->ops->hw_free != NULL) +- substream->ops->hw_free(substream); ++ if (err) { ++ /* hardware might be unusable from this time, ++ * so we force application to retry to set ++ * the correct hardware parameter settings ++ */ ++ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); ++ if (substream->ops->hw_free != NULL) ++ substream->ops->hw_free(substream); ++ } ++ unlock: ++ snd_pcm_buffer_access_unlock(runtime); + return err; + } + +@@ -777,22 +809,29 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; + runtime = substream->runtime; ++ result = snd_pcm_buffer_access_lock(runtime); ++ if (result < 0) ++ return result; + snd_pcm_stream_lock_irq(substream); + switch (runtime->status->state) { + case SNDRV_PCM_STATE_SETUP: + case SNDRV_PCM_STATE_PREPARED: ++ if (atomic_read(&substream->mmap_count)) ++ result = -EBADFD; + break; + default: +- snd_pcm_stream_unlock_irq(substream); +- return -EBADFD; ++ result = -EBADFD; ++ break; + } + snd_pcm_stream_unlock_irq(substream); +- if (atomic_read(&substream->mmap_count)) +- return -EBADFD; ++ if (result) ++ goto unlock; + if (substream->ops->hw_free) + result = substream->ops->hw_free(substream); + snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); + pm_qos_remove_request(&substream->latency_pm_qos_req); ++ unlock: ++ snd_pcm_buffer_access_unlock(runtime); + return result; + } + +@@ -1029,15 +1068,17 @@ struct action_ops { + */ + static int snd_pcm_action_group(const struct action_ops *ops, + struct snd_pcm_substream *substream, +- int state, int do_lock) ++ int state, int stream_lock) + { + struct snd_pcm_substream *s = NULL; + struct snd_pcm_substream *s1; + int res = 0, depth = 1; + + snd_pcm_group_for_each_entry(s, substream) { +- if (do_lock && s != substream) { +- if (s->pcm->nonatomic) ++ if (s != substream) { ++ if (!stream_lock) ++ mutex_lock_nested(&s->runtime->buffer_mutex, depth); ++ else if (s->pcm->nonatomic) + mutex_lock_nested(&s->self_group.mutex, depth); + else + spin_lock_nested(&s->self_group.lock, depth); +@@ -1065,18 +1106,18 @@ static int snd_pcm_action_group(const struct action_ops *ops, + ops->post_action(s, state); + } + _unlock: +- if (do_lock) { +- /* unlock streams */ +- snd_pcm_group_for_each_entry(s1, substream) { +- if (s1 != substream) { +- if (s1->pcm->nonatomic) +- mutex_unlock(&s1->self_group.mutex); +- else +- spin_unlock(&s1->self_group.lock); +- } +- if (s1 == s) /* end */ +- break; ++ /* unlock streams */ ++ snd_pcm_group_for_each_entry(s1, substream) { ++ if (s1 != substream) { ++ if (!stream_lock) ++ mutex_unlock(&s1->runtime->buffer_mutex); ++ else if (s1->pcm->nonatomic) ++ mutex_unlock(&s1->self_group.mutex); ++ else ++ spin_unlock(&s1->self_group.lock); + } ++ if (s1 == s) /* end */ ++ break; + } + return res; + } +@@ -1157,10 +1198,15 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops, + int res; + + down_read(&snd_pcm_link_rwsem); ++ res = snd_pcm_buffer_access_lock(substream->runtime); ++ if (res < 0) ++ goto unlock; + if (snd_pcm_stream_linked(substream)) + res = snd_pcm_action_group(ops, substream, state, 0); + else + res = snd_pcm_action_single(ops, substream, state); ++ snd_pcm_buffer_access_unlock(substream->runtime); ++ unlock: + up_read(&snd_pcm_link_rwsem); + return res; + }