From: Greg Kroah-Hartman Date: Mon, 13 Apr 2026 14:43:27 +0000 (+0200) Subject: 5.10-stable patches X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c0926a423fa3e3a0d8a899f4e0a65525c16b31aa;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: batman-adv-avoid-ogm-aggregation-when-skb-tailroom-is-insufficient.patch bluetooth-l2cap-fix-accepting-multiple-l2cap_ecred_conn_req.patch cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch cpufreq-governor-free-dbs_data-directly-when-gov-init-fails.patch device-property-add-fwnode_is_ancestor_of-and-fwnode_get_next_parent_dev.patch device-property-allow-error-pointer-to-be-passed-to-fwnode-apis.patch device-property-allow-secondary-lookup-in-fwnode_get_next_child_node.patch device-property-check-fwnode-secondary-in-fwnode_graph_get_next_endpoint.patch device-property-check-fwnode-secondary-when-finding-properties.patch device-property-retrieve-fwnode-from-of_node-via-accessor.patch device-property-unify-access-to-of_node.patch drm-fix-use-after-free-on-framebuffers-and-property-blobs-when-calling-drm_dev_unplug.patch ext4-fix-iloc.bh-leak-in-ext4_fc_replay_inode-error-paths.patch ext4-fix-the-might_sleep-warnings-in-kvfree.patch ext4-publish-jinode-after-initialization.patch media-device-property-return-true-in-fwnode_device_is_available-for-null-ops.patch mm-huge_memory-fix-folio-isn-t-locked-in-softleaf_to_folio.patch mmc-core-avoid-bitfield-rmw-for-claim-retune-flags.patch mmc-core-drop-redundant-member-in-struct-mmc-host.patch mmc-core-drop-reference-counting-of-the-bus_ops.patch mmc-core-drop-superfluous-validations-in-mmc_hw-sw_reset.patch net-macb-move-devm_-free-request-_irq-out-of-spin-lock-area.patch net-rfkill-prevent-unlimited-numbers-of-rfkill-events-from-being-created.patch nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch revert-nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch s390-syscalls-add-spectre-boundary-for-syscall-dispatch-table.patch seg6-separate-dst_cache-for-input-and-output-paths-in-seg6-lwtunnel.patch usb-gadget-f_hid-move-list-and-spinlock-inits-from-bind-to-alloc.patch usb-gadget-u_ether-fix-race-between-gether_disconnect-and-eth_stop.patch usb-gadget-uvc-fix-null-pointer-dereference-during-unbind-race.patch xfs-save-ailp-before-dropping-the-ail-lock-in-push-callbacks.patch xfs-stop-reclaim-before-pushing-ail-during-unmount.patch --- diff --git a/queue-5.10/batman-adv-avoid-ogm-aggregation-when-skb-tailroom-is-insufficient.patch b/queue-5.10/batman-adv-avoid-ogm-aggregation-when-skb-tailroom-is-insufficient.patch new file mode 100644 index 0000000000..d0367105bb --- /dev/null +++ b/queue-5.10/batman-adv-avoid-ogm-aggregation-when-skb-tailroom-is-insufficient.patch @@ -0,0 +1,50 @@ +From stable+bounces-227509-greg=kroah.com@vger.kernel.org Fri Mar 20 11:18:34 2026 +From: Sven Eckelmann +Date: Fri, 20 Mar 2026 11:12:23 +0100 +Subject: batman-adv: avoid OGM aggregation when skb tailroom is insufficient +To: stable@vger.kernel.org +Cc: Yang Yang , Yifan Wu , Juefei Pu , Yuan Tan , Xin Liu , Sven Eckelmann , Simon Wunderlich +Message-ID: <20260320101223.1554036-1-sven@narfation.org> + +From: Yang Yang + +commit 0d4aef630be9d5f9c1227d07669c26c4383b5ad0 upstream. + +When OGM aggregation state is toggled at runtime, an existing forwarded +packet may have been allocated with only packet_len bytes, while a later +packet can still be selected for aggregation. Appending in this case can +hit skb_put overflow conditions. + +Reject aggregation when the target skb tailroom cannot accommodate the new +packet. The caller then falls back to creating a new forward packet +instead of appending. + +Fixes: c6c8fea29769 ("net: Add batman-adv meshing protocol") +Cc: stable@vger.kernel.org +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Signed-off-by: Yuan Tan +Signed-off-by: Xin Liu +Signed-off-by: Ao Zhou +Signed-off-by: Yang Yang +Signed-off-by: Sven Eckelmann +Signed-off-by: Simon Wunderlich +[ Adjust context ] +Signed-off-by: Sven Eckelmann +Signed-off-by: Greg Kroah-Hartman +--- + net/batman-adv/bat_iv_ogm.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/batman-adv/bat_iv_ogm.c ++++ b/net/batman-adv/bat_iv_ogm.c +@@ -466,6 +466,9 @@ batadv_iv_ogm_can_aggregate(const struct + !time_after_eq(aggregation_end_time, forw_packet->send_time)) + return false; + ++ if (skb_tailroom(forw_packet->skb) < packet_len) ++ return false; ++ + if (aggregated_bytes > BATADV_MAX_AGGREGATION_BYTES) + return false; + diff --git a/queue-5.10/bluetooth-l2cap-fix-accepting-multiple-l2cap_ecred_conn_req.patch b/queue-5.10/bluetooth-l2cap-fix-accepting-multiple-l2cap_ecred_conn_req.patch new file mode 100644 index 0000000000..13176d31c9 --- /dev/null +++ b/queue-5.10/bluetooth-l2cap-fix-accepting-multiple-l2cap_ecred_conn_req.patch @@ -0,0 +1,64 @@ +From stable+bounces-227805-greg=kroah.com@vger.kernel.org Sun Mar 22 02:30:47 2026 +From: Sasha Levin +Date: Sat, 21 Mar 2026 21:30:42 -0400 +Subject: Bluetooth: L2CAP: Fix accepting multiple L2CAP_ECRED_CONN_REQ +To: stable@vger.kernel.org +Cc: Luiz Augusto von Dentz , Yiming Qian , Sasha Levin +Message-ID: <20260322013042.677010-1-sashal@kernel.org> + +From: Luiz Augusto von Dentz + +[ Upstream commit 5b3e2052334f2ff6d5200e952f4aa66994d09899 ] + +Currently the code attempts to accept requests regardless of the +command identifier which may cause multiple requests to be marked +as pending (FLAG_DEFER_SETUP) which can cause more than +L2CAP_ECRED_MAX_CID(5) to be allocated in l2cap_ecred_rsp_defer +causing an overflow. + +The spec is quite clear that the same identifier shall not be used on +subsequent requests: + +'Within each signaling channel a different Identifier shall be used +for each successive request or indication.' +https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-62/out/en/host/logical-link-control-and-adaptation-protocol-specification.html#UUID-32a25a06-4aa4-c6c7-77c5-dcfe3682355d + +So this attempts to check if there are any channels pending with the +same identifier and rejects if any are found. + +Fixes: 15f02b910562 ("Bluetooth: L2CAP: Add initial code for Enhanced Credit Based Mode") +Reported-by: Yiming Qian +Signed-off-by: Luiz Augusto von Dentz +[ adapted variable names ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/bluetooth/l2cap_core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -6053,7 +6053,7 @@ static inline int l2cap_ecred_conn_req(s + u16 mtu, mps; + __le16 psm; + u8 result, len = 0; +- int i, num_scid; ++ int i, num_scid = 0; + bool defer = false; + + if (!enable_ecred) +@@ -6063,6 +6063,14 @@ static inline int l2cap_ecred_conn_req(s + result = L2CAP_CR_LE_INVALID_PARAMS; + goto response; + } ++ ++ /* Check if there are no pending channels with the same ident */ ++ __l2cap_chan_list_id(conn, cmd->ident, l2cap_ecred_list_defer, ++ &num_scid); ++ if (num_scid) { ++ result = L2CAP_CR_LE_INVALID_PARAMS; ++ goto response; ++ } + + cmd_len -= sizeof(*req); + num_scid = cmd_len / sizeof(u16); diff --git a/queue-5.10/cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch b/queue-5.10/cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch new file mode 100644 index 0000000000..e773287cc1 --- /dev/null +++ b/queue-5.10/cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch @@ -0,0 +1,56 @@ +From stable+bounces-233898-greg=kroah.com@vger.kernel.org Wed Apr 8 15:02:11 2026 +From: Sasha Levin +Date: Wed, 8 Apr 2026 09:02:02 -0400 +Subject: cpufreq: governor: fix double free in cpufreq_dbs_governor_init() error path +To: stable@vger.kernel.org +Cc: Guangshuo Li , Zhongqiu Han , Viresh Kumar , "Rafael J. Wysocki" , Sasha Levin +Message-ID: <20260408130202.1050557-2-sashal@kernel.org> + +From: Guangshuo Li + +[ Upstream commit 6dcf9d0064ce2f3e3dfe5755f98b93abe6a98e1e ] + +When kobject_init_and_add() fails, cpufreq_dbs_governor_init() calls +kobject_put(&dbs_data->attr_set.kobj). + +The kobject release callback cpufreq_dbs_data_release() calls +gov->exit(dbs_data) and kfree(dbs_data), but the current error path +then calls gov->exit(dbs_data) and kfree(dbs_data) again, causing a +double free. + +Keep the direct kfree(dbs_data) for the gov->init() failure path, but +after kobject_init_and_add() has been called, let kobject_put() handle +the cleanup through cpufreq_dbs_data_release(). + +Fixes: 4ebe36c94aed ("cpufreq: Fix kobject memleak") +Signed-off-by: Guangshuo Li +Reviewed-by: Zhongqiu Han +Acked-by: Viresh Kumar +Cc: All applicable +Link: https://patch.msgid.link/20260401024535.1395801-1-lgs201920130244@gmail.com +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/cpufreq/cpufreq_governor.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/cpufreq/cpufreq_governor.c ++++ b/drivers/cpufreq/cpufreq_governor.c +@@ -457,13 +457,13 @@ int cpufreq_dbs_governor_init(struct cpu + /* Failure, so roll back. */ + pr_err("initialization failed (dbs_data kobject init error %d)\n", ret); + +- kobject_put(&dbs_data->attr_set.kobj); +- + policy->governor_data = NULL; + + if (!have_governor_per_policy()) + gov->gdbs_data = NULL; +- gov->exit(dbs_data); ++ ++ kobject_put(&dbs_data->attr_set.kobj); ++ goto free_policy_dbs_info; + + free_dbs_data: + kfree(dbs_data); diff --git a/queue-5.10/cpufreq-governor-free-dbs_data-directly-when-gov-init-fails.patch b/queue-5.10/cpufreq-governor-free-dbs_data-directly-when-gov-init-fails.patch new file mode 100644 index 0000000000..ae78a290eb --- /dev/null +++ b/queue-5.10/cpufreq-governor-free-dbs_data-directly-when-gov-init-fails.patch @@ -0,0 +1,46 @@ +From stable+bounces-233897-greg=kroah.com@vger.kernel.org Wed Apr 8 15:02:09 2026 +From: Sasha Levin +Date: Wed, 8 Apr 2026 09:02:01 -0400 +Subject: cpufreq: governor: Free dbs_data directly when gov->init() fails +To: stable@vger.kernel.org +Cc: Liao Chang , Viresh Kumar , "Rafael J. Wysocki" , Sasha Levin +Message-ID: <20260408130202.1050557-1-sashal@kernel.org> + +From: Liao Chang + +[ Upstream commit 916f13884042f615cfbfc0b42cc68dadee826f2a ] + +Due to the kobject embedded in the dbs_data doest not has a release() +method yet, it needs to use kfree() to free dbs_data directly when +governor fails to allocate the tunner field of dbs_data. + +Signed-off-by: Liao Chang +Acked-by: Viresh Kumar +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 6dcf9d0064ce ("cpufreq: governor: fix double free in cpufreq_dbs_governor_init() error path") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/cpufreq/cpufreq_governor.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/cpufreq/cpufreq_governor.c ++++ b/drivers/cpufreq/cpufreq_governor.c +@@ -430,7 +430,7 @@ int cpufreq_dbs_governor_init(struct cpu + + ret = gov->init(dbs_data); + if (ret) +- goto free_policy_dbs_info; ++ goto free_dbs_data; + + /* + * The sampling interval should not be less than the transition latency +@@ -464,6 +464,8 @@ int cpufreq_dbs_governor_init(struct cpu + if (!have_governor_per_policy()) + gov->gdbs_data = NULL; + gov->exit(dbs_data); ++ ++free_dbs_data: + kfree(dbs_data); + + free_policy_dbs_info: diff --git a/queue-5.10/device-property-add-fwnode_is_ancestor_of-and-fwnode_get_next_parent_dev.patch b/queue-5.10/device-property-add-fwnode_is_ancestor_of-and-fwnode_get_next_parent_dev.patch new file mode 100644 index 0000000000..eb9b974863 --- /dev/null +++ b/queue-5.10/device-property-add-fwnode_is_ancestor_of-and-fwnode_get_next_parent_dev.patch @@ -0,0 +1,113 @@ +From sashal@kernel.org Tue Mar 17 18:19:58 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:19:47 -0400 +Subject: device property: Add fwnode_is_ancestor_of() and fwnode_get_next_parent_dev() +To: stable@vger.kernel.org +Cc: Saravana Kannan , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260317171954.238398-1-sashal@kernel.org> + +From: Saravana Kannan + +[ Upstream commit b5d3e2fbcb10957521af14c4256cd0e5f68b9234 ] + +Add fwnode_is_ancestor_of() helper function to check if a fwnode is an +ancestor of another fwnode. + +Add fwnode_get_next_parent_dev() helper function that take as input a +fwnode and finds the closest ancestor fwnode that has a corresponding +struct device and returns that struct device. + +Signed-off-by: Saravana Kannan +Link: https://lore.kernel.org/r/20201121020232.908850-11-saravanak@google.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 2692c614f8f0 ("device property: Allow secondary lookup in fwnode_get_next_child_node()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/property.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/property.h | 3 ++ + 2 files changed, 55 insertions(+) + +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -615,6 +615,31 @@ struct fwnode_handle *fwnode_get_next_pa + EXPORT_SYMBOL_GPL(fwnode_get_next_parent); + + /** ++ * fwnode_get_next_parent_dev - Find device of closest ancestor fwnode ++ * @fwnode: firmware node ++ * ++ * Given a firmware node (@fwnode), this function finds its closest ancestor ++ * firmware node that has a corresponding struct device and returns that struct ++ * device. ++ * ++ * The caller of this function is expected to call put_device() on the returned ++ * device when they are done. ++ */ ++struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode) ++{ ++ struct device *dev = NULL; ++ ++ fwnode_handle_get(fwnode); ++ do { ++ fwnode = fwnode_get_next_parent(fwnode); ++ if (fwnode) ++ dev = get_dev_from_fwnode(fwnode); ++ } while (fwnode && !dev); ++ fwnode_handle_put(fwnode); ++ return dev; ++} ++ ++/** + * fwnode_count_parents - Return the number of parents a node has + * @fwnode: The node the parents of which are to be counted + * +@@ -661,6 +686,33 @@ struct fwnode_handle *fwnode_get_nth_par + EXPORT_SYMBOL_GPL(fwnode_get_nth_parent); + + /** ++ * fwnode_is_ancestor_of - Test if @test_ancestor is ancestor of @test_child ++ * @test_ancestor: Firmware which is tested for being an ancestor ++ * @test_child: Firmware which is tested for being the child ++ * ++ * A node is considered an ancestor of itself too. ++ * ++ * Returns true if @test_ancestor is an ancestor of @test_child. ++ * Otherwise, returns false. ++ */ ++bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor, ++ struct fwnode_handle *test_child) ++{ ++ if (!test_ancestor) ++ return false; ++ ++ fwnode_handle_get(test_child); ++ while (test_child) { ++ if (test_child == test_ancestor) { ++ fwnode_handle_put(test_child); ++ return true; ++ } ++ test_child = fwnode_get_next_parent(test_child); ++ } ++ return false; ++} ++ ++/** + * fwnode_get_next_child_node - Return the next child node handle for a node + * @fwnode: Firmware node to find the next child node for. + * @child: Handle to one of the node's child nodes or a %NULL handle. +--- a/include/linux/property.h ++++ b/include/linux/property.h +@@ -85,9 +85,12 @@ const char *fwnode_get_name_prefix(const + struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode); + struct fwnode_handle *fwnode_get_next_parent( + struct fwnode_handle *fwnode); ++struct device *fwnode_get_next_parent_dev(struct fwnode_handle *fwnode); + unsigned int fwnode_count_parents(const struct fwnode_handle *fwn); + struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwn, + unsigned int depth); ++bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor, ++ struct fwnode_handle *test_child); + struct fwnode_handle *fwnode_get_next_child_node( + const struct fwnode_handle *fwnode, struct fwnode_handle *child); + struct fwnode_handle *fwnode_get_next_available_child_node( diff --git a/queue-5.10/device-property-allow-error-pointer-to-be-passed-to-fwnode-apis.patch b/queue-5.10/device-property-allow-error-pointer-to-be-passed-to-fwnode-apis.patch new file mode 100644 index 0000000000..b07b73ccbd --- /dev/null +++ b/queue-5.10/device-property-allow-error-pointer-to-be-passed-to-fwnode-apis.patch @@ -0,0 +1,256 @@ +From stable+bounces-226740-greg=kroah.com@vger.kernel.org Tue Mar 17 18:23:29 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:19:53 -0400 +Subject: device property: Allow error pointer to be passed to fwnode APIs +To: stable@vger.kernel.org +Cc: "Andy Shevchenko" , "Nuno Sá" , "Sakari Ailus" , "Heikki Krogerus" , "Michael Walle" , "Rafael J. Wysocki" , "Sasha Levin" +Message-ID: <20260317171954.238398-7-sashal@kernel.org> + +From: Andy Shevchenko + +[ Upstream commit 002752af7b89b74c64fe6bec8c5fde3d3a7810d8 ] + +Some of the fwnode APIs might return an error pointer instead of NULL +or valid fwnode handle. The result of such API call may be considered +optional and hence the test for it is usually done in a form of + + fwnode = fwnode_find_reference(...); + if (IS_ERR(fwnode)) + ...error handling... + +Nevertheless the resulting fwnode may have bumped the reference count +and hence caller of the above API is obliged to call fwnode_handle_put(). +Since fwnode may be not valid either as NULL or error pointer the check +has to be performed there. This approach uglifies the code and adds +a point of making a mistake, i.e. forgetting about error point case. + +To prevent this, allow an error pointer to be passed to the fwnode APIs. + +Fixes: 83b34afb6b79 ("device property: Introduce fwnode_find_reference()") +Reported-by: Nuno Sá +Tested-by: Nuno Sá +Acked-by: Nuno Sá +Reviewed-by: Sakari Ailus +Reviewed-by: Heikki Krogerus +Signed-off-by: Andy Shevchenko +Tested-by: Michael Walle +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 2692c614f8f0 ("device property: Allow secondary lookup in fwnode_get_next_child_node()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/property.c | 89 +++++++++++++++++++++++++++--------------------- + include/linux/fwnode.h | 10 ++--- + 2 files changed, 56 insertions(+), 43 deletions(-) + +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -48,12 +48,14 @@ bool fwnode_property_present(const struc + { + bool ret; + ++ if (IS_ERR_OR_NULL(fwnode)) ++ return false; ++ + ret = fwnode_call_bool_op(fwnode, property_present, propname); +- if (ret == false && !IS_ERR_OR_NULL(fwnode) && +- !IS_ERR_OR_NULL(fwnode->secondary)) +- ret = fwnode_call_bool_op(fwnode->secondary, property_present, +- propname); +- return ret; ++ if (ret) ++ return ret; ++ ++ return fwnode_call_bool_op(fwnode->secondary, property_present, propname); + } + EXPORT_SYMBOL_GPL(fwnode_property_present); + +@@ -233,15 +235,16 @@ static int fwnode_property_read_int_arra + { + int ret; + ++ if (IS_ERR_OR_NULL(fwnode)) ++ return -EINVAL; ++ + ret = fwnode_call_int_op(fwnode, property_read_int_array, propname, + elem_size, val, nval); +- if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) && +- !IS_ERR_OR_NULL(fwnode->secondary)) +- ret = fwnode_call_int_op( +- fwnode->secondary, property_read_int_array, propname, +- elem_size, val, nval); ++ if (ret != -EINVAL) ++ return ret; + +- return ret; ++ return fwnode_call_int_op(fwnode->secondary, property_read_int_array, propname, ++ elem_size, val, nval); + } + + /** +@@ -372,14 +375,16 @@ int fwnode_property_read_string_array(co + { + int ret; + ++ if (IS_ERR_OR_NULL(fwnode)) ++ return -EINVAL; ++ + ret = fwnode_call_int_op(fwnode, property_read_string_array, propname, + val, nval); +- if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) && +- !IS_ERR_OR_NULL(fwnode->secondary)) +- ret = fwnode_call_int_op(fwnode->secondary, +- property_read_string_array, propname, +- val, nval); +- return ret; ++ if (ret != -EINVAL) ++ return ret; ++ ++ return fwnode_call_int_op(fwnode->secondary, property_read_string_array, propname, ++ val, nval); + } + EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); + +@@ -481,15 +486,19 @@ int fwnode_property_get_reference_args(c + { + int ret; + ++ if (IS_ERR_OR_NULL(fwnode)) ++ return -ENOENT; ++ + ret = fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop, + nargs, index, args); ++ if (ret == 0) ++ return ret; + +- if (ret < 0 && !IS_ERR_OR_NULL(fwnode) && +- !IS_ERR_OR_NULL(fwnode->secondary)) +- ret = fwnode_call_int_op(fwnode->secondary, get_reference_args, +- prop, nargs_prop, nargs, index, args); ++ if (IS_ERR_OR_NULL(fwnode->secondary)) ++ return ret; + +- return ret; ++ return fwnode_call_int_op(fwnode->secondary, get_reference_args, prop, nargs_prop, ++ nargs, index, args); + } + EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); + +@@ -683,12 +692,13 @@ EXPORT_SYMBOL_GPL(fwnode_count_parents); + struct fwnode_handle *fwnode_get_nth_parent(struct fwnode_handle *fwnode, + unsigned int depth) + { +- unsigned int i; +- + fwnode_handle_get(fwnode); + +- for (i = 0; i < depth && fwnode; i++) ++ do { ++ if (depth-- == 0) ++ break; + fwnode = fwnode_get_next_parent(fwnode); ++ } while (fwnode); + + return fwnode; + } +@@ -707,17 +717,17 @@ EXPORT_SYMBOL_GPL(fwnode_get_nth_parent) + bool fwnode_is_ancestor_of(struct fwnode_handle *test_ancestor, + struct fwnode_handle *test_child) + { +- if (!test_ancestor) ++ if (IS_ERR_OR_NULL(test_ancestor)) + return false; + + fwnode_handle_get(test_child); +- while (test_child) { ++ do { + if (test_child == test_ancestor) { + fwnode_handle_put(test_child); + return true; + } + test_child = fwnode_get_next_parent(test_child); +- } ++ } while (test_child); + return false; + } + +@@ -746,7 +756,7 @@ fwnode_get_next_available_child_node(con + { + struct fwnode_handle *next_child = child; + +- if (!fwnode) ++ if (IS_ERR_OR_NULL(fwnode)) + return NULL; + + do { +@@ -771,16 +781,16 @@ struct fwnode_handle *device_get_next_ch + const struct fwnode_handle *fwnode = dev_fwnode(dev); + struct fwnode_handle *next; + ++ if (IS_ERR_OR_NULL(fwnode)) ++ return NULL; ++ + /* Try to find a child in primary fwnode */ + next = fwnode_get_next_child_node(fwnode, child); + if (next) + return next; + + /* When no more children in primary, continue with secondary */ +- if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) +- next = fwnode_get_next_child_node(fwnode->secondary, child); +- +- return next; ++ return fwnode_get_next_child_node(fwnode->secondary, child); + } + EXPORT_SYMBOL_GPL(device_get_next_child_node); + +@@ -847,6 +857,9 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put); + */ + bool fwnode_device_is_available(const struct fwnode_handle *fwnode) + { ++ if (IS_ERR_OR_NULL(fwnode)) ++ return false; ++ + if (!fwnode_has_op(fwnode, device_is_available)) + return true; + +@@ -1054,14 +1067,14 @@ fwnode_graph_get_next_endpoint(const str + parent = fwnode_graph_get_port_parent(prev); + else + parent = fwnode; ++ if (IS_ERR_OR_NULL(parent)) ++ return NULL; + + ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev); ++ if (ep) ++ return ep; + +- if (IS_ERR_OR_NULL(ep) && +- !IS_ERR_OR_NULL(parent) && !IS_ERR_OR_NULL(parent->secondary)) +- ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL); +- +- return ep; ++ return fwnode_graph_get_next_endpoint(parent->secondary, NULL); + } + EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); + +--- a/include/linux/fwnode.h ++++ b/include/linux/fwnode.h +@@ -149,12 +149,12 @@ struct fwnode_operations { + struct device *dev); + }; + +-#define fwnode_has_op(fwnode, op) \ +- ((fwnode) && (fwnode)->ops && (fwnode)->ops->op) ++#define fwnode_has_op(fwnode, op) \ ++ (!IS_ERR_OR_NULL(fwnode) && (fwnode)->ops && (fwnode)->ops->op) ++ + #define fwnode_call_int_op(fwnode, op, ...) \ +- (fwnode ? (fwnode_has_op(fwnode, op) ? \ +- (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : -ENXIO) : \ +- -EINVAL) ++ (fwnode_has_op(fwnode, op) ? \ ++ (fwnode)->ops->op(fwnode, ## __VA_ARGS__) : (IS_ERR_OR_NULL(fwnode) ? -EINVAL : -ENXIO)) + + #define fwnode_call_bool_op(fwnode, op, ...) \ + (fwnode_has_op(fwnode, op) ? \ diff --git a/queue-5.10/device-property-allow-secondary-lookup-in-fwnode_get_next_child_node.patch b/queue-5.10/device-property-allow-secondary-lookup-in-fwnode_get_next_child_node.patch new file mode 100644 index 0000000000..e064837d79 --- /dev/null +++ b/queue-5.10/device-property-allow-secondary-lookup-in-fwnode_get_next_child_node.patch @@ -0,0 +1,79 @@ +From stable+bounces-226741-greg=kroah.com@vger.kernel.org Tue Mar 17 18:23:31 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:19:54 -0400 +Subject: device property: Allow secondary lookup in fwnode_get_next_child_node() +To: stable@vger.kernel.org +Cc: Andy Shevchenko , "Rafael J. Wysocki (Intel)" , Sakari Ailus , Danilo Krummrich , Sasha Levin +Message-ID: <20260317171954.238398-8-sashal@kernel.org> + +From: Andy Shevchenko + +[ Upstream commit 2692c614f8f05929d692b3dbfd3faef1f00fbaf0 ] + +When device_get_child_node_count() got split to the fwnode and device +respective APIs, the fwnode didn't inherit the ability to traverse over +the secondary fwnode. Hence any user, that switches from device to fwnode +API misses this feature. In particular, this was revealed by the commit +1490cbb9dbfd ("device property: Split fwnode_get_child_node_count()") +that effectively broke the GPIO enumeration on Intel Galileo boards. +Fix this by moving the secondary lookup from device to fwnode API. + +Note, in general no device_*() API should go into the depth of the fwnode +implementation. + +Fixes: 114dbb4fa7c4 ("drivers property: When no children in primary, try secondary") +Cc: stable@vger.kernel.org +Signed-off-by: Andy Shevchenko +Reviewed-by: Rafael J. Wysocki (Intel) +Reviewed-by: Sakari Ailus +Link: https://patch.msgid.link/20260210135822.47335-1-andriy.shevchenko@linux.intel.com +Signed-off-by: Danilo Krummrich +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/property.c | 27 +++++++++++++-------------- + 1 file changed, 13 insertions(+), 14 deletions(-) + +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -740,7 +740,18 @@ struct fwnode_handle * + fwnode_get_next_child_node(const struct fwnode_handle *fwnode, + struct fwnode_handle *child) + { +- return fwnode_call_ptr_op(fwnode, get_next_child_node, child); ++ struct fwnode_handle *next; ++ ++ if (IS_ERR_OR_NULL(fwnode)) ++ return NULL; ++ ++ /* Try to find a child in primary fwnode */ ++ next = fwnode_call_ptr_op(fwnode, get_next_child_node, child); ++ if (next) ++ return next; ++ ++ /* When no more children in primary, continue with secondary */ ++ return fwnode_call_ptr_op(fwnode->secondary, get_next_child_node, child); + } + EXPORT_SYMBOL_GPL(fwnode_get_next_child_node); + +@@ -778,19 +789,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_availa + struct fwnode_handle *device_get_next_child_node(struct device *dev, + struct fwnode_handle *child) + { +- const struct fwnode_handle *fwnode = dev_fwnode(dev); +- struct fwnode_handle *next; +- +- if (IS_ERR_OR_NULL(fwnode)) +- return NULL; +- +- /* Try to find a child in primary fwnode */ +- next = fwnode_get_next_child_node(fwnode, child); +- if (next) +- return next; +- +- /* When no more children in primary, continue with secondary */ +- return fwnode_get_next_child_node(fwnode->secondary, child); ++ return fwnode_get_next_child_node(dev_fwnode(dev), child); + } + EXPORT_SYMBOL_GPL(device_get_next_child_node); + diff --git a/queue-5.10/device-property-check-fwnode-secondary-in-fwnode_graph_get_next_endpoint.patch b/queue-5.10/device-property-check-fwnode-secondary-in-fwnode_graph_get_next_endpoint.patch new file mode 100644 index 0000000000..f24a9ae750 --- /dev/null +++ b/queue-5.10/device-property-check-fwnode-secondary-in-fwnode_graph_get_next_endpoint.patch @@ -0,0 +1,59 @@ +From stable+bounces-226737-greg=kroah.com@vger.kernel.org Tue Mar 17 18:51:06 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:19:51 -0400 +Subject: device property: Check fwnode->secondary in fwnode_graph_get_next_endpoint() +To: stable@vger.kernel.org +Cc: Daniel Scally , Andy Shevchenko , "Rafael J. Wysocki" , Sasha Levin +Message-ID: <20260317171954.238398-5-sashal@kernel.org> + +From: Daniel Scally + +[ Upstream commit b5b41ab6b0c1bb70fe37a0d193006c969e3b5909 ] + +Sensor drivers often check for an endpoint to make sure that they're +connected to a consuming device like a CIO2 during .probe(). Some of +those endpoints might be in the form of software_nodes assigned as +a secondary to the device's fwnode_handle. Account for this possibility +in fwnode_graph_get_next_endpoint() to avoid having to do it in the +sensor drivers themselves. + +Reviewed-by: Andy Shevchenko +Signed-off-by: Daniel Scally +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 2692c614f8f0 ("device property: Allow secondary lookup in fwnode_get_next_child_node()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/property.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -1033,7 +1033,26 @@ struct fwnode_handle * + fwnode_graph_get_next_endpoint(const struct fwnode_handle *fwnode, + struct fwnode_handle *prev) + { +- return fwnode_call_ptr_op(fwnode, graph_get_next_endpoint, prev); ++ const struct fwnode_handle *parent; ++ struct fwnode_handle *ep; ++ ++ /* ++ * If this function is in a loop and the previous iteration returned ++ * an endpoint from fwnode->secondary, then we need to use the secondary ++ * as parent rather than @fwnode. ++ */ ++ if (prev) ++ parent = fwnode_graph_get_port_parent(prev); ++ else ++ parent = fwnode; ++ ++ ep = fwnode_call_ptr_op(parent, graph_get_next_endpoint, prev); ++ ++ if (IS_ERR_OR_NULL(ep) && ++ !IS_ERR_OR_NULL(parent) && !IS_ERR_OR_NULL(parent->secondary)) ++ ep = fwnode_graph_get_next_endpoint(parent->secondary, NULL); ++ ++ return ep; + } + EXPORT_SYMBOL_GPL(fwnode_graph_get_next_endpoint); + diff --git a/queue-5.10/device-property-check-fwnode-secondary-when-finding-properties.patch b/queue-5.10/device-property-check-fwnode-secondary-when-finding-properties.patch new file mode 100644 index 0000000000..4298afa9eb --- /dev/null +++ b/queue-5.10/device-property-check-fwnode-secondary-when-finding-properties.patch @@ -0,0 +1,51 @@ +From sashal@kernel.org Tue Mar 17 18:20:03 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:19:52 -0400 +Subject: device property: Check fwnode->secondary when finding properties +To: stable@vger.kernel.org +Cc: Daniel Scally , Andy Shevchenko , Hans de Goede , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260317171954.238398-6-sashal@kernel.org> + +From: Daniel Scally + +[ Upstream commit c097af1d0a8483b44fa30e86b311991d76b6ae67 ] + +fwnode_property_get_reference_args() searches for named properties +against a fwnode_handle, but these could instead be against the fwnode's +secondary. If the property isn't found against the primary, check the +secondary to see if it's there instead. + +Reviewed-by: Andy Shevchenko +Reviewed-by: Hans de Goede +Signed-off-by: Daniel Scally +Link: https://lore.kernel.org/r/20211128232455.39332-1-djrscally@gmail.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 2692c614f8f0 ("device property: Allow secondary lookup in fwnode_get_next_child_node()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/property.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -479,8 +479,17 @@ int fwnode_property_get_reference_args(c + unsigned int nargs, unsigned int index, + struct fwnode_reference_args *args) + { +- return fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop, +- nargs, index, args); ++ int ret; ++ ++ ret = fwnode_call_int_op(fwnode, get_reference_args, prop, nargs_prop, ++ nargs, index, args); ++ ++ if (ret < 0 && !IS_ERR_OR_NULL(fwnode) && ++ !IS_ERR_OR_NULL(fwnode->secondary)) ++ ret = fwnode_call_int_op(fwnode->secondary, get_reference_args, ++ prop, nargs_prop, nargs, index, args); ++ ++ return ret; + } + EXPORT_SYMBOL_GPL(fwnode_property_get_reference_args); + diff --git a/queue-5.10/device-property-retrieve-fwnode-from-of_node-via-accessor.patch b/queue-5.10/device-property-retrieve-fwnode-from-of_node-via-accessor.patch new file mode 100644 index 0000000000..aa11b53549 --- /dev/null +++ b/queue-5.10/device-property-retrieve-fwnode-from-of_node-via-accessor.patch @@ -0,0 +1,44 @@ +From stable+bounces-226735-greg=kroah.com@vger.kernel.org Tue Mar 17 18:51:05 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:19:49 -0400 +Subject: device property: Retrieve fwnode from of_node via accessor +To: stable@vger.kernel.org +Cc: Andy Shevchenko , "Rafael J. Wysocki" , Sasha Levin +Message-ID: <20260317171954.238398-3-sashal@kernel.org> + +From: Andy Shevchenko + +[ Upstream commit 3cd8015040d7537a6b88e26f36768a90d9247829 ] + +OF provides a specific accessor to retrieve fwnode handle. +Use it instead of direct dereferencing. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 2692c614f8f0 ("device property: Allow secondary lookup in fwnode_get_next_child_node()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/property.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -21,7 +21,7 @@ + struct fwnode_handle *dev_fwnode(const struct device *dev) + { + return IS_ENABLED(CONFIG_OF) && dev->of_node ? +- &dev->of_node->fwnode : dev->fwnode; ++ of_fwnode_handle(dev->of_node) : dev->fwnode; + } + EXPORT_SYMBOL_GPL(dev_fwnode); + +@@ -763,7 +763,7 @@ struct fwnode_handle *device_get_next_ch + struct fwnode_handle *fwnode = NULL, *next; + + if (dev->of_node) +- fwnode = &dev->of_node->fwnode; ++ fwnode = of_fwnode_handle(dev->of_node); + else if (adev) + fwnode = acpi_fwnode_handle(adev); + diff --git a/queue-5.10/device-property-unify-access-to-of_node.patch b/queue-5.10/device-property-unify-access-to-of_node.patch new file mode 100644 index 0000000000..33f517e8bc --- /dev/null +++ b/queue-5.10/device-property-unify-access-to-of_node.patch @@ -0,0 +1,111 @@ +From stable+bounces-226736-greg=kroah.com@vger.kernel.org Tue Mar 17 18:50:50 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:19:50 -0400 +Subject: device property: Unify access to of_node +To: stable@vger.kernel.org +Cc: Andy Shevchenko , "Rafael J. Wysocki" , Sasha Levin +Message-ID: <20260317171954.238398-4-sashal@kernel.org> + +From: Andy Shevchenko + +[ Upstream commit fb38f314fbd173e2e9f9f0f2e720a5f4889562da ] + +Historically we have a few variants how we access dev->fwnode +and dev->of_node. Some of the functions during development +gained different versions of the getters. Unify access to of_node +and as a side change slightly refactor ACPI specific branches. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 2692c614f8f0 ("device property: Allow secondary lookup in fwnode_get_next_child_node()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/property.c | 29 +++++++++++++---------------- + include/linux/property.h | 2 +- + 2 files changed, 14 insertions(+), 17 deletions(-) + +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -759,13 +759,8 @@ EXPORT_SYMBOL_GPL(fwnode_get_next_availa + struct fwnode_handle *device_get_next_child_node(struct device *dev, + struct fwnode_handle *child) + { +- struct acpi_device *adev = ACPI_COMPANION(dev); +- struct fwnode_handle *fwnode = NULL, *next; +- +- if (dev->of_node) +- fwnode = of_fwnode_handle(dev->of_node); +- else if (adev) +- fwnode = acpi_fwnode_handle(adev); ++ const struct fwnode_handle *fwnode = dev_fwnode(dev); ++ struct fwnode_handle *next; + + /* Try to find a child in primary fwnode */ + next = fwnode_get_next_child_node(fwnode, child); +@@ -868,28 +863,31 @@ EXPORT_SYMBOL_GPL(device_get_child_node_ + + bool device_dma_supported(struct device *dev) + { ++ const struct fwnode_handle *fwnode = dev_fwnode(dev); ++ + /* For DT, this is always supported. + * For ACPI, this depends on CCA, which + * is determined by the acpi_dma_supported(). + */ +- if (IS_ENABLED(CONFIG_OF) && dev->of_node) ++ if (is_of_node(fwnode)) + return true; + +- return acpi_dma_supported(ACPI_COMPANION(dev)); ++ return acpi_dma_supported(to_acpi_device_node(fwnode)); + } + EXPORT_SYMBOL_GPL(device_dma_supported); + + enum dev_dma_attr device_get_dma_attr(struct device *dev) + { ++ const struct fwnode_handle *fwnode = dev_fwnode(dev); + enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED; + +- if (IS_ENABLED(CONFIG_OF) && dev->of_node) { +- if (of_dma_is_coherent(dev->of_node)) ++ if (is_of_node(fwnode)) { ++ if (of_dma_is_coherent(to_of_node(fwnode))) + attr = DEV_DMA_COHERENT; + else + attr = DEV_DMA_NON_COHERENT; + } else +- attr = acpi_get_dma_attr(ACPI_COMPANION(dev)); ++ attr = acpi_get_dma_attr(to_acpi_device_node(fwnode)); + + return attr; + } +@@ -1007,14 +1005,13 @@ EXPORT_SYMBOL(device_get_mac_address); + * Returns Linux IRQ number on success. Other values are determined + * accordingly to acpi_/of_ irq_get() operation. + */ +-int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index) ++int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index) + { +- struct device_node *of_node = to_of_node(fwnode); + struct resource res; + int ret; + +- if (IS_ENABLED(CONFIG_OF) && of_node) +- return of_irq_get(of_node, index); ++ if (is_of_node(fwnode)) ++ return of_irq_get(to_of_node(fwnode), index); + + ret = acpi_irq_get(ACPI_HANDLE_FWNODE(fwnode), index, &res); + if (ret) +--- a/include/linux/property.h ++++ b/include/linux/property.h +@@ -119,7 +119,7 @@ struct fwnode_handle *device_get_named_c + struct fwnode_handle *fwnode_handle_get(struct fwnode_handle *fwnode); + void fwnode_handle_put(struct fwnode_handle *fwnode); + +-int fwnode_irq_get(struct fwnode_handle *fwnode, unsigned int index); ++int fwnode_irq_get(const struct fwnode_handle *fwnode, unsigned int index); + + unsigned int device_get_child_node_count(struct device *dev); + diff --git a/queue-5.10/drm-fix-use-after-free-on-framebuffers-and-property-blobs-when-calling-drm_dev_unplug.patch b/queue-5.10/drm-fix-use-after-free-on-framebuffers-and-property-blobs-when-calling-drm_dev_unplug.patch new file mode 100644 index 0000000000..b11e02394d --- /dev/null +++ b/queue-5.10/drm-fix-use-after-free-on-framebuffers-and-property-blobs-when-calling-drm_dev_unplug.patch @@ -0,0 +1,237 @@ +From stable+bounces-227793-greg=kroah.com@vger.kernel.org Sat Mar 21 21:50:04 2026 +From: Sasha Levin +Date: Sat, 21 Mar 2026 16:49:57 -0400 +Subject: drm: Fix use-after-free on framebuffers and property blobs when calling drm_dev_unplug +To: stable@vger.kernel.org +Cc: "Maarten Lankhorst" , "Thomas Hellström" , "Sasha Levin" +Message-ID: <20260321204957.594424-1-sashal@kernel.org> + +From: Maarten Lankhorst + +[ Upstream commit 6bee098b91417654703e17eb5c1822c6dfd0c01d ] + +When trying to do a rather aggressive test of igt's "xe_module_load +--r reload" with a full desktop environment and game running I noticed +a few OOPSes when dereferencing freed pointers, related to +framebuffers and property blobs after the compositor exits. + +Solve this by guarding the freeing in drm_file with drm_dev_enter/exit, +and immediately put the references from struct drm_file objects during +drm_dev_unplug(). + +Related warnings for framebuffers on the subtest: +[ 739.713076] ------------[ cut here ]------------ + WARN_ON(!list_empty(&dev->mode_config.fb_list)) +[ 739.713079] WARNING: drivers/gpu/drm/drm_mode_config.c:584 at drm_mode_config_cleanup+0x30b/0x320 [drm], CPU#12: xe_module_load/13145 +.... +[ 739.713328] Call Trace: +[ 739.713330] +[ 739.713335] ? intel_pmdemand_destroy_state+0x11/0x20 [xe] +[ 739.713574] ? intel_atomic_global_obj_cleanup+0xe4/0x1a0 [xe] +[ 739.713794] intel_display_driver_remove_noirq+0x51/0xb0 [xe] +[ 739.714041] xe_display_fini_early+0x33/0x50 [xe] +[ 739.714284] devm_action_release+0xf/0x20 +[ 739.714294] devres_release_all+0xad/0xf0 +[ 739.714301] device_unbind_cleanup+0x12/0xa0 +[ 739.714305] device_release_driver_internal+0x1b7/0x210 +[ 739.714311] device_driver_detach+0x14/0x20 +[ 739.714315] unbind_store+0xa6/0xb0 +[ 739.714319] drv_attr_store+0x21/0x30 +[ 739.714322] sysfs_kf_write+0x48/0x60 +[ 739.714328] kernfs_fop_write_iter+0x16b/0x240 +[ 739.714333] vfs_write+0x266/0x520 +[ 739.714341] ksys_write+0x72/0xe0 +[ 739.714345] __x64_sys_write+0x19/0x20 +[ 739.714347] x64_sys_call+0xa15/0xa30 +[ 739.714355] do_syscall_64+0xd8/0xab0 +[ 739.714361] entry_SYSCALL_64_after_hwframe+0x4b/0x53 + +and + +[ 739.714459] ------------[ cut here ]------------ +[ 739.714461] xe 0000:67:00.0: [drm] drm_WARN_ON(!list_empty(&fb->filp_head)) +[ 739.714464] WARNING: drivers/gpu/drm/drm_framebuffer.c:833 at drm_framebuffer_free+0x6c/0x90 [drm], CPU#12: xe_module_load/13145 +[ 739.714715] RIP: 0010:drm_framebuffer_free+0x7a/0x90 [drm] +... +[ 739.714869] Call Trace: +[ 739.714871] +[ 739.714876] drm_mode_config_cleanup+0x26a/0x320 [drm] +[ 739.714998] ? __drm_printfn_seq_file+0x20/0x20 [drm] +[ 739.715115] ? drm_mode_config_cleanup+0x207/0x320 [drm] +[ 739.715235] intel_display_driver_remove_noirq+0x51/0xb0 [xe] +[ 739.715576] xe_display_fini_early+0x33/0x50 [xe] +[ 739.715821] devm_action_release+0xf/0x20 +[ 739.715828] devres_release_all+0xad/0xf0 +[ 739.715843] device_unbind_cleanup+0x12/0xa0 +[ 739.715850] device_release_driver_internal+0x1b7/0x210 +[ 739.715856] device_driver_detach+0x14/0x20 +[ 739.715860] unbind_store+0xa6/0xb0 +[ 739.715865] drv_attr_store+0x21/0x30 +[ 739.715868] sysfs_kf_write+0x48/0x60 +[ 739.715873] kernfs_fop_write_iter+0x16b/0x240 +[ 739.715878] vfs_write+0x266/0x520 +[ 739.715886] ksys_write+0x72/0xe0 +[ 739.715890] __x64_sys_write+0x19/0x20 +[ 739.715893] x64_sys_call+0xa15/0xa30 +[ 739.715900] do_syscall_64+0xd8/0xab0 +[ 739.715905] entry_SYSCALL_64_after_hwframe+0x4b/0x53 + +and then finally file close blows up: + +[ 743.186530] Oops: general protection fault, probably for non-canonical address 0xdead000000000122: 0000 [#1] SMP +[ 743.186535] CPU: 3 UID: 1000 PID: 3453 Comm: kwin_wayland Tainted: G W 7.0.0-rc1-valkyria+ #110 PREEMPT_{RT,(lazy)} +[ 743.186537] Tainted: [W]=WARN +[ 743.186538] Hardware name: Gigabyte Technology Co., Ltd. X299 AORUS Gaming 3/X299 AORUS Gaming 3-CF, BIOS F8n 12/06/2021 +[ 743.186539] RIP: 0010:drm_framebuffer_cleanup+0x55/0xc0 [drm] +[ 743.186588] Code: d8 72 73 0f b6 42 05 ff c3 39 c3 72 e8 49 8d bd 50 07 00 00 31 f6 e8 3a 80 d3 e1 49 8b 44 24 10 49 8d 7c 24 08 49 8b 54 24 08 <48> 3b 38 0f 85 95 7f 02 00 48 3b 7a 08 0f 85 8b 7f 02 00 48 89 42 +[ 743.186589] RSP: 0018:ffffc900085e3cf8 EFLAGS: 00010202 +[ 743.186591] RAX: dead000000000122 RBX: 0000000000000001 RCX: ffffffff8217ed03 +[ 743.186592] RDX: dead000000000100 RSI: 0000000000000000 RDI: ffff88814675ba08 +[ 743.186593] RBP: ffffc900085e3d10 R08: 0000000000000000 R09: 0000000000000000 +[ 743.186593] R10: 0000000000000000 R11: 0000000000000000 R12: ffff88814675ba00 +[ 743.186594] R13: ffff88810d778000 R14: ffff888119f6dca0 R15: ffff88810c660bb0 +[ 743.186595] FS: 00007ff377d21280(0000) GS:ffff888cec3f8000(0000) knlGS:0000000000000000 +[ 743.186596] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 743.186596] CR2: 000055690b55e000 CR3: 0000000113586003 CR4: 00000000003706f0 +[ 743.186597] Call Trace: +[ 743.186598] +[ 743.186603] intel_user_framebuffer_destroy+0x12/0x90 [xe] +[ 743.186722] drm_framebuffer_free+0x3a/0x90 [drm] +[ 743.186750] ? trace_hardirqs_on+0x5f/0x120 +[ 743.186754] drm_mode_object_put+0x51/0x70 [drm] +[ 743.186786] drm_fb_release+0x105/0x190 [drm] +[ 743.186812] ? rt_mutex_slowunlock+0x3aa/0x410 +[ 743.186817] ? rt_spin_lock+0xea/0x1b0 +[ 743.186819] drm_file_free+0x1e0/0x2c0 [drm] +[ 743.186843] drm_release_noglobal+0x91/0xf0 [drm] +[ 743.186865] __fput+0x100/0x2e0 +[ 743.186869] fput_close_sync+0x40/0xa0 +[ 743.186870] __x64_sys_close+0x3e/0x80 +[ 743.186873] x64_sys_call+0xa07/0xa30 +[ 743.186879] do_syscall_64+0xd8/0xab0 +[ 743.186881] entry_SYSCALL_64_after_hwframe+0x4b/0x53 +[ 743.186882] RIP: 0033:0x7ff37e567732 +[ 743.186884] Code: 08 0f 85 a1 38 ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 f3 0f 1e fa 55 bf 01 00 +[ 743.186885] RSP: 002b:00007ffc818169a8 EFLAGS: 00000246 ORIG_RAX: 0000000000000003 +[ 743.186886] RAX: ffffffffffffffda RBX: 00007ffc81816a30 RCX: 00007ff37e567732 +[ 743.186887] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000012 +[ 743.186888] RBP: 00007ffc818169d0 R08: 0000000000000000 R09: 0000000000000000 +[ 743.186889] R10: 0000000000000000 R11: 0000000000000246 R12: 000055d60a7996e0 +[ 743.186889] R13: 00007ffc81816a90 R14: 00007ffc81816a90 R15: 000055d60a782a30 +[ 743.186892] +[ 743.186893] Modules linked in: rfcomm snd_hrtimer xt_CHECKSUM xt_MASQUERADE xt_conntrack ipt_REJECT nf_reject_ipv4 xt_tcpudp xt_addrtype nft_compat x_tables nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables overlay cfg80211 bnep mtd_intel_dg snd_hda_codec_intelhdmi mtd snd_hda_codec_hdmi nls_utf8 mxm_wmi intel_wmi_thunderbolt gigabyte_wmi wmi_bmof xe drm_gpuvm drm_gpusvm_helper i2c_algo_bit drm_buddy drm_ttm_helper ttm video drm_suballoc_helper gpu_sched drm_client_lib drm_exec drm_display_helper cec drm_kunit_helpers drm_kms_helper kunit x86_pkg_temp_thermal intel_powerclamp coretemp snd_hda_codec_alc882 snd_hda_codec_realtek_lib snd_hda_codec_generic snd_hda_intel snd_soc_avs snd_soc_hda_codec snd_hda_ext_core snd_hda_codec snd_hwdep snd_hda_core snd_intel_dspcfg snd_soc_core snd_compress ac97_bus snd_pcm snd_seq snd_seq_device snd_timer i2c_i801 i2c_mux snd i2c_smbus btusb btrtl btbcm btmtk btintel bluetooth ecdh_generic rfkill ecc mei_me mei ioatdma dca wmi nfsd drm i2c_dev fuse nfnetlink +[ 743.186938] ---[ end trace 0000000000000000 ]--- + +And for property blobs: + +void drm_mode_config_cleanup(struct drm_device *dev) +{ +... + list_for_each_entry_safe(blob, bt, &dev->mode_config.property_blob_list, + head_global) { + drm_property_blob_put(blob); + } + +Resulting in: + +[ 371.072940] BUG: unable to handle page fault for address: 000001ffffffffff +[ 371.072944] #PF: supervisor read access in kernel mode +[ 371.072945] #PF: error_code(0x0000) - not-present page +[ 371.072947] PGD 0 P4D 0 +[ 371.072950] Oops: Oops: 0000 [#1] SMP +[ 371.072953] CPU: 0 UID: 1000 PID: 3693 Comm: kwin_wayland Not tainted 7.0.0-rc1-valkyria+ #111 PREEMPT_{RT,(lazy)} +[ 371.072956] Hardware name: Gigabyte Technology Co., Ltd. X299 AORUS Gaming 3/X299 AORUS Gaming 3-CF, BIOS F8n 12/06/2021 +[ 371.072957] RIP: 0010:drm_property_destroy_user_blobs+0x3b/0x90 [drm] +[ 371.073019] Code: 00 00 48 83 ec 10 48 8b 86 30 01 00 00 48 39 c3 74 59 48 89 c2 48 8d 48 c8 48 8b 00 4c 8d 60 c8 eb 04 4c 8d 60 c8 48 8b 71 40 <48> 39 16 0f 85 39 32 01 00 48 3b 50 08 0f 85 2f 32 01 00 48 89 70 +[ 371.073021] RSP: 0018:ffffc90006a73de8 EFLAGS: 00010293 +[ 371.073022] RAX: 000001ffffffffff RBX: ffff888118a1a930 RCX: ffff8881b92355c0 +[ 371.073024] RDX: ffff8881b92355f8 RSI: 000001ffffffffff RDI: ffff888118be4000 +[ 371.073025] RBP: ffffc90006a73e08 R08: ffff8881009b7300 R09: ffff888cecc5b000 +[ 371.073026] R10: ffffc90006a73e90 R11: 0000000000000002 R12: 000001ffffffffc7 +[ 371.073027] R13: ffff888118a1a980 R14: ffff88810b366d20 R15: ffff888118a1a970 +[ 371.073028] FS: 00007f1faccbb280(0000) GS:ffff888cec2db000(0000) knlGS:0000000000000000 +[ 371.073029] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 371.073030] CR2: 000001ffffffffff CR3: 000000010655c001 CR4: 00000000003706f0 +[ 371.073031] Call Trace: +[ 371.073033] +[ 371.073036] drm_file_free+0x1df/0x2a0 [drm] +[ 371.073077] drm_release_noglobal+0x7a/0xe0 [drm] +[ 371.073113] __fput+0xe2/0x2b0 +[ 371.073118] fput_close_sync+0x40/0xa0 +[ 371.073119] __x64_sys_close+0x3e/0x80 +[ 371.073122] x64_sys_call+0xa07/0xa30 +[ 371.073126] do_syscall_64+0xc0/0x840 +[ 371.073130] entry_SYSCALL_64_after_hwframe+0x4b/0x53 +[ 371.073132] RIP: 0033:0x7f1fb3501732 +[ 371.073133] Code: 08 0f 85 a1 38 ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 f3 0f 1e fa 55 bf 01 00 +[ 371.073135] RSP: 002b:00007ffe8e6f0278 EFLAGS: 00000246 ORIG_RAX: 0000000000000003 +[ 371.073136] RAX: ffffffffffffffda RBX: 00007ffe8e6f0300 RCX: 00007f1fb3501732 +[ 371.073137] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000012 +[ 371.073138] RBP: 00007ffe8e6f02a0 R08: 0000000000000000 R09: 0000000000000000 +[ 371.073139] R10: 0000000000000000 R11: 0000000000000246 R12: 00005585ba46eea0 +[ 371.073140] R13: 00007ffe8e6f0360 R14: 00007ffe8e6f0360 R15: 00005585ba458a30 +[ 371.073143] +[ 371.073144] Modules linked in: rfcomm snd_hrtimer xt_addrtype xt_CHECKSUM xt_MASQUERADE xt_conntrack ipt_REJECT nf_reject_ipv4 xt_tcpudp nft_compat x_tables nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables overlay cfg80211 bnep snd_hda_codec_intelhdmi snd_hda_codec_hdmi mtd_intel_dg mtd nls_utf8 wmi_bmof mxm_wmi gigabyte_wmi intel_wmi_thunderbolt xe drm_gpuvm drm_gpusvm_helper i2c_algo_bit drm_buddy drm_ttm_helper ttm video drm_suballoc_helper gpu_sched drm_client_lib drm_exec drm_display_helper cec drm_kunit_helpers drm_kms_helper kunit x86_pkg_temp_thermal intel_powerclamp coretemp snd_hda_codec_alc882 snd_hda_codec_realtek_lib snd_hda_codec_generic snd_hda_intel snd_soc_avs snd_soc_hda_codec snd_hda_ext_core snd_hda_codec snd_hwdep snd_hda_core snd_intel_dspcfg snd_soc_core snd_compress ac97_bus snd_pcm snd_seq snd_seq_device snd_timer i2c_i801 btusb i2c_mux i2c_smbus btrtl snd btbcm btmtk btintel bluetooth ecdh_generic rfkill ecc mei_me mei ioatdma dca wmi nfsd drm i2c_dev fuse nfnetlink +[ 371.073198] CR2: 000001ffffffffff +[ 371.073199] ---[ end trace 0000000000000000 ]--- + +Add a guard around file close, and ensure the warnings from drm_mode_config +do not trigger. Fix those by allowing an open reference to the file descriptor +and cleaning up the file linked list entry in drm_mode_config_cleanup(). + +Cc: # v4.18+ +Fixes: bee330f3d672 ("drm: Use srcu to protect drm_device.unplugged") +Cc: Thomas Hellström +Reviewed-by: Thomas Hellström +Link: https://patch.msgid.link/20260313151728.14990-4-dev@lankhorst.se +Signed-off-by: Maarten Lankhorst +[ adapted drm_dbg_printer(dev, DRM_UT_KMS, ...) call to older drm_debug_printer(...) API ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/drm_file.c | 5 ++++- + drivers/gpu/drm/drm_mode_config.c | 9 ++++++--- + 2 files changed, 10 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/drm_file.c ++++ b/drivers/gpu/drm/drm_file.c +@@ -248,6 +248,7 @@ static void drm_events_release(struct dr + void drm_file_free(struct drm_file *file) + { + struct drm_device *dev; ++ int idx; + + if (!file) + return; +@@ -271,9 +272,11 @@ void drm_file_free(struct drm_file *file + + drm_events_release(file); + +- if (drm_core_check_feature(dev, DRIVER_MODESET)) { ++ if (drm_core_check_feature(dev, DRIVER_MODESET) && ++ drm_dev_enter(dev, &idx)) { + drm_fb_release(file); + drm_property_destroy_user_blobs(dev, file); ++ drm_dev_exit(idx); + } + + if (drm_core_check_feature(dev, DRIVER_SYNCOBJ)) +--- a/drivers/gpu/drm/drm_mode_config.c ++++ b/drivers/gpu/drm/drm_mode_config.c +@@ -543,10 +543,13 @@ void drm_mode_config_cleanup(struct drm_ + */ + WARN_ON(!list_empty(&dev->mode_config.fb_list)); + list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { +- struct drm_printer p = drm_debug_printer("[leaked fb]"); ++ if (list_empty(&fb->filp_head) || drm_framebuffer_read_refcount(fb) > 1) { ++ struct drm_printer p = drm_debug_printer("[leaked fb]"); + +- drm_printf(&p, "framebuffer[%u]:\n", fb->base.id); +- drm_framebuffer_print_info(&p, 1, fb); ++ drm_printf(&p, "framebuffer[%u]:\n", fb->base.id); ++ drm_framebuffer_print_info(&p, 1, fb); ++ } ++ list_del_init(&fb->filp_head); + drm_framebuffer_free(&fb->base.refcount); + } + diff --git a/queue-5.10/ext4-fix-iloc.bh-leak-in-ext4_fc_replay_inode-error-paths.patch b/queue-5.10/ext4-fix-iloc.bh-leak-in-ext4_fc_replay_inode-error-paths.patch new file mode 100644 index 0000000000..11e4b3db20 --- /dev/null +++ b/queue-5.10/ext4-fix-iloc.bh-leak-in-ext4_fc_replay_inode-error-paths.patch @@ -0,0 +1,88 @@ +From stable+bounces-233181-greg=kroah.com@vger.kernel.org Fri Apr 3 13:58:38 2026 +From: Sasha Levin +Date: Fri, 3 Apr 2026 07:58:31 -0400 +Subject: ext4: fix iloc.bh leak in ext4_fc_replay_inode() error paths +To: stable@vger.kernel.org +Cc: Baokun Li , Joseph Qi , Zhang Yi , Jan Kara , Theodore Ts'o , stable@kernel.org, Sasha Levin +Message-ID: <20260403115831.2109038-1-sashal@kernel.org> + +From: Baokun Li + +[ Upstream commit ec0a7500d8eace5b4f305fa0c594dd148f0e8d29 ] + +During code review, Joseph found that ext4_fc_replay_inode() calls +ext4_get_fc_inode_loc() to get the inode location, which holds a +reference to iloc.bh that must be released via brelse(). + +However, several error paths jump to the 'out' label without +releasing iloc.bh: + + - ext4_handle_dirty_metadata() failure + - sync_dirty_buffer() failure + - ext4_mark_inode_used() failure + - ext4_iget() failure + +Fix this by introducing an 'out_brelse' label placed just before +the existing 'out' label to ensure iloc.bh is always released. + +Additionally, make ext4_fc_replay_inode() propagate errors +properly instead of always returning 0. + +Reported-by: Joseph Qi +Fixes: 8016e29f4362 ("ext4: fast commit recovery path") +Signed-off-by: Baokun Li +Reviewed-by: Zhang Yi +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20260323060836.3452660-1-libaokun@linux.alibaba.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/fast_commit.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/fs/ext4/fast_commit.c ++++ b/fs/ext4/fast_commit.c +@@ -1480,19 +1480,21 @@ static int ext4_fc_replay_inode(struct s + /* Immediately update the inode on disk. */ + ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh); + if (ret) +- goto out; ++ goto out_brelse; + ret = sync_dirty_buffer(iloc.bh); + if (ret) +- goto out; ++ goto out_brelse; + ret = ext4_mark_inode_used(sb, ino); + if (ret) +- goto out; ++ goto out_brelse; + + /* Given that we just wrote the inode on disk, this SHOULD succeed. */ + inode = ext4_iget(sb, ino, EXT4_IGET_NORMAL); + if (IS_ERR(inode)) { + jbd_debug(1, "Inode not found."); +- return -EFSCORRUPTED; ++ inode = NULL; ++ ret = -EFSCORRUPTED; ++ goto out_brelse; + } + + /* +@@ -1508,13 +1510,14 @@ static int ext4_fc_replay_inode(struct s + ext4_inode_csum_set(inode, ext4_raw_inode(&iloc), EXT4_I(inode)); + ret = ext4_handle_dirty_metadata(NULL, NULL, iloc.bh); + sync_dirty_buffer(iloc.bh); ++out_brelse: + brelse(iloc.bh); + out: + iput(inode); + if (!ret) + blkdev_issue_flush(sb->s_bdev, GFP_KERNEL); + +- return 0; ++ return ret; + } + + /* diff --git a/queue-5.10/ext4-fix-the-might_sleep-warnings-in-kvfree.patch b/queue-5.10/ext4-fix-the-might_sleep-warnings-in-kvfree.patch new file mode 100644 index 0000000000..4196d1a4d4 --- /dev/null +++ b/queue-5.10/ext4-fix-the-might_sleep-warnings-in-kvfree.patch @@ -0,0 +1,164 @@ +From stable+bounces-233084-greg=kroah.com@vger.kernel.org Thu Apr 2 19:46:55 2026 +From: Sasha Levin +Date: Thu, 2 Apr 2026 13:40:37 -0400 +Subject: ext4: fix the might_sleep() warnings in kvfree() +To: stable@vger.kernel.org +Cc: Zqiang , Baokun Li , Theodore Ts'o , stable@kernel.org, Sasha Levin +Message-ID: <20260402174037.1571365-1-sashal@kernel.org> + +From: Zqiang + +[ Upstream commit 496bb99b7e66f48b178126626f47e9ba79e2d0fa ] + +Use the kvfree() in the RCU read critical section can trigger +the following warnings: + +EXT4-fs (vdb): unmounting filesystem cd983e5b-3c83-4f5a-a136-17b00eb9d018. + +WARNING: suspicious RCU usage + +./include/linux/rcupdate.h:409 Illegal context switch in RCU read-side critical section! + +other info that might help us debug this: + +rcu_scheduler_active = 2, debug_locks = 1 + +Call Trace: + + dump_stack_lvl+0xbb/0xd0 + dump_stack+0x14/0x20 + lockdep_rcu_suspicious+0x15a/0x1b0 + __might_resched+0x375/0x4d0 + ? put_object.part.0+0x2c/0x50 + __might_sleep+0x108/0x160 + vfree+0x58/0x910 + ? ext4_group_desc_free+0x27/0x270 + kvfree+0x23/0x40 + ext4_group_desc_free+0x111/0x270 + ext4_put_super+0x3c8/0xd40 + generic_shutdown_super+0x14c/0x4a0 + ? __pfx_shrinker_free+0x10/0x10 + kill_block_super+0x40/0x90 + ext4_kill_sb+0x6d/0xb0 + deactivate_locked_super+0xb4/0x180 + deactivate_super+0x7e/0xa0 + cleanup_mnt+0x296/0x3e0 + __cleanup_mnt+0x16/0x20 + task_work_run+0x157/0x250 + ? __pfx_task_work_run+0x10/0x10 + ? exit_to_user_mode_loop+0x6a/0x550 + exit_to_user_mode_loop+0x102/0x550 + do_syscall_64+0x44a/0x500 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + + +BUG: sleeping function called from invalid context at mm/vmalloc.c:3441 +in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 556, name: umount +preempt_count: 1, expected: 0 +CPU: 3 UID: 0 PID: 556 Comm: umount +Call Trace: + + dump_stack_lvl+0xbb/0xd0 + dump_stack+0x14/0x20 + __might_resched+0x275/0x4d0 + ? put_object.part.0+0x2c/0x50 + __might_sleep+0x108/0x160 + vfree+0x58/0x910 + ? ext4_group_desc_free+0x27/0x270 + kvfree+0x23/0x40 + ext4_group_desc_free+0x111/0x270 + ext4_put_super+0x3c8/0xd40 + generic_shutdown_super+0x14c/0x4a0 + ? __pfx_shrinker_free+0x10/0x10 + kill_block_super+0x40/0x90 + ext4_kill_sb+0x6d/0xb0 + deactivate_locked_super+0xb4/0x180 + deactivate_super+0x7e/0xa0 + cleanup_mnt+0x296/0x3e0 + __cleanup_mnt+0x16/0x20 + task_work_run+0x157/0x250 + ? __pfx_task_work_run+0x10/0x10 + ? exit_to_user_mode_loop+0x6a/0x550 + exit_to_user_mode_loop+0x102/0x550 + do_syscall_64+0x44a/0x500 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + +The above scenarios occur in initialization failures and teardown +paths, there are no parallel operations on the resources released +by kvfree(), this commit therefore remove rcu_read_lock/unlock() and +use rcu_access_pointer() instead of rcu_dereference() operations. + +Fixes: 7c990728b99e ("ext4: fix potential race between s_flex_groups online resizing and access") +Fixes: df3da4ea5a0f ("ext4: fix potential race between s_group_info online resizing and access") +Signed-off-by: Zqiang +Reviewed-by: Baokun Li +Link: https://patch.msgid.link/20260319094545.19291-1-qiang.zhang@linux.dev +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +[ adapted inline rcu_read_lock/rcu_dereference/rcu_read_unlock removal ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/mballoc.c | 10 +++------- + fs/ext4/super.c | 6 ++---- + 2 files changed, 5 insertions(+), 11 deletions(-) + +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -2894,9 +2894,7 @@ err_freebuddy: + rcu_read_unlock(); + iput(sbi->s_buddy_cache); + err_freesgi: +- rcu_read_lock(); +- kvfree(rcu_dereference(sbi->s_group_info)); +- rcu_read_unlock(); ++ kvfree(rcu_access_pointer(sbi->s_group_info)); + return -ENOMEM; + } + +@@ -3088,7 +3086,8 @@ int ext4_mb_release(struct super_block * + struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits); + int count; + +- if (sbi->s_group_info) { ++ group_info = rcu_access_pointer(sbi->s_group_info); ++ if (group_info) { + for (i = 0; i < ngroups; i++) { + cond_resched(); + grinfo = ext4_get_group_info(sb, i); +@@ -3106,12 +3105,9 @@ int ext4_mb_release(struct super_block * + num_meta_group_infos = (ngroups + + EXT4_DESC_PER_BLOCK(sb) - 1) >> + EXT4_DESC_PER_BLOCK_BITS(sb); +- rcu_read_lock(); +- group_info = rcu_dereference(sbi->s_group_info); + for (i = 0; i < num_meta_group_infos; i++) + kfree(group_info[i]); + kvfree(group_info); +- rcu_read_unlock(); + } + kfree(sbi->s_mb_offsets); + kfree(sbi->s_mb_maxs); +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -1207,18 +1207,16 @@ static void ext4_put_super(struct super_ + if (!sb_rdonly(sb)) + ext4_commit_super(sb, 1); + +- rcu_read_lock(); +- group_desc = rcu_dereference(sbi->s_group_desc); ++ group_desc = rcu_access_pointer(sbi->s_group_desc); + for (i = 0; i < sbi->s_gdb_count; i++) + brelse(group_desc[i]); + kvfree(group_desc); +- flex_groups = rcu_dereference(sbi->s_flex_groups); ++ flex_groups = rcu_access_pointer(sbi->s_flex_groups); + if (flex_groups) { + for (i = 0; i < sbi->s_flex_groups_allocated; i++) + kvfree(flex_groups[i]); + kvfree(flex_groups); + } +- rcu_read_unlock(); + percpu_counter_destroy(&sbi->s_freeclusters_counter); + percpu_counter_destroy(&sbi->s_freeinodes_counter); + percpu_counter_destroy(&sbi->s_dirs_counter); diff --git a/queue-5.10/ext4-publish-jinode-after-initialization.patch b/queue-5.10/ext4-publish-jinode-after-initialization.patch new file mode 100644 index 0000000000..456de0cc6e --- /dev/null +++ b/queue-5.10/ext4-publish-jinode-after-initialization.patch @@ -0,0 +1,152 @@ +From stable+bounces-233178-greg=kroah.com@vger.kernel.org Fri Apr 3 13:49:14 2026 +From: Sasha Levin +Date: Fri, 3 Apr 2026 07:49:07 -0400 +Subject: ext4: publish jinode after initialization +To: stable@vger.kernel.org +Cc: Li Chen , Jan Kara , Theodore Ts'o , stable@kernel.org, Sasha Levin +Message-ID: <20260403114907.2051129-1-sashal@kernel.org> + +From: Li Chen + +[ Upstream commit 1aec30021edd410b986c156f195f3d23959a9d11 ] + +ext4_inode_attach_jinode() publishes ei->jinode to concurrent users. +It used to set ei->jinode before jbd2_journal_init_jbd_inode(), +allowing a reader to observe a non-NULL jinode with i_vfs_inode +still unset. + +The fast commit flush path can then pass this jinode to +jbd2_wait_inode_data(), which dereferences i_vfs_inode->i_mapping and +may crash. + +Below is the crash I observe: +``` +BUG: unable to handle page fault for address: 000000010beb47f4 +PGD 110e51067 P4D 110e51067 PUD 0 +Oops: Oops: 0000 [#1] SMP NOPTI +CPU: 1 UID: 0 PID: 4850 Comm: fc_fsync_bench_ Not tainted 6.18.0-00764-g795a690c06a5 #1 PREEMPT(voluntary) +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.17.0-2-2 04/01/2014 +RIP: 0010:xas_find_marked+0x3d/0x2e0 +Code: e0 03 48 83 f8 02 0f 84 f0 01 00 00 48 8b 47 08 48 89 c3 48 39 c6 0f 82 fd 01 00 00 48 85 c9 74 3d 48 83 f9 03 77 63 4c 8b 0f <49> 8b 71 08 48 c7 47 18 00 00 00 00 48 89 f1 83 e1 03 48 83 f9 02 +RSP: 0018:ffffbbee806e7bf0 EFLAGS: 00010246 +RAX: 000000000010beb4 RBX: 000000000010beb4 RCX: 0000000000000003 +RDX: 0000000000000001 RSI: 0000002000300000 RDI: ffffbbee806e7c10 +RBP: 0000000000000001 R08: 0000002000300000 R09: 000000010beb47ec +R10: ffff9ea494590090 R11: 0000000000000000 R12: 0000002000300000 +R13: ffffbbee806e7c90 R14: ffff9ea494513788 R15: ffffbbee806e7c88 +FS: 00007fc2f9e3e6c0(0000) GS:ffff9ea6b1444000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 000000010beb47f4 CR3: 0000000119ac5000 CR4: 0000000000750ef0 +PKRU: 55555554 +Call Trace: + +filemap_get_folios_tag+0x87/0x2a0 +__filemap_fdatawait_range+0x5f/0xd0 +? srso_alias_return_thunk+0x5/0xfbef5 +? __schedule+0x3e7/0x10c0 +? srso_alias_return_thunk+0x5/0xfbef5 +? srso_alias_return_thunk+0x5/0xfbef5 +? srso_alias_return_thunk+0x5/0xfbef5 +? preempt_count_sub+0x5f/0x80 +? srso_alias_return_thunk+0x5/0xfbef5 +? cap_safe_nice+0x37/0x70 +? srso_alias_return_thunk+0x5/0xfbef5 +? preempt_count_sub+0x5f/0x80 +? srso_alias_return_thunk+0x5/0xfbef5 +filemap_fdatawait_range_keep_errors+0x12/0x40 +ext4_fc_commit+0x697/0x8b0 +? ext4_file_write_iter+0x64b/0x950 +? srso_alias_return_thunk+0x5/0xfbef5 +? preempt_count_sub+0x5f/0x80 +? srso_alias_return_thunk+0x5/0xfbef5 +? vfs_write+0x356/0x480 +? srso_alias_return_thunk+0x5/0xfbef5 +? preempt_count_sub+0x5f/0x80 +ext4_sync_file+0xf7/0x370 +do_fsync+0x3b/0x80 +? syscall_trace_enter+0x108/0x1d0 +__x64_sys_fdatasync+0x16/0x20 +do_syscall_64+0x62/0x2c0 +entry_SYSCALL_64_after_hwframe+0x76/0x7e +... +``` + +Fix this by initializing the jbd2_inode first. +Use smp_wmb() and WRITE_ONCE() to publish ei->jinode after +initialization. Readers use READ_ONCE() to fetch the pointer. + +Fixes: a361293f5fede ("jbd2: Fix oops in jbd2_journal_file_inode()") +Cc: stable@vger.kernel.org +Signed-off-by: Li Chen +Reviewed-by: Jan Kara +Link: https://patch.msgid.link/20260225082617.147957-1-me@linux.beauty +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +[ adapted READ_ONCE(jinode) wrapping to split ext4_fc_submit_inode_data_all() and ext4_fc_wait_inode_data_all() ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/fast_commit.c | 4 ++-- + fs/ext4/inode.c | 15 +++++++++++---- + 2 files changed, 13 insertions(+), 6 deletions(-) + +--- a/fs/ext4/fast_commit.c ++++ b/fs/ext4/fast_commit.c +@@ -902,7 +902,7 @@ static int ext4_fc_submit_inode_data_all + finish_wait(&ei->i_fc_wait, &wait); + } + spin_unlock(&sbi->s_fc_lock); +- ret = jbd2_submit_inode_data(ei->jinode); ++ ret = jbd2_submit_inode_data(READ_ONCE(ei->jinode)); + if (ret) + return ret; + spin_lock(&sbi->s_fc_lock); +@@ -927,7 +927,7 @@ static int ext4_fc_wait_inode_data_all(j + continue; + spin_unlock(&sbi->s_fc_lock); + +- ret = jbd2_wait_inode_data(journal, pos->jinode); ++ ret = jbd2_wait_inode_data(journal, READ_ONCE(pos->jinode)); + if (ret) + return ret; + spin_lock(&sbi->s_fc_lock); +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -121,6 +121,8 @@ void ext4_inode_csum_set(struct inode *i + static inline int ext4_begin_ordered_truncate(struct inode *inode, + loff_t new_size) + { ++ struct jbd2_inode *jinode = READ_ONCE(EXT4_I(inode)->jinode); ++ + trace_ext4_begin_ordered_truncate(inode, new_size); + /* + * If jinode is zero, then we never opened the file for +@@ -128,10 +130,10 @@ static inline int ext4_begin_ordered_tru + * jbd2_journal_begin_ordered_truncate() since there's no + * outstanding writes we need to flush. + */ +- if (!EXT4_I(inode)->jinode) ++ if (!jinode) + return 0; + return jbd2_journal_begin_ordered_truncate(EXT4_JOURNAL(inode), +- EXT4_I(inode)->jinode, ++ jinode, + new_size); + } + +@@ -4231,8 +4233,13 @@ int ext4_inode_attach_jinode(struct inod + spin_unlock(&inode->i_lock); + return -ENOMEM; + } +- ei->jinode = jinode; +- jbd2_journal_init_jbd_inode(ei->jinode, inode); ++ jbd2_journal_init_jbd_inode(jinode, inode); ++ /* ++ * Publish ->jinode only after it is fully initialized so that ++ * readers never observe a partially initialized jbd2_inode. ++ */ ++ smp_wmb(); ++ WRITE_ONCE(ei->jinode, jinode); + jinode = NULL; + } + spin_unlock(&inode->i_lock); diff --git a/queue-5.10/media-device-property-return-true-in-fwnode_device_is_available-for-null-ops.patch b/queue-5.10/media-device-property-return-true-in-fwnode_device_is_available-for-null-ops.patch new file mode 100644 index 0000000000..569e45a315 --- /dev/null +++ b/queue-5.10/media-device-property-return-true-in-fwnode_device_is_available-for-null-ops.patch @@ -0,0 +1,52 @@ +From sashal@kernel.org Tue Mar 17 18:19:59 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 13:19:48 -0400 +Subject: media: device property: Return true in fwnode_device_is_available for NULL ops +To: stable@vger.kernel.org +Cc: Daniel Scally , Laurent Pinchart , Andy Shevchenko , Heikki Krogerus , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sakari Ailus , Mauro Carvalho Chehab , Sasha Levin +Message-ID: <20260317171954.238398-2-sashal@kernel.org> + +From: Daniel Scally + +[ Upstream commit 5273382d03763277aaf8c6a2d6088e2afaee0cf0 ] + +Some types of fwnode_handle do not implement the device_is_available() +check, such as those created by software_nodes. There isn't really a +meaningful way to check for the availability of a device that doesn't +actually exist, so if the check isn't implemented just assume that the +"device" is present. + +Suggested-by: Laurent Pinchart +Reviewed-by: Laurent Pinchart +Reviewed-by: Andy Shevchenko +Signed-off-by: Daniel Scally +Reviewed-by: Heikki Krogerus +Acked-by: Greg Kroah-Hartman +Acked-by: Rafael J. Wysocki +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Stable-dep-of: 2692c614f8f0 ("device property: Allow secondary lookup in fwnode_get_next_child_node()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/property.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/base/property.c ++++ b/drivers/base/property.c +@@ -837,9 +837,15 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put); + /** + * fwnode_device_is_available - check if a device is available for use + * @fwnode: Pointer to the fwnode of the device. ++ * ++ * For fwnode node types that don't implement the .device_is_available() ++ * operation, this function returns true. + */ + bool fwnode_device_is_available(const struct fwnode_handle *fwnode) + { ++ if (!fwnode_has_op(fwnode, device_is_available)) ++ return true; ++ + return fwnode_call_bool_op(fwnode, device_is_available); + } + EXPORT_SYMBOL_GPL(fwnode_device_is_available); diff --git a/queue-5.10/mm-huge_memory-fix-folio-isn-t-locked-in-softleaf_to_folio.patch b/queue-5.10/mm-huge_memory-fix-folio-isn-t-locked-in-softleaf_to_folio.patch new file mode 100644 index 0000000000..94c4626542 --- /dev/null +++ b/queue-5.10/mm-huge_memory-fix-folio-isn-t-locked-in-softleaf_to_folio.patch @@ -0,0 +1,87 @@ +From stable+bounces-231440-greg=kroah.com@vger.kernel.org Tue Mar 31 16:45:17 2026 +From: Sasha Levin +Date: Tue, 31 Mar 2026 10:43:42 -0400 +Subject: mm/huge_memory: fix folio isn't locked in softleaf_to_folio() +To: stable@vger.kernel.org +Cc: Jinjiang Tu , "David Hildenbrand (Arm)" , "Lorenzo Stoakes (Oracle)" , Barry Song , Kefeng Wang , Liam Howlett , Michal Hocko , Mike Rapoport , Nanyong Sun , Ryan Roberts , Suren Baghdasaryan , Vlastimil Babka , Andrew Morton , Sasha Levin +Message-ID: <20260331144342.2532713-1-sashal@kernel.org> + +From: Jinjiang Tu + +[ Upstream commit 4c5e7f0fcd592801c9cc18f29f80fbee84eb8669 ] + +On arm64 server, we found folio that get from migration entry isn't locked +in softleaf_to_folio(). This issue triggers when mTHP splitting and +zap_nonpresent_ptes() races, and the root cause is lack of memory barrier +in softleaf_to_folio(). The race is as follows: + + CPU0 CPU1 + +deferred_split_scan() zap_nonpresent_ptes() + lock folio + split_folio() + unmap_folio() + change ptes to migration entries + __split_folio_to_order() softleaf_to_folio() + set flags(including PG_locked) for tail pages folio = pfn_folio(softleaf_to_pfn(entry)) + smp_wmb() VM_WARN_ON_ONCE(!folio_test_locked(folio)) + prep_compound_page() for tail pages + +In __split_folio_to_order(), smp_wmb() guarantees page flags of tail pages +are visible before the tail page becomes non-compound. smp_wmb() should +be paired with smp_rmb() in softleaf_to_folio(), which is missed. As a +result, if zap_nonpresent_ptes() accesses migration entry that stores tail +pfn, softleaf_to_folio() may see the updated compound_head of tail page +before page->flags. + +This issue will trigger VM_WARN_ON_ONCE() in pfn_swap_entry_folio() +because of the race between folio split and zap_nonpresent_ptes() +leading to a folio incorrectly undergoing modification without a folio +lock being held. + +This is a BUG_ON() before commit 93976a20345b ("mm: eliminate further +swapops predicates"), which in merged in v6.19-rc1. + +To fix it, add missing smp_rmb() if the softleaf entry is migration entry +in softleaf_to_folio() and softleaf_to_page(). + +[tujinjiang@huawei.com: update function name and comments] + Link: https://lkml.kernel.org/r/20260321075214.3305564-1-tujinjiang@huawei.com +Link: https://lkml.kernel.org/r/20260319012541.4158561-1-tujinjiang@huawei.com +Fixes: e9b61f19858a ("thp: reintroduce split_huge_page()") +Signed-off-by: Jinjiang Tu +Acked-by: David Hildenbrand (Arm) +Reviewed-by: Lorenzo Stoakes (Oracle) +Cc: Barry Song +Cc: Kefeng Wang +Cc: Liam Howlett +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Nanyong Sun +Cc: Ryan Roberts +Cc: Suren Baghdasaryan +Cc: Vlastimil Babka +Cc: +Signed-off-by: Andrew Morton +[ adapted upstream leafops.h changes to swapops.h ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/swapops.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/include/linux/swapops.h ++++ b/include/linux/swapops.h +@@ -198,6 +198,12 @@ static inline struct page *migration_ent + { + struct page *p = pfn_to_page(swp_offset(entry)); + /* ++ * Ensure we do not race with split, which might alter tail pages ++ * into new folios and thus result in observing an unlocked page. ++ * This matches the write barrier in __split_huge_page_tail(). ++ */ ++ smp_rmb(); ++ /* + * Any use of migration entries may only occur while the + * corresponding page is locked + */ diff --git a/queue-5.10/mmc-core-avoid-bitfield-rmw-for-claim-retune-flags.patch b/queue-5.10/mmc-core-avoid-bitfield-rmw-for-claim-retune-flags.patch new file mode 100644 index 0000000000..8958d01790 --- /dev/null +++ b/queue-5.10/mmc-core-avoid-bitfield-rmw-for-claim-retune-flags.patch @@ -0,0 +1,63 @@ +From stable+bounces-225857-greg=kroah.com@vger.kernel.org Tue Mar 17 12:54:12 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 07:49:49 -0400 +Subject: mmc: core: Avoid bitfield RMW for claim/retune flags +To: stable@vger.kernel.org +Cc: Penghe Geng , Adrian Hunter , Ulf Hansson , Sasha Levin +Message-ID: <20260317114949.126875-4-sashal@kernel.org> + +From: Penghe Geng + +[ Upstream commit 901084c51a0a8fb42a3f37d2e9c62083c495f824 ] + +Move claimed and retune control flags out of the bitfield word to +avoid unrelated RMW side effects in asynchronous contexts. + +The host->claimed bit shared a word with retune flags. Writes to claimed +in __mmc_claim_host() or retune_now in mmc_mq_queue_rq() can overwrite +other bits when concurrent updates happen in other contexts, triggering +spurious WARN_ON(!host->claimed). Convert claimed, can_retune, +retune_now and retune_paused to bool to remove shared-word coupling. + +Fixes: 6c0cedd1ef952 ("mmc: core: Introduce host claiming by context") +Fixes: 1e8e55b67030c ("mmc: block: Add CQE support") +Cc: stable@vger.kernel.org +Suggested-by: Adrian Hunter +Signed-off-by: Penghe Geng +Acked-by: Adrian Hunter +Signed-off-by: Ulf Hansson +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/mmc/host.h | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -400,14 +400,12 @@ struct mmc_host { + + struct mmc_ios ios; /* current io bus settings */ + ++ bool claimed; /* host exclusively claimed */ ++ + /* group bitfields together to minimize padding */ + unsigned int use_spi_crc:1; +- unsigned int claimed:1; /* host exclusively claimed */ + unsigned int doing_init_tune:1; /* initial tuning in progress */ +- unsigned int can_retune:1; /* re-tuning can be used */ + unsigned int doing_retune:1; /* re-tuning in progress */ +- unsigned int retune_now:1; /* do re-tuning at next req */ +- unsigned int retune_paused:1; /* re-tuning is temporarily disabled */ + unsigned int retune_crc_disable:1; /* don't trigger retune upon crc */ + unsigned int can_dma_map_merge:1; /* merging can be used */ + unsigned int vqmmc_enabled:1; /* vqmmc regulator is enabled */ +@@ -415,6 +413,9 @@ struct mmc_host { + int rescan_disable; /* disable card detection */ + int rescan_entered; /* used with nonremovable devices */ + ++ bool can_retune; /* re-tuning can be used */ ++ bool retune_now; /* do re-tuning at next req */ ++ bool retune_paused; /* re-tuning is temporarily disabled */ + int need_retune; /* re-tuning is needed */ + int hold_retune; /* hold off re-tuning */ + unsigned int retune_period; /* re-tuning period in secs */ diff --git a/queue-5.10/mmc-core-drop-redundant-member-in-struct-mmc-host.patch b/queue-5.10/mmc-core-drop-redundant-member-in-struct-mmc-host.patch new file mode 100644 index 0000000000..47c3b95833 --- /dev/null +++ b/queue-5.10/mmc-core-drop-redundant-member-in-struct-mmc-host.patch @@ -0,0 +1,35 @@ +From stable+bounces-225854-greg=kroah.com@vger.kernel.org Tue Mar 17 12:54:00 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 07:49:46 -0400 +Subject: mmc: core: Drop redundant member in struct mmc host +To: stable@vger.kernel.org +Cc: Ulf Hansson , Sasha Levin +Message-ID: <20260317114949.126875-1-sashal@kernel.org> + +From: Ulf Hansson + +[ Upstream commit 951f6ccfcbb7e4a18bf5fef1fb373d21e5831957 ] + +The Kconfig option to use the blk-mq support was removed in commit +1bec43a3b181 ("mmc: core: Remove option not to use blk-mq"), but forgot to +remove the use_blk_mq member in the struct mmc_host, let's fix it. + +Signed-off-by: Ulf Hansson +Link: https://lore.kernel.org/r/20210202101924.69970-1-ulf.hansson@linaro.org +Stable-dep-of: 901084c51a0a ("mmc: core: Avoid bitfield RMW for claim/retune flags") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/mmc/host.h | 1 - + 1 file changed, 1 deletion(-) + +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -409,7 +409,6 @@ struct mmc_host { + unsigned int doing_retune:1; /* re-tuning in progress */ + unsigned int retune_now:1; /* do re-tuning at next req */ + unsigned int retune_paused:1; /* re-tuning is temporarily disabled */ +- unsigned int use_blk_mq:1; /* use blk-mq */ + unsigned int retune_crc_disable:1; /* don't trigger retune upon crc */ + unsigned int can_dma_map_merge:1; /* merging can be used */ + unsigned int vqmmc_enabled:1; /* vqmmc regulator is enabled */ diff --git a/queue-5.10/mmc-core-drop-reference-counting-of-the-bus_ops.patch b/queue-5.10/mmc-core-drop-reference-counting-of-the-bus_ops.patch new file mode 100644 index 0000000000..7e715ea4c8 --- /dev/null +++ b/queue-5.10/mmc-core-drop-reference-counting-of-the-bus_ops.patch @@ -0,0 +1,214 @@ +From stable+bounces-225856-greg=kroah.com@vger.kernel.org Tue Mar 17 12:49:59 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 07:49:48 -0400 +Subject: mmc: core: Drop reference counting of the bus_ops +To: stable@vger.kernel.org +Cc: Ulf Hansson , Pierre Ossman , Russell King , Adrian Hunter , Sasha Levin +Message-ID: <20260317114949.126875-3-sashal@kernel.org> + +From: Ulf Hansson + +[ Upstream commit e9ce2ce17da626d930812199568bd426b2832f57 ] + +When the mmc_rescan work is enabled for execution (host->rescan_disable), +it's the only instance per mmc host that is allowed to set/clear the +host->bus_ops pointer. + +Besides the mmc_rescan work, there are a couple of scenarios when the +host->bus_ops pointer may be accessed. Typically, those can be described as +as below: + +*) +Upper mmc driver layers (like the mmc block device driver or an SDIO +functional driver) needs to execute a host->bus_ops callback. This can be +considered as safe without having to use some special locking mechanism, +because they operate on top of the struct mmc_card. As long as there is a +card to operate upon, the mmc core guarantees that there is a host->bus_ops +assigned as well. Note that, upper layer mmc drivers are of course +responsible to clean up from themselves from their ->remove() callbacks, +otherwise things would fall apart anyways. + +**) +Via the mmc host instance, we may need to force a removal of an inserted +mmc card. This happens when a mmc host driver gets unbind, for example. In +this case, we protect the host->bus_ops pointer from concurrent accesses, +by disabling the mmc_rescan work upfront (host->rescan_disable). See +mmc_stop_host() for example. + +This said, it seems like the reference counting of the host->bus_ops +pointer at some point have become superfluous. As this is an old mechanism +of the mmc core, it a bit difficult to digest the history of when that +could have happened. However, let's drop the reference counting to avoid +unnecessary code-paths and lockings. + +Cc: Pierre Ossman +Cc: Russell King +Signed-off-by: Ulf Hansson +Reviewed-by: Adrian Hunter +Link: https://lore.kernel.org/r/20210212131610.236843-1-ulf.hansson@linaro.org +Stable-dep-of: 901084c51a0a ("mmc: core: Avoid bitfield RMW for claim/retune flags") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mmc/core/core.c | 89 ++--------------------------------------------- + include/linux/mmc/host.h | 2 - + 2 files changed, 4 insertions(+), 87 deletions(-) + +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -1389,62 +1389,12 @@ void mmc_power_cycle(struct mmc_host *ho + } + + /* +- * Cleanup when the last reference to the bus operator is dropped. +- */ +-static void __mmc_release_bus(struct mmc_host *host) +-{ +- WARN_ON(!host->bus_dead); +- +- host->bus_ops = NULL; +-} +- +-/* +- * Increase reference count of bus operator +- */ +-static inline void mmc_bus_get(struct mmc_host *host) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&host->lock, flags); +- host->bus_refs++; +- spin_unlock_irqrestore(&host->lock, flags); +-} +- +-/* +- * Decrease reference count of bus operator and free it if +- * it is the last reference. +- */ +-static inline void mmc_bus_put(struct mmc_host *host) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&host->lock, flags); +- host->bus_refs--; +- if ((host->bus_refs == 0) && host->bus_ops) +- __mmc_release_bus(host); +- spin_unlock_irqrestore(&host->lock, flags); +-} +- +-/* + * Assign a mmc bus handler to a host. Only one bus handler may control a + * host at any given time. + */ + void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) + { +- unsigned long flags; +- +- WARN_ON(!host->claimed); +- +- spin_lock_irqsave(&host->lock, flags); +- +- WARN_ON(host->bus_ops); +- WARN_ON(host->bus_refs); +- + host->bus_ops = ops; +- host->bus_refs = 1; +- host->bus_dead = 0; +- +- spin_unlock_irqrestore(&host->lock, flags); + } + + /* +@@ -1452,18 +1402,7 @@ void mmc_attach_bus(struct mmc_host *hos + */ + void mmc_detach_bus(struct mmc_host *host) + { +- unsigned long flags; +- +- WARN_ON(!host->claimed); +- WARN_ON(!host->bus_ops); +- +- spin_lock_irqsave(&host->lock, flags); +- +- host->bus_dead = 1; +- +- spin_unlock_irqrestore(&host->lock, flags); +- +- mmc_bus_put(host); ++ host->bus_ops = NULL; + } + + void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq) +@@ -2260,32 +2199,15 @@ void mmc_rescan(struct work_struct *work + host->trigger_card_event = false; + } + +- mmc_bus_get(host); +- + /* Verify a registered card to be functional, else remove it. */ +- if (host->bus_ops && !host->bus_dead) ++ if (host->bus_ops) + host->bus_ops->detect(host); + + host->detect_change = 0; + +- /* +- * Let mmc_bus_put() free the bus/bus_ops if we've found that +- * the card is no longer present. +- */ +- mmc_bus_put(host); +- mmc_bus_get(host); +- + /* if there still is a card present, stop here */ +- if (host->bus_ops != NULL) { +- mmc_bus_put(host); ++ if (host->bus_ops != NULL) + goto out; +- } +- +- /* +- * Only we can add a new handler, so it's safe to +- * release the lock here. +- */ +- mmc_bus_put(host); + + mmc_claim_host(host); + if (mmc_card_is_removable(host) && host->ops->get_cd && +@@ -2356,18 +2278,15 @@ void mmc_stop_host(struct mmc_host *host + /* clear pm flags now and let card drivers set them as needed */ + host->pm_flags = 0; + +- mmc_bus_get(host); +- if (host->bus_ops && !host->bus_dead) { ++ if (host->bus_ops) { + /* Calling bus_ops->remove() with a claimed host can deadlock */ + host->bus_ops->remove(host); + mmc_claim_host(host); + mmc_detach_bus(host); + mmc_power_off(host); + mmc_release_host(host); +- mmc_bus_put(host); + return; + } +- mmc_bus_put(host); + + mmc_claim_host(host); + mmc_power_off(host); +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -403,7 +403,6 @@ struct mmc_host { + /* group bitfields together to minimize padding */ + unsigned int use_spi_crc:1; + unsigned int claimed:1; /* host exclusively claimed */ +- unsigned int bus_dead:1; /* bus has been released */ + unsigned int doing_init_tune:1; /* initial tuning in progress */ + unsigned int can_retune:1; /* re-tuning can be used */ + unsigned int doing_retune:1; /* re-tuning in progress */ +@@ -435,7 +434,6 @@ struct mmc_host { + struct mmc_slot slot; + + const struct mmc_bus_ops *bus_ops; /* current bus driver */ +- unsigned int bus_refs; /* reference counter */ + + unsigned int sdio_irqs; + struct task_struct *sdio_irq_thread; diff --git a/queue-5.10/mmc-core-drop-superfluous-validations-in-mmc_hw-sw_reset.patch b/queue-5.10/mmc-core-drop-superfluous-validations-in-mmc_hw-sw_reset.patch new file mode 100644 index 0000000000..78e27e96c5 --- /dev/null +++ b/queue-5.10/mmc-core-drop-superfluous-validations-in-mmc_hw-sw_reset.patch @@ -0,0 +1,86 @@ +From stable+bounces-225855-greg=kroah.com@vger.kernel.org Tue Mar 17 12:49:58 2026 +From: Sasha Levin +Date: Tue, 17 Mar 2026 07:49:47 -0400 +Subject: mmc: core: Drop superfluous validations in mmc_hw|sw_reset() +To: stable@vger.kernel.org +Cc: Ulf Hansson , Adrian Hunter , Sasha Levin +Message-ID: <20260317114949.126875-2-sashal@kernel.org> + +From: Ulf Hansson + +[ Upstream commit fefdd3c91e0a7b3cbb3f25925d93a57c45cb0f31 ] + +The mmc_hw|sw_reset() APIs are designed to be called solely from upper +layers, which means drivers that operates on top of the struct mmc_card, +like the mmc block device driver and an SDIO functional driver. + +Additionally, as long as the struct mmc_host has a valid pointer to a +struct mmc_card, the corresponding host->bus_ops pointer stays valid and +assigned. + +For these reasons, let's drop the superfluous reference counting and the +redundant validations in mmc_hw|sw_reset(). + +Signed-off-by: Ulf Hansson +Reviewed-by: Adrian Hunter +Link: https://lore.kernel.org/r/20210212131532.236775-1-ulf.hansson@linaro.org +Stable-dep-of: 901084c51a0a ("mmc: core: Avoid bitfield RMW for claim/retune flags") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/mmc/core/block.c | 2 +- + drivers/mmc/core/core.c | 21 +-------------------- + 2 files changed, 2 insertions(+), 21 deletions(-) + +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -987,7 +987,7 @@ static int mmc_blk_reset(struct mmc_blk_ + md->reset_done |= type; + err = mmc_hw_reset(host); + /* Ensure we switch back to the correct partition */ +- if (err != -EOPNOTSUPP) { ++ if (err) { + struct mmc_blk_data *main_md = + dev_get_drvdata(&host->card->dev); + int part_err; +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -2096,18 +2096,7 @@ int mmc_hw_reset(struct mmc_host *host) + { + int ret; + +- if (!host->card) +- return -EINVAL; +- +- mmc_bus_get(host); +- if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) { +- mmc_bus_put(host); +- return -EOPNOTSUPP; +- } +- + ret = host->bus_ops->hw_reset(host); +- mmc_bus_put(host); +- + if (ret < 0) + pr_warn("%s: tried to HW reset card, got error %d\n", + mmc_hostname(host), ret); +@@ -2120,18 +2109,10 @@ int mmc_sw_reset(struct mmc_host *host) + { + int ret; + +- if (!host->card) +- return -EINVAL; +- +- mmc_bus_get(host); +- if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) { +- mmc_bus_put(host); ++ if (!host->bus_ops->sw_reset) + return -EOPNOTSUPP; +- } + + ret = host->bus_ops->sw_reset(host); +- mmc_bus_put(host); +- + if (ret) + pr_warn("%s: tried to SW reset card, got error %d\n", + mmc_hostname(host), ret); diff --git a/queue-5.10/net-macb-move-devm_-free-request-_irq-out-of-spin-lock-area.patch b/queue-5.10/net-macb-move-devm_-free-request-_irq-out-of-spin-lock-area.patch new file mode 100644 index 0000000000..fe10fb672b --- /dev/null +++ b/queue-5.10/net-macb-move-devm_-free-request-_irq-out-of-spin-lock-area.patch @@ -0,0 +1,147 @@ +From stable+bounces-232615-greg=kroah.com@vger.kernel.org Wed Apr 1 02:18:53 2026 +From: Sasha Levin +Date: Tue, 31 Mar 2026 20:18:48 -0400 +Subject: net: macb: Move devm_{free,request}_irq() out of spin lock area +To: stable@vger.kernel.org +Cc: "Kevin Hao" , "Théo Lebrun" , "Jakub Kicinski" , "Sasha Levin" +Message-ID: <20260401001848.3982933-1-sashal@kernel.org> + +From: Kevin Hao + +[ Upstream commit 317e49358ebbf6390fa439ef3c142f9239dd25fb ] + +The devm_free_irq() and devm_request_irq() functions should not be +executed in an atomic context. + +During device suspend, all userspace processes and most kernel threads +are frozen. Additionally, we flush all tx/rx status, disable all macb +interrupts, and halt rx operations. Therefore, it is safe to split the +region protected by bp->lock into two independent sections, allowing +devm_free_irq() and devm_request_irq() to run in a non-atomic context. +This modification resolves the following lockdep warning: + BUG: sleeping function called from invalid context at kernel/locking/mutex.c:591 + in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 501, name: rtcwake + preempt_count: 1, expected: 0 + RCU nest depth: 1, expected: 0 + 7 locks held by rtcwake/501: + #0: ffff0008038c3408 (sb_writers#5){.+.+}-{0:0}, at: vfs_write+0xf8/0x368 + #1: ffff0008049a5e88 (&of->mutex#2){+.+.}-{4:4}, at: kernfs_fop_write_iter+0xbc/0x1c8 + #2: ffff00080098d588 (kn->active#70){.+.+}-{0:0}, at: kernfs_fop_write_iter+0xcc/0x1c8 + #3: ffff800081c84888 (system_transition_mutex){+.+.}-{4:4}, at: pm_suspend+0x1ec/0x290 + #4: ffff0008009ba0f8 (&dev->mutex){....}-{4:4}, at: device_suspend+0x118/0x4f0 + #5: ffff800081d00458 (rcu_read_lock){....}-{1:3}, at: rcu_lock_acquire+0x4/0x48 + #6: ffff0008031fb9e0 (&bp->lock){-.-.}-{3:3}, at: macb_suspend+0x144/0x558 + irq event stamp: 8682 + hardirqs last enabled at (8681): [] _raw_spin_unlock_irqrestore+0x44/0x88 + hardirqs last disabled at (8682): [] _raw_spin_lock_irqsave+0x38/0x98 + softirqs last enabled at (7322): [] handle_softirqs+0x52c/0x588 + softirqs last disabled at (7317): [] __do_softirq+0x20/0x2c + CPU: 1 UID: 0 PID: 501 Comm: rtcwake Not tainted 7.0.0-rc3-next-20260310-yocto-standard+ #125 PREEMPT + Hardware name: ZynqMP ZCU102 Rev1.1 (DT) + Call trace: + show_stack+0x24/0x38 (C) + __dump_stack+0x28/0x38 + dump_stack_lvl+0x64/0x88 + dump_stack+0x18/0x24 + __might_resched+0x200/0x218 + __might_sleep+0x38/0x98 + __mutex_lock_common+0x7c/0x1378 + mutex_lock_nested+0x38/0x50 + free_irq+0x68/0x2b0 + devm_irq_release+0x24/0x38 + devres_release+0x40/0x80 + devm_free_irq+0x48/0x88 + macb_suspend+0x298/0x558 + device_suspend+0x218/0x4f0 + dpm_suspend+0x244/0x3a0 + dpm_suspend_start+0x50/0x78 + suspend_devices_and_enter+0xec/0x560 + pm_suspend+0x194/0x290 + state_store+0x110/0x158 + kobj_attr_store+0x1c/0x30 + sysfs_kf_write+0xa8/0xd0 + kernfs_fop_write_iter+0x11c/0x1c8 + vfs_write+0x248/0x368 + ksys_write+0x7c/0xf8 + __arm64_sys_write+0x28/0x40 + invoke_syscall+0x4c/0xe8 + el0_svc_common+0x98/0xf0 + do_el0_svc+0x28/0x40 + el0_svc+0x54/0x1e0 + el0t_64_sync_handler+0x84/0x130 + el0t_64_sync+0x198/0x1a0 + +Fixes: 558e35ccfe95 ("net: macb: WoL support for GEM type of Ethernet controller") +Cc: stable@vger.kernel.org +Reviewed-by: Théo Lebrun +Signed-off-by: Kevin Hao +Link: https://patch.msgid.link/20260318-macb-irq-v2-1-f1179768ab24@gmail.com +Signed-off-by: Jakub Kicinski +[ adapted WoL register writes to use MACB_BIT(MAG) instead of tmp variable ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/cadence/macb_main.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/cadence/macb_main.c ++++ b/drivers/net/ethernet/cadence/macb_main.c +@@ -4734,6 +4734,8 @@ static int __maybe_unused macb_suspend(s + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(queue, ISR, -1); + } ++ spin_unlock_irqrestore(&bp->lock, flags); ++ + /* Change interrupt handler and + * Enable WoL IRQ on queue 0 + */ +@@ -4745,11 +4747,12 @@ static int __maybe_unused macb_suspend(s + dev_err(dev, + "Unable to request IRQ %d (error %d)\n", + bp->queues[0].irq, err); +- spin_unlock_irqrestore(&bp->lock, flags); + return err; + } ++ spin_lock_irqsave(&bp->lock, flags); + queue_writel(bp->queues, IER, GEM_BIT(WOL)); + gem_writel(bp, WOL, MACB_BIT(MAG)); ++ spin_unlock_irqrestore(&bp->lock, flags); + } else { + err = devm_request_irq(dev, bp->queues[0].irq, macb_wol_interrupt, + IRQF_SHARED, netdev->name, bp->queues); +@@ -4757,13 +4760,13 @@ static int __maybe_unused macb_suspend(s + dev_err(dev, + "Unable to request IRQ %d (error %d)\n", + bp->queues[0].irq, err); +- spin_unlock_irqrestore(&bp->lock, flags); + return err; + } ++ spin_lock_irqsave(&bp->lock, flags); + queue_writel(bp->queues, IER, MACB_BIT(WOL)); + macb_writel(bp, WOL, MACB_BIT(MAG)); ++ spin_unlock_irqrestore(&bp->lock, flags); + } +- spin_unlock_irqrestore(&bp->lock, flags); + + enable_irq_wake(bp->queues[0].irq); + } +@@ -4825,6 +4828,8 @@ static int __maybe_unused macb_resume(st + queue_readl(bp->queues, ISR); + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + queue_writel(bp->queues, ISR, -1); ++ spin_unlock_irqrestore(&bp->lock, flags); ++ + /* Replace interrupt handler on queue 0 */ + devm_free_irq(dev, bp->queues[0].irq, bp->queues); + err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt, +@@ -4833,10 +4838,8 @@ static int __maybe_unused macb_resume(st + dev_err(dev, + "Unable to request IRQ %d (error %d)\n", + bp->queues[0].irq, err); +- spin_unlock_irqrestore(&bp->lock, flags); + return err; + } +- spin_unlock_irqrestore(&bp->lock, flags); + + disable_irq_wake(bp->queues[0].irq); + diff --git a/queue-5.10/net-rfkill-prevent-unlimited-numbers-of-rfkill-events-from-being-created.patch b/queue-5.10/net-rfkill-prevent-unlimited-numbers-of-rfkill-events-from-being-created.patch new file mode 100644 index 0000000000..51f7d40bdc --- /dev/null +++ b/queue-5.10/net-rfkill-prevent-unlimited-numbers-of-rfkill-events-from-being-created.patch @@ -0,0 +1,140 @@ +From stable+bounces-235850-greg=kroah.com@vger.kernel.org Sun Apr 12 22:03:15 2026 +From: Sasha Levin +Date: Sun, 12 Apr 2026 16:03:08 -0400 +Subject: net: rfkill: prevent unlimited numbers of rfkill events from being created +To: stable@vger.kernel.org +Cc: Greg Kroah-Hartman , Johannes Berg , Yuan Tan , Yifan Wu , Juefei Pu , Xin Liu , stable , Johannes Berg , Sasha Levin +Message-ID: <20260412200308.2406071-1-sashal@kernel.org> + +From: Greg Kroah-Hartman + +[ Upstream commit ea245d78dec594372e27d8c79616baf49e98a4a1 ] + +Userspace can create an unlimited number of rfkill events if the system +is so configured, while not consuming them from the rfkill file +descriptor, causing a potential out of memory situation. Prevent this +from bounding the number of pending rfkill events at a "large" number +(i.e. 1000) to prevent abuses like this. + +Cc: Johannes Berg +Reported-by: Yuan Tan +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Cc: stable +Signed-off-by: Greg Kroah-Hartman +Link: https://patch.msgid.link/2026033013-disfigure-scroll-e25e@gregkh +Signed-off-by: Johannes Berg +[ replaced `rfkill_event_ext` with `rfkill_event`, `scoped_guard` with explicit mutex calls, and removed outer `data->mtx` lock in `rfkill_fop_open` to avoid deadlock with new internal locking ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/rfkill/core.c | 40 +++++++++++++++++++++++++++------------- + 1 file changed, 27 insertions(+), 13 deletions(-) + +--- a/net/rfkill/core.c ++++ b/net/rfkill/core.c +@@ -71,11 +71,14 @@ struct rfkill_int_event { + struct rfkill_event ev; + }; + ++/* Max rfkill events that can be "in-flight" for one data source */ ++#define MAX_RFKILL_EVENT 1000 + struct rfkill_data { + struct list_head list; + struct list_head events; + struct mutex mtx; + wait_queue_head_t read_wait; ++ u32 event_count; + bool input_handler; + }; + +@@ -252,9 +255,12 @@ static void rfkill_global_led_trigger_un + } + #endif /* CONFIG_RFKILL_LEDS */ + +-static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill, +- enum rfkill_operation op) ++static int rfkill_fill_event(struct rfkill_int_event *int_ev, ++ struct rfkill *rfkill, ++ struct rfkill_data *data, ++ enum rfkill_operation op) + { ++ struct rfkill_event *ev = &int_ev->ev; + unsigned long flags; + + ev->idx = rfkill->idx; +@@ -266,6 +272,16 @@ static void rfkill_fill_event(struct rfk + ev->soft = !!(rfkill->state & (RFKILL_BLOCK_SW | + RFKILL_BLOCK_SW_PREV)); + spin_unlock_irqrestore(&rfkill->lock, flags); ++ ++ mutex_lock(&data->mtx); ++ if (data->event_count++ > MAX_RFKILL_EVENT) { ++ data->event_count--; ++ mutex_unlock(&data->mtx); ++ return -ENOSPC; ++ } ++ list_add_tail(&int_ev->list, &data->events); ++ mutex_unlock(&data->mtx); ++ return 0; + } + + static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op) +@@ -277,10 +293,10 @@ static void rfkill_send_events(struct rf + ev = kzalloc(sizeof(*ev), GFP_KERNEL); + if (!ev) + continue; +- rfkill_fill_event(&ev->ev, rfkill, op); +- mutex_lock(&data->mtx); +- list_add_tail(&ev->list, &data->events); +- mutex_unlock(&data->mtx); ++ if (rfkill_fill_event(ev, rfkill, data, op)) { ++ kfree(ev); ++ continue; ++ } + wake_up_interruptible(&data->read_wait); + } + } +@@ -1118,21 +1134,19 @@ static int rfkill_fop_open(struct inode + init_waitqueue_head(&data->read_wait); + + mutex_lock(&rfkill_global_mutex); +- mutex_lock(&data->mtx); + /* +- * start getting events from elsewhere but hold mtx to get +- * startup events added first ++ * start getting events from elsewhere but hold rfkill_global_mutex ++ * to get startup events added first + */ + + list_for_each_entry(rfkill, &rfkill_list, node) { + ev = kzalloc(sizeof(*ev), GFP_KERNEL); + if (!ev) + goto free; +- rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD); +- list_add_tail(&ev->list, &data->events); ++ if (rfkill_fill_event(ev, rfkill, data, RFKILL_OP_ADD)) ++ kfree(ev); + } + list_add(&data->list, &rfkill_fds); +- mutex_unlock(&data->mtx); + mutex_unlock(&rfkill_global_mutex); + + file->private_data = data; +@@ -1140,7 +1154,6 @@ static int rfkill_fop_open(struct inode + return stream_open(inode, file); + + free: +- mutex_unlock(&data->mtx); + mutex_unlock(&rfkill_global_mutex); + mutex_destroy(&data->mtx); + list_for_each_entry_safe(ev, tmp, &data->events, list) +@@ -1200,6 +1213,7 @@ static ssize_t rfkill_fop_read(struct fi + ret = -EFAULT; + + list_del(&ev->list); ++ data->event_count--; + kfree(ev); + out: + mutex_unlock(&data->mtx); diff --git a/queue-5.10/nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch b/queue-5.10/nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch new file mode 100644 index 0000000000..7f2f3c61d6 --- /dev/null +++ b/queue-5.10/nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch @@ -0,0 +1,94 @@ +From stable+bounces-217799-greg=kroah.com@vger.kernel.org Mon Feb 23 18:23:57 2026 +From: Jaskaran Singh +Date: Mon, 23 Feb 2026 22:52:41 +0530 +Subject: nvme: nvme-fc: Ensure ->ioerr_work is cancelled in nvme_fc_delete_ctrl() +To: stable@vger.kernel.org, james.smart@broadcom.com, kbusch@kernel.org, axboe@fb.com, hch@lst.de, sagi@grimberg.me +Cc: linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org, Jaskaran Singh , Marco Patalano , Justin Tee , "Ewan D . Milne" +Message-ID: <20260223172241.291649-3-jsingh@cloudlinux.com> + +From: Jaskaran Singh + +commit 0a2c5495b6d1ecb0fa18ef6631450f391a888256 upstream. + +nvme_fc_delete_assocation() waits for pending I/O to complete before +returning, and an error can cause ->ioerr_work to be queued after +cancel_work_sync() had been called. Move the call to cancel_work_sync() to +be after nvme_fc_delete_association() to ensure ->ioerr_work is not running +when the nvme_fc_ctrl object is freed. Otherwise the following can occur: + +[ 1135.911754] list_del corruption, ff2d24c8093f31f8->next is NULL +[ 1135.917705] ------------[ cut here ]------------ +[ 1135.922336] kernel BUG at lib/list_debug.c:52! +[ 1135.926784] Oops: invalid opcode: 0000 [#1] SMP NOPTI +[ 1135.931851] CPU: 48 UID: 0 PID: 726 Comm: kworker/u449:23 Kdump: loaded Not tainted 6.12.0 #1 PREEMPT(voluntary) +[ 1135.943490] Hardware name: Dell Inc. PowerEdge R660/0HGTK9, BIOS 2.5.4 01/16/2025 +[ 1135.950969] Workqueue: 0x0 (nvme-wq) +[ 1135.954673] RIP: 0010:__list_del_entry_valid_or_report.cold+0xf/0x6f +[ 1135.961041] Code: c7 c7 98 68 72 94 e8 26 45 fe ff 0f 0b 48 c7 c7 70 68 72 94 e8 18 45 fe ff 0f 0b 48 89 fe 48 c7 c7 80 69 72 94 e8 07 45 fe ff <0f> 0b 48 89 d1 48 c7 c7 a0 6a 72 94 48 89 c2 e8 f3 44 fe ff 0f 0b +[ 1135.979788] RSP: 0018:ff579b19482d3e50 EFLAGS: 00010046 +[ 1135.985015] RAX: 0000000000000033 RBX: ff2d24c8093f31f0 RCX: 0000000000000000 +[ 1135.992148] RDX: 0000000000000000 RSI: ff2d24d6bfa1d0c0 RDI: ff2d24d6bfa1d0c0 +[ 1135.999278] RBP: ff2d24c8093f31f8 R08: 0000000000000000 R09: ffffffff951e2b08 +[ 1136.006413] R10: ffffffff95122ac8 R11: 0000000000000003 R12: ff2d24c78697c100 +[ 1136.013546] R13: fffffffffffffff8 R14: 0000000000000000 R15: ff2d24c78697c0c0 +[ 1136.020677] FS: 0000000000000000(0000) GS:ff2d24d6bfa00000(0000) knlGS:0000000000000000 +[ 1136.028765] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 1136.034510] CR2: 00007fd207f90b80 CR3: 000000163ea22003 CR4: 0000000000f73ef0 +[ 1136.041641] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +[ 1136.048776] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400 +[ 1136.055910] PKRU: 55555554 +[ 1136.058623] Call Trace: +[ 1136.061074] +[ 1136.063179] ? show_trace_log_lvl+0x1b0/0x2f0 +[ 1136.067540] ? show_trace_log_lvl+0x1b0/0x2f0 +[ 1136.071898] ? move_linked_works+0x4a/0xa0 +[ 1136.075998] ? __list_del_entry_valid_or_report.cold+0xf/0x6f +[ 1136.081744] ? __die_body.cold+0x8/0x12 +[ 1136.085584] ? die+0x2e/0x50 +[ 1136.088469] ? do_trap+0xca/0x110 +[ 1136.091789] ? do_error_trap+0x65/0x80 +[ 1136.095543] ? __list_del_entry_valid_or_report.cold+0xf/0x6f +[ 1136.101289] ? exc_invalid_op+0x50/0x70 +[ 1136.105127] ? __list_del_entry_valid_or_report.cold+0xf/0x6f +[ 1136.110874] ? asm_exc_invalid_op+0x1a/0x20 +[ 1136.115059] ? __list_del_entry_valid_or_report.cold+0xf/0x6f +[ 1136.120806] move_linked_works+0x4a/0xa0 +[ 1136.124733] worker_thread+0x216/0x3a0 +[ 1136.128485] ? __pfx_worker_thread+0x10/0x10 +[ 1136.132758] kthread+0xfa/0x240 +[ 1136.135904] ? __pfx_kthread+0x10/0x10 +[ 1136.139657] ret_from_fork+0x31/0x50 +[ 1136.143236] ? __pfx_kthread+0x10/0x10 +[ 1136.146988] ret_from_fork_asm+0x1a/0x30 +[ 1136.150915] + +Fixes: 19fce0470f05 ("nvme-fc: avoid calling _nvme_fc_abort_outstanding_ios from interrupt context") +Cc: stable@vger.kernel.org +Tested-by: Marco Patalano +Reviewed-by: Justin Tee +Signed-off-by: Ewan D. Milne +Signed-off-by: Keith Busch +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Jaskaran Singh +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/host/fc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -3259,13 +3259,13 @@ nvme_fc_delete_ctrl(struct nvme_ctrl *nc + { + struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl); + +- cancel_work_sync(&ctrl->ioerr_work); + cancel_delayed_work_sync(&ctrl->connect_work); + /* + * kill the association on the link side. this will block + * waiting for io to terminate + */ + nvme_fc_delete_association(ctrl); ++ cancel_work_sync(&ctrl->ioerr_work); + } + + static void diff --git a/queue-5.10/revert-nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch b/queue-5.10/revert-nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch new file mode 100644 index 0000000000..7cb2bf9377 --- /dev/null +++ b/queue-5.10/revert-nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch @@ -0,0 +1,42 @@ +From stable+bounces-217798-greg=kroah.com@vger.kernel.org Mon Feb 23 18:23:34 2026 +From: Jaskaran Singh +Date: Mon, 23 Feb 2026 22:52:40 +0530 +Subject: Revert "nvme: nvme-fc: Ensure ->ioerr_work is cancelled in nvme_fc_delete_ctrl()" +To: stable@vger.kernel.org, james.smart@broadcom.com, kbusch@kernel.org, axboe@fb.com, hch@lst.de, sagi@grimberg.me +Cc: linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org, Jaskaran Singh +Message-ID: <20260223172241.291649-2-jsingh@cloudlinux.com> + +From: Jaskaran Singh + +This reverts commit 3d78e8e01251da032a5f7cbc9728e4ab1a5a5464. + +The backport of upstream commit 0a2c5495b6d1 was incorrectly applied. +The cancel_work_sync() call for ->ioerr_work was added to +nvme_fc_reset_ctrl_work() instead of nvme_fc_delete_ctrl(). + +Revert this commit so the correct fix can be applied. + +Signed-off-by: Jaskaran Singh +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvme/host/fc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -3259,6 +3259,7 @@ nvme_fc_delete_ctrl(struct nvme_ctrl *nc + { + struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl); + ++ cancel_work_sync(&ctrl->ioerr_work); + cancel_delayed_work_sync(&ctrl->connect_work); + /* + * kill the association on the link side. this will block +@@ -3322,7 +3323,6 @@ nvme_fc_reset_ctrl_work(struct work_stru + + /* will block will waiting for io to terminate */ + nvme_fc_delete_association(ctrl); +- cancel_work_sync(&ctrl->ioerr_work); + + if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) + dev_err(ctrl->ctrl.device, diff --git a/queue-5.10/s390-syscalls-add-spectre-boundary-for-syscall-dispatch-table.patch b/queue-5.10/s390-syscalls-add-spectre-boundary-for-syscall-dispatch-table.patch new file mode 100644 index 0000000000..41f337a715 --- /dev/null +++ b/queue-5.10/s390-syscalls-add-spectre-boundary-for-syscall-dispatch-table.patch @@ -0,0 +1,71 @@ +From stable+bounces-231418-greg=kroah.com@vger.kernel.org Tue Mar 31 14:25:10 2026 +From: Vasily Gorbik +Date: Tue, 31 Mar 2026 14:23:42 +0200 +Subject: s390/syscalls: Add spectre boundary for syscall dispatch table +To: stable@vger.kernel.org +Cc: Greg Kroah-Hartman , Ilya Leoshkevich , Sven Schnelle +Message-ID: +Content-Disposition: inline + +From: Greg Kroah-Hartman + +[ Upstream commit 48b8814e25d073dd84daf990a879a820bad2bcbd ] + +The s390 syscall number is directly controlled by userspace, but does +not have an array_index_nospec() boundary to prevent access past the +syscall function pointer tables. + +Cc: Heiko Carstens +Cc: Vasily Gorbik +Cc: Alexander Gordeev +Cc: Christian Borntraeger +Cc: Sven Schnelle +Cc: Arnd Bergmann +Fixes: 56e62a737028 ("s390: convert to generic entry") +Cc: stable@kernel.org +Assisted-by: gkh_clanker_2000 +Signed-off-by: Greg Kroah-Hartman +Reviewed-by: Vasily Gorbik +Link: https://lore.kernel.org/r/2026032404-sterling-swoosh-43e6@gregkh +Signed-off-by: Vasily Gorbik +[ gor: 5.10 backport. In 5.10, commit 56e62a737028 ("s390: convert to + generic entry") has not been applied — syscall dispatch is in + assembly (entry.S), not in C (syscall.c). The equivalent to + array_index_nospec() is implemented using the same clgr/slbgr/ngr. + + SVC 0 path: the user-controlled syscall number in r1 is clamped via + a single unsigned compare (clgr) followed by slbgr/ngr. The original + cghi/jnl bounds check branch is replaced — the clamp handles both + cases: in-bounds values pass through, out-of-bounds values are zeroed + (producing the same r8=0 dispatch to table[0] as the original branch). + + SVC 1-255 path: syscall number from the 8-bit instruction immediate + is always in bounds. ] +Reviewed-by: Sven Schnelle +Reviewed-by: Ilya Leoshkevich +Signed-off-by: Vasily Gorbik +Signed-off-by: Greg Kroah-Hartman +--- + arch/s390/kernel/entry.S | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/arch/s390/kernel/entry.S ++++ b/arch/s390/kernel/entry.S +@@ -420,12 +420,15 @@ ENTRY(system_call) + # svc 0: system call number in %r1 + llgfr %r1,%r1 # clear high word in r1 + sth %r1,__PT_INT_CODE+2(%r11) +- cghi %r1,NR_syscalls +- jnl .Lsysc_nr_ok ++ lghi %r0,NR_syscalls-1 ++ clgr %r1,%r0 # CC0/1 if r1 in bounds ++ slbgr %r0,%r0 # mask = -1 in bounds, 0 out of bounds ++ ngr %r1,%r0 # clamp r1 + slag %r8,%r1,3 + .Lsysc_nr_ok: + stg %r2,__PT_ORIG_GPR2(%r11) + stg %r7,STACK_FRAME_OVERHEAD(%r15) ++ xgr %r1,%r1 # scrub r1, unclamped user value for svc 1-255 + lg %r9,0(%r8,%r10) # get system call add. + TSTMSK __TI_flags(%r12),_TIF_TRACE + jnz .Lsysc_tracesys diff --git a/queue-5.10/seg6-separate-dst_cache-for-input-and-output-paths-in-seg6-lwtunnel.patch b/queue-5.10/seg6-separate-dst_cache-for-input-and-output-paths-in-seg6-lwtunnel.patch new file mode 100644 index 0000000000..0ad9973e1c --- /dev/null +++ b/queue-5.10/seg6-separate-dst_cache-for-input-and-output-paths-in-seg6-lwtunnel.patch @@ -0,0 +1,125 @@ +From stable+bounces-235865-greg=kroah.com@vger.kernel.org Mon Apr 13 00:51:51 2026 +From: Sasha Levin +Date: Sun, 12 Apr 2026 18:51:40 -0400 +Subject: seg6: separate dst_cache for input and output paths in seg6 lwtunnel +To: stable@vger.kernel.org +Cc: Andrea Mayer , Nicolas Dichtel , Justin Iurman , Jakub Kicinski , Sasha Levin +Message-ID: <20260412225140.2461891-1-sashal@kernel.org> + +From: Andrea Mayer + +[ Upstream commit c3812651b522fe8437ebb7063b75ddb95b571643 ] + +The seg6 lwtunnel uses a single dst_cache per encap route, shared +between seg6_input_core() and seg6_output_core(). These two paths +can perform the post-encap SID lookup in different routing contexts +(e.g., ip rules matching on the ingress interface, or VRF table +separation). Whichever path runs first populates the cache, and the +other reuses it blindly, bypassing its own lookup. + +Fix this by splitting the cache into cache_input and cache_output, +so each path maintains its own cached dst independently. + +Fixes: 6c8702c60b88 ("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels") +Cc: stable@vger.kernel.org +Signed-off-by: Andrea Mayer +Reviewed-by: Nicolas Dichtel +Reviewed-by: Justin Iurman +Link: https://patch.msgid.link/20260404004405.4057-2-andrea.mayer@uniroma2.it +Signed-off-by: Jakub Kicinski +[ adapted cache field references ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/seg6_iptunnel.c | 34 +++++++++++++++++++++++----------- + 1 file changed, 23 insertions(+), 11 deletions(-) + +--- a/net/ipv6/seg6_iptunnel.c ++++ b/net/ipv6/seg6_iptunnel.c +@@ -45,7 +45,8 @@ static size_t seg6_lwt_headroom(struct s + } + + struct seg6_lwt { +- struct dst_cache cache; ++ struct dst_cache cache_input; ++ struct dst_cache cache_output; + struct seg6_iptunnel_encap tuninfo[]; + }; + +@@ -326,7 +327,7 @@ static int seg6_input(struct sk_buff *sk + slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); + + local_bh_disable(); +- dst = dst_cache_get(&slwt->cache); ++ dst = dst_cache_get(&slwt->cache_input); + + skb_dst_drop(skb); + +@@ -334,7 +335,7 @@ static int seg6_input(struct sk_buff *sk + ip6_route_input(skb); + dst = skb_dst(skb); + if (!dst->error) { +- dst_cache_set_ip6(&slwt->cache, dst, ++ dst_cache_set_ip6(&slwt->cache_input, dst, + &ipv6_hdr(skb)->saddr); + } + } else { +@@ -363,7 +364,7 @@ static int seg6_output(struct net *net, + slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate); + + local_bh_disable(); +- dst = dst_cache_get(&slwt->cache); ++ dst = dst_cache_get(&slwt->cache_output); + local_bh_enable(); + + if (unlikely(!dst)) { +@@ -384,7 +385,7 @@ static int seg6_output(struct net *net, + } + + local_bh_disable(); +- dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr); ++ dst_cache_set_ip6(&slwt->cache_output, dst, &fl6.saddr); + local_bh_enable(); + } + +@@ -461,11 +462,13 @@ static int seg6_build_state(struct net * + + slwt = seg6_lwt_lwtunnel(newts); + +- err = dst_cache_init(&slwt->cache, GFP_ATOMIC); +- if (err) { +- kfree(newts); +- return err; +- } ++ err = dst_cache_init(&slwt->cache_input, GFP_ATOMIC); ++ if (err) ++ goto err_free_newts; ++ ++ err = dst_cache_init(&slwt->cache_output, GFP_ATOMIC); ++ if (err) ++ goto err_destroy_input; + + memcpy(&slwt->tuninfo, tuninfo, tuninfo_len); + +@@ -480,11 +483,20 @@ static int seg6_build_state(struct net * + *ts = newts; + + return 0; ++ ++err_destroy_input: ++ dst_cache_destroy(&slwt->cache_input); ++err_free_newts: ++ kfree(newts); ++ return err; + } + + static void seg6_destroy_state(struct lwtunnel_state *lwt) + { +- dst_cache_destroy(&seg6_lwt_lwtunnel(lwt)->cache); ++ struct seg6_lwt *slwt = seg6_lwt_lwtunnel(lwt); ++ ++ dst_cache_destroy(&slwt->cache_input); ++ dst_cache_destroy(&slwt->cache_output); + } + + static int seg6_fill_encap_info(struct sk_buff *skb, diff --git a/queue-5.10/series b/queue-5.10/series index ef32c85e16..fe0b6aec3b 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -458,3 +458,35 @@ xen-privcmd-unregister-xenstore-notifier-on-module-exit.patch asoc-soc-core-don-t-use-discriminatory-terms-on-snd_soc_runtime_get_dai_fmt.patch asoc-tegra-fix-master-volume-control.patch netlink-add-nla-be16-32-types-to-minlen-array.patch +cpufreq-governor-free-dbs_data-directly-when-gov-init-fails.patch +cpufreq-governor-fix-double-free-in-cpufreq_dbs_governor_init-error-path.patch +seg6-separate-dst_cache-for-input-and-output-paths-in-seg6-lwtunnel.patch +net-rfkill-prevent-unlimited-numbers-of-rfkill-events-from-being-created.patch +usb-gadget-f_hid-move-list-and-spinlock-inits-from-bind-to-alloc.patch +usb-gadget-u_ether-fix-race-between-gether_disconnect-and-eth_stop.patch +usb-gadget-uvc-fix-null-pointer-dereference-during-unbind-race.patch +net-macb-move-devm_-free-request-_irq-out-of-spin-lock-area.patch +mm-huge_memory-fix-folio-isn-t-locked-in-softleaf_to_folio.patch +ext4-fix-the-might_sleep-warnings-in-kvfree.patch +xfs-save-ailp-before-dropping-the-ail-lock-in-push-callbacks.patch +xfs-stop-reclaim-before-pushing-ail-during-unmount.patch +ext4-fix-iloc.bh-leak-in-ext4_fc_replay_inode-error-paths.patch +ext4-publish-jinode-after-initialization.patch +bluetooth-l2cap-fix-accepting-multiple-l2cap_ecred_conn_req.patch +drm-fix-use-after-free-on-framebuffers-and-property-blobs-when-calling-drm_dev_unplug.patch +mmc-core-drop-redundant-member-in-struct-mmc-host.patch +mmc-core-drop-superfluous-validations-in-mmc_hw-sw_reset.patch +mmc-core-drop-reference-counting-of-the-bus_ops.patch +mmc-core-avoid-bitfield-rmw-for-claim-retune-flags.patch +revert-nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch +nvme-nvme-fc-ensure-ioerr_work-is-cancelled-in-nvme_fc_delete_ctrl.patch +device-property-add-fwnode_is_ancestor_of-and-fwnode_get_next_parent_dev.patch +media-device-property-return-true-in-fwnode_device_is_available-for-null-ops.patch +device-property-retrieve-fwnode-from-of_node-via-accessor.patch +device-property-unify-access-to-of_node.patch +device-property-check-fwnode-secondary-in-fwnode_graph_get_next_endpoint.patch +device-property-check-fwnode-secondary-when-finding-properties.patch +device-property-allow-error-pointer-to-be-passed-to-fwnode-apis.patch +device-property-allow-secondary-lookup-in-fwnode_get_next_child_node.patch +batman-adv-avoid-ogm-aggregation-when-skb-tailroom-is-insufficient.patch +s390-syscalls-add-spectre-boundary-for-syscall-dispatch-table.patch diff --git a/queue-5.10/usb-gadget-f_hid-move-list-and-spinlock-inits-from-bind-to-alloc.patch b/queue-5.10/usb-gadget-f_hid-move-list-and-spinlock-inits-from-bind-to-alloc.patch new file mode 100644 index 0000000000..adecd7e1b5 --- /dev/null +++ b/queue-5.10/usb-gadget-f_hid-move-list-and-spinlock-inits-from-bind-to-alloc.patch @@ -0,0 +1,72 @@ +From stable+bounces-235809-greg=kroah.com@vger.kernel.org Sun Apr 12 14:11:25 2026 +From: Sasha Levin +Date: Sun, 12 Apr 2026 08:11:18 -0400 +Subject: usb: gadget: f_hid: move list and spinlock inits from bind to alloc +To: stable@vger.kernel.org +Cc: Michael Zimmermann , stable , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260412121118.2103786-1-sashal@kernel.org> + +From: Michael Zimmermann + +[ Upstream commit 4e0a88254ad59f6c53a34bf5fa241884ec09e8b2 ] + +There was an issue when you did the following: +- setup and bind an hid gadget +- open /dev/hidg0 +- use the resulting fd in EPOLL_CTL_ADD +- unbind the UDC +- bind the UDC +- use the fd in EPOLL_CTL_DEL + +When CONFIG_DEBUG_LIST was enabled, a list_del corruption was reported +within remove_wait_queue (via ep_remove_wait_queue). After some +debugging I found out that the queues, which f_hid registers via +poll_wait were the problem. These were initialized using +init_waitqueue_head inside hidg_bind. So effectively, the bind function +re-initialized the queues while there were still items in them. + +The solution is to move the initialization from hidg_bind to hidg_alloc +to extend their lifetimes to the lifetime of the function instance. + +Additionally, I found many other possibly problematic init calls in the +bind function, which I moved as well. + +Signed-off-by: Michael Zimmermann +Cc: stable +Link: https://patch.msgid.link/20260331184844.2388761-1-sigmaepsilon92@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_hid.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +--- a/drivers/usb/gadget/function/f_hid.c ++++ b/drivers/usb/gadget/function/f_hid.c +@@ -996,13 +996,8 @@ static int hidg_bind(struct usb_configur + if (status) + goto fail; + +- spin_lock_init(&hidg->write_spinlock); + hidg->write_pending = 1; + hidg->req = NULL; +- spin_lock_init(&hidg->read_spinlock); +- init_waitqueue_head(&hidg->write_queue); +- init_waitqueue_head(&hidg->read_queue); +- INIT_LIST_HEAD(&hidg->completed_out_req); + + /* create char device */ + cdev_init(&hidg->cdev, &f_hidg_fops); +@@ -1272,6 +1267,12 @@ static struct usb_function *hidg_alloc(s + mutex_lock(&opts->lock); + ++opts->refcnt; + ++ spin_lock_init(&hidg->write_spinlock); ++ spin_lock_init(&hidg->read_spinlock); ++ init_waitqueue_head(&hidg->write_queue); ++ init_waitqueue_head(&hidg->read_queue); ++ INIT_LIST_HEAD(&hidg->completed_out_req); ++ + device_initialize(&hidg->dev); + hidg->dev.release = hidg_release; + hidg->dev.class = hidg_class; diff --git a/queue-5.10/usb-gadget-u_ether-fix-race-between-gether_disconnect-and-eth_stop.patch b/queue-5.10/usb-gadget-u_ether-fix-race-between-gether_disconnect-and-eth_stop.patch new file mode 100644 index 0000000000..b75b525a30 --- /dev/null +++ b/queue-5.10/usb-gadget-u_ether-fix-race-between-gether_disconnect-and-eth_stop.patch @@ -0,0 +1,80 @@ +From stable+bounces-235759-greg=kroah.com@vger.kernel.org Sat Apr 11 20:15:50 2026 +From: Sasha Levin +Date: Sat, 11 Apr 2026 14:14:06 -0400 +Subject: usb: gadget: u_ether: Fix race between gether_disconnect and eth_stop +To: stable@vger.kernel.org +Cc: Kuen-Han Tsai , stable , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260411181406.842742-1-sashal@kernel.org> + +From: Kuen-Han Tsai + +[ Upstream commit e1eabb072c75681f78312c484ccfffb7430f206e ] + +A race condition between gether_disconnect() and eth_stop() leads to a +NULL pointer dereference. Specifically, if eth_stop() is triggered +concurrently while gether_disconnect() is tearing down the endpoints, +eth_stop() attempts to access the cleared endpoint descriptor, causing +the following NPE: + + Unable to handle kernel NULL pointer dereference + Call trace: + __dwc3_gadget_ep_enable+0x60/0x788 + dwc3_gadget_ep_enable+0x70/0xe4 + usb_ep_enable+0x60/0x15c + eth_stop+0xb8/0x108 + +Because eth_stop() crashes while holding the dev->lock, the thread +running gether_disconnect() fails to acquire the same lock and spins +forever, resulting in a hardlockup: + + Core - Debugging Information for Hardlockup core(7) + Call trace: + queued_spin_lock_slowpath+0x94/0x488 + _raw_spin_lock+0x64/0x6c + gether_disconnect+0x19c/0x1e8 + ncm_set_alt+0x68/0x1a0 + composite_setup+0x6a0/0xc50 + +The root cause is that the clearing of dev->port_usb in +gether_disconnect() is delayed until the end of the function. + +Move the clearing of dev->port_usb to the very beginning of +gether_disconnect() while holding dev->lock. This cuts off the link +immediately, ensuring eth_stop() will see dev->port_usb as NULL and +safely bail out. + +Fixes: 2b3d942c4878 ("usb ethernet gadget: split out network core") +Cc: stable +Signed-off-by: Kuen-Han Tsai +Link: https://patch.msgid.link/20260311-gether-disconnect-npe-v1-1-454966adf7c7@google.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/u_ether.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/usb/gadget/function/u_ether.c ++++ b/drivers/usb/gadget/function/u_ether.c +@@ -1141,6 +1141,10 @@ void gether_disconnect(struct gether *li + + DBG(dev, "%s\n", __func__); + ++ spin_lock(&dev->lock); ++ dev->port_usb = NULL; ++ spin_unlock(&dev->lock); ++ + netif_stop_queue(dev->net); + netif_carrier_off(dev->net); + +@@ -1178,10 +1182,6 @@ void gether_disconnect(struct gether *li + dev->header_len = 0; + dev->unwrap = NULL; + dev->wrap = NULL; +- +- spin_lock(&dev->lock); +- dev->port_usb = NULL; +- spin_unlock(&dev->lock); + } + EXPORT_SYMBOL_GPL(gether_disconnect); + diff --git a/queue-5.10/usb-gadget-uvc-fix-null-pointer-dereference-during-unbind-race.patch b/queue-5.10/usb-gadget-uvc-fix-null-pointer-dereference-during-unbind-race.patch new file mode 100644 index 0000000000..24e55443e4 --- /dev/null +++ b/queue-5.10/usb-gadget-uvc-fix-null-pointer-dereference-during-unbind-race.patch @@ -0,0 +1,244 @@ +From stable+bounces-235748-greg=kroah.com@vger.kernel.org Sat Apr 11 18:31:44 2026 +From: Sasha Levin +Date: Sat, 11 Apr 2026 12:31:15 -0400 +Subject: usb: gadget: uvc: fix NULL pointer dereference during unbind race +To: stable@vger.kernel.org +Cc: Jimmy Hu , stable , Alan Stern , Greg Kroah-Hartman , Sasha Levin +Message-ID: <20260411163115.807395-1-sashal@kernel.org> + +From: Jimmy Hu + +[ Upstream commit eba2936bbe6b752a31725a9eb5c674ecbf21ee7d ] + +Commit b81ac4395bbe ("usb: gadget: uvc: allow for application to cleanly +shutdown") introduced two stages of synchronization waits totaling 1500ms +in uvc_function_unbind() to prevent several types of kernel panics. +However, this timing-based approach is insufficient during power +management (PM) transitions. + +When the PM subsystem starts freezing user space processes, the +wait_event_interruptible_timeout() is aborted early, which allows the +unbind thread to proceed and nullify the gadget pointer +(cdev->gadget = NULL): + +[ 814.123447][ T947] configfs-gadget.g1 gadget.0: uvc: uvc_function_unbind() +[ 814.178583][ T3173] PM: suspend entry (deep) +[ 814.192487][ T3173] Freezing user space processes +[ 814.197668][ T947] configfs-gadget.g1 gadget.0: uvc: uvc_function_unbind no clean disconnect, wait for release + +When the PM subsystem resumes or aborts the suspend and tasks are +restarted, the V4L2 release path is executed and attempts to access the +already nullified gadget pointer, triggering a kernel panic: + +[ 814.292597][ C0] PM: pm_system_irq_wakeup: 479 triggered dhdpcie_host_wake +[ 814.386727][ T3173] Restarting tasks ... +[ 814.403522][ T4558] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000030 +[ 814.404021][ T4558] pc : usb_gadget_deactivate+0x14/0xf4 +[ 814.404031][ T4558] lr : usb_function_deactivate+0x54/0x94 +[ 814.404078][ T4558] Call trace: +[ 814.404080][ T4558] usb_gadget_deactivate+0x14/0xf4 +[ 814.404083][ T4558] usb_function_deactivate+0x54/0x94 +[ 814.404087][ T4558] uvc_function_disconnect+0x1c/0x5c +[ 814.404092][ T4558] uvc_v4l2_release+0x44/0xac +[ 814.404095][ T4558] v4l2_release+0xcc/0x130 + +Address the race condition and NULL pointer dereference by: + +1. State Synchronization (flag + mutex) +Introduce a 'func_unbound' flag in struct uvc_device. This allows +uvc_function_disconnect() to safely skip accessing the nullified +cdev->gadget pointer. As suggested by Alan Stern, this flag is protected +by a new mutex (uvc->lock) to ensure proper memory ordering and prevent +instruction reordering or speculative loads. This mutex is also used to +protect 'func_connected' for consistent state management. + +2. Explicit Synchronization (completion) +Use a completion to synchronize uvc_function_unbind() with the +uvc_vdev_release() callback. This prevents Use-After-Free (UAF) by +ensuring struct uvc_device is freed after all video device resources +are released. + +Fixes: b81ac4395bbe ("usb: gadget: uvc: allow for application to cleanly shutdown") +Cc: stable +Suggested-by: Alan Stern +Suggested-by: Greg Kroah-Hartman +Signed-off-by: Jimmy Hu +Link: https://patch.msgid.link/20260320065427.1374555-1-hhhuuu@google.com +Signed-off-by: Greg Kroah-Hartman +[ replaced guard()/scoped_guard() macros ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/function/f_uvc.c | 46 ++++++++++++++++++++++++++++++--- + drivers/usb/gadget/function/uvc.h | 3 ++ + drivers/usb/gadget/function/uvc_v4l2.c | 13 +++++++-- + 3 files changed, 56 insertions(+), 6 deletions(-) + +--- a/drivers/usb/gadget/function/f_uvc.c ++++ b/drivers/usb/gadget/function/f_uvc.c +@@ -393,6 +393,14 @@ uvc_function_disconnect(struct uvc_devic + { + int ret; + ++ mutex_lock(&uvc->lock); ++ if (uvc->func_unbound) { ++ dev_dbg(&uvc->vdev.dev, "skipping function deactivate (unbound)\n"); ++ mutex_unlock(&uvc->lock); ++ return; ++ } ++ mutex_unlock(&uvc->lock); ++ + if ((ret = usb_function_deactivate(&uvc->func)) < 0) + uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret); + } +@@ -411,6 +419,15 @@ static ssize_t function_name_show(struct + + static DEVICE_ATTR_RO(function_name); + ++static void uvc_vdev_release(struct video_device *vdev) ++{ ++ struct uvc_device *uvc = video_get_drvdata(vdev); ++ ++ /* Signal uvc_function_unbind() that the video device has been released */ ++ if (uvc->vdev_release_done) ++ complete(uvc->vdev_release_done); ++} ++ + static int + uvc_register_video(struct uvc_device *uvc) + { +@@ -421,7 +438,7 @@ uvc_register_video(struct uvc_device *uv + uvc->vdev.v4l2_dev = &uvc->v4l2_dev; + uvc->vdev.fops = &uvc_v4l2_fops; + uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops; +- uvc->vdev.release = video_device_release_empty; ++ uvc->vdev.release = uvc_vdev_release; + uvc->vdev.vfl_dir = VFL_DIR_TX; + uvc->vdev.lock = &uvc->video.mutex; + uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; +@@ -595,6 +612,9 @@ uvc_function_bind(struct usb_configurati + int ret = -EINVAL; + + uvcg_info(f, "%s()\n", __func__); ++ mutex_lock(&uvc->lock); ++ uvc->func_unbound = false; ++ mutex_unlock(&uvc->lock); + + opts = fi_to_f_uvc_opts(f->fi); + /* Sanity check the streaming endpoint module parameters. +@@ -887,18 +907,25 @@ static void uvc_free(struct usb_function + static void uvc_function_unbind(struct usb_configuration *c, + struct usb_function *f) + { ++ DECLARE_COMPLETION_ONSTACK(vdev_release_done); + struct usb_composite_dev *cdev = c->cdev; + struct uvc_device *uvc = to_uvc(f); + long wait_ret = 1; ++ bool connected; + + uvcg_info(f, "%s()\n", __func__); ++ mutex_lock(&uvc->lock); ++ uvc->func_unbound = true; ++ uvc->vdev_release_done = &vdev_release_done; ++ connected = uvc->func_connected; ++ mutex_unlock(&uvc->lock); + + /* If we know we're connected via v4l2, then there should be a cleanup + * of the device from userspace either via UVC_EVENT_DISCONNECT or + * though the video device removal uevent. Allow some time for the + * application to close out before things get deleted. + */ +- if (uvc->func_connected) { ++ if (connected) { + uvcg_dbg(f, "waiting for clean disconnect\n"); + wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue, + uvc->func_connected == false, msecs_to_jiffies(500)); +@@ -909,8 +936,13 @@ static void uvc_function_unbind(struct u + video_unregister_device(&uvc->vdev); + v4l2_device_unregister(&uvc->v4l2_dev); + +- if (uvc->func_connected) { +- /* Wait for the release to occur to ensure there are no longer any ++ mutex_lock(&uvc->lock); ++ connected = uvc->func_connected; ++ mutex_unlock(&uvc->lock); ++ ++ if (connected) { ++ /* ++ * Wait for the release to occur to ensure there are no longer any + * pending operations that may cause panics when resources are cleaned + * up. + */ +@@ -920,6 +952,10 @@ static void uvc_function_unbind(struct u + uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret); + } + ++ /* Wait for the video device to be released */ ++ wait_for_completion(&vdev_release_done); ++ uvc->vdev_release_done = NULL; ++ + usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); + kfree(uvc->control_buf); + +@@ -937,6 +973,8 @@ static struct usb_function *uvc_alloc(st + return ERR_PTR(-ENOMEM); + + mutex_init(&uvc->video.mutex); ++ mutex_init(&uvc->lock); ++ uvc->func_unbound = true; + uvc->state = UVC_STATE_DISCONNECTED; + init_waitqueue_head(&uvc->func_connected_queue); + opts = fi_to_f_uvc_opts(fi); +--- a/drivers/usb/gadget/function/uvc.h ++++ b/drivers/usb/gadget/function/uvc.h +@@ -118,6 +118,9 @@ struct uvc_device { + enum uvc_state state; + struct usb_function func; + struct uvc_video video; ++ struct completion *vdev_release_done; ++ struct mutex lock; /* protects func_unbound and func_connected */ ++ bool func_unbound; + bool func_connected; + wait_queue_head_t func_connected_queue; + +--- a/drivers/usb/gadget/function/uvc_v4l2.c ++++ b/drivers/usb/gadget/function/uvc_v4l2.c +@@ -234,12 +234,18 @@ uvc_v4l2_subscribe_event(struct v4l2_fh + if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) + return -EINVAL; + +- if (sub->type == UVC_EVENT_SETUP && uvc->func_connected) ++ mutex_lock(&uvc->lock); ++ ++ if (sub->type == UVC_EVENT_SETUP && uvc->func_connected) { ++ mutex_unlock(&uvc->lock); + return -EBUSY; ++ } + + ret = v4l2_event_subscribe(fh, sub, 2, NULL); +- if (ret < 0) ++ if (ret < 0) { ++ mutex_unlock(&uvc->lock); + return ret; ++ } + + if (sub->type == UVC_EVENT_SETUP) { + uvc->func_connected = true; +@@ -247,6 +253,7 @@ uvc_v4l2_subscribe_event(struct v4l2_fh + uvc_function_connect(uvc); + } + ++ mutex_unlock(&uvc->lock); + return 0; + } + +@@ -255,7 +262,9 @@ static void uvc_v4l2_disable(struct uvc_ + uvc_function_disconnect(uvc); + uvcg_video_enable(&uvc->video, 0); + uvcg_free_buffers(&uvc->video.queue); ++ mutex_lock(&uvc->lock); + uvc->func_connected = false; ++ mutex_unlock(&uvc->lock); + wake_up_interruptible(&uvc->func_connected_queue); + } + diff --git a/queue-5.10/xfs-save-ailp-before-dropping-the-ail-lock-in-push-callbacks.patch b/queue-5.10/xfs-save-ailp-before-dropping-the-ail-lock-in-push-callbacks.patch new file mode 100644 index 0000000000..5b898643d8 --- /dev/null +++ b/queue-5.10/xfs-save-ailp-before-dropping-the-ail-lock-in-push-callbacks.patch @@ -0,0 +1,100 @@ +From stable+bounces-232961-greg=kroah.com@vger.kernel.org Thu Apr 2 11:44:42 2026 +From: Sasha Levin +Date: Thu, 2 Apr 2026 05:44:17 -0400 +Subject: xfs: save ailp before dropping the AIL lock in push callbacks +To: stable@vger.kernel.org +Cc: Yuto Ohnuki , syzbot+652af2b3c5569c4ab63c@syzkaller.appspotmail.com, "Darrick J. Wong" , Dave Chinner , Carlos Maiolino , Sasha Levin +Message-ID: <20260402094417.718088-1-sashal@kernel.org> + +From: Yuto Ohnuki + +[ Upstream commit 394d70b86fae9fe865e7e6d9540b7696f73aa9b6 ] + +In xfs_inode_item_push() and xfs_qm_dquot_logitem_push(), the AIL lock +is dropped to perform buffer IO. Once the cluster buffer no longer +protects the log item from reclaim, the log item may be freed by +background reclaim or the dquot shrinker. The subsequent spin_lock() +call dereferences lip->li_ailp, which is a use-after-free. + +Fix this by saving the ailp pointer in a local variable while the AIL +lock is held and the log item is guaranteed to be valid. + +Reported-by: syzbot+652af2b3c5569c4ab63c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=652af2b3c5569c4ab63c +Fixes: 90c60e164012 ("xfs: xfs_iflush() is no longer necessary") +Cc: stable@vger.kernel.org # v5.9 +Reviewed-by: Darrick J. Wong +Reviewed-by: Dave Chinner +Signed-off-by: Yuto Ohnuki +Signed-off-by: Carlos Maiolino +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/xfs_dquot_item.c | 9 +++++++-- + fs/xfs/xfs_inode_item.c | 9 +++++++-- + 2 files changed, 14 insertions(+), 4 deletions(-) + +--- a/fs/xfs/xfs_dquot_item.c ++++ b/fs/xfs/xfs_dquot_item.c +@@ -124,6 +124,7 @@ xfs_qm_dquot_logitem_push( + { + struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; + struct xfs_buf *bp = lip->li_buf; ++ struct xfs_ail *ailp = lip->li_ailp; + uint rval = XFS_ITEM_SUCCESS; + int error; + +@@ -152,7 +153,7 @@ xfs_qm_dquot_logitem_push( + goto out_unlock; + } + +- spin_unlock(&lip->li_ailp->ail_lock); ++ spin_unlock(&ailp->ail_lock); + + error = xfs_qm_dqflush(dqp, &bp); + if (!error) { +@@ -162,7 +163,11 @@ xfs_qm_dquot_logitem_push( + } else if (error == -EAGAIN) + rval = XFS_ITEM_LOCKED; + +- spin_lock(&lip->li_ailp->ail_lock); ++ /* ++ * The buffer no longer protects the log item from reclaim, so ++ * do not reference lip after this point. ++ */ ++ spin_lock(&ailp->ail_lock); + out_unlock: + xfs_dqunlock(dqp); + return rval; +--- a/fs/xfs/xfs_inode_item.c ++++ b/fs/xfs/xfs_inode_item.c +@@ -514,6 +514,7 @@ xfs_inode_item_push( + struct xfs_inode_log_item *iip = INODE_ITEM(lip); + struct xfs_inode *ip = iip->ili_inode; + struct xfs_buf *bp = lip->li_buf; ++ struct xfs_ail *ailp = lip->li_ailp; + uint rval = XFS_ITEM_SUCCESS; + int error; + +@@ -529,7 +530,7 @@ xfs_inode_item_push( + if (!xfs_buf_trylock(bp)) + return XFS_ITEM_LOCKED; + +- spin_unlock(&lip->li_ailp->ail_lock); ++ spin_unlock(&ailp->ail_lock); + + /* + * We need to hold a reference for flushing the cluster buffer as it may +@@ -553,7 +554,11 @@ xfs_inode_item_push( + rval = XFS_ITEM_LOCKED; + } + +- spin_lock(&lip->li_ailp->ail_lock); ++ /* ++ * The buffer no longer protects the log item from reclaim, so ++ * do not reference lip after this point. ++ */ ++ spin_lock(&ailp->ail_lock); + return rval; + } + diff --git a/queue-5.10/xfs-stop-reclaim-before-pushing-ail-during-unmount.patch b/queue-5.10/xfs-stop-reclaim-before-pushing-ail-during-unmount.patch new file mode 100644 index 0000000000..b1feb02f5a --- /dev/null +++ b/queue-5.10/xfs-stop-reclaim-before-pushing-ail-during-unmount.patch @@ -0,0 +1,62 @@ +From stable+bounces-232938-greg=kroah.com@vger.kernel.org Thu Apr 2 10:34:53 2026 +From: Sasha Levin +Date: Thu, 2 Apr 2026 04:32:18 -0400 +Subject: xfs: stop reclaim before pushing AIL during unmount +To: stable@vger.kernel.org +Cc: Yuto Ohnuki , syzbot+652af2b3c5569c4ab63c@syzkaller.appspotmail.com, "Darrick J. Wong" , Carlos Maiolino , Sasha Levin +Message-ID: <20260402083218.458355-1-sashal@kernel.org> + +From: Yuto Ohnuki + +[ Upstream commit 4f24a767e3d64a5f58c595b5c29b6063a201f1e3 ] + +The unmount sequence in xfs_unmount_flush_inodes() pushed the AIL while +background reclaim and inodegc are still running. This is broken +independently of any use-after-free issues - background reclaim and +inodegc should not be running while the AIL is being pushed during +unmount, as inodegc can dirty and insert inodes into the AIL during the +flush, and background reclaim can race to abort and free dirty inodes. + +Reorder xfs_unmount_flush_inodes() to stop inodegc and cancel background +reclaim before pushing the AIL. Stop inodegc before cancelling +m_reclaim_work because the inodegc worker can re-queue m_reclaim_work +via xfs_inodegc_set_reclaimable. + +Reported-by: syzbot+652af2b3c5569c4ab63c@syzkaller.appspotmail.com +Closes: https://syzkaller.appspot.com/bug?extid=652af2b3c5569c4ab63c +Fixes: 90c60e164012 ("xfs: xfs_iflush() is no longer necessary") +Cc: stable@vger.kernel.org # v5.9 +Signed-off-by: Yuto Ohnuki +Reviewed-by: Darrick J. Wong +Signed-off-by: Carlos Maiolino +[ dropped xfs_inodegc_stop() call ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/xfs/xfs_mount.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/fs/xfs/xfs_mount.c ++++ b/fs/xfs/xfs_mount.c +@@ -652,8 +652,9 @@ xfs_check_summary_counts( + * have been retrying in the background. This will prevent never-ending + * retries in AIL pushing from hanging the unmount. + * +- * Finally, we can push the AIL to clean all the remaining dirty objects, then +- * reclaim the remaining inodes that are still in memory at this point in time. ++ * Stop inodegc and background reclaim before pushing the AIL so that they ++ * are not running while the AIL is being flushed. Then push the AIL to ++ * clean all the remaining dirty objects and reclaim the remaining inodes. + */ + static void + xfs_unmount_flush_inodes( +@@ -665,8 +666,8 @@ xfs_unmount_flush_inodes( + + mp->m_flags |= XFS_MOUNT_UNMOUNTING; + +- xfs_ail_push_all_sync(mp->m_ail); + cancel_delayed_work_sync(&mp->m_reclaim_work); ++ xfs_ail_push_all_sync(mp->m_ail); + xfs_reclaim_inodes(mp); + xfs_health_unmount(mp); + }