]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 4.19
authorSasha Levin <sashal@kernel.org>
Tue, 10 Jan 2023 01:55:38 +0000 (20:55 -0500)
committerSasha Levin <sashal@kernel.org>
Tue, 10 Jan 2023 01:55:38 +0000 (20:55 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
31 files changed:
queue-4.19/asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch [new file with mode: 0644]
queue-4.19/bpf-pull-before-calling-skb_postpull_rcsum.patch [new file with mode: 0644]
queue-4.19/caif-fix-memory-leak-in-cfctrl_linkup_request.patch [new file with mode: 0644]
queue-4.19/dm-thin-resume-even-if-in-fail-mode.patch [new file with mode: 0644]
queue-4.19/driver-core-set-deferred_probe_timeout-to-a-longer-d.patch [new file with mode: 0644]
queue-4.19/ext4-correct-inconsistent-error-msg-in-nojournal-mod.patch [new file with mode: 0644]
queue-4.19/ext4-fix-deadlock-due-to-mbcache-entry-corruption.patch [new file with mode: 0644]
queue-4.19/ext4-fix-race-when-reusing-xattr-blocks.patch [new file with mode: 0644]
queue-4.19/ext4-goto-right-label-failed_mount3a.patch [new file with mode: 0644]
queue-4.19/ext4-remove-ea-inode-entry-from-mbcache-on-inode-evi.patch [new file with mode: 0644]
queue-4.19/ext4-unindent-codeblock-in-ext4_xattr_block_set.patch [new file with mode: 0644]
queue-4.19/ext4-use-kmemdup-to-replace-kmalloc-memcpy.patch [new file with mode: 0644]
queue-4.19/mbcache-add-functions-to-delete-entry-if-unused.patch [new file with mode: 0644]
queue-4.19/mbcache-automatically-delete-entries-from-cache-on-f.patch [new file with mode: 0644]
queue-4.19/mbcache-don-t-reclaim-used-entries.patch [new file with mode: 0644]
queue-4.19/net-amd-xgbe-add-missed-tasklet_kill.patch [new file with mode: 0644]
queue-4.19/net-phy-xgmiitorgmii-fix-refcount-leak-in-xgmiitorgm.patch [new file with mode: 0644]
queue-4.19/net-sched-atm-dont-intepret-cls-results-when-asked-t.patch [new file with mode: 0644]
queue-4.19/nfc-fix-potential-resource-leaks.patch [new file with mode: 0644]
queue-4.19/perf-probe-fix-to-get-the-dw_at_decl_file-and-dw_at_.patch [new file with mode: 0644]
queue-4.19/perf-probe-use-dwarf_attr_integrate-as-generic-dwarf.patch [new file with mode: 0644]
queue-4.19/qlcnic-prevent-dcb-use-after-free-on-qlcnic_dcb_enab.patch [new file with mode: 0644]
queue-4.19/ravb-fix-failed-to-switch-device-to-config-mode-mess.patch [new file with mode: 0644]
queue-4.19/rdma-mlx5-fix-validation-of-max_rd_atomic-caps-for-d.patch [new file with mode: 0644]
queue-4.19/riscv-remove-unreachable-have_function_graph_ret_add.patch [new file with mode: 0644]
queue-4.19/riscv-stacktrace-fix-stack-output-without-ra-on-the-.patch [new file with mode: 0644]
queue-4.19/riscv-stacktrace-fixup-ftrace_graph_ret_addr-retp-ar.patch [new file with mode: 0644]
queue-4.19/series
queue-4.19/sunrpc-ensure-the-matching-upcall-is-in-flight-upon-.patch [new file with mode: 0644]
queue-4.19/udf-fix-extension-of-the-last-extent-in-the-file.patch [new file with mode: 0644]
queue-4.19/usb-rndis_host-secure-rndis_query-check-against-int-.patch [new file with mode: 0644]

diff --git a/queue-4.19/asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch b/queue-4.19/asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch
new file mode 100644 (file)
index 0000000..dd731a6
--- /dev/null
@@ -0,0 +1,59 @@
+From 94551df8a1ed817d40347cd7c25d83d99f4d0efc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Dec 2022 13:32:46 +0100
+Subject: ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071
+ tablet
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit a1dec9d70b6ad97087b60b81d2492134a84208c6 ]
+
+The Advantech MICA-071 tablet deviates from the defaults for
+a non CR Bay Trail based tablet in several ways:
+
+1. It uses an analog MIC on IN3 rather then using DMIC1
+2. It only has 1 speaker
+3. It needs the OVCD current threshold to be set to 1500uA instead of
+   the default 2000uA to reliable differentiate between headphones vs
+   headsets
+
+Add a quirk with these settings for this tablet.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Link: https://lore.kernel.org/r/20221213123246.11226-1-hdegoede@redhat.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/intel/boards/bytcr_rt5640.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
+index c4d19b88d17d..2001bc774c64 100644
+--- a/sound/soc/intel/boards/bytcr_rt5640.c
++++ b/sound/soc/intel/boards/bytcr_rt5640.c
+@@ -437,6 +437,21 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+                                       BYT_RT5640_SSP0_AIF1 |
+                                       BYT_RT5640_MCLK_EN),
+       },
++      {
++              /* Advantech MICA-071 */
++              .matches = {
++                      DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Advantech"),
++                      DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MICA-071"),
++              },
++              /* OVCD Th = 1500uA to reliable detect head-phones vs -set */
++              .driver_data = (void *)(BYT_RT5640_IN3_MAP |
++                                      BYT_RT5640_JD_SRC_JD2_IN4N |
++                                      BYT_RT5640_OVCD_TH_1500UA |
++                                      BYT_RT5640_OVCD_SF_0P75 |
++                                      BYT_RT5640_MONO_SPEAKER |
++                                      BYT_RT5640_DIFF_MIC |
++                                      BYT_RT5640_MCLK_EN),
++      },
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"),
+-- 
+2.35.1
+
diff --git a/queue-4.19/bpf-pull-before-calling-skb_postpull_rcsum.patch b/queue-4.19/bpf-pull-before-calling-skb_postpull_rcsum.patch
new file mode 100644 (file)
index 0000000..67ea20e
--- /dev/null
@@ -0,0 +1,61 @@
+From bde099d959e905a194a292d3d53661c248e47529 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 19 Dec 2022 16:47:00 -0800
+Subject: bpf: pull before calling skb_postpull_rcsum()
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit 54c3f1a81421f85e60ae2eaae7be3727a09916ee ]
+
+Anand hit a BUG() when pulling off headers on egress to a SW tunnel.
+We get to skb_checksum_help() with an invalid checksum offset
+(commit d7ea0d9df2a6 ("net: remove two BUG() from skb_checksum_help()")
+converted those BUGs to WARN_ONs()).
+He points out oddness in how skb_postpull_rcsum() gets used.
+Indeed looks like we should pull before "postpull", otherwise
+the CHECKSUM_PARTIAL fixup from skb_postpull_rcsum() will not
+be able to do its job:
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL &&
+           skb_checksum_start_offset(skb) < 0)
+               skb->ip_summed = CHECKSUM_NONE;
+
+Reported-by: Anand Parthasarathy <anpartha@meta.com>
+Fixes: 6578171a7ff0 ("bpf: add bpf_skb_change_proto helper")
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Acked-by: Stanislav Fomichev <sdf@google.com>
+Link: https://lore.kernel.org/r/20221220004701.402165-1-kuba@kernel.org
+Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/filter.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/net/core/filter.c b/net/core/filter.c
+index aa2e7baa13c4..32d0b8f14aab 100644
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -2565,15 +2565,18 @@ static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len)
+ static int bpf_skb_generic_pop(struct sk_buff *skb, u32 off, u32 len)
+ {
++      void *old_data;
++
+       /* skb_ensure_writable() is not needed here, as we're
+        * already working on an uncloned skb.
+        */
+       if (unlikely(!pskb_may_pull(skb, off + len)))
+               return -ENOMEM;
+-      skb_postpull_rcsum(skb, skb->data + off, len);
+-      memmove(skb->data + len, skb->data, off);
++      old_data = skb->data;
+       __skb_pull(skb, len);
++      skb_postpull_rcsum(skb, old_data + off, len);
++      memmove(skb->data, old_data, off);
+       return 0;
+ }
+-- 
+2.35.1
+
diff --git a/queue-4.19/caif-fix-memory-leak-in-cfctrl_linkup_request.patch b/queue-4.19/caif-fix-memory-leak-in-cfctrl_linkup_request.patch
new file mode 100644 (file)
index 0000000..d667ae7
--- /dev/null
@@ -0,0 +1,47 @@
+From edf56f9914f237065c78cff9bb7a962059ebf56e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Jan 2023 14:51:46 +0800
+Subject: caif: fix memory leak in cfctrl_linkup_request()
+
+From: Zhengchao Shao <shaozhengchao@huawei.com>
+
+[ Upstream commit fe69230f05897b3de758427b574fc98025dfc907 ]
+
+When linktype is unknown or kzalloc failed in cfctrl_linkup_request(),
+pkt is not released. Add release process to error path.
+
+Fixes: b482cd2053e3 ("net-caif: add CAIF core protocol stack")
+Fixes: 8d545c8f958f ("caif: Disconnect without waiting for response")
+Signed-off-by: Zhengchao Shao <shaozhengchao@huawei.com>
+Reviewed-by: Jiri Pirko <jiri@nvidia.com>
+Link: https://lore.kernel.org/r/20230104065146.1153009-1-shaozhengchao@huawei.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/caif/cfctrl.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
+index a1e85f032108..330cb2b087bb 100644
+--- a/net/caif/cfctrl.c
++++ b/net/caif/cfctrl.c
+@@ -269,11 +269,15 @@ int cfctrl_linkup_request(struct cflayer *layer,
+       default:
+               pr_warn("Request setup of bad link type = %d\n",
+                       param->linktype);
++              cfpkt_destroy(pkt);
+               return -EINVAL;
+       }
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+-      if (!req)
++      if (!req) {
++              cfpkt_destroy(pkt);
+               return -ENOMEM;
++      }
++
+       req->client_layer = user_layer;
+       req->cmd = CFCTRL_CMD_LINK_SETUP;
+       req->param = *param;
+-- 
+2.35.1
+
diff --git a/queue-4.19/dm-thin-resume-even-if-in-fail-mode.patch b/queue-4.19/dm-thin-resume-even-if-in-fail-mode.patch
new file mode 100644 (file)
index 0000000..19045c8
--- /dev/null
@@ -0,0 +1,77 @@
+From a73aeed02ca2e67f6b7ed6662f664affd8fb3d82 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Nov 2022 10:09:45 +0800
+Subject: dm thin: resume even if in FAIL mode
+
+From: Luo Meng <luomeng12@huawei.com>
+
+[ Upstream commit 19eb1650afeb1aa86151f61900e9e5f1de5d8d02 ]
+
+If a thinpool set fail_io while suspending, resume will fail with:
+ device-mapper: resume ioctl on vg-thinpool  failed: Invalid argument
+
+The thin-pool also can't be removed if an in-flight bio is in the
+deferred list.
+
+This can be easily reproduced using:
+
+  echo "offline" > /sys/block/sda/device/state
+  dd if=/dev/zero of=/dev/mapper/thin bs=4K count=1
+  dmsetup suspend /dev/mapper/pool
+  mkfs.ext4 /dev/mapper/thin
+  dmsetup resume /dev/mapper/pool
+
+The root cause is maybe_resize_data_dev() will check fail_io and return
+error before called dm_resume.
+
+Fix this by adding FAIL mode check at the end of pool_preresume().
+
+Cc: stable@vger.kernel.org
+Fixes: da105ed5fd7e ("dm thin metadata: introduce dm_pool_abort_metadata")
+Signed-off-by: Luo Meng <luomeng12@huawei.com>
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/md/dm-thin.c | 16 ++++++++++++----
+ 1 file changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
+index 1916becc20e0..386cb3395378 100644
+--- a/drivers/md/dm-thin.c
++++ b/drivers/md/dm-thin.c
+@@ -3549,20 +3549,28 @@ static int pool_preresume(struct dm_target *ti)
+        */
+       r = bind_control_target(pool, ti);
+       if (r)
+-              return r;
++              goto out;
+       r = maybe_resize_data_dev(ti, &need_commit1);
+       if (r)
+-              return r;
++              goto out;
+       r = maybe_resize_metadata_dev(ti, &need_commit2);
+       if (r)
+-              return r;
++              goto out;
+       if (need_commit1 || need_commit2)
+               (void) commit(pool);
++out:
++      /*
++       * When a thin-pool is PM_FAIL, it cannot be rebuilt if
++       * bio is in deferred list. Therefore need to return 0
++       * to allow pool_resume() to flush IO.
++       */
++      if (r && get_pool_mode(pool) == PM_FAIL)
++              r = 0;
+-      return 0;
++      return r;
+ }
+ static void pool_suspend_active_thins(struct pool *pool)
+-- 
+2.35.1
+
diff --git a/queue-4.19/driver-core-set-deferred_probe_timeout-to-a-longer-d.patch b/queue-4.19/driver-core-set-deferred_probe_timeout-to-a-longer-d.patch
new file mode 100644 (file)
index 0000000..4b41cb0
--- /dev/null
@@ -0,0 +1,69 @@
+From b1a12d0dc447462f5e0cafa2c8fa8cc72939a5a6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2020 05:08:24 +0000
+Subject: driver core: Set deferred_probe_timeout to a longer default if
+ CONFIG_MODULES is set
+
+From: John Stultz <john.stultz@linaro.org>
+
+[ Upstream commit e2cec7d6853712295cef5377762165a489b2957f ]
+
+When using modules, its common for the modules not to be loaded
+until quite late by userland. With the current code,
+driver_deferred_probe_check_state() will stop returning
+EPROBE_DEFER after late_initcall, which can cause module
+dependency resolution to fail after that.
+
+So allow a longer window of 30 seconds (picked somewhat
+arbitrarily, but influenced by the similar regulator core
+timeout value) in the case where modules are enabled.
+
+Cc: linux-pm@vger.kernel.org
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Linus Walleij <linus.walleij@linaro.org>
+Cc: Thierry Reding <treding@nvidia.com>
+Cc: Mark Brown <broonie@kernel.org>
+Cc: Liam Girdwood <lgirdwood@gmail.com>
+Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
+Cc: Saravana Kannan <saravanak@google.com>
+Cc: Todd Kjos <tkjos@google.com>
+Cc: Len Brown <len.brown@intel.com>
+Cc: Pavel Machek <pavel@ucw.cz>
+Cc: Ulf Hansson <ulf.hansson@linaro.org>
+Cc: Kevin Hilman <khilman@kernel.org>
+Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
+Cc: Rob Herring <robh@kernel.org>
+Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
+Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: John Stultz <john.stultz@linaro.org>
+Link: https://lore.kernel.org/r/20200225050828.56458-3-john.stultz@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/dd.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/base/dd.c b/drivers/base/dd.c
+index 63390a416b44..529d324a0f20 100644
+--- a/drivers/base/dd.c
++++ b/drivers/base/dd.c
+@@ -220,7 +220,16 @@ static int deferred_devs_show(struct seq_file *s, void *data)
+ }
+ DEFINE_SHOW_ATTRIBUTE(deferred_devs);
++#ifdef CONFIG_MODULES
++/*
++ * In the case of modules, set the default probe timeout to
++ * 30 seconds to give userland some time to load needed modules
++ */
++static int deferred_probe_timeout = 30;
++#else
++/* In the case of !modules, no probe timeout needed */
+ static int deferred_probe_timeout = -1;
++#endif
+ static int __init deferred_probe_timeout_setup(char *str)
+ {
+       deferred_probe_timeout = simple_strtol(str, NULL, 10);
+-- 
+2.35.1
+
diff --git a/queue-4.19/ext4-correct-inconsistent-error-msg-in-nojournal-mod.patch b/queue-4.19/ext4-correct-inconsistent-error-msg-in-nojournal-mod.patch
new file mode 100644 (file)
index 0000000..272c52c
--- /dev/null
@@ -0,0 +1,55 @@
+From c9e85056623690f9af667358882560a8056cbcf7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 9 Nov 2022 15:43:43 +0800
+Subject: ext4: correct inconsistent error msg in nojournal mode
+
+From: Baokun Li <libaokun1@huawei.com>
+
+[ Upstream commit 89481b5fa8c0640e62ba84c6020cee895f7ac643 ]
+
+When we used the journal_async_commit mounting option in nojournal mode,
+the kernel told me that "can't mount with journal_checksum", was very
+confusing. I find that when we mount with journal_async_commit, both the
+JOURNAL_ASYNC_COMMIT and EXPLICIT_JOURNAL_CHECKSUM flags are set. However,
+in the error branch, CHECKSUM is checked before ASYNC_COMMIT. As a result,
+the above inconsistency occurs, and the ASYNC_COMMIT branch becomes dead
+code that cannot be executed. Therefore, we exchange the positions of the
+two judgments to make the error msg more accurate.
+
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20221109074343.4184862-1-libaokun1@huawei.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/super.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 3198c276b434..e0d597719133 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -4305,14 +4305,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
+               goto failed_mount3a;
+       } else {
+               /* Nojournal mode, all journal mount options are illegal */
+-              if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) {
++              if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+-                               "journal_checksum, fs mounted w/o journal");
++                               "journal_async_commit, fs mounted w/o journal");
+                       goto failed_mount3a;
+               }
+-              if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
++
++              if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+-                               "journal_async_commit, fs mounted w/o journal");
++                               "journal_checksum, fs mounted w/o journal");
+                       goto failed_mount3a;
+               }
+               if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
+-- 
+2.35.1
+
diff --git a/queue-4.19/ext4-fix-deadlock-due-to-mbcache-entry-corruption.patch b/queue-4.19/ext4-fix-deadlock-due-to-mbcache-entry-corruption.patch
new file mode 100644 (file)
index 0000000..9e26928
--- /dev/null
@@ -0,0 +1,143 @@
+From 0440d482716e6e40af5ab20ce95600586caa82b7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Nov 2022 20:39:50 +0100
+Subject: ext4: fix deadlock due to mbcache entry corruption
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit a44e84a9b7764c72896f7241a0ec9ac7e7ef38dd ]
+
+When manipulating xattr blocks, we can deadlock infinitely looping
+inside ext4_xattr_block_set() where we constantly keep finding xattr
+block for reuse in mbcache but we are unable to reuse it because its
+reference count is too big. This happens because cache entry for the
+xattr block is marked as reusable (e_reusable set) although its
+reference count is too big. When this inconsistency happens, this
+inconsistent state is kept indefinitely and so ext4_xattr_block_set()
+keeps retrying indefinitely.
+
+The inconsistent state is caused by non-atomic update of e_reusable bit.
+e_reusable is part of a bitfield and e_reusable update can race with
+update of e_referenced bit in the same bitfield resulting in loss of one
+of the updates. Fix the problem by using atomic bitops instead.
+
+This bug has been around for many years, but it became *much* easier
+to hit after commit 65f8b80053a1 ("ext4: fix race when reusing xattr
+blocks").
+
+Cc: stable@vger.kernel.org
+Fixes: 6048c64b2609 ("mbcache: add reusable flag to cache entries")
+Fixes: 65f8b80053a1 ("ext4: fix race when reusing xattr blocks")
+Reported-and-tested-by: Jeremi Piotrowski <jpiotrowski@linux.microsoft.com>
+Reported-by: Thilo Fromm <t-lo@linux.microsoft.com>
+Link: https://lore.kernel.org/r/c77bf00f-4618-7149-56f1-b8d1664b9d07@linux.microsoft.com/
+Signed-off-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Andreas Dilger <adilger@dilger.ca>
+Link: https://lore.kernel.org/r/20221123193950.16758-1-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/xattr.c         |  4 ++--
+ fs/mbcache.c            | 14 ++++++++------
+ include/linux/mbcache.h |  9 +++++++--
+ 3 files changed, 17 insertions(+), 10 deletions(-)
+
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index f759ab8c1a68..0772941bbe92 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -1297,7 +1297,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
+                               ce = mb_cache_entry_get(ea_block_cache, hash,
+                                                       bh->b_blocknr);
+                               if (ce) {
+-                                      ce->e_reusable = 1;
++                                      set_bit(MBE_REUSABLE_B, &ce->e_flags);
+                                       mb_cache_entry_put(ea_block_cache, ce);
+                               }
+                       }
+@@ -2058,7 +2058,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+                               }
+                               BHDR(new_bh)->h_refcount = cpu_to_le32(ref);
+                               if (ref == EXT4_XATTR_REFCOUNT_MAX)
+-                                      ce->e_reusable = 0;
++                                      clear_bit(MBE_REUSABLE_B, &ce->e_flags);
+                               ea_bdebug(new_bh, "reusing; refcount now=%d",
+                                         ref);
+                               ext4_xattr_block_csum_set(inode, new_bh);
+diff --git a/fs/mbcache.c b/fs/mbcache.c
+index aa564e79891d..8e9e1888e448 100644
+--- a/fs/mbcache.c
++++ b/fs/mbcache.c
+@@ -93,8 +93,9 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
+       atomic_set(&entry->e_refcnt, 1);
+       entry->e_key = key;
+       entry->e_value = value;
+-      entry->e_reusable = reusable;
+-      entry->e_referenced = 0;
++      entry->e_flags = 0;
++      if (reusable)
++              set_bit(MBE_REUSABLE_B, &entry->e_flags);
+       head = mb_cache_entry_head(cache, key);
+       hlist_bl_lock(head);
+       hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) {
+@@ -161,7 +162,8 @@ static struct mb_cache_entry *__entry_find(struct mb_cache *cache,
+       while (node) {
+               entry = hlist_bl_entry(node, struct mb_cache_entry,
+                                      e_hash_list);
+-              if (entry->e_key == key && entry->e_reusable &&
++              if (entry->e_key == key &&
++                  test_bit(MBE_REUSABLE_B, &entry->e_flags) &&
+                   atomic_inc_not_zero(&entry->e_refcnt))
+                       goto out;
+               node = node->next;
+@@ -317,7 +319,7 @@ EXPORT_SYMBOL(mb_cache_entry_delete_or_get);
+ void mb_cache_entry_touch(struct mb_cache *cache,
+                         struct mb_cache_entry *entry)
+ {
+-      entry->e_referenced = 1;
++      set_bit(MBE_REFERENCED_B, &entry->e_flags);
+ }
+ EXPORT_SYMBOL(mb_cache_entry_touch);
+@@ -342,9 +344,9 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache,
+               entry = list_first_entry(&cache->c_list,
+                                        struct mb_cache_entry, e_list);
+               /* Drop initial hash reference if there is no user */
+-              if (entry->e_referenced ||
++              if (test_bit(MBE_REFERENCED_B, &entry->e_flags) ||
+                   atomic_cmpxchg(&entry->e_refcnt, 1, 0) != 1) {
+-                      entry->e_referenced = 0;
++                      clear_bit(MBE_REFERENCED_B, &entry->e_flags);
+                       list_move_tail(&entry->e_list, &cache->c_list);
+                       continue;
+               }
+diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h
+index e9d5ece87794..591bc4cefe1d 100644
+--- a/include/linux/mbcache.h
++++ b/include/linux/mbcache.h
+@@ -10,6 +10,12 @@
+ struct mb_cache;
++/* Cache entry flags */
++enum {
++      MBE_REFERENCED_B = 0,
++      MBE_REUSABLE_B
++};
++
+ struct mb_cache_entry {
+       /* List of entries in cache - protected by cache->c_list_lock */
+       struct list_head        e_list;
+@@ -26,8 +32,7 @@ struct mb_cache_entry {
+       atomic_t                e_refcnt;
+       /* Key in hash - stable during lifetime of the entry */
+       u32                     e_key;
+-      u32                     e_referenced:1;
+-      u32                     e_reusable:1;
++      unsigned long           e_flags;
+       /* User provided value - stable during lifetime of the entry */
+       u64                     e_value;
+ };
+-- 
+2.35.1
+
diff --git a/queue-4.19/ext4-fix-race-when-reusing-xattr-blocks.patch b/queue-4.19/ext4-fix-race-when-reusing-xattr-blocks.patch
new file mode 100644 (file)
index 0000000..ac18e9a
--- /dev/null
@@ -0,0 +1,180 @@
+From b45508d4ada679f38795f3dd0a16d07df565cbcd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Jul 2022 12:54:24 +0200
+Subject: ext4: fix race when reusing xattr blocks
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 65f8b80053a1b2fd602daa6814e62d6fa90e5e9b ]
+
+When ext4_xattr_block_set() decides to remove xattr block the following
+race can happen:
+
+CPU1                                    CPU2
+ext4_xattr_block_set()                  ext4_xattr_release_block()
+  new_bh = ext4_xattr_block_cache_find()
+
+                                          lock_buffer(bh);
+                                          ref = le32_to_cpu(BHDR(bh)->h_refcount);
+                                          if (ref == 1) {
+                                            ...
+                                            mb_cache_entry_delete();
+                                            unlock_buffer(bh);
+                                            ext4_free_blocks();
+                                              ...
+                                              ext4_forget(..., bh, ...);
+                                                jbd2_journal_revoke(..., bh);
+
+  ext4_journal_get_write_access(..., new_bh, ...)
+    do_get_write_access()
+      jbd2_journal_cancel_revoke(..., new_bh);
+
+Later the code in ext4_xattr_block_set() finds out the block got freed
+and cancels reusal of the block but the revoke stays canceled and so in
+case of block reuse and journal replay the filesystem can get corrupted.
+If the race works out slightly differently, we can also hit assertions
+in the jbd2 code.
+
+Fix the problem by making sure that once matching mbcache entry is
+found, code dropping the last xattr block reference (or trying to modify
+xattr block in place) waits until the mbcache entry reference is
+dropped. This way code trying to reuse xattr block is protected from
+someone trying to drop the last reference to xattr block.
+
+Reported-and-tested-by: Ritesh Harjani <ritesh.list@gmail.com>
+CC: stable@vger.kernel.org
+Fixes: 82939d7999df ("ext4: convert to mbcache2")
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20220712105436.32204-5-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/xattr.c | 67 +++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 45 insertions(+), 22 deletions(-)
+
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index c23d7d68d7a1..f759ab8c1a68 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -437,9 +437,16 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
+ /* Remove entry from mbcache when EA inode is getting evicted */
+ void ext4_evict_ea_inode(struct inode *inode)
+ {
+-      if (EA_INODE_CACHE(inode))
+-              mb_cache_entry_delete(EA_INODE_CACHE(inode),
+-                      ext4_xattr_inode_get_hash(inode), inode->i_ino);
++      struct mb_cache_entry *oe;
++
++      if (!EA_INODE_CACHE(inode))
++              return;
++      /* Wait for entry to get unused so that we can remove it */
++      while ((oe = mb_cache_entry_delete_or_get(EA_INODE_CACHE(inode),
++                      ext4_xattr_inode_get_hash(inode), inode->i_ino))) {
++              mb_cache_entry_wait_unused(oe);
++              mb_cache_entry_put(EA_INODE_CACHE(inode), oe);
++      }
+ }
+ static int
+@@ -1245,6 +1252,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
+       if (error)
+               goto out;
++retry_ref:
+       lock_buffer(bh);
+       hash = le32_to_cpu(BHDR(bh)->h_hash);
+       ref = le32_to_cpu(BHDR(bh)->h_refcount);
+@@ -1254,9 +1262,18 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,
+                * This must happen under buffer lock for
+                * ext4_xattr_block_set() to reliably detect freed block
+                */
+-              if (ea_block_cache)
+-                      mb_cache_entry_delete(ea_block_cache, hash,
+-                                            bh->b_blocknr);
++              if (ea_block_cache) {
++                      struct mb_cache_entry *oe;
++
++                      oe = mb_cache_entry_delete_or_get(ea_block_cache, hash,
++                                                        bh->b_blocknr);
++                      if (oe) {
++                              unlock_buffer(bh);
++                              mb_cache_entry_wait_unused(oe);
++                              mb_cache_entry_put(ea_block_cache, oe);
++                              goto retry_ref;
++                      }
++              }
+               get_bh(bh);
+               unlock_buffer(bh);
+@@ -1883,9 +1900,20 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+                        * ext4_xattr_block_set() to reliably detect modified
+                        * block
+                        */
+-                      if (ea_block_cache)
+-                              mb_cache_entry_delete(ea_block_cache, hash,
+-                                                    bs->bh->b_blocknr);
++                      if (ea_block_cache) {
++                              struct mb_cache_entry *oe;
++
++                              oe = mb_cache_entry_delete_or_get(ea_block_cache,
++                                      hash, bs->bh->b_blocknr);
++                              if (oe) {
++                                      /*
++                                       * Xattr block is getting reused. Leave
++                                       * it alone.
++                                       */
++                                      mb_cache_entry_put(ea_block_cache, oe);
++                                      goto clone_block;
++                              }
++                      }
+                       ea_bdebug(bs->bh, "modifying in-place");
+                       error = ext4_xattr_set_entry(i, s, handle, inode,
+                                                    true /* is_block */);
+@@ -1901,6 +1929,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+                               goto cleanup;
+                       goto inserted;
+               }
++clone_block:
+               unlock_buffer(bs->bh);
+               ea_bdebug(bs->bh, "cloning");
+               s->base = kmemdup(BHDR(bs->bh), bs->bh->b_size, GFP_NOFS);
+@@ -2006,18 +2035,13 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+                               lock_buffer(new_bh);
+                               /*
+                                * We have to be careful about races with
+-                               * freeing, rehashing or adding references to
+-                               * xattr block. Once we hold buffer lock xattr
+-                               * block's state is stable so we can check
+-                               * whether the block got freed / rehashed or
+-                               * not.  Since we unhash mbcache entry under
+-                               * buffer lock when freeing / rehashing xattr
+-                               * block, checking whether entry is still
+-                               * hashed is reliable. Same rules hold for
+-                               * e_reusable handling.
++                               * adding references to xattr block. Once we
++                               * hold buffer lock xattr block's state is
++                               * stable so we can check the additional
++                               * reference fits.
+                                */
+-                              if (hlist_bl_unhashed(&ce->e_hash_list) ||
+-                                  !ce->e_reusable) {
++                              ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1;
++                              if (ref > EXT4_XATTR_REFCOUNT_MAX) {
+                                       /*
+                                        * Undo everything and check mbcache
+                                        * again.
+@@ -2032,9 +2056,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+                                       new_bh = NULL;
+                                       goto inserted;
+                               }
+-                              ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1;
+                               BHDR(new_bh)->h_refcount = cpu_to_le32(ref);
+-                              if (ref >= EXT4_XATTR_REFCOUNT_MAX)
++                              if (ref == EXT4_XATTR_REFCOUNT_MAX)
+                                       ce->e_reusable = 0;
+                               ea_bdebug(new_bh, "reusing; refcount now=%d",
+                                         ref);
+-- 
+2.35.1
+
diff --git a/queue-4.19/ext4-goto-right-label-failed_mount3a.patch b/queue-4.19/ext4-goto-right-label-failed_mount3a.patch
new file mode 100644 (file)
index 0000000..7e06a5d
--- /dev/null
@@ -0,0 +1,69 @@
+From bef45f166bc13af29c9626bab997e80295f2c475 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 Sep 2022 22:15:12 +0800
+Subject: ext4: goto right label 'failed_mount3a'
+
+From: Jason Yan <yanaijie@huawei.com>
+
+[ Upstream commit 43bd6f1b49b61f43de4d4e33661b8dbe8c911f14 ]
+
+Before these two branches neither loaded the journal nor created the
+xattr cache. So the right label to goto is 'failed_mount3a'. Although
+this did not cause any issues because the error handler validated if the
+pointer is null. However this still made me confused when reading
+the code. So it's still worth to modify to goto the right label.
+
+Signed-off-by: Jason Yan <yanaijie@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
+Link: https://lore.kernel.org/r/20220916141527.1012715-2-yanaijie@huawei.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 89481b5fa8c0 ("ext4: correct inconsistent error msg in nojournal mode")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/super.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 796588dc531b..3198c276b434 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -4302,30 +4302,30 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
+                  ext4_has_feature_journal_needs_recovery(sb)) {
+               ext4_msg(sb, KERN_ERR, "required journal recovery "
+                      "suppressed and not mounted read-only");
+-              goto failed_mount_wq;
++              goto failed_mount3a;
+       } else {
+               /* Nojournal mode, all journal mount options are illegal */
+               if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "journal_checksum, fs mounted w/o journal");
+-                      goto failed_mount_wq;
++                      goto failed_mount3a;
+               }
+               if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "journal_async_commit, fs mounted w/o journal");
+-                      goto failed_mount_wq;
++                      goto failed_mount3a;
+               }
+               if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "commit=%lu, fs mounted w/o journal",
+                                sbi->s_commit_interval / HZ);
+-                      goto failed_mount_wq;
++                      goto failed_mount3a;
+               }
+               if (EXT4_MOUNT_DATA_FLAGS &
+                   (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "data=, fs mounted w/o journal");
+-                      goto failed_mount_wq;
++                      goto failed_mount3a;
+               }
+               sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM;
+               clear_opt(sb, JOURNAL_CHECKSUM);
+-- 
+2.35.1
+
diff --git a/queue-4.19/ext4-remove-ea-inode-entry-from-mbcache-on-inode-evi.patch b/queue-4.19/ext4-remove-ea-inode-entry-from-mbcache-on-inode-evi.patch
new file mode 100644 (file)
index 0000000..3b28d2a
--- /dev/null
@@ -0,0 +1,117 @@
+From 6dc5dfb9380c5b00d83acbb68b31c2dab15184bf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Jul 2022 12:54:22 +0200
+Subject: ext4: remove EA inode entry from mbcache on inode eviction
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 6bc0d63dad7f9f54d381925ee855b402f652fa39 ]
+
+Currently we remove EA inode from mbcache as soon as its xattr refcount
+drops to zero. However there can be pending attempts to reuse the inode
+and thus refcount handling code has to handle the situation when
+refcount increases from zero anyway. So save some work and just keep EA
+inode in mbcache until it is getting evicted. At that moment we are sure
+following iget() of EA inode will fail anyway (or wait for eviction to
+finish and load things from the disk again) and so removing mbcache
+entry at that moment is fine and simplifies the code a bit.
+
+CC: stable@vger.kernel.org
+Fixes: 82939d7999df ("ext4: convert to mbcache2")
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20220712105436.32204-3-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/inode.c |  2 ++
+ fs/ext4/xattr.c | 24 ++++++++----------------
+ fs/ext4/xattr.h |  1 +
+ 3 files changed, 11 insertions(+), 16 deletions(-)
+
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 2ad0a9540481..b322658ceff1 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -207,6 +207,8 @@ void ext4_evict_inode(struct inode *inode)
+       trace_ext4_evict_inode(inode);
++      if (EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)
++              ext4_evict_ea_inode(inode);
+       if (inode->i_nlink) {
+               /*
+                * When journalling data dirty buffers are tracked only in the
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index 959fc3328c3a..648368b02c79 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -434,6 +434,14 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
+       return err;
+ }
++/* Remove entry from mbcache when EA inode is getting evicted */
++void ext4_evict_ea_inode(struct inode *inode)
++{
++      if (EA_INODE_CACHE(inode))
++              mb_cache_entry_delete(EA_INODE_CACHE(inode),
++                      ext4_xattr_inode_get_hash(inode), inode->i_ino);
++}
++
+ static int
+ ext4_xattr_inode_verify_hashes(struct inode *ea_inode,
+                              struct ext4_xattr_entry *entry, void *buffer,
+@@ -1019,10 +1027,8 @@ static int ext4_xattr_ensure_credits(handle_t *handle, struct inode *inode,
+ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
+                                      int ref_change)
+ {
+-      struct mb_cache *ea_inode_cache = EA_INODE_CACHE(ea_inode);
+       struct ext4_iloc iloc;
+       s64 ref_count;
+-      u32 hash;
+       int ret;
+       inode_lock(ea_inode);
+@@ -1047,14 +1053,6 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
+                       set_nlink(ea_inode, 1);
+                       ext4_orphan_del(handle, ea_inode);
+-
+-                      if (ea_inode_cache) {
+-                              hash = ext4_xattr_inode_get_hash(ea_inode);
+-                              mb_cache_entry_create(ea_inode_cache,
+-                                                    GFP_NOFS, hash,
+-                                                    ea_inode->i_ino,
+-                                                    true /* reusable */);
+-                      }
+               }
+       } else {
+               WARN_ONCE(ref_count < 0, "EA inode %lu ref_count=%lld",
+@@ -1067,12 +1065,6 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode,
+                       clear_nlink(ea_inode);
+                       ext4_orphan_add(handle, ea_inode);
+-
+-                      if (ea_inode_cache) {
+-                              hash = ext4_xattr_inode_get_hash(ea_inode);
+-                              mb_cache_entry_delete(ea_inode_cache, hash,
+-                                                    ea_inode->i_ino);
+-                      }
+               }
+       }
+diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
+index 990084e00374..231ef308d10c 100644
+--- a/fs/ext4/xattr.h
++++ b/fs/ext4/xattr.h
+@@ -190,6 +190,7 @@ extern void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *array);
+ extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+                           struct ext4_inode *raw_inode, handle_t *handle);
++extern void ext4_evict_ea_inode(struct inode *inode);
+ extern const struct xattr_handler *ext4_xattr_handlers[];
+-- 
+2.35.1
+
diff --git a/queue-4.19/ext4-unindent-codeblock-in-ext4_xattr_block_set.patch b/queue-4.19/ext4-unindent-codeblock-in-ext4_xattr_block_set.patch
new file mode 100644 (file)
index 0000000..96bdab9
--- /dev/null
@@ -0,0 +1,126 @@
+From fca1e436800300c4d9b959ba41635593db5fd689 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Jul 2022 12:54:23 +0200
+Subject: ext4: unindent codeblock in ext4_xattr_block_set()
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit fd48e9acdf26d0cbd80051de07d4a735d05d29b2 ]
+
+Remove unnecessary else (and thus indentation level) from a code block
+in ext4_xattr_block_set(). It will also make following code changes
+easier. No functional changes.
+
+CC: stable@vger.kernel.org
+Fixes: 82939d7999df ("ext4: convert to mbcache2")
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20220712105436.32204-4-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/xattr.c | 77 ++++++++++++++++++++++++-------------------------
+ 1 file changed, 38 insertions(+), 39 deletions(-)
+
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index 648368b02c79..c23d7d68d7a1 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -1867,6 +1867,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+ #define header(x) ((struct ext4_xattr_header *)(x))
+       if (s->base) {
++              int offset = (char *)s->here - bs->bh->b_data;
++
+               BUFFER_TRACE(bs->bh, "get_write_access");
+               error = ext4_journal_get_write_access(handle, bs->bh);
+               if (error)
+@@ -1898,49 +1900,46 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+                       if (error)
+                               goto cleanup;
+                       goto inserted;
+-              } else {
+-                      int offset = (char *)s->here - bs->bh->b_data;
++              }
++              unlock_buffer(bs->bh);
++              ea_bdebug(bs->bh, "cloning");
++              s->base = kmemdup(BHDR(bs->bh), bs->bh->b_size, GFP_NOFS);
++              error = -ENOMEM;
++              if (s->base == NULL)
++                      goto cleanup;
++              s->first = ENTRY(header(s->base)+1);
++              header(s->base)->h_refcount = cpu_to_le32(1);
++              s->here = ENTRY(s->base + offset);
++              s->end = s->base + bs->bh->b_size;
+-                      unlock_buffer(bs->bh);
+-                      ea_bdebug(bs->bh, "cloning");
+-                      s->base = kmemdup(BHDR(bs->bh), bs->bh->b_size, GFP_NOFS);
+-                      error = -ENOMEM;
+-                      if (s->base == NULL)
++              /*
++               * If existing entry points to an xattr inode, we need
++               * to prevent ext4_xattr_set_entry() from decrementing
++               * ref count on it because the reference belongs to the
++               * original block. In this case, make the entry look
++               * like it has an empty value.
++               */
++              if (!s->not_found && s->here->e_value_inum) {
++                      ea_ino = le32_to_cpu(s->here->e_value_inum);
++                      error = ext4_xattr_inode_iget(inode, ea_ino,
++                                    le32_to_cpu(s->here->e_hash),
++                                    &tmp_inode);
++                      if (error)
+                               goto cleanup;
+-                      s->first = ENTRY(header(s->base)+1);
+-                      header(s->base)->h_refcount = cpu_to_le32(1);
+-                      s->here = ENTRY(s->base + offset);
+-                      s->end = s->base + bs->bh->b_size;
+-                      /*
+-                       * If existing entry points to an xattr inode, we need
+-                       * to prevent ext4_xattr_set_entry() from decrementing
+-                       * ref count on it because the reference belongs to the
+-                       * original block. In this case, make the entry look
+-                       * like it has an empty value.
+-                       */
+-                      if (!s->not_found && s->here->e_value_inum) {
+-                              ea_ino = le32_to_cpu(s->here->e_value_inum);
+-                              error = ext4_xattr_inode_iget(inode, ea_ino,
+-                                            le32_to_cpu(s->here->e_hash),
+-                                            &tmp_inode);
+-                              if (error)
+-                                      goto cleanup;
+-
+-                              if (!ext4_test_inode_state(tmp_inode,
+-                                              EXT4_STATE_LUSTRE_EA_INODE)) {
+-                                      /*
+-                                       * Defer quota free call for previous
+-                                       * inode until success is guaranteed.
+-                                       */
+-                                      old_ea_inode_quota = le32_to_cpu(
+-                                                      s->here->e_value_size);
+-                              }
+-                              iput(tmp_inode);
+-
+-                              s->here->e_value_inum = 0;
+-                              s->here->e_value_size = 0;
++                      if (!ext4_test_inode_state(tmp_inode,
++                                      EXT4_STATE_LUSTRE_EA_INODE)) {
++                              /*
++                               * Defer quota free call for previous
++                               * inode until success is guaranteed.
++                               */
++                              old_ea_inode_quota = le32_to_cpu(
++                                              s->here->e_value_size);
+                       }
++                      iput(tmp_inode);
++
++                      s->here->e_value_inum = 0;
++                      s->here->e_value_size = 0;
+               }
+       } else {
+               /* Allocate a buffer where we construct the new block. */
+-- 
+2.35.1
+
diff --git a/queue-4.19/ext4-use-kmemdup-to-replace-kmalloc-memcpy.patch b/queue-4.19/ext4-use-kmemdup-to-replace-kmalloc-memcpy.patch
new file mode 100644 (file)
index 0000000..2383ff0
--- /dev/null
@@ -0,0 +1,41 @@
+From 9cac30ee5a4959e6ae031feaae25067c8d24b31a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 May 2022 11:01:20 +0800
+Subject: ext4: use kmemdup() to replace kmalloc + memcpy
+
+From: Shuqi Zhang <zhangshuqi3@huawei.com>
+
+[ Upstream commit 4efd9f0d120c55b08852ee5605dbb02a77089a5d ]
+
+Replace kmalloc + memcpy with kmemdup()
+
+Signed-off-by: Shuqi Zhang <zhangshuqi3@huawei.com>
+Reviewed-by: Ritesh Harjani <ritesh.list@gmail.com>
+Link: https://lore.kernel.org/r/20220525030120.803330-1-zhangshuqi3@huawei.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/xattr.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
+index 7195a7ff65a6..959fc3328c3a 100644
+--- a/fs/ext4/xattr.c
++++ b/fs/ext4/xattr.c
+@@ -1911,11 +1911,10 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+                       unlock_buffer(bs->bh);
+                       ea_bdebug(bs->bh, "cloning");
+-                      s->base = kmalloc(bs->bh->b_size, GFP_NOFS);
++                      s->base = kmemdup(BHDR(bs->bh), bs->bh->b_size, GFP_NOFS);
+                       error = -ENOMEM;
+                       if (s->base == NULL)
+                               goto cleanup;
+-                      memcpy(s->base, BHDR(bs->bh), bs->bh->b_size);
+                       s->first = ENTRY(header(s->base)+1);
+                       header(s->base)->h_refcount = cpu_to_le32(1);
+                       s->here = ENTRY(s->base + offset);
+-- 
+2.35.1
+
diff --git a/queue-4.19/mbcache-add-functions-to-delete-entry-if-unused.patch b/queue-4.19/mbcache-add-functions-to-delete-entry-if-unused.patch
new file mode 100644 (file)
index 0000000..a407b96
--- /dev/null
@@ -0,0 +1,156 @@
+From 5597b9d1616c53e0617c3a9b97b933096ab162ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Jul 2022 12:54:21 +0200
+Subject: mbcache: add functions to delete entry if unused
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 3dc96bba65f53daa217f0a8f43edad145286a8f5 ]
+
+Add function mb_cache_entry_delete_or_get() to delete mbcache entry if
+it is unused and also add a function to wait for entry to become unused
+- mb_cache_entry_wait_unused(). We do not share code between the two
+deleting function as one of them will go away soon.
+
+CC: stable@vger.kernel.org
+Fixes: 82939d7999df ("ext4: convert to mbcache2")
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20220712105436.32204-2-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/mbcache.c            | 66 +++++++++++++++++++++++++++++++++++++++--
+ include/linux/mbcache.h | 10 ++++++-
+ 2 files changed, 73 insertions(+), 3 deletions(-)
+
+diff --git a/fs/mbcache.c b/fs/mbcache.c
+index 12203e5a91e7..c76030e20d92 100644
+--- a/fs/mbcache.c
++++ b/fs/mbcache.c
+@@ -10,7 +10,7 @@
+ /*
+  * Mbcache is a simple key-value store. Keys need not be unique, however
+  * key-value pairs are expected to be unique (we use this fact in
+- * mb_cache_entry_delete()).
++ * mb_cache_entry_delete_or_get()).
+  *
+  * Ext2 and ext4 use this cache for deduplication of extended attribute blocks.
+  * Ext4 also uses it for deduplication of xattr values stored in inodes.
+@@ -124,6 +124,19 @@ void __mb_cache_entry_free(struct mb_cache_entry *entry)
+ }
+ EXPORT_SYMBOL(__mb_cache_entry_free);
++/*
++ * mb_cache_entry_wait_unused - wait to be the last user of the entry
++ *
++ * @entry - entry to work on
++ *
++ * Wait to be the last user of the entry.
++ */
++void mb_cache_entry_wait_unused(struct mb_cache_entry *entry)
++{
++      wait_var_event(&entry->e_refcnt, atomic_read(&entry->e_refcnt) <= 3);
++}
++EXPORT_SYMBOL(mb_cache_entry_wait_unused);
++
+ static struct mb_cache_entry *__entry_find(struct mb_cache *cache,
+                                          struct mb_cache_entry *entry,
+                                          u32 key)
+@@ -216,7 +229,7 @@ struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key,
+ }
+ EXPORT_SYMBOL(mb_cache_entry_get);
+-/* mb_cache_entry_delete - remove a cache entry
++/* mb_cache_entry_delete - try to remove a cache entry
+  * @cache - cache we work with
+  * @key - key
+  * @value - value
+@@ -253,6 +266,55 @@ void mb_cache_entry_delete(struct mb_cache *cache, u32 key, u64 value)
+ }
+ EXPORT_SYMBOL(mb_cache_entry_delete);
++/* mb_cache_entry_delete_or_get - remove a cache entry if it has no users
++ * @cache - cache we work with
++ * @key - key
++ * @value - value
++ *
++ * Remove entry from cache @cache with key @key and value @value. The removal
++ * happens only if the entry is unused. The function returns NULL in case the
++ * entry was successfully removed or there's no entry in cache. Otherwise the
++ * function grabs reference of the entry that we failed to delete because it
++ * still has users and return it.
++ */
++struct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache,
++                                                  u32 key, u64 value)
++{
++      struct hlist_bl_node *node;
++      struct hlist_bl_head *head;
++      struct mb_cache_entry *entry;
++
++      head = mb_cache_entry_head(cache, key);
++      hlist_bl_lock(head);
++      hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
++              if (entry->e_key == key && entry->e_value == value) {
++                      if (atomic_read(&entry->e_refcnt) > 2) {
++                              atomic_inc(&entry->e_refcnt);
++                              hlist_bl_unlock(head);
++                              return entry;
++                      }
++                      /* We keep hash list reference to keep entry alive */
++                      hlist_bl_del_init(&entry->e_hash_list);
++                      hlist_bl_unlock(head);
++                      spin_lock(&cache->c_list_lock);
++                      if (!list_empty(&entry->e_list)) {
++                              list_del_init(&entry->e_list);
++                              if (!WARN_ONCE(cache->c_entry_count == 0,
++              "mbcache: attempt to decrement c_entry_count past zero"))
++                                      cache->c_entry_count--;
++                              atomic_dec(&entry->e_refcnt);
++                      }
++                      spin_unlock(&cache->c_list_lock);
++                      mb_cache_entry_put(cache, entry);
++                      return NULL;
++              }
++      }
++      hlist_bl_unlock(head);
++
++      return NULL;
++}
++EXPORT_SYMBOL(mb_cache_entry_delete_or_get);
++
+ /* mb_cache_entry_touch - cache entry got used
+  * @cache - cache the entry belongs to
+  * @entry - entry that got used
+diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h
+index 20f1e3ff6013..8eca7f25c432 100644
+--- a/include/linux/mbcache.h
++++ b/include/linux/mbcache.h
+@@ -30,15 +30,23 @@ void mb_cache_destroy(struct mb_cache *cache);
+ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
+                         u64 value, bool reusable);
+ void __mb_cache_entry_free(struct mb_cache_entry *entry);
++void mb_cache_entry_wait_unused(struct mb_cache_entry *entry);
+ static inline int mb_cache_entry_put(struct mb_cache *cache,
+                                    struct mb_cache_entry *entry)
+ {
+-      if (!atomic_dec_and_test(&entry->e_refcnt))
++      unsigned int cnt = atomic_dec_return(&entry->e_refcnt);
++
++      if (cnt > 0) {
++              if (cnt <= 3)
++                      wake_up_var(&entry->e_refcnt);
+               return 0;
++      }
+       __mb_cache_entry_free(entry);
+       return 1;
+ }
++struct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache,
++                                                  u32 key, u64 value);
+ void mb_cache_entry_delete(struct mb_cache *cache, u32 key, u64 value);
+ struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key,
+                                         u64 value);
+-- 
+2.35.1
+
diff --git a/queue-4.19/mbcache-automatically-delete-entries-from-cache-on-f.patch b/queue-4.19/mbcache-automatically-delete-entries-from-cache-on-f.patch
new file mode 100644 (file)
index 0000000..db90924
--- /dev/null
@@ -0,0 +1,274 @@
+From 76d07f5ac8d1bb41a0502fa01498cbc014404c74 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Jul 2022 12:54:29 +0200
+Subject: mbcache: automatically delete entries from cache on freeing
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 307af6c879377c1c63e71cbdd978201f9c7ee8df ]
+
+Use the fact that entries with elevated refcount are not removed from
+the hash and just move removal of the entry from the hash to the entry
+freeing time. When doing this we also change the generic code to hold
+one reference to the cache entry, not two of them, which makes code
+somewhat more obvious.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20220712105436.32204-10-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/mbcache.c            | 108 +++++++++++++++-------------------------
+ include/linux/mbcache.h |  24 ++++++---
+ 2 files changed, 55 insertions(+), 77 deletions(-)
+
+diff --git a/fs/mbcache.c b/fs/mbcache.c
+index c76030e20d92..aa564e79891d 100644
+--- a/fs/mbcache.c
++++ b/fs/mbcache.c
+@@ -89,7 +89,7 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
+               return -ENOMEM;
+       INIT_LIST_HEAD(&entry->e_list);
+-      /* One ref for hash, one ref returned */
++      /* Initial hash reference */
+       atomic_set(&entry->e_refcnt, 1);
+       entry->e_key = key;
+       entry->e_value = value;
+@@ -105,21 +105,28 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
+               }
+       }
+       hlist_bl_add_head(&entry->e_hash_list, head);
+-      hlist_bl_unlock(head);
+-
++      /*
++       * Add entry to LRU list before it can be found by
++       * mb_cache_entry_delete() to avoid races
++       */
+       spin_lock(&cache->c_list_lock);
+       list_add_tail(&entry->e_list, &cache->c_list);
+-      /* Grab ref for LRU list */
+-      atomic_inc(&entry->e_refcnt);
+       cache->c_entry_count++;
+       spin_unlock(&cache->c_list_lock);
++      hlist_bl_unlock(head);
+       return 0;
+ }
+ EXPORT_SYMBOL(mb_cache_entry_create);
+-void __mb_cache_entry_free(struct mb_cache_entry *entry)
++void __mb_cache_entry_free(struct mb_cache *cache, struct mb_cache_entry *entry)
+ {
++      struct hlist_bl_head *head;
++
++      head = mb_cache_entry_head(cache, entry->e_key);
++      hlist_bl_lock(head);
++      hlist_bl_del(&entry->e_hash_list);
++      hlist_bl_unlock(head);
+       kmem_cache_free(mb_entry_cache, entry);
+ }
+ EXPORT_SYMBOL(__mb_cache_entry_free);
+@@ -133,7 +140,7 @@ EXPORT_SYMBOL(__mb_cache_entry_free);
+  */
+ void mb_cache_entry_wait_unused(struct mb_cache_entry *entry)
+ {
+-      wait_var_event(&entry->e_refcnt, atomic_read(&entry->e_refcnt) <= 3);
++      wait_var_event(&entry->e_refcnt, atomic_read(&entry->e_refcnt) <= 2);
+ }
+ EXPORT_SYMBOL(mb_cache_entry_wait_unused);
+@@ -154,10 +161,9 @@ static struct mb_cache_entry *__entry_find(struct mb_cache *cache,
+       while (node) {
+               entry = hlist_bl_entry(node, struct mb_cache_entry,
+                                      e_hash_list);
+-              if (entry->e_key == key && entry->e_reusable) {
+-                      atomic_inc(&entry->e_refcnt);
++              if (entry->e_key == key && entry->e_reusable &&
++                  atomic_inc_not_zero(&entry->e_refcnt))
+                       goto out;
+-              }
+               node = node->next;
+       }
+       entry = NULL;
+@@ -217,10 +223,9 @@ struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key,
+       head = mb_cache_entry_head(cache, key);
+       hlist_bl_lock(head);
+       hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
+-              if (entry->e_key == key && entry->e_value == value) {
+-                      atomic_inc(&entry->e_refcnt);
++              if (entry->e_key == key && entry->e_value == value &&
++                  atomic_inc_not_zero(&entry->e_refcnt))
+                       goto out;
+-              }
+       }
+       entry = NULL;
+ out:
+@@ -280,37 +285,25 @@ EXPORT_SYMBOL(mb_cache_entry_delete);
+ struct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache,
+                                                   u32 key, u64 value)
+ {
+-      struct hlist_bl_node *node;
+-      struct hlist_bl_head *head;
+       struct mb_cache_entry *entry;
+-      head = mb_cache_entry_head(cache, key);
+-      hlist_bl_lock(head);
+-      hlist_bl_for_each_entry(entry, node, head, e_hash_list) {
+-              if (entry->e_key == key && entry->e_value == value) {
+-                      if (atomic_read(&entry->e_refcnt) > 2) {
+-                              atomic_inc(&entry->e_refcnt);
+-                              hlist_bl_unlock(head);
+-                              return entry;
+-                      }
+-                      /* We keep hash list reference to keep entry alive */
+-                      hlist_bl_del_init(&entry->e_hash_list);
+-                      hlist_bl_unlock(head);
+-                      spin_lock(&cache->c_list_lock);
+-                      if (!list_empty(&entry->e_list)) {
+-                              list_del_init(&entry->e_list);
+-                              if (!WARN_ONCE(cache->c_entry_count == 0,
+-              "mbcache: attempt to decrement c_entry_count past zero"))
+-                                      cache->c_entry_count--;
+-                              atomic_dec(&entry->e_refcnt);
+-                      }
+-                      spin_unlock(&cache->c_list_lock);
+-                      mb_cache_entry_put(cache, entry);
+-                      return NULL;
+-              }
+-      }
+-      hlist_bl_unlock(head);
++      entry = mb_cache_entry_get(cache, key, value);
++      if (!entry)
++              return NULL;
++      /*
++       * Drop the ref we got from mb_cache_entry_get() and the initial hash
++       * ref if we are the last user
++       */
++      if (atomic_cmpxchg(&entry->e_refcnt, 2, 0) != 2)
++              return entry;
++
++      spin_lock(&cache->c_list_lock);
++      if (!list_empty(&entry->e_list))
++              list_del_init(&entry->e_list);
++      cache->c_entry_count--;
++      spin_unlock(&cache->c_list_lock);
++      __mb_cache_entry_free(cache, entry);
+       return NULL;
+ }
+ EXPORT_SYMBOL(mb_cache_entry_delete_or_get);
+@@ -342,42 +335,24 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache,
+                                    unsigned long nr_to_scan)
+ {
+       struct mb_cache_entry *entry;
+-      struct hlist_bl_head *head;
+       unsigned long shrunk = 0;
+       spin_lock(&cache->c_list_lock);
+       while (nr_to_scan-- && !list_empty(&cache->c_list)) {
+               entry = list_first_entry(&cache->c_list,
+                                        struct mb_cache_entry, e_list);
+-              if (entry->e_referenced || atomic_read(&entry->e_refcnt) > 2) {
++              /* Drop initial hash reference if there is no user */
++              if (entry->e_referenced ||
++                  atomic_cmpxchg(&entry->e_refcnt, 1, 0) != 1) {
+                       entry->e_referenced = 0;
+                       list_move_tail(&entry->e_list, &cache->c_list);
+                       continue;
+               }
+               list_del_init(&entry->e_list);
+               cache->c_entry_count--;
+-              /*
+-               * We keep LRU list reference so that entry doesn't go away
+-               * from under us.
+-               */
+               spin_unlock(&cache->c_list_lock);
+-              head = mb_cache_entry_head(cache, entry->e_key);
+-              hlist_bl_lock(head);
+-              /* Now a reliable check if the entry didn't get used... */
+-              if (atomic_read(&entry->e_refcnt) > 2) {
+-                      hlist_bl_unlock(head);
+-                      spin_lock(&cache->c_list_lock);
+-                      list_add_tail(&entry->e_list, &cache->c_list);
+-                      cache->c_entry_count++;
+-                      continue;
+-              }
+-              if (!hlist_bl_unhashed(&entry->e_hash_list)) {
+-                      hlist_bl_del_init(&entry->e_hash_list);
+-                      atomic_dec(&entry->e_refcnt);
+-              }
+-              hlist_bl_unlock(head);
+-              if (mb_cache_entry_put(cache, entry))
+-                      shrunk++;
++              __mb_cache_entry_free(cache, entry);
++              shrunk++;
+               cond_resched();
+               spin_lock(&cache->c_list_lock);
+       }
+@@ -469,11 +444,6 @@ void mb_cache_destroy(struct mb_cache *cache)
+        * point.
+        */
+       list_for_each_entry_safe(entry, next, &cache->c_list, e_list) {
+-              if (!hlist_bl_unhashed(&entry->e_hash_list)) {
+-                      hlist_bl_del_init(&entry->e_hash_list);
+-                      atomic_dec(&entry->e_refcnt);
+-              } else
+-                      WARN_ON(1);
+               list_del(&entry->e_list);
+               WARN_ON(atomic_read(&entry->e_refcnt) != 1);
+               mb_cache_entry_put(cache, entry);
+diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h
+index 8eca7f25c432..e9d5ece87794 100644
+--- a/include/linux/mbcache.h
++++ b/include/linux/mbcache.h
+@@ -13,8 +13,16 @@ struct mb_cache;
+ struct mb_cache_entry {
+       /* List of entries in cache - protected by cache->c_list_lock */
+       struct list_head        e_list;
+-      /* Hash table list - protected by hash chain bitlock */
++      /*
++       * Hash table list - protected by hash chain bitlock. The entry is
++       * guaranteed to be hashed while e_refcnt > 0.
++       */
+       struct hlist_bl_node    e_hash_list;
++      /*
++       * Entry refcount. Once it reaches zero, entry is unhashed and freed.
++       * While refcount > 0, the entry is guaranteed to stay in the hash and
++       * e.g. mb_cache_entry_try_delete() will fail.
++       */
+       atomic_t                e_refcnt;
+       /* Key in hash - stable during lifetime of the entry */
+       u32                     e_key;
+@@ -29,20 +37,20 @@ void mb_cache_destroy(struct mb_cache *cache);
+ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key,
+                         u64 value, bool reusable);
+-void __mb_cache_entry_free(struct mb_cache_entry *entry);
++void __mb_cache_entry_free(struct mb_cache *cache,
++                         struct mb_cache_entry *entry);
+ void mb_cache_entry_wait_unused(struct mb_cache_entry *entry);
+-static inline int mb_cache_entry_put(struct mb_cache *cache,
+-                                   struct mb_cache_entry *entry)
++static inline void mb_cache_entry_put(struct mb_cache *cache,
++                                    struct mb_cache_entry *entry)
+ {
+       unsigned int cnt = atomic_dec_return(&entry->e_refcnt);
+       if (cnt > 0) {
+-              if (cnt <= 3)
++              if (cnt <= 2)
+                       wake_up_var(&entry->e_refcnt);
+-              return 0;
++              return;
+       }
+-      __mb_cache_entry_free(entry);
+-      return 1;
++      __mb_cache_entry_free(cache, entry);
+ }
+ struct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache,
+-- 
+2.35.1
+
diff --git a/queue-4.19/mbcache-don-t-reclaim-used-entries.patch b/queue-4.19/mbcache-don-t-reclaim-used-entries.patch
new file mode 100644 (file)
index 0000000..b645d8e
--- /dev/null
@@ -0,0 +1,56 @@
+From 94987d5de838fa00998363f2252e9a577b32fea5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Jul 2022 12:54:20 +0200
+Subject: mbcache: don't reclaim used entries
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 58318914186c157477b978b1739dfe2f1b9dc0fe ]
+
+Do not reclaim entries that are currently used by somebody from a
+shrinker. Firstly, these entries are likely useful. Secondly, we will
+need to keep such entries to protect pending increment of xattr block
+refcount.
+
+CC: stable@vger.kernel.org
+Fixes: 82939d7999df ("ext4: convert to mbcache2")
+Signed-off-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20220712105436.32204-1-jack@suse.cz
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/mbcache.c | 10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+diff --git a/fs/mbcache.c b/fs/mbcache.c
+index 081ccf0caee3..12203e5a91e7 100644
+--- a/fs/mbcache.c
++++ b/fs/mbcache.c
+@@ -287,7 +287,7 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache,
+       while (nr_to_scan-- && !list_empty(&cache->c_list)) {
+               entry = list_first_entry(&cache->c_list,
+                                        struct mb_cache_entry, e_list);
+-              if (entry->e_referenced) {
++              if (entry->e_referenced || atomic_read(&entry->e_refcnt) > 2) {
+                       entry->e_referenced = 0;
+                       list_move_tail(&entry->e_list, &cache->c_list);
+                       continue;
+@@ -301,6 +301,14 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache,
+               spin_unlock(&cache->c_list_lock);
+               head = mb_cache_entry_head(cache, entry->e_key);
+               hlist_bl_lock(head);
++              /* Now a reliable check if the entry didn't get used... */
++              if (atomic_read(&entry->e_refcnt) > 2) {
++                      hlist_bl_unlock(head);
++                      spin_lock(&cache->c_list_lock);
++                      list_add_tail(&entry->e_list, &cache->c_list);
++                      cache->c_entry_count++;
++                      continue;
++              }
+               if (!hlist_bl_unhashed(&entry->e_hash_list)) {
+                       hlist_bl_del_init(&entry->e_hash_list);
+                       atomic_dec(&entry->e_refcnt);
+-- 
+2.35.1
+
diff --git a/queue-4.19/net-amd-xgbe-add-missed-tasklet_kill.patch b/queue-4.19/net-amd-xgbe-add-missed-tasklet_kill.patch
new file mode 100644 (file)
index 0000000..6ba0996
--- /dev/null
@@ -0,0 +1,71 @@
+From 827f49139b1fb861793f6714567e645e3637fd2c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 28 Dec 2022 16:14:47 +0800
+Subject: net: amd-xgbe: add missed tasklet_kill
+
+From: Jiguang Xiao <jiguang.xiao@windriver.com>
+
+[ Upstream commit d530ece70f16f912e1d1bfeea694246ab78b0a4b ]
+
+The driver does not call tasklet_kill in several places.
+Add the calls to fix it.
+
+Fixes: 85b85c853401 ("amd-xgbe: Re-issue interrupt if interrupt status not cleared")
+Signed-off-by: Jiguang Xiao <jiguang.xiao@windriver.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/amd/xgbe/xgbe-drv.c  | 3 +++
+ drivers/net/ethernet/amd/xgbe/xgbe-i2c.c  | 4 +++-
+ drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 4 +++-
+ 3 files changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+index 35659f0dbe74..c1fb1e62557c 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+@@ -1140,6 +1140,9 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata)
+       devm_free_irq(pdata->dev, pdata->dev_irq, pdata);
++      tasklet_kill(&pdata->tasklet_dev);
++      tasklet_kill(&pdata->tasklet_ecc);
++
+       if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq))
+               devm_free_irq(pdata->dev, pdata->ecc_irq, pdata);
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c
+index 4d9062d35930..530043742a07 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c
+@@ -447,8 +447,10 @@ static void xgbe_i2c_stop(struct xgbe_prv_data *pdata)
+       xgbe_i2c_disable(pdata);
+       xgbe_i2c_clear_all_interrupts(pdata);
+-      if (pdata->dev_irq != pdata->i2c_irq)
++      if (pdata->dev_irq != pdata->i2c_irq) {
+               devm_free_irq(pdata->dev, pdata->i2c_irq, pdata);
++              tasklet_kill(&pdata->tasklet_i2c);
++      }
+ }
+ static int xgbe_i2c_start(struct xgbe_prv_data *pdata)
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+index 156a0bc8ab01..97167fc9bebe 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+@@ -1390,8 +1390,10 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata)
+       /* Disable auto-negotiation */
+       xgbe_an_disable_all(pdata);
+-      if (pdata->dev_irq != pdata->an_irq)
++      if (pdata->dev_irq != pdata->an_irq) {
+               devm_free_irq(pdata->dev, pdata->an_irq, pdata);
++              tasklet_kill(&pdata->tasklet_an);
++      }
+       pdata->phy_if.phy_impl.stop(pdata);
+-- 
+2.35.1
+
diff --git a/queue-4.19/net-phy-xgmiitorgmii-fix-refcount-leak-in-xgmiitorgm.patch b/queue-4.19/net-phy-xgmiitorgmii-fix-refcount-leak-in-xgmiitorgm.patch
new file mode 100644 (file)
index 0000000..e477e21
--- /dev/null
@@ -0,0 +1,35 @@
+From 00f32d127b01efd2b60110f5d0216e834cd96b2a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Dec 2022 10:29:25 +0400
+Subject: net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe
+
+From: Miaoqian Lin <linmq006@gmail.com>
+
+[ Upstream commit d039535850ee47079d59527e96be18d8e0daa84b ]
+
+of_phy_find_device() return device node with refcount incremented.
+Call put_device() to relese it when not needed anymore.
+
+Fixes: ab4e6ee578e8 ("net: phy: xgmiitorgmii: Check phy_driver ready before accessing")
+Signed-off-by: Miaoqian Lin <linmq006@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/phy/xilinx_gmii2rgmii.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c
+index bd6084e315de..f44dc80ed3e6 100644
+--- a/drivers/net/phy/xilinx_gmii2rgmii.c
++++ b/drivers/net/phy/xilinx_gmii2rgmii.c
+@@ -91,6 +91,7 @@ static int xgmiitorgmii_probe(struct mdio_device *mdiodev)
+       if (!priv->phy_dev->drv) {
+               dev_info(dev, "Attached phy not ready\n");
++              put_device(&priv->phy_dev->mdio.dev);
+               return -EPROBE_DEFER;
+       }
+-- 
+2.35.1
+
diff --git a/queue-4.19/net-sched-atm-dont-intepret-cls-results-when-asked-t.patch b/queue-4.19/net-sched-atm-dont-intepret-cls-results-when-asked-t.patch
new file mode 100644 (file)
index 0000000..03c6e77
--- /dev/null
@@ -0,0 +1,42 @@
+From c2b8bfafcd315259417594a5dd3279e469bc6682 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Jan 2023 16:57:43 -0500
+Subject: net: sched: atm: dont intepret cls results when asked to drop
+
+From: Jamal Hadi Salim <jhs@mojatatu.com>
+
+[ Upstream commit a2965c7be0522eaa18808684b7b82b248515511b ]
+
+If asked to drop a packet via TC_ACT_SHOT it is unsafe to assume
+res.class contains a valid pointer
+Fixes: b0188d4dbe5f ("[NET_SCHED]: sch_atm: Lindent")
+
+Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sched/sch_atm.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
+index 9a1bfa13a6cd..ff825f40ea04 100644
+--- a/net/sched/sch_atm.c
++++ b/net/sched/sch_atm.c
+@@ -394,10 +394,13 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
+                               result = tcf_classify(skb, fl, &res, true);
+                               if (result < 0)
+                                       continue;
++                              if (result == TC_ACT_SHOT)
++                                      goto done;
++
+                               flow = (struct atm_flow_data *)res.class;
+                               if (!flow)
+                                       flow = lookup_flow(sch, res.classid);
+-                              goto done;
++                              goto drop;
+                       }
+               }
+               flow = NULL;
+-- 
+2.35.1
+
diff --git a/queue-4.19/nfc-fix-potential-resource-leaks.patch b/queue-4.19/nfc-fix-potential-resource-leaks.patch
new file mode 100644 (file)
index 0000000..08415aa
--- /dev/null
@@ -0,0 +1,127 @@
+From cb541bb566e5ed8fa73d2ecd272a93475d5715a3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 Dec 2022 11:37:18 +0400
+Subject: nfc: Fix potential resource leaks
+
+From: Miaoqian Lin <linmq006@gmail.com>
+
+[ Upstream commit df49908f3c52d211aea5e2a14a93bbe67a2cb3af ]
+
+nfc_get_device() take reference for the device, add missing
+nfc_put_device() to release it when not need anymore.
+Also fix the style warnning by use error EOPNOTSUPP instead of
+ENOTSUPP.
+
+Fixes: 5ce3f32b5264 ("NFC: netlink: SE API implementation")
+Fixes: 29e76924cf08 ("nfc: netlink: Add capability to reply to vendor_cmd with data")
+Signed-off-by: Miaoqian Lin <linmq006@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/nfc/netlink.c | 52 ++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 38 insertions(+), 14 deletions(-)
+
+diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
+index 39fb01ee9222..8953b03d5a52 100644
+--- a/net/nfc/netlink.c
++++ b/net/nfc/netlink.c
+@@ -1515,6 +1515,7 @@ static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info)
+       u32 dev_idx, se_idx;
+       u8 *apdu;
+       size_t apdu_len;
++      int rc;
+       if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
+           !info->attrs[NFC_ATTR_SE_INDEX] ||
+@@ -1528,25 +1529,37 @@ static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info)
+       if (!dev)
+               return -ENODEV;
+-      if (!dev->ops || !dev->ops->se_io)
+-              return -ENOTSUPP;
++      if (!dev->ops || !dev->ops->se_io) {
++              rc = -EOPNOTSUPP;
++              goto put_dev;
++      }
+       apdu_len = nla_len(info->attrs[NFC_ATTR_SE_APDU]);
+-      if (apdu_len == 0)
+-              return -EINVAL;
++      if (apdu_len == 0) {
++              rc = -EINVAL;
++              goto put_dev;
++      }
+       apdu = nla_data(info->attrs[NFC_ATTR_SE_APDU]);
+-      if (!apdu)
+-              return -EINVAL;
++      if (!apdu) {
++              rc = -EINVAL;
++              goto put_dev;
++      }
+       ctx = kzalloc(sizeof(struct se_io_ctx), GFP_KERNEL);
+-      if (!ctx)
+-              return -ENOMEM;
++      if (!ctx) {
++              rc = -ENOMEM;
++              goto put_dev;
++      }
+       ctx->dev_idx = dev_idx;
+       ctx->se_idx = se_idx;
+-      return nfc_se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx);
++      rc = nfc_se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx);
++
++put_dev:
++      nfc_put_device(dev);
++      return rc;
+ }
+ static int nfc_genl_vendor_cmd(struct sk_buff *skb,
+@@ -1569,14 +1582,21 @@ static int nfc_genl_vendor_cmd(struct sk_buff *skb,
+       subcmd = nla_get_u32(info->attrs[NFC_ATTR_VENDOR_SUBCMD]);
+       dev = nfc_get_device(dev_idx);
+-      if (!dev || !dev->vendor_cmds || !dev->n_vendor_cmds)
++      if (!dev)
+               return -ENODEV;
++      if (!dev->vendor_cmds || !dev->n_vendor_cmds) {
++              err = -ENODEV;
++              goto put_dev;
++      }
++
+       if (info->attrs[NFC_ATTR_VENDOR_DATA]) {
+               data = nla_data(info->attrs[NFC_ATTR_VENDOR_DATA]);
+               data_len = nla_len(info->attrs[NFC_ATTR_VENDOR_DATA]);
+-              if (data_len == 0)
+-                      return -EINVAL;
++              if (data_len == 0) {
++                      err = -EINVAL;
++                      goto put_dev;
++              }
+       } else {
+               data = NULL;
+               data_len = 0;
+@@ -1591,10 +1611,14 @@ static int nfc_genl_vendor_cmd(struct sk_buff *skb,
+               dev->cur_cmd_info = info;
+               err = cmd->doit(dev, data, data_len);
+               dev->cur_cmd_info = NULL;
+-              return err;
++              goto put_dev;
+       }
+-      return -EOPNOTSUPP;
++      err = -EOPNOTSUPP;
++
++put_dev:
++      nfc_put_device(dev);
++      return err;
+ }
+ /* message building helper */
+-- 
+2.35.1
+
diff --git a/queue-4.19/perf-probe-fix-to-get-the-dw_at_decl_file-and-dw_at_.patch b/queue-4.19/perf-probe-fix-to-get-the-dw_at_decl_file-and-dw_at_.patch
new file mode 100644 (file)
index 0000000..f6b0c1c
--- /dev/null
@@ -0,0 +1,92 @@
+From 84de40bf3602ddd00c4dc6f785b891adc087abb2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 5 Nov 2022 12:01:14 +0900
+Subject: perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as
+ unsinged data
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit a9dfc46c67b52ad43b8e335e28f4cf8002c67793 ]
+
+DWARF version 5 standard Sec 2.14 says that
+
+  Any debugging information entry representing the declaration of an object,
+  module, subprogram or type may have DW_AT_decl_file, DW_AT_decl_line and
+  DW_AT_decl_column attributes, each of whose value is an unsigned integer
+  constant.
+
+So it should be an unsigned integer data. Also, even though the standard
+doesn't clearly say the DW_AT_call_file is signed or unsigned, the
+elfutils (eu-readelf) interprets it as unsigned integer data and it is
+natural to handle it as unsigned integer data as same as DW_AT_decl_file.
+This changes the DW_AT_call_file as unsigned integer data too.
+
+Fixes: 3f4460a28fb2f73d ("perf probe: Filter out redundant inline-instances")
+Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
+Acked-by: Namhyung Kim <namhyung@kernel.org>
+Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: stable@vger.kernel.org
+Cc: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Link: https://lore.kernel.org/r/166761727445.480106.3738447577082071942.stgit@devnote3
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/perf/util/dwarf-aux.c | 21 ++++-----------------
+ 1 file changed, 4 insertions(+), 17 deletions(-)
+
+diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
+index 3b7386527794..6de57d9ee7cc 100644
+--- a/tools/perf/util/dwarf-aux.c
++++ b/tools/perf/util/dwarf-aux.c
+@@ -274,19 +274,6 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
+       return 0;
+ }
+-/* Get attribute and translate it as a sdata */
+-static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
+-                            Dwarf_Sword *result)
+-{
+-      Dwarf_Attribute attr;
+-
+-      if (dwarf_attr_integrate(tp_die, attr_name, &attr) == NULL ||
+-          dwarf_formsdata(&attr, result) != 0)
+-              return -ENOENT;
+-
+-      return 0;
+-}
+-
+ /**
+  * die_is_signed_type - Check whether a type DIE is signed or not
+  * @tp_die: a DIE of a type
+@@ -410,9 +397,9 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
+ /* Get the call file index number in CU DIE */
+ static int die_get_call_fileno(Dwarf_Die *in_die)
+ {
+-      Dwarf_Sword idx;
++      Dwarf_Word idx;
+-      if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0)
++      if (die_get_attr_udata(in_die, DW_AT_call_file, &idx) == 0)
+               return (int)idx;
+       else
+               return -ENOENT;
+@@ -421,9 +408,9 @@ static int die_get_call_fileno(Dwarf_Die *in_die)
+ /* Get the declared file index number in CU DIE */
+ static int die_get_decl_fileno(Dwarf_Die *pdie)
+ {
+-      Dwarf_Sword idx;
++      Dwarf_Word idx;
+-      if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0)
++      if (die_get_attr_udata(pdie, DW_AT_decl_file, &idx) == 0)
+               return (int)idx;
+       else
+               return -ENOENT;
+-- 
+2.35.1
+
diff --git a/queue-4.19/perf-probe-use-dwarf_attr_integrate-as-generic-dwarf.patch b/queue-4.19/perf-probe-use-dwarf_attr_integrate-as-generic-dwarf.patch
new file mode 100644 (file)
index 0000000..f4afa67
--- /dev/null
@@ -0,0 +1,54 @@
+From f1950d4660bd829816ab733a9e364337a32b1cb1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 1 Nov 2022 22:48:39 +0900
+Subject: perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit f828929ab7f0dc3353e4a617f94f297fa8f3dec3 ]
+
+Use dwarf_attr_integrate() instead of dwarf_attr() for generic attribute
+acccessor functions, so that it can find the specified attribute from
+abstact origin DIE etc.
+
+Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
+Acked-by: Namhyung Kim <namhyung@kernel.org>
+Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Link: https://lore.kernel.org/r/166731051988.2100653.13595339994343449770.stgit@devnote3
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Stable-dep-of: a9dfc46c67b5 ("perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged data")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/perf/util/dwarf-aux.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
+index 230e94bf7775..3b7386527794 100644
+--- a/tools/perf/util/dwarf-aux.c
++++ b/tools/perf/util/dwarf-aux.c
+@@ -267,7 +267,7 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
+ {
+       Dwarf_Attribute attr;
+-      if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
++      if (dwarf_attr_integrate(tp_die, attr_name, &attr) == NULL ||
+           dwarf_formudata(&attr, result) != 0)
+               return -ENOENT;
+@@ -280,7 +280,7 @@ static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
+ {
+       Dwarf_Attribute attr;
+-      if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
++      if (dwarf_attr_integrate(tp_die, attr_name, &attr) == NULL ||
+           dwarf_formsdata(&attr, result) != 0)
+               return -ENOENT;
+-- 
+2.35.1
+
diff --git a/queue-4.19/qlcnic-prevent-dcb-use-after-free-on-qlcnic_dcb_enab.patch b/queue-4.19/qlcnic-prevent-dcb-use-after-free-on-qlcnic_dcb_enab.patch
new file mode 100644 (file)
index 0000000..59eac7a
--- /dev/null
@@ -0,0 +1,103 @@
+From be10d9dbbec173d5e3d0a094a537c017061d9374 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 22 Dec 2022 14:52:28 +0300
+Subject: qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure
+
+From: Daniil Tatianin <d-tatianin@yandex-team.ru>
+
+[ Upstream commit 13a7c8964afcd8ca43c0b6001ebb0127baa95362 ]
+
+adapter->dcb would get silently freed inside qlcnic_dcb_enable() in
+case qlcnic_dcb_attach() would return an error, which always happens
+under OOM conditions. This would lead to use-after-free because both
+of the existing callers invoke qlcnic_dcb_get_info() on the obtained
+pointer, which is potentially freed at that point.
+
+Propagate errors from qlcnic_dcb_enable(), and instead free the dcb
+pointer at callsite using qlcnic_dcb_free(). This also removes the now
+unused qlcnic_clear_dcb_ops() helper, which was a simple wrapper around
+kfree() also causing memory leaks for partially initialized dcb.
+
+Found by Linux Verification Center (linuxtesting.org) with the SVACE
+static analysis tool.
+
+Fixes: 3c44bba1d270 ("qlcnic: Disable DCB operations from SR-IOV VFs")
+Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
+Signed-off-by: Daniil Tatianin <d-tatianin@yandex-team.ru>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c |  8 +++++++-
+ drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h       | 10 ++--------
+ drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c      |  8 +++++++-
+ 3 files changed, 16 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+index 10286215092f..85419b8258b5 100644
+--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
++++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+@@ -2525,7 +2525,13 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
+               goto disable_mbx_intr;
+       qlcnic_83xx_clear_function_resources(adapter);
+-      qlcnic_dcb_enable(adapter->dcb);
++
++      err = qlcnic_dcb_enable(adapter->dcb);
++      if (err) {
++              qlcnic_dcb_free(adapter->dcb);
++              goto disable_mbx_intr;
++      }
++
+       qlcnic_83xx_initialize_nic(adapter, 1);
+       qlcnic_dcb_get_info(adapter->dcb);
+diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h
+index 0a9d24e86715..eb8000d9b6d0 100644
+--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h
++++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h
+@@ -42,11 +42,6 @@ struct qlcnic_dcb {
+       unsigned long                   state;
+ };
+-static inline void qlcnic_clear_dcb_ops(struct qlcnic_dcb *dcb)
+-{
+-      kfree(dcb);
+-}
+-
+ static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_dcb *dcb)
+ {
+       if (dcb && dcb->ops->get_hw_capability)
+@@ -113,9 +108,8 @@ static inline void qlcnic_dcb_init_dcbnl_ops(struct qlcnic_dcb *dcb)
+               dcb->ops->init_dcbnl_ops(dcb);
+ }
+-static inline void qlcnic_dcb_enable(struct qlcnic_dcb *dcb)
++static inline int qlcnic_dcb_enable(struct qlcnic_dcb *dcb)
+ {
+-      if (dcb && qlcnic_dcb_attach(dcb))
+-              qlcnic_clear_dcb_ops(dcb);
++      return dcb ? qlcnic_dcb_attach(dcb) : 0;
+ }
+ #endif
+diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+index 43920374beae..a0c427f3b180 100644
+--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
++++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+@@ -2638,7 +2638,13 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+                        "Device does not support MSI interrupts\n");
+       if (qlcnic_82xx_check(adapter)) {
+-              qlcnic_dcb_enable(adapter->dcb);
++              err = qlcnic_dcb_enable(adapter->dcb);
++              if (err) {
++                      qlcnic_dcb_free(adapter->dcb);
++                      dev_err(&pdev->dev, "Failed to enable DCB\n");
++                      goto err_out_free_hw;
++              }
++
+               qlcnic_dcb_get_info(adapter->dcb);
+               err = qlcnic_setup_intr(adapter);
+-- 
+2.35.1
+
diff --git a/queue-4.19/ravb-fix-failed-to-switch-device-to-config-mode-mess.patch b/queue-4.19/ravb-fix-failed-to-switch-device-to-config-mode-mess.patch
new file mode 100644 (file)
index 0000000..72629b6
--- /dev/null
@@ -0,0 +1,68 @@
+From 9472dc55baeed2163760a6baee606b91394cd0c9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 14 Dec 2022 10:51:18 +0000
+Subject: ravb: Fix "failed to switch device to config mode" message during
+ unbind
+
+From: Biju Das <biju.das.jz@bp.renesas.com>
+
+[ Upstream commit c72a7e42592b2e18d862cf120876070947000d7a ]
+
+This patch fixes the error "ravb 11c20000.ethernet eth0: failed to switch
+device to config mode" during unbind.
+
+We are doing register access after pm_runtime_put_sync().
+
+We usually do cleanup in reverse order of init. Currently in
+remove(), the "pm_runtime_put_sync" is not in reverse order.
+
+Probe
+       reset_control_deassert(rstc);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
+remove
+       pm_runtime_put_sync(&pdev->dev);
+       unregister_netdev(ndev);
+       ..
+       ravb_mdio_release(priv);
+       pm_runtime_disable(&pdev->dev);
+
+Consider the call to unregister_netdev()
+unregister_netdev->unregister_netdevice_queue->rollback_registered_many
+that calls the below functions which access the registers after
+pm_runtime_put_sync()
+ 1) ravb_get_stats
+ 2) ravb_close
+
+Fixes: c156633f1353 ("Renesas Ethernet AVB driver proper")
+Cc: stable@vger.kernel.org
+Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
+Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
+Link: https://lore.kernel.org/r/20221214105118.2495313-1-biju.das.jz@bp.renesas.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/renesas/ravb_main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
+index 9077014f6f40..ff374d0d80a7 100644
+--- a/drivers/net/ethernet/renesas/ravb_main.c
++++ b/drivers/net/ethernet/renesas/ravb_main.c
+@@ -2199,11 +2199,11 @@ static int ravb_remove(struct platform_device *pdev)
+                         priv->desc_bat_dma);
+       /* Set reset mode */
+       ravb_write(ndev, CCC_OPC_RESET, CCC);
+-      pm_runtime_put_sync(&pdev->dev);
+       unregister_netdev(ndev);
+       netif_napi_del(&priv->napi[RAVB_NC]);
+       netif_napi_del(&priv->napi[RAVB_BE]);
+       ravb_mdio_release(priv);
++      pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       free_netdev(ndev);
+       platform_set_drvdata(pdev, NULL);
+-- 
+2.35.1
+
diff --git a/queue-4.19/rdma-mlx5-fix-validation-of-max_rd_atomic-caps-for-d.patch b/queue-4.19/rdma-mlx5-fix-validation-of-max_rd_atomic-caps-for-d.patch
new file mode 100644 (file)
index 0000000..32f73b1
--- /dev/null
@@ -0,0 +1,95 @@
+From 7210d3e68b898423c7c81bba0a1191ab9099767c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 28 Dec 2022 14:56:10 +0200
+Subject: RDMA/mlx5: Fix validation of max_rd_atomic caps for DC
+
+From: Maor Gottlieb <maorg@nvidia.com>
+
+[ Upstream commit 8de8482fe5732fbef4f5af82bc0c0362c804cd1f ]
+
+Currently, when modifying DC, we validate max_rd_atomic user attribute
+against the RC cap, validate against DC. RC and DC QP types have different
+device limitations.
+
+This can cause userspace created DC QPs to malfunction.
+
+Fixes: c32a4f296e1d ("IB/mlx5: Add support for DC Initiator QP")
+Link: https://lore.kernel.org/r/0c5aee72cea188c3bb770f4207cce7abc9b6fc74.1672231736.git.leonro@nvidia.com
+Signed-off-by: Maor Gottlieb <maorg@nvidia.com>
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/infiniband/hw/mlx5/qp.c | 49 +++++++++++++++++++++++----------
+ 1 file changed, 35 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
+index 361b1b859782..1520a3098f7d 100644
+--- a/drivers/infiniband/hw/mlx5/qp.c
++++ b/drivers/infiniband/hw/mlx5/qp.c
+@@ -3411,6 +3411,40 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+       return err;
+ }
++static int validate_rd_atomic(struct mlx5_ib_dev *dev, struct ib_qp_attr *attr,
++                            int attr_mask, enum ib_qp_type qp_type)
++{
++      int log_max_ra_res;
++      int log_max_ra_req;
++
++      if (qp_type == MLX5_IB_QPT_DCI) {
++              log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev,
++                                                 log_max_ra_res_dc);
++              log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev,
++                                                 log_max_ra_req_dc);
++      } else {
++              log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev,
++                                                 log_max_ra_res_qp);
++              log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev,
++                                                 log_max_ra_req_qp);
++      }
++
++      if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
++          attr->max_rd_atomic > log_max_ra_res) {
++              mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n",
++                          attr->max_rd_atomic);
++              return false;
++      }
++
++      if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
++          attr->max_dest_rd_atomic > log_max_ra_req) {
++              mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n",
++                          attr->max_dest_rd_atomic);
++              return false;
++      }
++      return true;
++}
++
+ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+                     int attr_mask, struct ib_udata *udata)
+ {
+@@ -3508,21 +3542,8 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+               }
+       }
+-      if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
+-          attr->max_rd_atomic >
+-          (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_res_qp))) {
+-              mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n",
+-                          attr->max_rd_atomic);
+-              goto out;
+-      }
+-
+-      if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
+-          attr->max_dest_rd_atomic >
+-          (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_req_qp))) {
+-              mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n",
+-                          attr->max_dest_rd_atomic);
++      if (!validate_rd_atomic(dev, attr, attr_mask, qp_type))
+               goto out;
+-      }
+       if (cur_state == new_state && cur_state == IB_QPS_RESET) {
+               err = 0;
+-- 
+2.35.1
+
diff --git a/queue-4.19/riscv-remove-unreachable-have_function_graph_ret_add.patch b/queue-4.19/riscv-remove-unreachable-have_function_graph_ret_add.patch
new file mode 100644 (file)
index 0000000..3c1944f
--- /dev/null
@@ -0,0 +1,39 @@
+From 8bc6d6af4c47438cd8ac86927f6072797bed3786 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Apr 2019 11:14:39 +0200
+Subject: riscv: remove unreachable !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR code
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit 877425424d6c853b804e6b6a6045a5b4ea97c510 ]
+
+HAVE_FUNCTION_GRAPH_RET_ADDR_PTR is always defined for RISC-V.
+
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
+Stable-dep-of: 5c3022e4a616 ("riscv: stacktrace: Fixup ftrace_graph_ret_addr retp argument")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/kernel/stacktrace.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
+index 74b2168d7298..39cd3cf9f06b 100644
+--- a/arch/riscv/kernel/stacktrace.c
++++ b/arch/riscv/kernel/stacktrace.c
+@@ -64,12 +64,8 @@ static void notrace walk_stackframe(struct task_struct *task,
+               frame = (struct stackframe *)fp - 1;
+               sp = fp;
+               fp = frame->fp;
+-#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
+               pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
+                                          (unsigned long *)(fp - 8));
+-#else
+-              pc = frame->ra - 0x4;
+-#endif
+       }
+ }
+-- 
+2.35.1
+
diff --git a/queue-4.19/riscv-stacktrace-fix-stack-output-without-ra-on-the-.patch b/queue-4.19/riscv-stacktrace-fix-stack-output-without-ra-on-the-.patch
new file mode 100644 (file)
index 0000000..20041f6
--- /dev/null
@@ -0,0 +1,72 @@
+From 25e0560ab7e86c2b9ddd753f22b26fdb0f928ccf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 11 Jan 2021 20:40:14 +0800
+Subject: riscv/stacktrace: Fix stack output without ra on the stack top
+
+From: Chen Huang <chenhuang5@huawei.com>
+
+[ Upstream commit f766f77a74f5784d8d4d3c36b1900731f97d08d0 ]
+
+When a function doesn't have a callee, then it will not
+push ra into the stack, such as lkdtm_BUG() function,
+
+addi   sp,sp,-16
+sd     s0,8(sp)
+addi   s0,sp,16
+ebreak
+
+The struct stackframe use {fp,ra} to get information from
+stack, if walk_stackframe() with pr_regs, we will obtain
+wrong value and bad stacktrace,
+
+[<ffffffe00066c56c>] lkdtm_BUG+0x6/0x8
+---[ end trace 18da3fbdf08e25d5 ]---
+
+Correct the next fp and pc, after that, full stacktrace
+shown as expects,
+
+[<ffffffe00066c56c>] lkdtm_BUG+0x6/0x8
+[<ffffffe0008b24a4>] lkdtm_do_action+0x14/0x1c
+[<ffffffe00066c372>] direct_entry+0xc0/0x10a
+[<ffffffe000439f86>] full_proxy_write+0x42/0x6a
+[<ffffffe000309626>] vfs_write+0x7e/0x214
+[<ffffffe00030992a>] ksys_write+0x98/0xc0
+[<ffffffe000309960>] sys_write+0xe/0x16
+[<ffffffe0002014bc>] ret_from_syscall+0x0/0x2
+---[ end trace 61917f3d9a9fadcd ]---
+
+Signed-off-by: Chen Huang <chenhuang5@huawei.com>
+Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
+Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
+Stable-dep-of: 5c3022e4a616 ("riscv: stacktrace: Fixup ftrace_graph_ret_addr retp argument")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/kernel/stacktrace.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
+index 39cd3cf9f06b..3d1e184e39e9 100644
+--- a/arch/riscv/kernel/stacktrace.c
++++ b/arch/riscv/kernel/stacktrace.c
+@@ -63,9 +63,15 @@ static void notrace walk_stackframe(struct task_struct *task,
+               /* Unwind stack frame */
+               frame = (struct stackframe *)fp - 1;
+               sp = fp;
+-              fp = frame->fp;
+-              pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
+-                                         (unsigned long *)(fp - 8));
++              if (regs && (regs->epc == pc) && (frame->fp & 0x7)) {
++                      fp = frame->ra;
++                      pc = regs->ra;
++              } else {
++                      fp = frame->fp;
++                      pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
++                                                 (unsigned long *)(fp - 8));
++              }
++
+       }
+ }
+-- 
+2.35.1
+
diff --git a/queue-4.19/riscv-stacktrace-fixup-ftrace_graph_ret_addr-retp-ar.patch b/queue-4.19/riscv-stacktrace-fixup-ftrace_graph_ret_addr-retp-ar.patch
new file mode 100644 (file)
index 0000000..12152b1
--- /dev/null
@@ -0,0 +1,41 @@
+From 72dea6c020220e8f4916d698293730b8f3dc8b27 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 9 Nov 2022 01:49:36 -0500
+Subject: riscv: stacktrace: Fixup ftrace_graph_ret_addr retp argument
+
+From: Guo Ren <guoren@linux.alibaba.com>
+
+[ Upstream commit 5c3022e4a616d800cf5f4c3a981d7992179e44a1 ]
+
+The 'retp' is a pointer to the return address on the stack, so we
+must pass the current return address pointer as the 'retp'
+argument to ftrace_push_return_trace(). Not parent function's
+return address on the stack.
+
+Fixes: b785ec129bd9 ("riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support")
+Signed-off-by: Guo Ren <guoren@linux.alibaba.com>
+Signed-off-by: Guo Ren <guoren@kernel.org>
+Link: https://lore.kernel.org/r/20221109064937.3643993-2-guoren@kernel.org
+Cc: stable@vger.kernel.org
+Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/riscv/kernel/stacktrace.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
+index 3d1e184e39e9..75ed5b5b1f9b 100644
+--- a/arch/riscv/kernel/stacktrace.c
++++ b/arch/riscv/kernel/stacktrace.c
+@@ -69,7 +69,7 @@ static void notrace walk_stackframe(struct task_struct *task,
+               } else {
+                       fp = frame->fp;
+                       pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
+-                                                 (unsigned long *)(fp - 8));
++                                                 &frame->ra);
+               }
+       }
+-- 
+2.35.1
+
index 00592d24c1343d6b9f68ac434caaf01ec99f9c0c..b85c1edf2dd2af942b302fc0035a9fb7913fe061 100644 (file)
@@ -423,3 +423,33 @@ btrfs-replace-strncpy-with-strscpy.patch
 media-s5p-mfc-fix-to-handle-reference-queue-during-f.patch
 media-s5p-mfc-clear-workbit-to-handle-error-conditio.patch
 media-s5p-mfc-fix-in-register-read-and-write-for-h26.patch
