--- /dev/null
+From stable+bounces-186154-greg=kroah.com@vger.kernel.org Thu Oct 16 15:34:54 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Oct 2025 09:34:38 -0400
+Subject: ACPI: battery: Add synchronization between interface updates
+To: stable@vger.kernel.org
+Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>, GuangFei Luo <luogf2025@163.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251016133438.3296275-4-sashal@kernel.org>
+
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 399dbcadc01ebf0035f325eaa8c264f8b5cd0a14 ]
+
+There is no synchronization between different code paths in the ACPI
+battery driver that update its sysfs interface or its power supply
+class device interface. In some cases this results to functional
+failures due to race conditions.
+
+One example of this is when two ACPI notifications:
+
+ - ACPI_BATTERY_NOTIFY_STATUS (0x80)
+ - ACPI_BATTERY_NOTIFY_INFO (0x81)
+
+are triggered (by the platform firmware) in a row with a little delay
+in between after removing and reinserting a laptop battery. Both
+notifications cause acpi_battery_update() to be called and if the delay
+between them is sufficiently small, sysfs_add_battery() can be re-entered
+before battery->bat is set which leads to a duplicate sysfs entry error:
+
+ sysfs: cannot create duplicate filename '/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0A:00/power_supply/BAT1'
+ CPU: 1 UID: 0 PID: 185 Comm: kworker/1:4 Kdump: loaded Not tainted 6.12.38+deb13-amd64 #1 Debian 6.12.38-1
+ Hardware name: Gateway NV44 /SJV40-MV , BIOS V1.3121 04/08/2009
+ Workqueue: kacpi_notify acpi_os_execute_deferred
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x5d/0x80
+ sysfs_warn_dup.cold+0x17/0x23
+ sysfs_create_dir_ns+0xce/0xe0
+ kobject_add_internal+0xba/0x250
+ kobject_add+0x96/0xc0
+ ? get_device_parent+0xde/0x1e0
+ device_add+0xe2/0x870
+ __power_supply_register.part.0+0x20f/0x3f0
+ ? wake_up_q+0x4e/0x90
+ sysfs_add_battery+0xa4/0x1d0 [battery]
+ acpi_battery_update+0x19e/0x290 [battery]
+ acpi_battery_notify+0x50/0x120 [battery]
+ acpi_ev_notify_dispatch+0x49/0x70
+ acpi_os_execute_deferred+0x1a/0x30
+ process_one_work+0x177/0x330
+ worker_thread+0x251/0x390
+ ? __pfx_worker_thread+0x10/0x10
+ kthread+0xd2/0x100
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork+0x34/0x50
+ ? __pfx_kthread+0x10/0x10
+ ret_from_fork_asm+0x1a/0x30
+ </TASK>
+ kobject: kobject_add_internal failed for BAT1 with -EEXIST, don't try to register things with the same name in the same directory.
+
+There are also other scenarios in which analogous issues may occur.
+
+Address this by using a common lock in all of the code paths leading
+to updates of driver interfaces: ACPI Notify () handler, system resume
+callback and post-resume notification, device addition and removal.
+
+This new lock replaces sysfs_lock that has been used only in
+sysfs_remove_battery() which now is going to be always called under
+the new lock, so it doesn't need any internal locking any more.
+
+Fixes: 10666251554c ("ACPI: battery: Install Notify() handler directly")
+Closes: https://lore.kernel.org/linux-acpi/20250910142653.313360-1-luogf2025@163.com/
+Reported-by: GuangFei Luo <luogf2025@163.com>
+Tested-by: GuangFei Luo <luogf2025@163.com>
+Cc: 6.6+ <stable@vger.kernel.org> # 6.6+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/battery.c | 43 +++++++++++++++++++++++++++++--------------
+ 1 file changed, 29 insertions(+), 14 deletions(-)
+
+--- a/drivers/acpi/battery.c
++++ b/drivers/acpi/battery.c
+@@ -92,7 +92,7 @@ enum {
+
+ struct acpi_battery {
+ struct mutex lock;
+- struct mutex sysfs_lock;
++ struct mutex update_lock;
+ struct power_supply *bat;
+ struct power_supply_desc bat_desc;
+ struct acpi_device *device;
+@@ -903,15 +903,12 @@ static int sysfs_add_battery(struct acpi
+
+ static void sysfs_remove_battery(struct acpi_battery *battery)
+ {
+- mutex_lock(&battery->sysfs_lock);
+- if (!battery->bat) {
+- mutex_unlock(&battery->sysfs_lock);
++ if (!battery->bat)
+ return;
+- }
++
+ battery_hook_remove_battery(battery);
+ power_supply_unregister(battery->bat);
+ battery->bat = NULL;
+- mutex_unlock(&battery->sysfs_lock);
+ }
+
+ static void find_battery(const struct dmi_header *dm, void *private)
+@@ -1071,6 +1068,9 @@ static void acpi_battery_notify(acpi_han
+
+ if (!battery)
+ return;
++
++ guard(mutex)(&battery->update_lock);
++
+ old = battery->bat;
+ /*
+ * On Acer Aspire V5-573G notifications are sometimes triggered too
+@@ -1093,21 +1093,22 @@ static void acpi_battery_notify(acpi_han
+ }
+
+ static int battery_notify(struct notifier_block *nb,
+- unsigned long mode, void *_unused)
++ unsigned long mode, void *_unused)
+ {
+ struct acpi_battery *battery = container_of(nb, struct acpi_battery,
+ pm_nb);
+- int result;
+
+- switch (mode) {
+- case PM_POST_HIBERNATION:
+- case PM_POST_SUSPEND:
++ if (mode == PM_POST_SUSPEND || mode == PM_POST_HIBERNATION) {
++ guard(mutex)(&battery->update_lock);
++
+ if (!acpi_battery_present(battery))
+ return 0;
+
+ if (battery->bat) {
+ acpi_battery_refresh(battery);
+ } else {
++ int result;
++
+ result = acpi_battery_get_info(battery);
+ if (result)
+ return result;
+@@ -1119,7 +1120,6 @@ static int battery_notify(struct notifie
+
+ acpi_battery_init_alarm(battery);
+ acpi_battery_get_state(battery);
+- break;
+ }
+
+ return 0;
+@@ -1197,6 +1197,8 @@ static int acpi_battery_update_retry(str
+ {
+ int retry, ret;
+
++ guard(mutex)(&battery->update_lock);
++
+ for (retry = 5; retry; retry--) {
+ ret = acpi_battery_update(battery, false);
+ if (!ret)
+@@ -1207,6 +1209,13 @@ static int acpi_battery_update_retry(str
+ return ret;
+ }
+
++static void sysfs_battery_cleanup(struct acpi_battery *battery)
++{
++ guard(mutex)(&battery->update_lock);
++
++ sysfs_remove_battery(battery);
++}
++
+ static int acpi_battery_add(struct acpi_device *device)
+ {
+ int result = 0;
+@@ -1229,7 +1238,7 @@ static int acpi_battery_add(struct acpi_
+ if (result)
+ return result;
+
+- result = devm_mutex_init(&device->dev, &battery->sysfs_lock);
++ result = devm_mutex_init(&device->dev, &battery->update_lock);
+ if (result)
+ return result;
+
+@@ -1259,7 +1268,7 @@ fail_pm:
+ device_init_wakeup(&device->dev, 0);
+ unregister_pm_notifier(&battery->pm_nb);
+ fail:
+- sysfs_remove_battery(battery);
++ sysfs_battery_cleanup(battery);
+
+ return result;
+ }
+@@ -1278,6 +1287,9 @@ static void acpi_battery_remove(struct a
+
+ device_init_wakeup(&device->dev, 0);
+ unregister_pm_notifier(&battery->pm_nb);
++
++ guard(mutex)(&battery->update_lock);
++
+ sysfs_remove_battery(battery);
+ }
+
+@@ -1295,6 +1307,9 @@ static int acpi_battery_resume(struct de
+ return -EINVAL;
+
+ battery->update_time = 0;
++
++ guard(mutex)(&battery->update_lock);
++
+ acpi_battery_update(battery, true);
+ return 0;
+ }
--- /dev/null
+From stable+bounces-186151-greg=kroah.com@vger.kernel.org Thu Oct 16 15:34:49 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Oct 2025 09:34:35 -0400
+Subject: ACPI: battery: allocate driver data through devm_ APIs
+To: stable@vger.kernel.org
+Cc: "Thomas Weißschuh" <linux@weissschuh.net>, "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20251016133438.3296275-1-sashal@kernel.org>
+
+From: Thomas Weißschuh <linux@weissschuh.net>
+
+[ Upstream commit 909dfc60692331e1599d5e28a8f08a611f353aef ]
+
+Simplify the cleanup logic a bit.
+
+Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
+Link: https://patch.msgid.link/20240904-acpi-battery-cleanups-v1-2-a3bf74f22d40@weissschuh.net
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Stable-dep-of: 399dbcadc01e ("ACPI: battery: Add synchronization between interface updates")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/battery.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/acpi/battery.c
++++ b/drivers/acpi/battery.c
+@@ -1218,7 +1218,7 @@ static int acpi_battery_add(struct acpi_
+ if (device->dep_unmet)
+ return -EPROBE_DEFER;
+
+- battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
++ battery = devm_kzalloc(&device->dev, sizeof(*battery), GFP_KERNEL);
+ if (!battery)
+ return -ENOMEM;
+ battery->device = device;
+@@ -1256,7 +1256,6 @@ fail:
+ sysfs_remove_battery(battery);
+ mutex_destroy(&battery->lock);
+ mutex_destroy(&battery->sysfs_lock);
+- kfree(battery);
+
+ return result;
+ }
+@@ -1279,7 +1278,6 @@ static void acpi_battery_remove(struct a
+
+ mutex_destroy(&battery->lock);
+ mutex_destroy(&battery->sysfs_lock);
+- kfree(battery);
+ }
+
+ #ifdef CONFIG_PM_SLEEP
--- /dev/null
+From stable+bounces-186153-greg=kroah.com@vger.kernel.org Thu Oct 16 15:35:02 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Oct 2025 09:34:37 -0400
+Subject: ACPI: battery: Check for error code from devm_mutex_init() call
+To: stable@vger.kernel.org
+Cc: "Andy Shevchenko" <andriy.shevchenko@linux.intel.com>, "Thomas Weißschuh" <linux@weissschuh.net>, "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20251016133438.3296275-3-sashal@kernel.org>
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+[ Upstream commit 815daedc318b2f9f1b956d0631377619a0d69d96 ]
+
+Even if it's not critical, the avoidance of checking the error code
+from devm_mutex_init() call today diminishes the point of using devm
+variant of it. Tomorrow it may even leak something. Add the missed
+check.
+
+Fixes: 0710c1ce5045 ("ACPI: battery: initialize mutexes through devm_ APIs")
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Reviewed-by: Thomas Weißschuh <linux@weissschuh.net>
+Link: https://patch.msgid.link/20241030162754.2110946-1-andriy.shevchenko@linux.intel.com
+[ rjw: Added 2 empty code lines ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Stable-dep-of: 399dbcadc01e ("ACPI: battery: Add synchronization between interface updates")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/battery.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/drivers/acpi/battery.c
++++ b/drivers/acpi/battery.c
+@@ -1225,8 +1225,14 @@ static int acpi_battery_add(struct acpi_
+ strscpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
+ strscpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
+ device->driver_data = battery;
+- devm_mutex_init(&device->dev, &battery->lock);
+- devm_mutex_init(&device->dev, &battery->sysfs_lock);
++ result = devm_mutex_init(&device->dev, &battery->lock);
++ if (result)
++ return result;
++
++ result = devm_mutex_init(&device->dev, &battery->sysfs_lock);
++ if (result)
++ return result;
++
+ if (acpi_has_method(battery->device->handle, "_BIX"))
+ set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
+
--- /dev/null
+From stable+bounces-186152-greg=kroah.com@vger.kernel.org Thu Oct 16 15:34:55 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Oct 2025 09:34:36 -0400
+Subject: ACPI: battery: initialize mutexes through devm_ APIs
+To: stable@vger.kernel.org
+Cc: "Thomas Weißschuh" <linux@weissschuh.net>, "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20251016133438.3296275-2-sashal@kernel.org>
+
+From: Thomas Weißschuh <linux@weissschuh.net>
+
+[ Upstream commit 0710c1ce50455ed0db91bffa0eebbaa4f69b1773 ]
+
+Simplify the cleanup logic a bit.
+
+Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
+Link: https://patch.msgid.link/20240904-acpi-battery-cleanups-v1-3-a3bf74f22d40@weissschuh.net
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Stable-dep-of: 399dbcadc01e ("ACPI: battery: Add synchronization between interface updates")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/battery.c | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+--- a/drivers/acpi/battery.c
++++ b/drivers/acpi/battery.c
+@@ -1225,8 +1225,8 @@ static int acpi_battery_add(struct acpi_
+ strscpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
+ strscpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
+ device->driver_data = battery;
+- mutex_init(&battery->lock);
+- mutex_init(&battery->sysfs_lock);
++ devm_mutex_init(&device->dev, &battery->lock);
++ devm_mutex_init(&device->dev, &battery->sysfs_lock);
+ if (acpi_has_method(battery->device->handle, "_BIX"))
+ set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
+
+@@ -1254,8 +1254,6 @@ fail_pm:
+ unregister_pm_notifier(&battery->pm_nb);
+ fail:
+ sysfs_remove_battery(battery);
+- mutex_destroy(&battery->lock);
+- mutex_destroy(&battery->sysfs_lock);
+
+ return result;
+ }
+@@ -1275,9 +1273,6 @@ static void acpi_battery_remove(struct a
+ device_init_wakeup(&device->dev, 0);
+ unregister_pm_notifier(&battery->pm_nb);
+ sysfs_remove_battery(battery);
+-
+- mutex_destroy(&battery->lock);
+- mutex_destroy(&battery->sysfs_lock);
+ }
+
+ #ifdef CONFIG_PM_SLEEP
--- /dev/null
+From stable+bounces-186193-greg=kroah.com@vger.kernel.org Thu Oct 16 21:12:38 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Oct 2025 15:12:26 -0400
+Subject: ACPI: property: Add code comments explaining what is going on
+To: stable@vger.kernel.org
+Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>, Sakari Ailus <sakari.ailus@linux.intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251016191227.3377985-3-sashal@kernel.org>
+
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 737c3a09dcf69ba2814f3674947ccaec1861c985 ]
+
+In some places in the ACPI device properties handling code, it is
+unclear why the code is what it is. Some assumptions are not documented
+and some pieces of code are based on knowledge that is not mentioned
+anywhere.
+
+Add code comments explaining these things.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Tested-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Stable-dep-of: baf60d5cb8bc ("ACPI: property: Do not pass NULL handles to acpi_attach_data()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/property.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 44 insertions(+), 2 deletions(-)
+
+--- a/drivers/acpi/property.c
++++ b/drivers/acpi/property.c
+@@ -108,7 +108,18 @@ static bool acpi_nondev_subnode_extract(
+ if (handle)
+ acpi_get_parent(handle, &scope);
+
++ /*
++ * Extract properties from the _DSD-equivalent package pointed to by
++ * desc and use scope (if not NULL) for the completion of relative
++ * pathname segments.
++ *
++ * The extracted properties will be held in the new data node dn.
++ */
+ result = acpi_extract_properties(scope, desc, &dn->data);
++ /*
++ * Look for subnodes in the _DSD-equivalent package pointed to by desc
++ * and create child nodes of dn if there are any.
++ */
+ if (acpi_enumerate_nondev_subnodes(scope, desc, &dn->data, &dn->fwnode))
+ result = true;
+
+@@ -133,6 +144,12 @@ static bool acpi_nondev_subnode_ok(acpi_
+ acpi_handle handle;
+ acpi_status status;
+
++ /*
++ * If the scope is unknown, the _DSD-equivalent package being parsed
++ * was embedded in an outer _DSD-equivalent package as a result of
++ * direct evaluation of an object pointed to by a reference. In that
++ * case, using a pathname as the target object pointer is invalid.
++ */
+ if (!scope)
+ return false;
+
+@@ -162,6 +179,10 @@ static bool acpi_add_nondev_subnodes(acp
+ bool ret = false;
+ int i;
+
++ /*
++ * Every element in the links package is expected to represent a link
++ * to a non-device node in a tree containing device-specific data.
++ */
+ for (i = 0; i < links->package.count; i++) {
+ union acpi_object *link, *desc;
+ bool result;
+@@ -171,17 +192,38 @@ static bool acpi_add_nondev_subnodes(acp
+ if (link->package.count != 2)
+ continue;
+
+- /* The first one must be a string. */
++ /* The first one (the key) must be a string. */
+ if (link->package.elements[0].type != ACPI_TYPE_STRING)
+ continue;
+
+- /* The second one may be a string or a package. */
++ /* The second one (the target) may be a string or a package. */
+ switch (link->package.elements[1].type) {
+ case ACPI_TYPE_STRING:
++ /*
++ * The string is expected to be a full pathname or a
++ * pathname segment relative to the given scope. That
++ * pathname is expected to point to an object returning
++ * a package that contains _DSD-equivalent information.
++ */
+ result = acpi_nondev_subnode_ok(scope, link, list,
+ parent);
+ break;
+ case ACPI_TYPE_PACKAGE:
++ /*
++ * This happens when a reference is used in AML to
++ * point to the target. Since the target is expected
++ * to be a named object, a reference to it will cause it
++ * to be avaluated in place and its return package will
++ * be embedded in the links package at the location of
++ * the reference.
++ *
++ * The target package is expected to contain _DSD-
++ * equivalent information, but the scope in which it
++ * is located in the original AML is unknown. Thus
++ * it cannot contain pathname segments represented as
++ * strings because there is no way to build full
++ * pathnames out of them.
++ */
+ desc = &link->package.elements[1];
+ result = acpi_nondev_subnode_extract(desc, NULL, link,
+ list, parent);
--- /dev/null
+From stable+bounces-186192-greg=kroah.com@vger.kernel.org Thu Oct 16 21:12:37 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Oct 2025 15:12:25 -0400
+Subject: ACPI: property: Disregard references in data-only subnode lists
+To: stable@vger.kernel.org
+Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>, Sakari Ailus <sakari.ailus@linux.intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251016191227.3377985-2-sashal@kernel.org>
+
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+
+[ Upstream commit d06118fe9b03426484980ed4c189a8c7b99fa631 ]
+
+Data-only subnode links following the ACPI data subnode GUID in a _DSD
+package are expected to point to named objects returning _DSD-equivalent
+packages. If a reference to such an object is used in the target field
+of any of those links, that object will be evaluated in place (as a
+named object) and its return data will be embedded in the outer _DSD
+package.
+
+For this reason, it is not expected to see a subnode link with the
+target field containing a local reference (that would mean pointing
+to a device or another object that cannot be evaluated in place and
+therefore cannot return a _DSD-equivalent package).
+
+Accordingly, simplify the code parsing data-only subnode links to
+simply print a message when it encounters a local reference in the
+target field of one of those links.
+
+Moreover, since acpi_nondev_subnode_data_ok() would only have one
+caller after the change above, fold it into that caller.
+
+Link: https://lore.kernel.org/linux-acpi/CAJZ5v0jVeSrDO6hrZhKgRZrH=FpGD4vNUjFD8hV9WwN9TLHjzQ@mail.gmail.com/
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Tested-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Stable-dep-of: baf60d5cb8bc ("ACPI: property: Do not pass NULL handles to acpi_attach_data()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/property.c | 51 ++++++++++++++++++++----------------------------
+ 1 file changed, 22 insertions(+), 29 deletions(-)
+
+--- a/drivers/acpi/property.c
++++ b/drivers/acpi/property.c
+@@ -124,32 +124,12 @@ static bool acpi_nondev_subnode_extract(
+ return false;
+ }
+
+-static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
+- const union acpi_object *link,
+- struct list_head *list,
+- struct fwnode_handle *parent)
+-{
+- struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+- acpi_status status;
+-
+- status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
+- ACPI_TYPE_PACKAGE);
+- if (ACPI_FAILURE(status))
+- return false;
+-
+- if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list,
+- parent))
+- return true;
+-
+- ACPI_FREE(buf.pointer);
+- return false;
+-}
+-
+ static bool acpi_nondev_subnode_ok(acpi_handle scope,
+ const union acpi_object *link,
+ struct list_head *list,
+ struct fwnode_handle *parent)
+ {
++ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ acpi_handle handle;
+ acpi_status status;
+
+@@ -161,7 +141,17 @@ static bool acpi_nondev_subnode_ok(acpi_
+ if (ACPI_FAILURE(status))
+ return false;
+
+- return acpi_nondev_subnode_data_ok(handle, link, list, parent);
++ status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
++ ACPI_TYPE_PACKAGE);
++ if (ACPI_FAILURE(status))
++ return false;
++
++ if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list,
++ parent))
++ return true;
++
++ ACPI_FREE(buf.pointer);
++ return false;
+ }
+
+ static bool acpi_add_nondev_subnodes(acpi_handle scope,
+@@ -174,7 +164,6 @@ static bool acpi_add_nondev_subnodes(acp
+
+ for (i = 0; i < links->package.count; i++) {
+ union acpi_object *link, *desc;
+- acpi_handle handle;
+ bool result;
+
+ link = &links->package.elements[i];
+@@ -186,22 +175,26 @@ static bool acpi_add_nondev_subnodes(acp
+ if (link->package.elements[0].type != ACPI_TYPE_STRING)
+ continue;
+
+- /* The second one may be a string, a reference or a package. */
++ /* The second one may be a string or a package. */
+ switch (link->package.elements[1].type) {
+ case ACPI_TYPE_STRING:
+ result = acpi_nondev_subnode_ok(scope, link, list,
+ parent);
+ break;
+- case ACPI_TYPE_LOCAL_REFERENCE:
+- handle = link->package.elements[1].reference.handle;
+- result = acpi_nondev_subnode_data_ok(handle, link, list,
+- parent);
+- break;
+ case ACPI_TYPE_PACKAGE:
+ desc = &link->package.elements[1];
+ result = acpi_nondev_subnode_extract(desc, NULL, link,
+ list, parent);
+ break;
++ case ACPI_TYPE_LOCAL_REFERENCE:
++ /*
++ * It is not expected to see any local references in
++ * the links package because referencing a named object
++ * should cause it to be evaluated in place.
++ */
++ acpi_handle_info(scope, "subnode %s: Unexpected reference\n",
++ link->package.elements[0].string.pointer);
++ fallthrough;
+ default:
+ result = false;
+ break;
--- /dev/null
+From stable+bounces-186194-greg=kroah.com@vger.kernel.org Thu Oct 16 21:12:39 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Oct 2025 15:12:27 -0400
+Subject: ACPI: property: Do not pass NULL handles to acpi_attach_data()
+To: stable@vger.kernel.org
+Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>, Sakari Ailus <sakari.ailus@linux.intel.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251016191227.3377985-4-sashal@kernel.org>
+
+From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+
+[ Upstream commit baf60d5cb8bc6b85511c5df5f0ad7620bb66d23c ]
+
+In certain circumstances, the ACPI handle of a data-only node may be
+NULL, in which case it does not make sense to attempt to attach that
+node to an ACPI namespace object, so update the code to avoid attempts
+to do so.
+
+This prevents confusing and unuseful error messages from being printed.
+
+Also document the fact that the ACPI handle of a data-only node may be
+NULL and when that happens in a code comment. In addition, make
+acpi_add_nondev_subnodes() print a diagnostic message for each data-only
+node with an unknown ACPI namespace scope.
+
+Fixes: 1d52f10917a7 ("ACPI: property: Tie data nodes to acpi handles")
+Cc: 6.0+ <stable@vger.kernel.org> # 6.0+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Tested-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/property.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/acpi/property.c
++++ b/drivers/acpi/property.c
+@@ -124,6 +124,10 @@ static bool acpi_nondev_subnode_extract(
+ result = true;
+
+ if (result) {
++ /*
++ * This will be NULL if the desc package is embedded in an outer
++ * _DSD-equivalent package and its scope cannot be determined.
++ */
+ dn->handle = handle;
+ dn->data.pointer = desc;
+ list_add_tail(&dn->sibling, list);
+@@ -224,6 +228,8 @@ static bool acpi_add_nondev_subnodes(acp
+ * strings because there is no way to build full
+ * pathnames out of them.
+ */
++ acpi_handle_debug(scope, "subnode %s: Unknown scope\n",
++ link->package.elements[0].string.pointer);
+ desc = &link->package.elements[1];
+ result = acpi_nondev_subnode_extract(desc, NULL, link,
+ list, parent);
+@@ -396,6 +402,9 @@ static void acpi_untie_nondev_subnodes(s
+ struct acpi_data_node *dn;
+
+ list_for_each_entry(dn, &data->subnodes, sibling) {
++ if (!dn->handle)
++ continue;
++
+ acpi_detach_data(dn->handle, acpi_nondev_subnode_tag);
+
+ acpi_untie_nondev_subnodes(&dn->data);
+@@ -410,6 +419,9 @@ static bool acpi_tie_nondev_subnodes(str
+ acpi_status status;
+ bool ret;
+
++ if (!dn->handle)
++ continue;
++
+ status = acpi_attach_data(dn->handle, acpi_nondev_subnode_tag, dn);
+ if (ACPI_FAILURE(status) && status != AE_ALREADY_EXISTS) {
+ acpi_handle_err(dn->handle, "Can't tag data node\n");
--- /dev/null
+From stable+bounces-186184-greg=kroah.com@vger.kernel.org Thu Oct 16 20:49:33 2025
+From: Corey Minyard <corey@minyard.net>
+Date: Thu, 16 Oct 2025 13:49:17 -0500
+Subject: ipmi: Fix handling of messages with provided receive message pointer
+To: stable@vger.kernel.org
+Cc: Guenter Roeck <linux@roeck-us.net>, Eric Dumazet <edumazet@google.com>, Greg Thelen <gthelen@google.com>, Corey Minyard <corey@minyard.net>
+Message-ID: <20251016184917.1875857-2-corey@minyard.net>
+
+From: Guenter Roeck <linux@roeck-us.net>
+
+commit e2c69490dda5d4c9f1bfbb2898989c8f3530e354 upstream
+
+Prior to commit b52da4054ee0 ("ipmi: Rework user message limit handling"),
+i_ipmi_request() used to increase the user reference counter if the receive
+message is provided by the caller of IPMI API functions. This is no longer
+the case. However, ipmi_free_recv_msg() is still called and decreases the
+reference counter. This results in the reference counter reaching zero,
+the user data pointer is released, and all kinds of interesting crashes are
+seen.
+
+Fix the problem by increasing user reference counter if the receive message
+has been provided by the caller.
+
+Fixes: b52da4054ee0 ("ipmi: Rework user message limit handling")
+Reported-by: Eric Dumazet <edumazet@google.com>
+Cc: Eric Dumazet <edumazet@google.com>
+Cc: Greg Thelen <gthelen@google.com>
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Message-ID: <20251006201857.3433837-1-linux@roeck-us.net>
+Signed-off-by: Corey Minyard <corey@minyard.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/char/ipmi/ipmi_msghandler.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/char/ipmi/ipmi_msghandler.c
++++ b/drivers/char/ipmi/ipmi_msghandler.c
+@@ -2311,8 +2311,11 @@ static int i_ipmi_request(struct ipmi_us
+ if (supplied_recv) {
+ recv_msg = supplied_recv;
+ recv_msg->user = user;
+- if (user)
++ if (user) {
+ atomic_inc(&user->nr_msgs);
++ /* The put happens when the message is freed. */
++ kref_get(&user->refcount);
++ }
+ } else {
+ recv_msg = ipmi_alloc_recv_msg(user);
+ if (IS_ERR(recv_msg))
--- /dev/null
+From stable+bounces-186185-greg=kroah.com@vger.kernel.org Thu Oct 16 20:49:37 2025
+From: Corey Minyard <corey@minyard.net>
+Date: Thu, 16 Oct 2025 13:49:16 -0500
+Subject: ipmi: Rework user message limit handling
+To: stable@vger.kernel.org
+Cc: Corey Minyard <corey@minyard.net>, Gilles BULOZ <gilles.buloz@kontron.com>
+Message-ID: <20251016184917.1875857-1-corey@minyard.net>
+
+From: Corey Minyard <corey@minyard.net>
+
+commit b52da4054ee0bf9ecb44996f2c83236ff50b3812 upstream
+
+This patch required quite a bit of work to backport due to a number
+of unrelated changes that do not make sense to backport. This has
+been run against my test suite and passes all tests.
+
+The limit on the number of user messages had a number of issues,
+improper counting in some cases and a use after free.
+
+Restructure how this is all done to handle more in the receive message
+allocation routine, so all refcouting and user message limit counts
+are done in that routine. It's a lot cleaner and safer.
+
+Reported-by: Gilles BULOZ <gilles.buloz@kontron.com>
+Closes: https://lore.kernel.org/lkml/aLsw6G0GyqfpKs2S@mail.minyard.net/
+Fixes: 8e76741c3d8b ("ipmi: Add a limit on the number of users that may use IPMI")
+Cc: <stable@vger.kernel.org> # 4.19
+Signed-off-by: Corey Minyard <corey@minyard.net>
+Tested-by: Gilles BULOZ <gilles.buloz@kontron.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/char/ipmi/ipmi_msghandler.c | 415 +++++++++++++++++-------------------
+ 1 file changed, 198 insertions(+), 217 deletions(-)
+
+--- a/drivers/char/ipmi/ipmi_msghandler.c
++++ b/drivers/char/ipmi/ipmi_msghandler.c
+@@ -39,7 +39,9 @@
+
+ #define IPMI_DRIVER_VERSION "39.2"
+
+-static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
++static struct ipmi_recv_msg *ipmi_alloc_recv_msg(struct ipmi_user *user);
++static void ipmi_set_recv_msg_user(struct ipmi_recv_msg *msg,
++ struct ipmi_user *user);
+ static int ipmi_init_msghandler(void);
+ static void smi_recv_work(struct work_struct *t);
+ static void handle_new_recv_msgs(struct ipmi_smi *intf);
+@@ -939,13 +941,11 @@ static int deliver_response(struct ipmi_
+ * risk. At this moment, simply skip it in that case.
+ */
+ ipmi_free_recv_msg(msg);
+- atomic_dec(&msg->user->nr_msgs);
+ } else {
+ int index;
+ struct ipmi_user *user = acquire_ipmi_user(msg->user, &index);
+
+ if (user) {
+- atomic_dec(&user->nr_msgs);
+ user->handler->ipmi_recv_hndl(msg, user->handler_data);
+ release_ipmi_user(user, index);
+ } else {
+@@ -1634,8 +1634,7 @@ int ipmi_set_gets_events(struct ipmi_use
+ spin_unlock_irqrestore(&intf->events_lock, flags);
+
+ list_for_each_entry_safe(msg, msg2, &msgs, link) {
+- msg->user = user;
+- kref_get(&user->refcount);
++ ipmi_set_recv_msg_user(msg, user);
+ deliver_local_response(intf, msg);
+ }
+
+@@ -2309,22 +2308,15 @@ static int i_ipmi_request(struct ipmi_us
+ struct ipmi_recv_msg *recv_msg;
+ int rv = 0;
+
+- if (user) {
+- if (atomic_add_return(1, &user->nr_msgs) > max_msgs_per_user) {
+- /* Decrement will happen at the end of the routine. */
+- rv = -EBUSY;
+- goto out;
+- }
+- }
+-
+- if (supplied_recv)
++ if (supplied_recv) {
+ recv_msg = supplied_recv;
+- else {
+- recv_msg = ipmi_alloc_recv_msg();
+- if (recv_msg == NULL) {
+- rv = -ENOMEM;
+- goto out;
+- }
++ recv_msg->user = user;
++ if (user)
++ atomic_inc(&user->nr_msgs);
++ } else {
++ recv_msg = ipmi_alloc_recv_msg(user);
++ if (IS_ERR(recv_msg))
++ return PTR_ERR(recv_msg);
+ }
+ recv_msg->user_msg_data = user_msg_data;
+
+@@ -2335,8 +2327,7 @@ static int i_ipmi_request(struct ipmi_us
+ if (smi_msg == NULL) {
+ if (!supplied_recv)
+ ipmi_free_recv_msg(recv_msg);
+- rv = -ENOMEM;
+- goto out;
++ return -ENOMEM;
+ }
+ }
+
+@@ -2346,10 +2337,6 @@ static int i_ipmi_request(struct ipmi_us
+ goto out_err;
+ }
+
+- recv_msg->user = user;
+- if (user)
+- /* The put happens when the message is freed. */
+- kref_get(&user->refcount);
+ recv_msg->msgid = msgid;
+ /*
+ * Store the message to send in the receive message so timeout
+@@ -2378,8 +2365,10 @@ static int i_ipmi_request(struct ipmi_us
+
+ if (rv) {
+ out_err:
+- ipmi_free_smi_msg(smi_msg);
+- ipmi_free_recv_msg(recv_msg);
++ if (!supplied_smi)
++ ipmi_free_smi_msg(smi_msg);
++ if (!supplied_recv)
++ ipmi_free_recv_msg(recv_msg);
+ } else {
+ dev_dbg(intf->si_dev, "Send: %*ph\n",
+ smi_msg->data_size, smi_msg->data);
+@@ -2388,9 +2377,6 @@ out_err:
+ }
+ rcu_read_unlock();
+
+-out:
+- if (rv && user)
+- atomic_dec(&user->nr_msgs);
+ return rv;
+ }
+
+@@ -3882,7 +3868,7 @@ static int handle_ipmb_get_msg_cmd(struc
+ unsigned char chan;
+ struct ipmi_user *user = NULL;
+ struct ipmi_ipmb_addr *ipmb_addr;
+- struct ipmi_recv_msg *recv_msg;
++ struct ipmi_recv_msg *recv_msg = NULL;
+
+ if (msg->rsp_size < 10) {
+ /* Message not big enough, just ignore it. */
+@@ -3903,9 +3889,8 @@ static int handle_ipmb_get_msg_cmd(struc
+ rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
+ if (rcvr) {
+ user = rcvr->user;
+- kref_get(&user->refcount);
+- } else
+- user = NULL;
++ recv_msg = ipmi_alloc_recv_msg(user);
++ }
+ rcu_read_unlock();
+
+ if (user == NULL) {
+@@ -3940,47 +3925,41 @@ static int handle_ipmb_get_msg_cmd(struc
+ rv = -1;
+ }
+ rcu_read_unlock();
+- } else {
+- recv_msg = ipmi_alloc_recv_msg();
+- if (!recv_msg) {
+- /*
+- * We couldn't allocate memory for the
+- * message, so requeue it for handling
+- * later.
+- */
+- rv = 1;
+- kref_put(&user->refcount, free_user);
+- } else {
+- /* Extract the source address from the data. */
+- ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
+- ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
+- ipmb_addr->slave_addr = msg->rsp[6];
+- ipmb_addr->lun = msg->rsp[7] & 3;
+- ipmb_addr->channel = msg->rsp[3] & 0xf;
++ } else if (!IS_ERR(recv_msg)) {
++ /* Extract the source address from the data. */
++ ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;
++ ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;
++ ipmb_addr->slave_addr = msg->rsp[6];
++ ipmb_addr->lun = msg->rsp[7] & 3;
++ ipmb_addr->channel = msg->rsp[3] & 0xf;
+
+- /*
+- * Extract the rest of the message information
+- * from the IPMB header.
+- */
+- recv_msg->user = user;
+- recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
+- recv_msg->msgid = msg->rsp[7] >> 2;
+- recv_msg->msg.netfn = msg->rsp[4] >> 2;
+- recv_msg->msg.cmd = msg->rsp[8];
+- recv_msg->msg.data = recv_msg->msg_data;
++ /*
++ * Extract the rest of the message information
++ * from the IPMB header.
++ */
++ recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
++ recv_msg->msgid = msg->rsp[7] >> 2;
++ recv_msg->msg.netfn = msg->rsp[4] >> 2;
++ recv_msg->msg.cmd = msg->rsp[8];
++ recv_msg->msg.data = recv_msg->msg_data;
+
+- /*
+- * We chop off 10, not 9 bytes because the checksum
+- * at the end also needs to be removed.
+- */
+- recv_msg->msg.data_len = msg->rsp_size - 10;
+- memcpy(recv_msg->msg_data, &msg->rsp[9],
+- msg->rsp_size - 10);
+- if (deliver_response(intf, recv_msg))
+- ipmi_inc_stat(intf, unhandled_commands);
+- else
+- ipmi_inc_stat(intf, handled_commands);
+- }
++ /*
++ * We chop off 10, not 9 bytes because the checksum
++ * at the end also needs to be removed.
++ */
++ recv_msg->msg.data_len = msg->rsp_size - 10;
++ memcpy(recv_msg->msg_data, &msg->rsp[9],
++ msg->rsp_size - 10);
++ if (deliver_response(intf, recv_msg))
++ ipmi_inc_stat(intf, unhandled_commands);
++ else
++ ipmi_inc_stat(intf, handled_commands);
++ } else {
++ /*
++ * We couldn't allocate memory for the message, so
++ * requeue it for handling later.
++ */
++ rv = 1;
+ }
+
+ return rv;
+@@ -3993,7 +3972,7 @@ static int handle_ipmb_direct_rcv_cmd(st
+ int rv = 0;
+ struct ipmi_user *user = NULL;
+ struct ipmi_ipmb_direct_addr *daddr;
+- struct ipmi_recv_msg *recv_msg;
++ struct ipmi_recv_msg *recv_msg = NULL;
+ unsigned char netfn = msg->rsp[0] >> 2;
+ unsigned char cmd = msg->rsp[3];
+
+@@ -4002,9 +3981,8 @@ static int handle_ipmb_direct_rcv_cmd(st
+ rcvr = find_cmd_rcvr(intf, netfn, cmd, 0);
+ if (rcvr) {
+ user = rcvr->user;
+- kref_get(&user->refcount);
+- } else
+- user = NULL;
++ recv_msg = ipmi_alloc_recv_msg(user);
++ }
+ rcu_read_unlock();
+
+ if (user == NULL) {
+@@ -4031,44 +4009,38 @@ static int handle_ipmb_direct_rcv_cmd(st
+ rv = -1;
+ }
+ rcu_read_unlock();
+- } else {
+- recv_msg = ipmi_alloc_recv_msg();
+- if (!recv_msg) {
+- /*
+- * We couldn't allocate memory for the
+- * message, so requeue it for handling
+- * later.
+- */
+- rv = 1;
+- kref_put(&user->refcount, free_user);
+- } else {
+- /* Extract the source address from the data. */
+- daddr = (struct ipmi_ipmb_direct_addr *)&recv_msg->addr;
+- daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE;
+- daddr->channel = 0;
+- daddr->slave_addr = msg->rsp[1];
+- daddr->rs_lun = msg->rsp[0] & 3;
+- daddr->rq_lun = msg->rsp[2] & 3;
++ } else if (!IS_ERR(recv_msg)) {
++ /* Extract the source address from the data. */
++ daddr = (struct ipmi_ipmb_direct_addr *)&recv_msg->addr;
++ daddr->addr_type = IPMI_IPMB_DIRECT_ADDR_TYPE;
++ daddr->channel = 0;
++ daddr->slave_addr = msg->rsp[1];
++ daddr->rs_lun = msg->rsp[0] & 3;
++ daddr->rq_lun = msg->rsp[2] & 3;
+
+- /*
+- * Extract the rest of the message information
+- * from the IPMB header.
+- */
+- recv_msg->user = user;
+- recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
+- recv_msg->msgid = (msg->rsp[2] >> 2);
+- recv_msg->msg.netfn = msg->rsp[0] >> 2;
+- recv_msg->msg.cmd = msg->rsp[3];
+- recv_msg->msg.data = recv_msg->msg_data;
+-
+- recv_msg->msg.data_len = msg->rsp_size - 4;
+- memcpy(recv_msg->msg_data, msg->rsp + 4,
+- msg->rsp_size - 4);
+- if (deliver_response(intf, recv_msg))
+- ipmi_inc_stat(intf, unhandled_commands);
+- else
+- ipmi_inc_stat(intf, handled_commands);
+- }
++ /*
++ * Extract the rest of the message information
++ * from the IPMB header.
++ */
++ recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
++ recv_msg->msgid = (msg->rsp[2] >> 2);
++ recv_msg->msg.netfn = msg->rsp[0] >> 2;
++ recv_msg->msg.cmd = msg->rsp[3];
++ recv_msg->msg.data = recv_msg->msg_data;
++
++ recv_msg->msg.data_len = msg->rsp_size - 4;
++ memcpy(recv_msg->msg_data, msg->rsp + 4,
++ msg->rsp_size - 4);
++ if (deliver_response(intf, recv_msg))
++ ipmi_inc_stat(intf, unhandled_commands);
++ else
++ ipmi_inc_stat(intf, handled_commands);
++ } else {
++ /*
++ * We couldn't allocate memory for the message, so
++ * requeue it for handling later.
++ */
++ rv = 1;
+ }
+
+ return rv;
+@@ -4182,7 +4154,7 @@ static int handle_lan_get_msg_cmd(struct
+ unsigned char chan;
+ struct ipmi_user *user = NULL;
+ struct ipmi_lan_addr *lan_addr;
+- struct ipmi_recv_msg *recv_msg;
++ struct ipmi_recv_msg *recv_msg = NULL;
+
+ if (msg->rsp_size < 12) {
+ /* Message not big enough, just ignore it. */
+@@ -4203,9 +4175,8 @@ static int handle_lan_get_msg_cmd(struct
+ rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
+ if (rcvr) {
+ user = rcvr->user;
+- kref_get(&user->refcount);
+- } else
+- user = NULL;
++ recv_msg = ipmi_alloc_recv_msg(user);
++ }
+ rcu_read_unlock();
+
+ if (user == NULL) {
+@@ -4217,49 +4188,44 @@ static int handle_lan_get_msg_cmd(struct
+ * them to be freed.
+ */
+ rv = 0;
+- } else {
+- recv_msg = ipmi_alloc_recv_msg();
+- if (!recv_msg) {
+- /*
+- * We couldn't allocate memory for the
+- * message, so requeue it for handling later.
+- */
+- rv = 1;
+- kref_put(&user->refcount, free_user);
+- } else {
+- /* Extract the source address from the data. */
+- lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
+- lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
+- lan_addr->session_handle = msg->rsp[4];
+- lan_addr->remote_SWID = msg->rsp[8];
+- lan_addr->local_SWID = msg->rsp[5];
+- lan_addr->lun = msg->rsp[9] & 3;
+- lan_addr->channel = msg->rsp[3] & 0xf;
+- lan_addr->privilege = msg->rsp[3] >> 4;
++ } else if (!IS_ERR(recv_msg)) {
++ /* Extract the source address from the data. */
++ lan_addr = (struct ipmi_lan_addr *) &recv_msg->addr;
++ lan_addr->addr_type = IPMI_LAN_ADDR_TYPE;
++ lan_addr->session_handle = msg->rsp[4];
++ lan_addr->remote_SWID = msg->rsp[8];
++ lan_addr->local_SWID = msg->rsp[5];
++ lan_addr->lun = msg->rsp[9] & 3;
++ lan_addr->channel = msg->rsp[3] & 0xf;
++ lan_addr->privilege = msg->rsp[3] >> 4;
+
+- /*
+- * Extract the rest of the message information
+- * from the IPMB header.
+- */
+- recv_msg->user = user;
+- recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
+- recv_msg->msgid = msg->rsp[9] >> 2;
+- recv_msg->msg.netfn = msg->rsp[6] >> 2;
+- recv_msg->msg.cmd = msg->rsp[10];
+- recv_msg->msg.data = recv_msg->msg_data;
++ /*
++ * Extract the rest of the message information
++ * from the IPMB header.
++ */
++ recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
++ recv_msg->msgid = msg->rsp[9] >> 2;
++ recv_msg->msg.netfn = msg->rsp[6] >> 2;
++ recv_msg->msg.cmd = msg->rsp[10];
++ recv_msg->msg.data = recv_msg->msg_data;
+
+- /*
+- * We chop off 12, not 11 bytes because the checksum
+- * at the end also needs to be removed.
+- */
+- recv_msg->msg.data_len = msg->rsp_size - 12;
+- memcpy(recv_msg->msg_data, &msg->rsp[11],
+- msg->rsp_size - 12);
+- if (deliver_response(intf, recv_msg))
+- ipmi_inc_stat(intf, unhandled_commands);
+- else
+- ipmi_inc_stat(intf, handled_commands);
+- }
++ /*
++ * We chop off 12, not 11 bytes because the checksum
++ * at the end also needs to be removed.
++ */
++ recv_msg->msg.data_len = msg->rsp_size - 12;
++ memcpy(recv_msg->msg_data, &msg->rsp[11],
++ msg->rsp_size - 12);
++ if (deliver_response(intf, recv_msg))
++ ipmi_inc_stat(intf, unhandled_commands);
++ else
++ ipmi_inc_stat(intf, handled_commands);
++ } else {
++ /*
++ * We couldn't allocate memory for the message, so
++ * requeue it for handling later.
++ */
++ rv = 1;
+ }
+
+ return rv;
+@@ -4281,7 +4247,7 @@ static int handle_oem_get_msg_cmd(struct
+ unsigned char chan;
+ struct ipmi_user *user = NULL;
+ struct ipmi_system_interface_addr *smi_addr;
+- struct ipmi_recv_msg *recv_msg;
++ struct ipmi_recv_msg *recv_msg = NULL;
+
+ /*
+ * We expect the OEM SW to perform error checking
+@@ -4310,9 +4276,8 @@ static int handle_oem_get_msg_cmd(struct
+ rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
+ if (rcvr) {
+ user = rcvr->user;
+- kref_get(&user->refcount);
+- } else
+- user = NULL;
++ recv_msg = ipmi_alloc_recv_msg(user);
++ }
+ rcu_read_unlock();
+
+ if (user == NULL) {
+@@ -4325,48 +4290,42 @@ static int handle_oem_get_msg_cmd(struct
+ */
+
+ rv = 0;
+- } else {
+- recv_msg = ipmi_alloc_recv_msg();
+- if (!recv_msg) {
+- /*
+- * We couldn't allocate memory for the
+- * message, so requeue it for handling
+- * later.
+- */
+- rv = 1;
+- kref_put(&user->refcount, free_user);
+- } else {
+- /*
+- * OEM Messages are expected to be delivered via
+- * the system interface to SMS software. We might
+- * need to visit this again depending on OEM
+- * requirements
+- */
+- smi_addr = ((struct ipmi_system_interface_addr *)
+- &recv_msg->addr);
+- smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+- smi_addr->channel = IPMI_BMC_CHANNEL;
+- smi_addr->lun = msg->rsp[0] & 3;
+-
+- recv_msg->user = user;
+- recv_msg->user_msg_data = NULL;
+- recv_msg->recv_type = IPMI_OEM_RECV_TYPE;
+- recv_msg->msg.netfn = msg->rsp[0] >> 2;
+- recv_msg->msg.cmd = msg->rsp[1];
+- recv_msg->msg.data = recv_msg->msg_data;
++ } else if (!IS_ERR(recv_msg)) {
++ /*
++ * OEM Messages are expected to be delivered via
++ * the system interface to SMS software. We might
++ * need to visit this again depending on OEM
++ * requirements
++ */
++ smi_addr = ((struct ipmi_system_interface_addr *)
++ &recv_msg->addr);
++ smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
++ smi_addr->channel = IPMI_BMC_CHANNEL;
++ smi_addr->lun = msg->rsp[0] & 3;
++
++ recv_msg->user_msg_data = NULL;
++ recv_msg->recv_type = IPMI_OEM_RECV_TYPE;
++ recv_msg->msg.netfn = msg->rsp[0] >> 2;
++ recv_msg->msg.cmd = msg->rsp[1];
++ recv_msg->msg.data = recv_msg->msg_data;
+
+- /*
+- * The message starts at byte 4 which follows the
+- * Channel Byte in the "GET MESSAGE" command
+- */
+- recv_msg->msg.data_len = msg->rsp_size - 4;
+- memcpy(recv_msg->msg_data, &msg->rsp[4],
+- msg->rsp_size - 4);
+- if (deliver_response(intf, recv_msg))
+- ipmi_inc_stat(intf, unhandled_commands);
+- else
+- ipmi_inc_stat(intf, handled_commands);
+- }
++ /*
++ * The message starts at byte 4 which follows the
++ * Channel Byte in the "GET MESSAGE" command
++ */
++ recv_msg->msg.data_len = msg->rsp_size - 4;
++ memcpy(recv_msg->msg_data, &msg->rsp[4],
++ msg->rsp_size - 4);
++ if (deliver_response(intf, recv_msg))
++ ipmi_inc_stat(intf, unhandled_commands);
++ else
++ ipmi_inc_stat(intf, handled_commands);
++ } else {
++ /*
++ * We couldn't allocate memory for the message, so
++ * requeue it for handling later.
++ */
++ rv = 1;
+ }
+
+ return rv;
+@@ -4425,8 +4384,8 @@ static int handle_read_event_rsp(struct
+ if (!user->gets_events)
+ continue;
+
+- recv_msg = ipmi_alloc_recv_msg();
+- if (!recv_msg) {
++ recv_msg = ipmi_alloc_recv_msg(user);
++ if (IS_ERR(recv_msg)) {
+ rcu_read_unlock();
+ list_for_each_entry_safe(recv_msg, recv_msg2, &msgs,
+ link) {
+@@ -4445,8 +4404,6 @@ static int handle_read_event_rsp(struct
+ deliver_count++;
+
+ copy_event_into_recv_msg(recv_msg, msg);
+- recv_msg->user = user;
+- kref_get(&user->refcount);
+ list_add_tail(&recv_msg->link, &msgs);
+ }
+ srcu_read_unlock(&intf->users_srcu, index);
+@@ -4462,8 +4419,8 @@ static int handle_read_event_rsp(struct
+ * No one to receive the message, put it in queue if there's
+ * not already too many things in the queue.
+ */
+- recv_msg = ipmi_alloc_recv_msg();
+- if (!recv_msg) {
++ recv_msg = ipmi_alloc_recv_msg(NULL);
++ if (IS_ERR(recv_msg)) {
+ /*
+ * We couldn't allocate memory for the
+ * message, so requeue it for handling
+@@ -5155,27 +5112,51 @@ static void free_recv_msg(struct ipmi_re
+ kfree(msg);
+ }
+
+-static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
++static struct ipmi_recv_msg *ipmi_alloc_recv_msg(struct ipmi_user *user)
+ {
+ struct ipmi_recv_msg *rv;
+
++ if (user) {
++ if (atomic_add_return(1, &user->nr_msgs) > max_msgs_per_user) {
++ atomic_dec(&user->nr_msgs);
++ return ERR_PTR(-EBUSY);
++ }
++ }
++
+ rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
+- if (rv) {
+- rv->user = NULL;
+- rv->done = free_recv_msg;
+- atomic_inc(&recv_msg_inuse_count);
++ if (!rv) {
++ if (user)
++ atomic_dec(&user->nr_msgs);
++ return ERR_PTR(-ENOMEM);
+ }
++
++ rv->user = user;
++ rv->done = free_recv_msg;
++ if (user)
++ kref_get(&user->refcount);
++ atomic_inc(&recv_msg_inuse_count);
+ return rv;
+ }
+
+ void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
+ {
+- if (msg->user && !oops_in_progress)
++ if (msg->user && !oops_in_progress) {
++ atomic_dec(&msg->user->nr_msgs);
+ kref_put(&msg->user->refcount, free_user);
++ }
+ msg->done(msg);
+ }
+ EXPORT_SYMBOL(ipmi_free_recv_msg);
+
++static void ipmi_set_recv_msg_user(struct ipmi_recv_msg *msg,
++ struct ipmi_user *user)
++{
++ WARN_ON_ONCE(msg->user); /* User should not be set. */
++ msg->user = user;
++ atomic_inc(&user->nr_msgs);
++ kref_get(&user->refcount);
++}
++
+ static atomic_t panic_done_count = ATOMIC_INIT(0);
+
+ static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
--- /dev/null
+From stable+bounces-186178-greg=kroah.com@vger.kernel.org Thu Oct 16 18:57:55 2025
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+Date: Thu, 16 Oct 2025 18:56:57 +0200
+Subject: mptcp: pm: in-kernel: usable client side with C-flag
+To: stable@vger.kernel.org, gregkh@linuxfoundation.org
+Cc: MPTCP Upstream <mptcp@lists.linux.dev>, "Matthieu Baerts (NGI0)" <matttbe@kernel.org>, Geliang Tang <geliang@kernel.org>, Jakub Kicinski <kuba@kernel.org>
+Message-ID: <20251016165656.940021-2-matttbe@kernel.org>
+
+From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
+
+commit 4b1ff850e0c1aacc23e923ed22989b827b9808f9 upstream.
+
+When servers set the C-flag in their MP_CAPABLE to tell clients not to
+create subflows to the initial address and port, clients will likely not
+use their other endpoints. That's because the in-kernel path-manager
+uses the 'subflow' endpoints to create subflows only to the initial
+address and port.
+
+If the limits have not been modified to accept ADD_ADDR, the client
+doesn't try to establish new subflows. If the limits accept ADD_ADDR,
+the routing routes will be used to select the source IP.
+
+The C-flag is typically set when the server is operating behind a legacy
+Layer 4 load balancer, or using anycast IP address. Clients having their
+different 'subflow' endpoints setup, don't end up creating multiple
+subflows as expected, and causing some deployment issues.
+
+A special case is then added here: when servers set the C-flag in the
+MPC and directly sends an ADD_ADDR, this single ADD_ADDR is accepted.
+The 'subflows' endpoints will then be used with this new remote IP and
+port. This exception is only allowed when the ADD_ADDR is sent
+immediately after the 3WHS, and makes the client switching to the 'fully
+established' mode. After that, 'select_local_address()' will not be able
+to find any subflows, because 'id_avail_bitmap' will be filled in
+mptcp_pm_create_subflow_or_signal_addr(), when switching to 'fully
+established' mode.
+
+Fixes: df377be38725 ("mptcp: add deny_join_id0 in mptcp_options_received")
+Cc: stable@vger.kernel.org
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/536
+Reviewed-by: Geliang Tang <geliang@kernel.org>
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Link: https://patch.msgid.link/20250925-net-next-mptcp-c-flag-laminar-v1-1-ad126cc47c6b@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+[ Conflict in pm.c, because commit 498d7d8b75f1 ("mptcp: pm: remove
+ '_nl' from mptcp_pm_nl_is_init_remote_addr") renamed an helper in the
+ context, and it is not in this version. The same new code can be
+ applied at the same place.
+ Conflict in pm_kernel.c, because the modified code has been moved from
+ pm_netlink.c to pm_kernel.c in commit 8617e85e04bd ("mptcp: pm: split
+ in-kernel PM specific code"), which is not in this version. The
+ resolution is easy: simply by applying the patch where 'pm_kernel.c'
+ has been replaced 'pm_netlink.c'. 'patch --merge' managed to apply
+ this modified patch without creating any conflicts. ]
+Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mptcp/pm.c | 7 ++++--
+ net/mptcp/pm_netlink.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ net/mptcp/protocol.h | 8 +++++++
+ 3 files changed, 62 insertions(+), 3 deletions(-)
+
+--- a/net/mptcp/pm.c
++++ b/net/mptcp/pm.c
+@@ -226,9 +226,12 @@ void mptcp_pm_add_addr_received(const st
+ } else {
+ __MPTCP_INC_STATS(sock_net((struct sock *)msk), MPTCP_MIB_ADDADDRDROP);
+ }
+- /* id0 should not have a different address */
++ /* - id0 should not have a different address
++ * - special case for C-flag: linked to fill_local_addresses_vec()
++ */
+ } else if ((addr->id == 0 && !mptcp_pm_nl_is_init_remote_addr(msk, addr)) ||
+- (addr->id > 0 && !READ_ONCE(pm->accept_addr))) {
++ (addr->id > 0 && !READ_ONCE(pm->accept_addr) &&
++ !mptcp_pm_add_addr_c_flag_case(msk))) {
+ mptcp_pm_announce_addr(msk, addr, true);
+ mptcp_pm_add_addr_send_ack(msk);
+ } else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED)) {
+--- a/net/mptcp/pm_netlink.c
++++ b/net/mptcp/pm_netlink.c
+@@ -674,10 +674,12 @@ static unsigned int fill_local_addresses
+ struct mptcp_addr_info mpc_addr;
+ struct pm_nl_pernet *pernet;
+ unsigned int subflows_max;
++ bool c_flag_case;
+ int i = 0;
+
+ pernet = pm_nl_get_pernet_from_msk(msk);
+ subflows_max = mptcp_pm_get_subflows_max(msk);
++ c_flag_case = remote->id && mptcp_pm_add_addr_c_flag_case(msk);
+
+ mptcp_local_address((struct sock_common *)msk, &mpc_addr);
+
+@@ -690,12 +692,27 @@ static unsigned int fill_local_addresses
+ continue;
+
+ if (msk->pm.subflows < subflows_max) {
++ bool is_id0;
++
+ locals[i].addr = entry->addr;
+ locals[i].flags = entry->flags;
+ locals[i].ifindex = entry->ifindex;
+
++ is_id0 = mptcp_addresses_equal(&locals[i].addr,
++ &mpc_addr,
++ locals[i].addr.port);
++
++ if (c_flag_case &&
++ (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW)) {
++ __clear_bit(locals[i].addr.id,
++ msk->pm.id_avail_bitmap);
++
++ if (!is_id0)
++ msk->pm.local_addr_used++;
++ }
++
+ /* Special case for ID0: set the correct ID */
+- if (mptcp_addresses_equal(&locals[i].addr, &mpc_addr, locals[i].addr.port))
++ if (is_id0)
+ locals[i].addr.id = 0;
+
+ msk->pm.subflows++;
+@@ -704,6 +721,37 @@ static unsigned int fill_local_addresses
+ }
+ rcu_read_unlock();
+
++ /* Special case: peer sets the C flag, accept one ADD_ADDR if default
++ * limits are used -- accepting no ADD_ADDR -- and use subflow endpoints
++ */
++ if (!i && c_flag_case) {
++ unsigned int local_addr_max = mptcp_pm_get_local_addr_max(msk);
++
++ while (msk->pm.local_addr_used < local_addr_max &&
++ msk->pm.subflows < subflows_max) {
++ struct mptcp_pm_local *local = &locals[i];
++
++ if (!select_local_address(pernet, msk, local))
++ break;
++
++ __clear_bit(local->addr.id, msk->pm.id_avail_bitmap);
++
++ if (!mptcp_pm_addr_families_match(sk, &local->addr,
++ remote))
++ continue;
++
++ if (mptcp_addresses_equal(&local->addr, &mpc_addr,
++ local->addr.port))
++ continue;
++
++ msk->pm.local_addr_used++;
++ msk->pm.subflows++;
++ i++;
++ }
++
++ return i;
++ }
++
+ /* If the array is empty, fill in the single
+ * 'IPADDRANY' local address
+ */
+--- a/net/mptcp/protocol.h
++++ b/net/mptcp/protocol.h
+@@ -1172,6 +1172,14 @@ static inline void mptcp_pm_close_subflo
+ spin_unlock_bh(&msk->pm.lock);
+ }
+
++static inline bool mptcp_pm_add_addr_c_flag_case(struct mptcp_sock *msk)
++{
++ return READ_ONCE(msk->pm.remote_deny_join_id0) &&
++ msk->pm.local_addr_used == 0 &&
++ mptcp_pm_get_add_addr_accept_max(msk) == 0 &&
++ msk->pm.subflows < mptcp_pm_get_subflows_max(msk);
++}
++
+ void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk);
+
+ static inline struct mptcp_ext *mptcp_get_ext(const struct sk_buff *skb)
--- /dev/null
+From stable+bounces-185865-greg=kroah.com@vger.kernel.org Thu Oct 16 00:09:00 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Oct 2025 18:08:45 -0400
+Subject: nfsd: don't use sv_nrthreads in connection limiting calculations.
+To: stable@vger.kernel.org
+Cc: NeilBrown <neilb@suse.de>, Jeff Layton <jlayton@kernel.org>, Chuck Lever <chuck.lever@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251015220846.1531878-4-sashal@kernel.org>
+
+From: NeilBrown <neilb@suse.de>
+
+[ Upstream commit eccbbc7c00a5aae5e704d4002adfaf4c3fa4b30d ]
+
+The heuristic for limiting the number of incoming connections to nfsd
+currently uses sv_nrthreads - allowing more connections if more threads
+were configured.
+
+A future patch will allow number of threads to grow dynamically so that
+there will be no need to configure sv_nrthreads. So we need a different
+solution for limiting connections.
+
+It isn't clear what problem is solved by limiting connections (as
+mentioned in a code comment) but the most likely problem is a connection
+storm - many connections that are not doing productive work. These will
+be closed after about 6 minutes already but it might help to slow down a
+storm.
+
+This patch adds a per-connection flag XPT_PEER_VALID which indicates
+that the peer has presented a filehandle for which it has some sort of
+access. i.e the peer is known to be trusted in some way. We now only
+count connections which have NOT been determined to be valid. There
+should be relative few of these at any given time.
+
+If the number of non-validated peer exceed a limit - currently 64 - we
+close the oldest non-validated peer to avoid having too many of these
+useless connections.
+
+Note that this patch significantly changes the meaning of the various
+configuration parameters for "max connections". The next patch will
+remove all of these.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Stable-dep-of: 898374fdd7f0 ("nfsd: unregister with rpcbind when deleting a transport")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/callback.c | 4 ----
+ fs/nfs/callback_xdr.c | 1 +
+ fs/nfsd/netns.h | 4 ++--
+ fs/nfsd/nfsfh.c | 2 ++
+ include/linux/sunrpc/svc.h | 2 +-
+ include/linux/sunrpc/svc_xprt.h | 16 ++++++++++++++++
+ net/sunrpc/svc_xprt.c | 32 ++++++++++++++++----------------
+ 7 files changed, 38 insertions(+), 23 deletions(-)
+
+--- a/fs/nfs/callback.c
++++ b/fs/nfs/callback.c
+@@ -211,10 +211,6 @@ static struct svc_serv *nfs_callback_cre
+ return ERR_PTR(-ENOMEM);
+ }
+ cb_info->serv = serv;
+- /* As there is only one thread we need to over-ride the
+- * default maximum of 80 connections
+- */
+- serv->sv_maxconn = 1024;
+ dprintk("nfs_callback_create_svc: service created\n");
+ return serv;
+ }
+--- a/fs/nfs/callback_xdr.c
++++ b/fs/nfs/callback_xdr.c
+@@ -984,6 +984,7 @@ static __be32 nfs4_callback_compound(str
+ nfs_put_client(cps.clp);
+ goto out_invalidcred;
+ }
++ svc_xprt_set_valid(rqstp->rq_xprt);
+ }
+
+ cps.minorversion = hdr_arg.minorversion;
+--- a/fs/nfsd/netns.h
++++ b/fs/nfsd/netns.h
+@@ -129,8 +129,8 @@ struct nfsd_net {
+ unsigned char writeverf[8];
+
+ /*
+- * Max number of connections this nfsd container will allow. Defaults
+- * to '0' which is means that it bases this on the number of threads.
++ * Max number of non-validated connections this nfsd container
++ * will allow. Defaults to '0' gets mapped to 64.
+ */
+ unsigned int max_connections;
+
+--- a/fs/nfsd/nfsfh.c
++++ b/fs/nfsd/nfsfh.c
+@@ -382,6 +382,8 @@ __fh_verify(struct svc_rqst *rqstp,
+ if (error)
+ goto out;
+
++ svc_xprt_set_valid(rqstp->rq_xprt);
++
+ /* Finally, check access permissions. */
+ error = nfsd_permission(cred, exp, dentry, access);
+ out:
+--- a/include/linux/sunrpc/svc.h
++++ b/include/linux/sunrpc/svc.h
+@@ -81,7 +81,7 @@ struct svc_serv {
+ unsigned int sv_xdrsize; /* XDR buffer size */
+ struct list_head sv_permsocks; /* all permanent sockets */
+ struct list_head sv_tempsocks; /* all temporary sockets */
+- int sv_tmpcnt; /* count of temporary sockets */
++ int sv_tmpcnt; /* count of temporary "valid" sockets */
+ struct timer_list sv_temptimer; /* timer for aging temporary sockets */
+
+ char * sv_name; /* service name */
+--- a/include/linux/sunrpc/svc_xprt.h
++++ b/include/linux/sunrpc/svc_xprt.h
+@@ -99,8 +99,24 @@ enum {
+ XPT_HANDSHAKE, /* xprt requests a handshake */
+ XPT_TLS_SESSION, /* transport-layer security established */
+ XPT_PEER_AUTH, /* peer has been authenticated */
++ XPT_PEER_VALID, /* peer has presented a filehandle that
++ * it has access to. It is NOT counted
++ * in ->sv_tmpcnt.
++ */
+ };
+
++static inline void svc_xprt_set_valid(struct svc_xprt *xpt)
++{
++ if (test_bit(XPT_TEMP, &xpt->xpt_flags) &&
++ !test_and_set_bit(XPT_PEER_VALID, &xpt->xpt_flags)) {
++ struct svc_serv *serv = xpt->xpt_server;
++
++ spin_lock(&serv->sv_lock);
++ serv->sv_tmpcnt -= 1;
++ spin_unlock(&serv->sv_lock);
++ }
++}
++
+ static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
+ {
+ spin_lock(&xpt->xpt_lock);
+--- a/net/sunrpc/svc_xprt.c
++++ b/net/sunrpc/svc_xprt.c
+@@ -606,7 +606,8 @@ int svc_port_is_privileged(struct sockad
+ }
+
+ /*
+- * Make sure that we don't have too many active connections. If we have,
++ * Make sure that we don't have too many connections that have not yet
++ * demonstrated that they have access to the NFS server. If we have,
+ * something must be dropped. It's not clear what will happen if we allow
+ * "too many" connections, but when dealing with network-facing software,
+ * we have to code defensively. Here we do that by imposing hard limits.
+@@ -625,27 +626,25 @@ int svc_port_is_privileged(struct sockad
+ */
+ static void svc_check_conn_limits(struct svc_serv *serv)
+ {
+- unsigned int limit = serv->sv_maxconn ? serv->sv_maxconn :
+- (serv->sv_nrthreads+3) * 20;
++ unsigned int limit = serv->sv_maxconn ? serv->sv_maxconn : 64;
+
+ if (serv->sv_tmpcnt > limit) {
+- struct svc_xprt *xprt = NULL;
++ struct svc_xprt *xprt = NULL, *xprti;
+ spin_lock_bh(&serv->sv_lock);
+ if (!list_empty(&serv->sv_tempsocks)) {
+- /* Try to help the admin */
+- net_notice_ratelimited("%s: too many open connections, consider increasing the %s\n",
+- serv->sv_name, serv->sv_maxconn ?
+- "max number of connections" :
+- "number of threads");
+ /*
+ * Always select the oldest connection. It's not fair,
+- * but so is life
++ * but nor is life.
+ */
+- xprt = list_entry(serv->sv_tempsocks.prev,
+- struct svc_xprt,
+- xpt_list);
+- set_bit(XPT_CLOSE, &xprt->xpt_flags);
+- svc_xprt_get(xprt);
++ list_for_each_entry_reverse(xprti, &serv->sv_tempsocks,
++ xpt_list) {
++ if (!test_bit(XPT_PEER_VALID, &xprti->xpt_flags)) {
++ xprt = xprti;
++ set_bit(XPT_CLOSE, &xprt->xpt_flags);
++ svc_xprt_get(xprt);
++ break;
++ }
++ }
+ }
+ spin_unlock_bh(&serv->sv_lock);
+
+@@ -1039,7 +1038,8 @@ static void svc_delete_xprt(struct svc_x
+
+ spin_lock_bh(&serv->sv_lock);
+ list_del_init(&xprt->xpt_list);
+- if (test_bit(XPT_TEMP, &xprt->xpt_flags))
++ if (test_bit(XPT_TEMP, &xprt->xpt_flags) &&
++ !test_bit(XPT_PEER_VALID, &xprt->xpt_flags))
+ serv->sv_tmpcnt--;
+ spin_unlock_bh(&serv->sv_lock);
+
--- /dev/null
+From stable+bounces-185862-greg=kroah.com@vger.kernel.org Thu Oct 16 00:08:56 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Oct 2025 18:08:42 -0400
+Subject: nfsd: Fix NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT
+To: stable@vger.kernel.org
+Cc: "Pali Rohár" <pali@kernel.org>, NeilBrown <neilb@suse.de>, "Chuck Lever" <chuck.lever@oracle.com>, "Sasha Levin" <sashal@kernel.org>
+Message-ID: <20251015220846.1531878-1-sashal@kernel.org>
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit bb4f07f2409c26c01e97e6f9b432545f353e3b66 ]
+
+Currently NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT do not bypass
+only GSS, but bypass any method. This is a problem specially for NFS3
+AUTH_NULL-only exports.
+
+The purpose of NFSD_MAY_BYPASS_GSS_ON_ROOT is described in RFC 2623,
+section 2.3.2, to allow mounting NFS2/3 GSS-only export without
+authentication. So few procedures which do not expose security risk used
+during mount time can be called also with AUTH_NONE or AUTH_SYS, to allow
+client mount operation to finish successfully.
+
+The problem with current implementation is that for AUTH_NULL-only exports,
+the NFSD_MAY_BYPASS_GSS_ON_ROOT is active also for NFS3 AUTH_UNIX mount
+attempts which confuse NFS3 clients, and make them think that AUTH_UNIX is
+enabled and is working. Linux NFS3 client never switches from AUTH_UNIX to
+AUTH_NONE on active mount, which makes the mount inaccessible.
+
+Fix the NFSD_MAY_BYPASS_GSS and NFSD_MAY_BYPASS_GSS_ON_ROOT implementation
+and really allow to bypass only exports which have enabled some real
+authentication (GSS, TLS, or any other).
+
+The result would be: For AUTH_NULL-only export if client attempts to do
+mount with AUTH_UNIX flavor then it will receive access errors, which
+instruct client that AUTH_UNIX flavor is not usable and will either try
+other auth flavor (AUTH_NULL if enabled) or fails mount procedure.
+Similarly if client attempt to do mount with AUTH_NULL flavor and only
+AUTH_UNIX flavor is enabled then the client will receive access error.
+
+This should fix problems with AUTH_NULL-only or AUTH_UNIX-only exports if
+client attempts to mount it with other auth flavor (e.g. with AUTH_NULL for
+AUTH_UNIX-only export, or with AUTH_UNIX for AUTH_NULL-only export).
+
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Stable-dep-of: 898374fdd7f0 ("nfsd: unregister with rpcbind when deleting a transport")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/export.c | 21 ++++++++++++++++++++-
+ fs/nfsd/export.h | 3 ++-
+ fs/nfsd/nfs4proc.c | 2 +-
+ fs/nfsd/nfs4xdr.c | 2 +-
+ fs/nfsd/nfsfh.c | 9 ++++++---
+ fs/nfsd/vfs.c | 2 +-
+ 6 files changed, 31 insertions(+), 8 deletions(-)
+
+--- a/fs/nfsd/export.c
++++ b/fs/nfsd/export.c
+@@ -1078,12 +1078,14 @@ static struct svc_export *exp_find(struc
+ * check_nfsd_access - check if access to export is allowed.
+ * @exp: svc_export that is being accessed.
+ * @rqstp: svc_rqst attempting to access @exp (will be NULL for LOCALIO).
++ * @may_bypass_gss: reduce strictness of authorization check
+ *
+ * Return values:
+ * %nfs_ok if access is granted, or
+ * %nfserr_wrongsec if access is denied
+ */
+-__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
++__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
++ bool may_bypass_gss)
+ {
+ struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
+ struct svc_xprt *xprt;
+@@ -1140,6 +1142,23 @@ ok:
+ if (nfsd4_spo_must_allow(rqstp))
+ return nfs_ok;
+
++ /* Some calls may be processed without authentication
++ * on GSS exports. For example NFS2/3 calls on root
++ * directory, see section 2.3.2 of rfc 2623.
++ * For "may_bypass_gss" check that export has really
++ * enabled some flavor with authentication (GSS or any
++ * other) and also check that the used auth flavor is
++ * without authentication (none or sys).
++ */
++ if (may_bypass_gss && (
++ rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
++ rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)) {
++ for (f = exp->ex_flavors; f < end; f++) {
++ if (f->pseudoflavor >= RPC_AUTH_DES)
++ return 0;
++ }
++ }
++
+ denied:
+ return nfserr_wrongsec;
+ }
+--- a/fs/nfsd/export.h
++++ b/fs/nfsd/export.h
+@@ -101,7 +101,8 @@ struct svc_expkey {
+
+ struct svc_cred;
+ int nfsexp_flags(struct svc_cred *cred, struct svc_export *exp);
+-__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
++__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
++ bool may_bypass_gss);
+
+ /*
+ * Function declarations
+--- a/fs/nfsd/nfs4proc.c
++++ b/fs/nfsd/nfs4proc.c
+@@ -2799,7 +2799,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
+
+ if (current_fh->fh_export &&
+ need_wrongsec_check(rqstp))
+- op->status = check_nfsd_access(current_fh->fh_export, rqstp);
++ op->status = check_nfsd_access(current_fh->fh_export, rqstp, false);
+ }
+ encode_op:
+ if (op->status == nfserr_replay_me) {
+--- a/fs/nfsd/nfs4xdr.c
++++ b/fs/nfsd/nfs4xdr.c
+@@ -3784,7 +3784,7 @@ nfsd4_encode_entry4_fattr(struct nfsd4_r
+ nfserr = nfserrno(err);
+ goto out_put;
+ }
+- nfserr = check_nfsd_access(exp, cd->rd_rqstp);
++ nfserr = check_nfsd_access(exp, cd->rd_rqstp, false);
+ if (nfserr)
+ goto out_put;
+
+--- a/fs/nfsd/nfsfh.c
++++ b/fs/nfsd/nfsfh.c
+@@ -320,6 +320,7 @@ __fh_verify(struct svc_rqst *rqstp,
+ {
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct svc_export *exp = NULL;
++ bool may_bypass_gss = false;
+ struct dentry *dentry;
+ __be32 error;
+
+@@ -367,8 +368,10 @@ __fh_verify(struct svc_rqst *rqstp,
+ * which clients virtually always use auth_sys for,
+ * even while using RPCSEC_GSS for NFS.
+ */
+- if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
++ if (access & NFSD_MAY_LOCK)
+ goto skip_pseudoflavor_check;
++ if (access & NFSD_MAY_BYPASS_GSS)
++ may_bypass_gss = true;
+ /*
+ * Clients may expect to be able to use auth_sys during mount,
+ * even if they use gss for everything else; see section 2.3.2
+@@ -376,9 +379,9 @@ __fh_verify(struct svc_rqst *rqstp,
+ */
+ if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
+ && exp->ex_path.dentry == dentry)
+- goto skip_pseudoflavor_check;
++ may_bypass_gss = true;
+
+- error = check_nfsd_access(exp, rqstp);
++ error = check_nfsd_access(exp, rqstp, may_bypass_gss);
+ if (error)
+ goto out;
+
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -321,7 +321,7 @@ nfsd_lookup(struct svc_rqst *rqstp, stru
+ err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
+ if (err)
+ return err;
+- err = check_nfsd_access(exp, rqstp);
++ err = check_nfsd_access(exp, rqstp, false);
+ if (err)
+ goto out;
+ /*
--- /dev/null
+From stable+bounces-185864-greg=kroah.com@vger.kernel.org Thu Oct 16 00:08:57 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Oct 2025 18:08:44 -0400
+Subject: nfsd: refine and rename NFSD_MAY_LOCK
+To: stable@vger.kernel.org
+Cc: NeilBrown <neilb@suse.de>, Chuck Lever <chuck.lever@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251015220846.1531878-3-sashal@kernel.org>
+
+From: NeilBrown <neilb@suse.de>
+
+[ Upstream commit 4cc9b9f2bf4dfe13fe573da978e626e2248df388 ]
+
+NFSD_MAY_LOCK means a few different things.
+- it means that GSS is not required.
+- it means that with NFSEXP_NOAUTHNLM, authentication is not required
+- it means that OWNER_OVERRIDE is allowed.
+
+None of these are specific to locking, they are specific to the NLM
+protocol.
+So:
+ - rename to NFSD_MAY_NLM
+ - set NFSD_MAY_OWNER_OVERRIDE and NFSD_MAY_BYPASS_GSS in nlm_fopen()
+ so that NFSD_MAY_NLM doesn't need to imply these.
+ - move the test on NFSEXP_NOAUTHNLM out of nfsd_permission() and
+ into fh_verify where other special-case tests on the MAY flags
+ happen. nfsd_permission() can be called from other places than
+ fh_verify(), but none of these will have NFSD_MAY_NLM.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Stable-dep-of: 898374fdd7f0 ("nfsd: unregister with rpcbind when deleting a transport")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/lockd.c | 13 +++++++++++--
+ fs/nfsd/nfsfh.c | 12 ++++--------
+ fs/nfsd/trace.h | 2 +-
+ fs/nfsd/vfs.c | 12 +-----------
+ fs/nfsd/vfs.h | 2 +-
+ 5 files changed, 18 insertions(+), 23 deletions(-)
+
+--- a/fs/nfsd/lockd.c
++++ b/fs/nfsd/lockd.c
+@@ -38,11 +38,20 @@ nlm_fopen(struct svc_rqst *rqstp, struct
+ memcpy(&fh.fh_handle.fh_raw, f->data, f->size);
+ fh.fh_export = NULL;
+
++ /*
++ * Allow BYPASS_GSS as some client implementations use AUTH_SYS
++ * for NLM even when GSS is used for NFS.
++ * Allow OWNER_OVERRIDE as permission might have been changed
++ * after the file was opened.
++ * Pass MAY_NLM so that authentication can be completely bypassed
++ * if NFSEXP_NOAUTHNLM is set. Some older clients use AUTH_NULL
++ * for NLM requests.
++ */
+ access = (mode == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ;
+- access |= NFSD_MAY_LOCK;
++ access |= NFSD_MAY_NLM | NFSD_MAY_OWNER_OVERRIDE | NFSD_MAY_BYPASS_GSS;
+ nfserr = nfsd_open(rqstp, &fh, S_IFREG, access, filp);
+ fh_put(&fh);
+- /* We return nlm error codes as nlm doesn't know
++ /* We return nlm error codes as nlm doesn't know
+ * about nfsd, but nfsd does know about nlm..
+ */
+ switch (nfserr) {
+--- a/fs/nfsd/nfsfh.c
++++ b/fs/nfsd/nfsfh.c
+@@ -363,13 +363,10 @@ __fh_verify(struct svc_rqst *rqstp,
+ if (error)
+ goto out;
+
+- /*
+- * pseudoflavor restrictions are not enforced on NLM,
+- * which clients virtually always use auth_sys for,
+- * even while using RPCSEC_GSS for NFS.
+- */
+- if (access & NFSD_MAY_LOCK)
+- goto skip_pseudoflavor_check;
++ if ((access & NFSD_MAY_NLM) && (exp->ex_flags & NFSEXP_NOAUTHNLM))
++ /* NLM is allowed to fully bypass authentication */
++ goto out;
++
+ if (access & NFSD_MAY_BYPASS_GSS)
+ may_bypass_gss = true;
+ /*
+@@ -385,7 +382,6 @@ __fh_verify(struct svc_rqst *rqstp,
+ if (error)
+ goto out;
+
+-skip_pseudoflavor_check:
+ /* Finally, check access permissions. */
+ error = nfsd_permission(cred, exp, dentry, access);
+ out:
+--- a/fs/nfsd/trace.h
++++ b/fs/nfsd/trace.h
+@@ -79,7 +79,7 @@ DEFINE_NFSD_XDR_ERR_EVENT(cant_encode);
+ { NFSD_MAY_READ, "READ" }, \
+ { NFSD_MAY_SATTR, "SATTR" }, \
+ { NFSD_MAY_TRUNC, "TRUNC" }, \
+- { NFSD_MAY_LOCK, "LOCK" }, \
++ { NFSD_MAY_NLM, "NLM" }, \
+ { NFSD_MAY_OWNER_OVERRIDE, "OWNER_OVERRIDE" }, \
+ { NFSD_MAY_LOCAL_ACCESS, "LOCAL_ACCESS" }, \
+ { NFSD_MAY_BYPASS_GSS_ON_ROOT, "BYPASS_GSS_ON_ROOT" }, \
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -2519,7 +2519,7 @@ nfsd_permission(struct svc_cred *cred, s
+ (acc & NFSD_MAY_EXEC)? " exec" : "",
+ (acc & NFSD_MAY_SATTR)? " sattr" : "",
+ (acc & NFSD_MAY_TRUNC)? " trunc" : "",
+- (acc & NFSD_MAY_LOCK)? " lock" : "",
++ (acc & NFSD_MAY_NLM)? " nlm" : "",
+ (acc & NFSD_MAY_OWNER_OVERRIDE)? " owneroverride" : "",
+ inode->i_mode,
+ IS_IMMUTABLE(inode)? " immut" : "",
+@@ -2544,16 +2544,6 @@ nfsd_permission(struct svc_cred *cred, s
+ if ((acc & NFSD_MAY_TRUNC) && IS_APPEND(inode))
+ return nfserr_perm;
+
+- if (acc & NFSD_MAY_LOCK) {
+- /* If we cannot rely on authentication in NLM requests,
+- * just allow locks, otherwise require read permission, or
+- * ownership
+- */
+- if (exp->ex_flags & NFSEXP_NOAUTHNLM)
+- return 0;
+- else
+- acc = NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE;
+- }
+ /*
+ * The file owner always gets access permission for accesses that
+ * would normally be checked at open time. This is to make
+--- a/fs/nfsd/vfs.h
++++ b/fs/nfsd/vfs.h
+@@ -20,7 +20,7 @@
+ #define NFSD_MAY_READ 0x004 /* == MAY_READ */
+ #define NFSD_MAY_SATTR 0x008
+ #define NFSD_MAY_TRUNC 0x010
+-#define NFSD_MAY_LOCK 0x020
++#define NFSD_MAY_NLM 0x020 /* request is from lockd */
+ #define NFSD_MAY_MASK 0x03f
+
+ /* extra hints to permission and open routines: */
--- /dev/null
+From stable+bounces-185863-greg=kroah.com@vger.kernel.org Thu Oct 16 00:08:56 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Oct 2025 18:08:43 -0400
+Subject: NFSD: Replace use of NFSD_MAY_LOCK in nfsd4_lock()
+To: stable@vger.kernel.org
+Cc: Chuck Lever <chuck.lever@oracle.com>, NeilBrown <neilb@suse.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251015220846.1531878-2-sashal@kernel.org>
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit 6640556b0c80edc66d6f50abe53f00311a873536 ]
+
+NFSv4 LOCK operations should not avoid the set of authorization
+checks that apply to all other NFSv4 operations. Also, the
+"no_auth_nlm" export option should apply only to NLM LOCK requests.
+It's not necessary or sensible to apply it to NFSv4 LOCK operations.
+
+Instead, set no permission bits when calling fh_verify(). Subsequent
+stateid processing handles authorization checks.
+
+Reported-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Stable-dep-of: 898374fdd7f0 ("nfsd: unregister with rpcbind when deleting a transport")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/nfs4state.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -7998,11 +7998,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
+ if (check_lock_length(lock->lk_offset, lock->lk_length))
+ return nfserr_inval;
+
+- if ((status = fh_verify(rqstp, &cstate->current_fh,
+- S_IFREG, NFSD_MAY_LOCK))) {
+- dprintk("NFSD: nfsd4_lock: permission denied!\n");
++ status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
++ if (status != nfs_ok)
+ return status;
+- }
+ sb = cstate->current_fh.fh_dentry->d_sb;
+
+ if (lock->lk_is_new) {
--- /dev/null
+From stable+bounces-185866-greg=kroah.com@vger.kernel.org Thu Oct 16 00:09:01 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Oct 2025 18:08:46 -0400
+Subject: nfsd: unregister with rpcbind when deleting a transport
+To: stable@vger.kernel.org
+Cc: Olga Kornievskaia <okorniev@redhat.com>, Chuck Lever <chuck.lever@oracle.com>, Jeff Layton <jlayton@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20251015220846.1531878-5-sashal@kernel.org>
+
+From: Olga Kornievskaia <okorniev@redhat.com>
+
+[ Upstream commit 898374fdd7f06fa4c4a66e8be3135efeae6128d5 ]
+
+When a listener is added, a part of creation of transport also registers
+program/port with rpcbind. However, when the listener is removed,
+while transport goes away, rpcbind still has the entry for that
+port/type.
+
+When deleting the transport, unregister with rpcbind when appropriate.
+
+---v2 created a new xpt_flag XPT_RPCB_UNREG to mark TCP and UDP
+transport and at xprt destroy send rpcbind unregister if flag set.
+
+Suggested-by: Chuck Lever <chuck.lever@oracle.com>
+Fixes: d093c9089260 ("nfsd: fix management of listener transports")
+Cc: stable@vger.kernel.org
+Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/sunrpc/svc_xprt.h | 3 +++
+ net/sunrpc/svc_xprt.c | 13 +++++++++++++
+ net/sunrpc/svcsock.c | 2 ++
+ 3 files changed, 18 insertions(+)
+
+--- a/include/linux/sunrpc/svc_xprt.h
++++ b/include/linux/sunrpc/svc_xprt.h
+@@ -103,6 +103,9 @@ enum {
+ * it has access to. It is NOT counted
+ * in ->sv_tmpcnt.
+ */
++ XPT_RPCB_UNREG, /* transport that needs unregistering
++ * with rpcbind (TCP, UDP) on destroy
++ */
+ };
+
+ static inline void svc_xprt_set_valid(struct svc_xprt *xpt)
+--- a/net/sunrpc/svc_xprt.c
++++ b/net/sunrpc/svc_xprt.c
+@@ -1028,6 +1028,19 @@ static void svc_delete_xprt(struct svc_x
+ struct svc_serv *serv = xprt->xpt_server;
+ struct svc_deferred_req *dr;
+
++ /* unregister with rpcbind for when transport type is TCP or UDP.
++ */
++ if (test_bit(XPT_RPCB_UNREG, &xprt->xpt_flags)) {
++ struct svc_sock *svsk = container_of(xprt, struct svc_sock,
++ sk_xprt);
++ struct socket *sock = svsk->sk_sock;
++
++ if (svc_register(serv, xprt->xpt_net, sock->sk->sk_family,
++ sock->sk->sk_protocol, 0) < 0)
++ pr_warn("failed to unregister %s with rpcbind\n",
++ xprt->xpt_class->xcl_name);
++ }
++
+ if (test_and_set_bit(XPT_DEAD, &xprt->xpt_flags))
+ return;
+
+--- a/net/sunrpc/svcsock.c
++++ b/net/sunrpc/svcsock.c
+@@ -837,6 +837,7 @@ static void svc_udp_init(struct svc_sock
+ /* data might have come in before data_ready set up */
+ set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+ set_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags);
++ set_bit(XPT_RPCB_UNREG, &svsk->sk_xprt.xpt_flags);
+
+ /* make sure we get destination address info */
+ switch (svsk->sk_sk->sk_family) {
+@@ -1357,6 +1358,7 @@ static void svc_tcp_init(struct svc_sock
+ if (sk->sk_state == TCP_LISTEN) {
+ strcpy(svsk->sk_xprt.xpt_remotebuf, "listener");
+ set_bit(XPT_LISTENER, &svsk->sk_xprt.xpt_flags);
++ set_bit(XPT_RPCB_UNREG, &svsk->sk_xprt.xpt_flags);
+ sk->sk_data_ready = svc_tcp_listen_data_ready;
+ set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
+ } else {
arm64-mte-do-not-flag-the-zero-page-as-pg_mte_tagged.patch
x86-mtrr-rename-mtrr_overwrite_state-to-guest_force_mtrr_state.patch
x86-kvm-force-legacy-pci-hole-to-uc-when-overriding-mtrrs-for-tdx-snp.patch
+nfsd-fix-nfsd_may_bypass_gss-and-nfsd_may_bypass_gss_on_root.patch
+nfsd-replace-use-of-nfsd_may_lock-in-nfsd4_lock.patch
+nfsd-refine-and-rename-nfsd_may_lock.patch
+nfsd-don-t-use-sv_nrthreads-in-connection-limiting-calculations.patch
+nfsd-unregister-with-rpcbind-when-deleting-a-transport.patch
+acpi-battery-allocate-driver-data-through-devm_-apis.patch
+acpi-battery-initialize-mutexes-through-devm_-apis.patch
+acpi-battery-check-for-error-code-from-devm_mutex_init-call.patch
+acpi-battery-add-synchronization-between-interface-updates.patch
+acpi-property-disregard-references-in-data-only-subnode-lists.patch
+acpi-property-add-code-comments-explaining-what-is-going-on.patch
+acpi-property-do-not-pass-null-handles-to-acpi_attach_data.patch
+mptcp-pm-in-kernel-usable-client-side-with-c-flag.patch
+ipmi-rework-user-message-limit-handling.patch
+ipmi-fix-handling-of-messages-with-provided-receive-message-pointer.patch