summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2022-05-15 18:13:06 -0400
committerMike Pagano <mpagano@gentoo.org>2022-05-15 18:13:06 -0400
commitfb92d09eb8774cb7ac3bc6aadc65db19eeb408a7 (patch)
tree4ce065d1df445cc106b9768a03c7a3e36561258b
parentLinux patch 4.14.278 (diff)
downloadlinux-patches-fb92d09eb8774cb7ac3bc6aadc65db19eeb408a7.tar.gz
linux-patches-fb92d09eb8774cb7ac3bc6aadc65db19eeb408a7.tar.bz2
linux-patches-fb92d09eb8774cb7ac3bc6aadc65db19eeb408a7.zip
Linux patch 4.14.2794.14-290
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r--0000_README4
-rw-r--r--1278_linux-4.14.279.patch688
2 files changed, 692 insertions, 0 deletions
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;
+ }