+dm-thin-resume-even-if-in-fail-mode.patch
+perf-probe-use-dwarf_attr_integrate-as-generic-dwarf.patch
+perf-probe-fix-to-get-the-dw_at_decl_file-and-dw_at_.patch
+ravb-fix-failed-to-switch-device-to-config-mode-mess.patch
+riscv-remove-unreachable-have_function_graph_ret_add.patch
+riscv-stacktrace-fix-stack-output-without-ra-on-the-.patch
+riscv-stacktrace-fixup-ftrace_graph_ret_addr-retp-ar.patch
+driver-core-set-deferred_probe_timeout-to-a-longer-d.patch
+ext4-goto-right-label-failed_mount3a.patch
+ext4-correct-inconsistent-error-msg-in-nojournal-mod.patch
+ext4-use-kmemdup-to-replace-kmalloc-memcpy.patch
+mbcache-don-t-reclaim-used-entries.patch
+mbcache-add-functions-to-delete-entry-if-unused.patch
+ext4-remove-ea-inode-entry-from-mbcache-on-inode-evi.patch
+ext4-unindent-codeblock-in-ext4_xattr_block_set.patch
+ext4-fix-race-when-reusing-xattr-blocks.patch
+mbcache-automatically-delete-entries-from-cache-on-f.patch
+ext4-fix-deadlock-due-to-mbcache-entry-corruption.patch
+sunrpc-ensure-the-matching-upcall-is-in-flight-upon-.patch
+bpf-pull-before-calling-skb_postpull_rcsum.patch
+qlcnic-prevent-dcb-use-after-free-on-qlcnic_dcb_enab.patch
+nfc-fix-potential-resource-leaks.patch
+net-amd-xgbe-add-missed-tasklet_kill.patch
+net-phy-xgmiitorgmii-fix-refcount-leak-in-xgmiitorgm.patch
+rdma-mlx5-fix-validation-of-max_rd_atomic-caps-for-d.patch
+net-sched-atm-dont-intepret-cls-results-when-asked-t.patch
+usb-rndis_host-secure-rndis_query-check-against-int-.patch
+caif-fix-memory-leak-in-cfctrl_linkup_request.patch
+udf-fix-extension-of-the-last-extent-in-the-file.patch
+asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch
diff --git a/queue-4.19/sunrpc-ensure-the-matching-upcall-is-in-flight-upon-.patch b/queue-4.19/sunrpc-ensure-the-matching-upcall-is-in-flight-upon-.patch
new file mode 100644 (file)
index 0000000..3df8bd8
--- /dev/null
@@ -0,0 +1,133 @@
+From 2dd149c938913e7c12d2cbc69d0e50e5b3f0d756 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Dec 2022 13:14:31 +0900
+Subject: SUNRPC: ensure the matching upcall is in-flight upon downcall
+
+From: minoura makoto <minoura@valinux.co.jp>
+
+[ Upstream commit b18cba09e374637a0a3759d856a6bca94c133952 ]
+
+Commit 9130b8dbc6ac ("SUNRPC: allow for upcalls for the same uid
+but different gss service") introduced `auth` argument to
+__gss_find_upcall(), but in gss_pipe_downcall() it was left as NULL
+since it (and auth->service) was not (yet) determined.
+
+When multiple upcalls with the same uid and different service are
+ongoing, it could happen that __gss_find_upcall(), which returns the
+first match found in the pipe->in_downcall list, could not find the
+correct gss_msg corresponding to the downcall we are looking for.
+Moreover, it might return a msg which is not sent to rpc.gssd yet.
+
+We could see mount.nfs process hung in D state with multiple mount.nfs
+are executed in parallel.  The call trace below is of CentOS 7.9
+kernel-3.10.0-1160.24.1.el7.x86_64 but we observed the same hang w/
+elrepo kernel-ml-6.0.7-1.el7.
+
+PID: 71258  TASK: ffff91ebd4be0000  CPU: 36  COMMAND: "mount.nfs"
+ #0 [ffff9203ca3234f8] __schedule at ffffffffa3b8899f
+ #1 [ffff9203ca323580] schedule at ffffffffa3b88eb9
+ #2 [ffff9203ca323590] gss_cred_init at ffffffffc0355818 [auth_rpcgss]
+ #3 [ffff9203ca323658] rpcauth_lookup_credcache at ffffffffc0421ebc
+[sunrpc]
+ #4 [ffff9203ca3236d8] gss_lookup_cred at ffffffffc0353633 [auth_rpcgss]
+ #5 [ffff9203ca3236e8] rpcauth_lookupcred at ffffffffc0421581 [sunrpc]
+ #6 [ffff9203ca323740] rpcauth_refreshcred at ffffffffc04223d3 [sunrpc]
+ #7 [ffff9203ca3237a0] call_refresh at ffffffffc04103dc [sunrpc]
+ #8 [ffff9203ca3237b8] __rpc_execute at ffffffffc041e1c9 [sunrpc]
+ #9 [ffff9203ca323820] rpc_execute at ffffffffc0420a48 [sunrpc]
+
+The scenario is like this. Let's say there are two upcalls for
+services A and B, A -> B in pipe->in_downcall, B -> A in pipe->pipe.
+
+When rpc.gssd reads pipe to get the upcall msg corresponding to
+service B from pipe->pipe and then writes the response, in
+gss_pipe_downcall the msg corresponding to service A will be picked
+because only uid is used to find the msg and it is before the one for
+B in pipe->in_downcall.  And the process waiting for the msg
+corresponding to service A will be woken up.
+
+Actual scheduing of that process might be after rpc.gssd processes the
+next msg.  In rpc_pipe_generic_upcall it clears msg->errno (for A).
+The process is scheduled to see gss_msg->ctx == NULL and
+gss_msg->msg.errno == 0, therefore it cannot break the loop in
+gss_create_upcall and is never woken up after that.
+
+This patch adds a simple check to ensure that a msg which is not
+sent to rpc.gssd yet is not chosen as the matching upcall upon
+receiving a downcall.
+
+Signed-off-by: minoura makoto <minoura@valinux.co.jp>
+Signed-off-by: Hiroshi Shimamoto <h-shimamoto@nec.com>
+Tested-by: Hiroshi Shimamoto <h-shimamoto@nec.com>
+Cc: Trond Myklebust <trondmy@hammerspace.com>
+Fixes: 9130b8dbc6ac ("SUNRPC: allow for upcalls for same uid but different gss service")
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/sunrpc/rpc_pipe_fs.h |  5 +++++
+ net/sunrpc/auth_gss/auth_gss.c     | 19 +++++++++++++++++--
+ 2 files changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
+index e90b9bd99ded..396de2ef8767 100644
+--- a/include/linux/sunrpc/rpc_pipe_fs.h
++++ b/include/linux/sunrpc/rpc_pipe_fs.h
+@@ -94,6 +94,11 @@ extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *,
+                                      char __user *, size_t);
+ extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *);
++/* returns true if the msg is in-flight, i.e., already eaten by the peer */
++static inline bool rpc_msg_is_inflight(const struct rpc_pipe_msg *msg) {
++      return (msg->copied != 0 && list_empty(&msg->list));
++}
++
+ struct rpc_clnt;
+ extern struct dentry *rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *);
+ extern int rpc_remove_client_dir(struct rpc_clnt *);
+diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
+index e61c48c1b37d..c11e68539602 100644
+--- a/net/sunrpc/auth_gss/auth_gss.c
++++ b/net/sunrpc/auth_gss/auth_gss.c
+@@ -323,7 +323,7 @@ __gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid, const struct gss_auth *auth
+       list_for_each_entry(pos, &pipe->in_downcall, list) {
+               if (!uid_eq(pos->uid, uid))
+                       continue;
+-              if (auth && pos->auth->service != auth->service)
++              if (pos->auth->service != auth->service)
+                       continue;
+               refcount_inc(&pos->count);
+               dprintk("RPC:       %s found msg %p\n", __func__, pos);
+@@ -677,6 +677,21 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
+       return err;
+ }
++static struct gss_upcall_msg *
++gss_find_downcall(struct rpc_pipe *pipe, kuid_t uid)
++{
++      struct gss_upcall_msg *pos;
++      list_for_each_entry(pos, &pipe->in_downcall, list) {
++              if (!uid_eq(pos->uid, uid))
++                      continue;
++              if (!rpc_msg_is_inflight(&pos->msg))
++                      continue;
++              refcount_inc(&pos->count);
++              return pos;
++      }
++      return NULL;
++}
++
+ #define MSG_BUF_MAXSIZE 1024
+ static ssize_t
+@@ -723,7 +738,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
+       err = -ENOENT;
+       /* Find a matching upcall */
+       spin_lock(&pipe->lock);
+-      gss_msg = __gss_find_upcall(pipe, uid, NULL);
++      gss_msg = gss_find_downcall(pipe, uid);
+       if (gss_msg == NULL) {
+               spin_unlock(&pipe->lock);
+               goto err_put_ctx;
+-- 
+2.35.1
+
diff --git a/queue-4.19/udf-fix-extension-of-the-last-extent-in-the-file.patch b/queue-4.19/udf-fix-extension-of-the-last-extent-in-the-file.patch
new file mode 100644 (file)
index 0000000..af43eb9
--- /dev/null
@@ -0,0 +1,37 @@
+From 38f877f49a704493a6b5d51ec63f77d23bfdfb16 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 21 Dec 2022 17:45:51 +0100
+Subject: udf: Fix extension of the last extent in the file
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit 83c7423d1eb6806d13c521d1002cc1a012111719 ]
+
+When extending the last extent in the file within the last block, we
+wrongly computed the length of the last extent. This is mostly a
+cosmetical problem since the extent does not contain any data and the
+length will be fixed up by following operations but still.
+
+Fixes: 1f3868f06855 ("udf: Fix extending file within last block")
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/udf/inode.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/udf/inode.c b/fs/udf/inode.c
+index 8ff8cd0d2801..55a86120e756 100644
+--- a/fs/udf/inode.c
++++ b/fs/udf/inode.c
+@@ -595,7 +595,7 @@ static void udf_do_extend_final_block(struct inode *inode,
+        */
+       if (new_elen <= (last_ext->extLength & UDF_EXTENT_LENGTH_MASK))
+               return;
+-      added_bytes = (last_ext->extLength & UDF_EXTENT_LENGTH_MASK) - new_elen;
++      added_bytes = new_elen - (last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+       last_ext->extLength += added_bytes;
+       UDF_I(inode)->i_lenExtents += added_bytes;
+-- 
+2.35.1
+
diff --git a/queue-4.19/usb-rndis_host-secure-rndis_query-check-against-int-.patch b/queue-4.19/usb-rndis_host-secure-rndis_query-check-against-int-.patch
new file mode 100644 (file)
index 0000000..67c4946
--- /dev/null
@@ -0,0 +1,43 @@
+From 222ef43d7b1aa8025766444d3cdefd14761c0a87 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Jan 2023 10:17:09 +0100
+Subject: usb: rndis_host: Secure rndis_query check against int overflow
+
+From: Szymon Heidrich <szymon.heidrich@gmail.com>
+
+[ Upstream commit c7dd13805f8b8fc1ce3b6d40f6aff47e66b72ad2 ]
+
+Variables off and len typed as uint32 in rndis_query function
+are controlled by incoming RNDIS response message thus their
+value may be manipulated. Setting off to a unexpectetly large
+value will cause the sum with len and 8 to overflow and pass
+the implemented validation step. Consequently the response
+pointer will be referring to a location past the expected
+buffer boundaries allowing information leakage e.g. via
+RNDIS_OID_802_3_PERMANENT_ADDRESS OID.
+
+Fixes: ddda08624013 ("USB: rndis_host, various cleanups")
+Signed-off-by: Szymon Heidrich <szymon.heidrich@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/usb/rndis_host.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
+index ab41a63aa4aa..497d6bcdc276 100644
+--- a/drivers/net/usb/rndis_host.c
++++ b/drivers/net/usb/rndis_host.c
+@@ -267,7 +267,8 @@ static int rndis_query(struct usbnet *dev, struct usb_interface *intf,
+       off = le32_to_cpu(u.get_c->offset);
+       len = le32_to_cpu(u.get_c->len);
+-      if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE))
++      if (unlikely((off > CONTROL_BUFFER_SIZE - 8) ||
++                   (len > CONTROL_BUFFER_SIZE - 8 - off)))
+               goto response_error;
+       if (*reply_len != -1 && len != *reply_len)
+-- 
+2.35.1
+