From: Greg Kroah-Hartman Date: Fri, 17 Oct 2025 07:18:31 +0000 (+0200) Subject: 6.12-stable patches X-Git-Tag: v5.15.195~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=84ffa4e2768d1bbb1ca4b86bc1b6590de670a0a7;p=thirdparty%2Fkernel%2Fstable-queue.git 6.12-stable patches added patches: acpi-battery-add-synchronization-between-interface-updates.patch acpi-battery-allocate-driver-data-through-devm_-apis.patch acpi-battery-check-for-error-code-from-devm_mutex_init-call.patch acpi-battery-initialize-mutexes-through-devm_-apis.patch acpi-property-add-code-comments-explaining-what-is-going-on.patch acpi-property-disregard-references-in-data-only-subnode-lists.patch acpi-property-do-not-pass-null-handles-to-acpi_attach_data.patch ipmi-fix-handling-of-messages-with-provided-receive-message-pointer.patch ipmi-rework-user-message-limit-handling.patch mptcp-pm-in-kernel-usable-client-side-with-c-flag.patch nfsd-don-t-use-sv_nrthreads-in-connection-limiting-calculations.patch nfsd-fix-nfsd_may_bypass_gss-and-nfsd_may_bypass_gss_on_root.patch nfsd-refine-and-rename-nfsd_may_lock.patch nfsd-replace-use-of-nfsd_may_lock-in-nfsd4_lock.patch nfsd-unregister-with-rpcbind-when-deleting-a-transport.patch --- diff --git a/queue-6.12/acpi-battery-add-synchronization-between-interface-updates.patch b/queue-6.12/acpi-battery-add-synchronization-between-interface-updates.patch new file mode 100644 index 0000000000..24b34051d1 --- /dev/null +++ b/queue-6.12/acpi-battery-add-synchronization-between-interface-updates.patch @@ -0,0 +1,217 @@ +From stable+bounces-186154-greg=kroah.com@vger.kernel.org Thu Oct 16 15:34:54 2025 +From: Sasha Levin +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" , GuangFei Luo , Sasha Levin +Message-ID: <20251016133438.3296275-4-sashal@kernel.org> + +From: "Rafael J. Wysocki" + +[ 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: + + 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 + + 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 +Tested-by: GuangFei Luo +Cc: 6.6+ # 6.6+ +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; + } diff --git a/queue-6.12/acpi-battery-allocate-driver-data-through-devm_-apis.patch b/queue-6.12/acpi-battery-allocate-driver-data-through-devm_-apis.patch new file mode 100644 index 0000000000..bb11ae263f --- /dev/null +++ b/queue-6.12/acpi-battery-allocate-driver-data-through-devm_-apis.patch @@ -0,0 +1,51 @@ +From stable+bounces-186151-greg=kroah.com@vger.kernel.org Thu Oct 16 15:34:49 2025 +From: Sasha Levin +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" , "Rafael J. Wysocki" , "Sasha Levin" +Message-ID: <20251016133438.3296275-1-sashal@kernel.org> + +From: Thomas Weißschuh + +[ Upstream commit 909dfc60692331e1599d5e28a8f08a611f353aef ] + +Simplify the cleanup logic a bit. + +Signed-off-by: Thomas Weißschuh +Link: https://patch.msgid.link/20240904-acpi-battery-cleanups-v1-2-a3bf74f22d40@weissschuh.net +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 399dbcadc01e ("ACPI: battery: Add synchronization between interface updates") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 diff --git a/queue-6.12/acpi-battery-check-for-error-code-from-devm_mutex_init-call.patch b/queue-6.12/acpi-battery-check-for-error-code-from-devm_mutex_init-call.patch new file mode 100644 index 0000000000..ae5d9237d5 --- /dev/null +++ b/queue-6.12/acpi-battery-check-for-error-code-from-devm_mutex_init-call.patch @@ -0,0 +1,49 @@ +From stable+bounces-186153-greg=kroah.com@vger.kernel.org Thu Oct 16 15:35:02 2025 +From: Sasha Levin +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" , "Thomas Weißschuh" , "Rafael J. Wysocki" , "Sasha Levin" +Message-ID: <20251016133438.3296275-3-sashal@kernel.org> + +From: Andy Shevchenko + +[ 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 +Reviewed-by: Thomas Weißschuh +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 +Stable-dep-of: 399dbcadc01e ("ACPI: battery: Add synchronization between interface updates") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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); + diff --git a/queue-6.12/acpi-battery-initialize-mutexes-through-devm_-apis.patch b/queue-6.12/acpi-battery-initialize-mutexes-through-devm_-apis.patch new file mode 100644 index 0000000000..e18ba97fc5 --- /dev/null +++ b/queue-6.12/acpi-battery-initialize-mutexes-through-devm_-apis.patch @@ -0,0 +1,56 @@ +From stable+bounces-186152-greg=kroah.com@vger.kernel.org Thu Oct 16 15:34:55 2025 +From: Sasha Levin +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" , "Rafael J. Wysocki" , "Sasha Levin" +Message-ID: <20251016133438.3296275-2-sashal@kernel.org> + +From: Thomas Weißschuh + +[ Upstream commit 0710c1ce50455ed0db91bffa0eebbaa4f69b1773 ] + +Simplify the cleanup logic a bit. + +Signed-off-by: Thomas Weißschuh +Link: https://patch.msgid.link/20240904-acpi-battery-cleanups-v1-3-a3bf74f22d40@weissschuh.net +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 399dbcadc01e ("ACPI: battery: Add synchronization between interface updates") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 diff --git a/queue-6.12/acpi-property-add-code-comments-explaining-what-is-going-on.patch b/queue-6.12/acpi-property-add-code-comments-explaining-what-is-going-on.patch new file mode 100644 index 0000000000..04ad366dbc --- /dev/null +++ b/queue-6.12/acpi-property-add-code-comments-explaining-what-is-going-on.patch @@ -0,0 +1,115 @@ +From stable+bounces-186193-greg=kroah.com@vger.kernel.org Thu Oct 16 21:12:38 2025 +From: Sasha Levin +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" , Sakari Ailus , Sasha Levin +Message-ID: <20251016191227.3377985-3-sashal@kernel.org> + +From: "Rafael J. Wysocki" + +[ 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 +Reviewed-by: Sakari Ailus +Tested-by: Sakari Ailus +Stable-dep-of: baf60d5cb8bc ("ACPI: property: Do not pass NULL handles to acpi_attach_data()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-6.12/acpi-property-disregard-references-in-data-only-subnode-lists.patch b/queue-6.12/acpi-property-disregard-references-in-data-only-subnode-lists.patch new file mode 100644 index 0000000000..a907f39a6c --- /dev/null +++ b/queue-6.12/acpi-property-disregard-references-in-data-only-subnode-lists.patch @@ -0,0 +1,138 @@ +From stable+bounces-186192-greg=kroah.com@vger.kernel.org Thu Oct 16 21:12:37 2025 +From: Sasha Levin +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" , Sakari Ailus , Sasha Levin +Message-ID: <20251016191227.3377985-2-sashal@kernel.org> + +From: "Rafael J. Wysocki" + +[ 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 +Reviewed-by: Sakari Ailus +Tested-by: Sakari Ailus +Stable-dep-of: baf60d5cb8bc ("ACPI: property: Do not pass NULL handles to acpi_attach_data()") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; diff --git a/queue-6.12/acpi-property-do-not-pass-null-handles-to-acpi_attach_data.patch b/queue-6.12/acpi-property-do-not-pass-null-handles-to-acpi_attach_data.patch new file mode 100644 index 0000000000..f0a2f0c606 --- /dev/null +++ b/queue-6.12/acpi-property-do-not-pass-null-handles-to-acpi_attach_data.patch @@ -0,0 +1,77 @@ +From stable+bounces-186194-greg=kroah.com@vger.kernel.org Thu Oct 16 21:12:39 2025 +From: Sasha Levin +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" , Sakari Ailus , Sasha Levin +Message-ID: <20251016191227.3377985-4-sashal@kernel.org> + +From: "Rafael J. Wysocki" + +[ 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+ # 6.0+ +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Sakari Ailus +Tested-by: Sakari Ailus +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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"); diff --git a/queue-6.12/ipmi-fix-handling-of-messages-with-provided-receive-message-pointer.patch b/queue-6.12/ipmi-fix-handling-of-messages-with-provided-receive-message-pointer.patch new file mode 100644 index 0000000000..bf4dc61bad --- /dev/null +++ b/queue-6.12/ipmi-fix-handling-of-messages-with-provided-receive-message-pointer.patch @@ -0,0 +1,50 @@ +From stable+bounces-186184-greg=kroah.com@vger.kernel.org Thu Oct 16 20:49:33 2025 +From: Corey Minyard +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 , Eric Dumazet , Greg Thelen , Corey Minyard +Message-ID: <20251016184917.1875857-2-corey@minyard.net> + +From: Guenter Roeck + +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 +Cc: Eric Dumazet +Cc: Greg Thelen +Signed-off-by: Guenter Roeck +Message-ID: <20251006201857.3433837-1-linux@roeck-us.net> +Signed-off-by: Corey Minyard +Signed-off-by: Greg Kroah-Hartman +--- + 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)) diff --git a/queue-6.12/ipmi-rework-user-message-limit-handling.patch b/queue-6.12/ipmi-rework-user-message-limit-handling.patch new file mode 100644 index 0000000000..8110856e21 --- /dev/null +++ b/queue-6.12/ipmi-rework-user-message-limit-handling.patch @@ -0,0 +1,646 @@ +From stable+bounces-186185-greg=kroah.com@vger.kernel.org Thu Oct 16 20:49:37 2025 +From: Corey Minyard +Date: Thu, 16 Oct 2025 13:49:16 -0500 +Subject: ipmi: Rework user message limit handling +To: stable@vger.kernel.org +Cc: Corey Minyard , Gilles BULOZ +Message-ID: <20251016184917.1875857-1-corey@minyard.net> + +From: Corey Minyard + +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 +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: # 4.19 +Signed-off-by: Corey Minyard +Tested-by: Gilles BULOZ +Signed-off-by: Greg Kroah-Hartman +--- + 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) diff --git a/queue-6.12/mptcp-pm-in-kernel-usable-client-side-with-c-flag.patch b/queue-6.12/mptcp-pm-in-kernel-usable-client-side-with-c-flag.patch new file mode 100644 index 0000000000..0eb594ad59 --- /dev/null +++ b/queue-6.12/mptcp-pm-in-kernel-usable-client-side-with-c-flag.patch @@ -0,0 +1,178 @@ +From stable+bounces-186178-greg=kroah.com@vger.kernel.org Thu Oct 16 18:57:55 2025 +From: "Matthieu Baerts (NGI0)" +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 , "Matthieu Baerts (NGI0)" , Geliang Tang , Jakub Kicinski +Message-ID: <20251016165656.940021-2-matttbe@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +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 +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20250925-net-next-mptcp-c-flag-laminar-v1-1-ad126cc47c6b@kernel.org +Signed-off-by: Jakub Kicinski +[ 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) +Signed-off-by: Greg Kroah-Hartman +--- + 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) diff --git a/queue-6.12/nfsd-don-t-use-sv_nrthreads-in-connection-limiting-calculations.patch b/queue-6.12/nfsd-don-t-use-sv_nrthreads-in-connection-limiting-calculations.patch new file mode 100644 index 0000000000..4b0b415ca4 --- /dev/null +++ b/queue-6.12/nfsd-don-t-use-sv_nrthreads-in-connection-limiting-calculations.patch @@ -0,0 +1,203 @@ +From stable+bounces-185865-greg=kroah.com@vger.kernel.org Thu Oct 16 00:09:00 2025 +From: Sasha Levin +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 , Jeff Layton , Chuck Lever , Sasha Levin +Message-ID: <20251015220846.1531878-4-sashal@kernel.org> + +From: NeilBrown + +[ 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 +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Stable-dep-of: 898374fdd7f0 ("nfsd: unregister with rpcbind when deleting a transport") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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); + diff --git a/queue-6.12/nfsd-fix-nfsd_may_bypass_gss-and-nfsd_may_bypass_gss_on_root.patch b/queue-6.12/nfsd-fix-nfsd_may_bypass_gss-and-nfsd_may_bypass_gss_on_root.patch new file mode 100644 index 0000000000..0866ce059a --- /dev/null +++ b/queue-6.12/nfsd-fix-nfsd_may_bypass_gss-and-nfsd_may_bypass_gss_on_root.patch @@ -0,0 +1,179 @@ +From stable+bounces-185862-greg=kroah.com@vger.kernel.org Thu Oct 16 00:08:56 2025 +From: Sasha Levin +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" , NeilBrown , "Chuck Lever" , "Sasha Levin" +Message-ID: <20251015220846.1531878-1-sashal@kernel.org> + +From: Pali Rohár + +[ 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 +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Stable-dep-of: 898374fdd7f0 ("nfsd: unregister with rpcbind when deleting a transport") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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; + /* diff --git a/queue-6.12/nfsd-refine-and-rename-nfsd_may_lock.patch b/queue-6.12/nfsd-refine-and-rename-nfsd_may_lock.patch new file mode 100644 index 0000000000..e65e63cd98 --- /dev/null +++ b/queue-6.12/nfsd-refine-and-rename-nfsd_may_lock.patch @@ -0,0 +1,144 @@ +From stable+bounces-185864-greg=kroah.com@vger.kernel.org Thu Oct 16 00:08:57 2025 +From: Sasha Levin +Date: Wed, 15 Oct 2025 18:08:44 -0400 +Subject: nfsd: refine and rename NFSD_MAY_LOCK +To: stable@vger.kernel.org +Cc: NeilBrown , Chuck Lever , Sasha Levin +Message-ID: <20251015220846.1531878-3-sashal@kernel.org> + +From: NeilBrown + +[ 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 +Signed-off-by: Chuck Lever +Stable-dep-of: 898374fdd7f0 ("nfsd: unregister with rpcbind when deleting a transport") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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: */ diff --git a/queue-6.12/nfsd-replace-use-of-nfsd_may_lock-in-nfsd4_lock.patch b/queue-6.12/nfsd-replace-use-of-nfsd_may_lock-in-nfsd4_lock.patch new file mode 100644 index 0000000000..77a7958309 --- /dev/null +++ b/queue-6.12/nfsd-replace-use-of-nfsd_may_lock-in-nfsd4_lock.patch @@ -0,0 +1,45 @@ +From stable+bounces-185863-greg=kroah.com@vger.kernel.org Thu Oct 16 00:08:56 2025 +From: Sasha Levin +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 , NeilBrown , Sasha Levin +Message-ID: <20251015220846.1531878-2-sashal@kernel.org> + +From: Chuck Lever + +[ 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 +Signed-off-by: Chuck Lever +Stable-dep-of: 898374fdd7f0 ("nfsd: unregister with rpcbind when deleting a transport") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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) { diff --git a/queue-6.12/nfsd-unregister-with-rpcbind-when-deleting-a-transport.patch b/queue-6.12/nfsd-unregister-with-rpcbind-when-deleting-a-transport.patch new file mode 100644 index 0000000000..eecbf70a8c --- /dev/null +++ b/queue-6.12/nfsd-unregister-with-rpcbind-when-deleting-a-transport.patch @@ -0,0 +1,88 @@ +From stable+bounces-185866-greg=kroah.com@vger.kernel.org Thu Oct 16 00:09:01 2025 +From: Sasha Levin +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 , Chuck Lever , Jeff Layton , Sasha Levin +Message-ID: <20251015220846.1531878-5-sashal@kernel.org> + +From: Olga Kornievskaia + +[ 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 +Fixes: d093c9089260 ("nfsd: fix management of listener transports") +Cc: stable@vger.kernel.org +Signed-off-by: Olga Kornievskaia +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + 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 { diff --git a/queue-6.12/series b/queue-6.12/series index 7ad2e113d9..15bdf4ad91 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -240,3 +240,18 @@ statmount-don-t-call-path_put-under-namespace-semaphore.patch 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