--- /dev/null
+From stable+bounces-208187-greg=kroah.com@vger.kernel.org Mon Jan 12 18:35:39 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Jan 2026 12:31:09 -0500
+Subject: ALSA: ac97: fix a double free in snd_ac97_controller_register()
+To: stable@vger.kernel.org
+Cc: Haoxiang Li <lihaoxiang@isrc.iscas.ac.cn>, Takashi Iwai <tiwai@suse.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260112173109.826518-2-sashal@kernel.org>
+
+From: Haoxiang Li <lihaoxiang@isrc.iscas.ac.cn>
+
+[ Upstream commit 830988b6cf197e6dcffdfe2008c5738e6c6c3c0f ]
+
+If ac97_add_adapter() fails, put_device() is the correct way to drop
+the device reference. kfree() is not required.
+Add kfree() if idr_alloc() fails and in ac97_adapter_release() to do
+the cleanup.
+
+Found by code review.
+
+Fixes: 74426fbff66e ("ALSA: ac97: add an ac97 bus")
+Cc: stable@vger.kernel.org
+Signed-off-by: Haoxiang Li <lihaoxiang@isrc.iscas.ac.cn>
+Link: https://patch.msgid.link/20251219162845.657525-1-lihaoxiang@isrc.iscas.ac.cn
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/ac97/bus.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/sound/ac97/bus.c
++++ b/sound/ac97/bus.c
+@@ -299,6 +299,7 @@ static void ac97_adapter_release(struct
+ idr_remove(&ac97_adapter_idr, ac97_ctrl->nr);
+ dev_dbg(&ac97_ctrl->adap, "adapter unregistered by %s\n",
+ dev_name(ac97_ctrl->parent));
++ kfree(ac97_ctrl);
+ }
+
+ static const struct device_type ac97_adapter_type = {
+@@ -320,7 +321,9 @@ static int ac97_add_adapter(struct ac97_
+ ret = device_register(&ac97_ctrl->adap);
+ if (ret)
+ put_device(&ac97_ctrl->adap);
+- }
++ } else
++ kfree(ac97_ctrl);
++
+ if (!ret) {
+ list_add(&ac97_ctrl->controllers, &ac97_controllers);
+ dev_dbg(&ac97_ctrl->adap, "adapter registered by %s\n",
+@@ -361,14 +364,11 @@ struct ac97_controller *snd_ac97_control
+ ret = ac97_add_adapter(ac97_ctrl);
+
+ if (ret)
+- goto err;
++ return ERR_PTR(ret);
+ ac97_bus_reset(ac97_ctrl);
+ ac97_bus_scan(ac97_ctrl);
+
+ return ac97_ctrl;
+-err:
+- kfree(ac97_ctrl);
+- return ERR_PTR(ret);
+ }
+ EXPORT_SYMBOL_GPL(snd_ac97_controller_register);
+
--- /dev/null
+From stable+bounces-208186-greg=kroah.com@vger.kernel.org Mon Jan 12 18:35:37 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Jan 2026 12:31:08 -0500
+Subject: ALSA: ac97bus: Use guard() for mutex locks
+To: stable@vger.kernel.org
+Cc: Takashi Iwai <tiwai@suse.de>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260112173109.826518-1-sashal@kernel.org>
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit c07824a14d99c10edd4ec4c389d219af336ecf20 ]
+
+Replace the manual mutex lock/unlock pairs with guard() for code
+simplification.
+
+Only code refactoring, and no behavior change.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Link: https://patch.msgid.link/20250829151335.7342-18-tiwai@suse.de
+Stable-dep-of: 830988b6cf19 ("ALSA: ac97: fix a double free in snd_ac97_controller_register()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/ac97/bus.c | 22 +++++++++-------------
+ 1 file changed, 9 insertions(+), 13 deletions(-)
+
+--- a/sound/ac97/bus.c
++++ b/sound/ac97/bus.c
+@@ -242,10 +242,9 @@ static ssize_t cold_reset_store(struct d
+ {
+ struct ac97_controller *ac97_ctrl;
+
+- mutex_lock(&ac97_controllers_mutex);
++ guard(mutex)(&ac97_controllers_mutex);
+ ac97_ctrl = to_ac97_controller(dev);
+ ac97_ctrl->ops->reset(ac97_ctrl);
+- mutex_unlock(&ac97_controllers_mutex);
+ return len;
+ }
+ static DEVICE_ATTR_WO(cold_reset);
+@@ -259,10 +258,9 @@ static ssize_t warm_reset_store(struct d
+ if (!dev)
+ return -ENODEV;
+
+- mutex_lock(&ac97_controllers_mutex);
++ guard(mutex)(&ac97_controllers_mutex);
+ ac97_ctrl = to_ac97_controller(dev);
+ ac97_ctrl->ops->warm_reset(ac97_ctrl);
+- mutex_unlock(&ac97_controllers_mutex);
+ return len;
+ }
+ static DEVICE_ATTR_WO(warm_reset);
+@@ -285,10 +283,10 @@ static const struct attribute_group *ac9
+
+ static void ac97_del_adapter(struct ac97_controller *ac97_ctrl)
+ {
+- mutex_lock(&ac97_controllers_mutex);
+- ac97_ctrl_codecs_unregister(ac97_ctrl);
+- list_del(&ac97_ctrl->controllers);
+- mutex_unlock(&ac97_controllers_mutex);
++ scoped_guard(mutex, &ac97_controllers_mutex) {
++ ac97_ctrl_codecs_unregister(ac97_ctrl);
++ list_del(&ac97_ctrl->controllers);
++ }
+
+ device_unregister(&ac97_ctrl->adap);
+ }
+@@ -312,7 +310,7 @@ static int ac97_add_adapter(struct ac97_
+ {
+ int ret;
+
+- mutex_lock(&ac97_controllers_mutex);
++ guard(mutex)(&ac97_controllers_mutex);
+ ret = idr_alloc(&ac97_adapter_idr, ac97_ctrl, 0, 0, GFP_KERNEL);
+ ac97_ctrl->nr = ret;
+ if (ret >= 0) {
+@@ -323,13 +321,11 @@ static int ac97_add_adapter(struct ac97_
+ if (ret)
+ put_device(&ac97_ctrl->adap);
+ }
+- if (!ret)
++ if (!ret) {
+ list_add(&ac97_ctrl->controllers, &ac97_controllers);
+- mutex_unlock(&ac97_controllers_mutex);
+-
+- if (!ret)
+ dev_dbg(&ac97_ctrl->adap, "adapter registered by %s\n",
+ dev_name(ac97_ctrl->parent));
++ }
+ return ret;
+ }
+
--- /dev/null
+From stable+bounces-208267-greg=kroah.com@vger.kernel.org Tue Jan 13 14:23:13 2026
+From: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
+Date: Tue, 13 Jan 2026 10:01:56 -0300
+Subject: ksm: use range-walk function to jump over holes in scan_get_next_rmap_item
+To: stable@vger.kernel.org
+Cc: Zhi.Yang@windriver.com, Pedro Demarchi Gomes <pedrodemargomes@gmail.com>, David Hildenbrand <david@redhat.com>, craftfever <craftfever@airmail.cc>, Chengming Zhou <chengming.zhou@linux.dev>, xu xin <xu.xin16@zte.com.cn>, Andrew Morton <akpm@linux-foundation.org>
+Message-ID: <20260113130156.220078-2-pedrodemargomes@gmail.com>
+
+From: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
+
+[ Upstream commit f5548c318d6520d4fa3c5ed6003eeb710763cbc5 ]
+
+Currently, scan_get_next_rmap_item() walks every page address in a VMA to
+locate mergeable pages. This becomes highly inefficient when scanning
+large virtual memory areas that contain mostly unmapped regions, causing
+ksmd to use large amount of cpu without deduplicating much pages.
+
+This patch replaces the per-address lookup with a range walk using
+walk_page_range(). The range walker allows KSM to skip over entire
+unmapped holes in a VMA, avoiding unnecessary lookups. This problem was
+previously discussed in [1].
+
+Consider the following test program which creates a 32 TiB mapping in the
+virtual address space but only populates a single page:
+
+/* 32 TiB */
+const size_t size = 32ul * 1024 * 1024 * 1024 * 1024;
+
+int main() {
+ char *area = mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_NORESERVE | MAP_PRIVATE | MAP_ANON, -1, 0);
+
+ if (area == MAP_FAILED) {
+ perror("mmap() failed\n");
+ return -1;
+ }
+
+ /* Populate a single page such that we get an anon_vma. */
+ *area = 0;
+
+ /* Enable KSM. */
+ madvise(area, size, MADV_MERGEABLE);
+ pause();
+ return 0;
+}
+
+$ ./ksm-sparse &
+$ echo 1 > /sys/kernel/mm/ksm/run
+
+Without this patch ksmd uses 100% of the cpu for a long time (more then 1
+hour in my test machine) scanning all the 32 TiB virtual address space
+that contain only one mapped page. This makes ksmd essentially deadlocked
+not able to deduplicate anything of value. With this patch ksmd walks
+only the one mapped page and skips the rest of the 32 TiB virtual address
+space, making the scan fast using little cpu.
+
+Link: https://lkml.kernel.org/r/20251023035841.41406-1-pedrodemargomes@gmail.com
+Link: https://lkml.kernel.org/r/20251022153059.22763-1-pedrodemargomes@gmail.com
+Link: https://lore.kernel.org/linux-mm/423de7a3-1c62-4e72-8e79-19a6413e420c@redhat.com/ [1]
+Fixes: 31dbd01f3143 ("ksm: Kernel SamePage Merging")
+Signed-off-by: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
+Co-developed-by: David Hildenbrand <david@redhat.com>
+Signed-off-by: David Hildenbrand <david@redhat.com>
+Reported-by: craftfever <craftfever@airmail.cc>
+Closes: https://lkml.kernel.org/r/020cf8de6e773bb78ba7614ef250129f11a63781@murena.io
+Suggested-by: David Hildenbrand <david@redhat.com>
+Acked-by: David Hildenbrand <david@redhat.com>
+Cc: Chengming Zhou <chengming.zhou@linux.dev>
+Cc: xu xin <xu.xin16@zte.com.cn>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+[ replace pmdp_get_lockless with pmd_read_atomic and pmdp_get with
+ READ_ONCE(*pmdp) ]
+Signed-off-by: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/ksm.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 113 insertions(+), 13 deletions(-)
+
+--- a/mm/ksm.c
++++ b/mm/ksm.c
+@@ -39,6 +39,7 @@
+ #include <linux/freezer.h>
+ #include <linux/oom.h>
+ #include <linux/numa.h>
++#include <linux/pagewalk.h>
+
+ #include <asm/tlbflush.h>
+ #include "internal.h"
+@@ -2223,6 +2224,94 @@ static struct ksm_rmap_item *get_next_rm
+ return rmap_item;
+ }
+
++struct ksm_next_page_arg {
++ struct folio *folio;
++ struct page *page;
++ unsigned long addr;
++};
++
++static int ksm_next_page_pmd_entry(pmd_t *pmdp, unsigned long addr, unsigned long end,
++ struct mm_walk *walk)
++{
++ struct ksm_next_page_arg *private = walk->private;
++ struct vm_area_struct *vma = walk->vma;
++ pte_t *start_ptep = NULL, *ptep, pte;
++ struct mm_struct *mm = walk->mm;
++ struct folio *folio;
++ struct page *page;
++ spinlock_t *ptl;
++ pmd_t pmd;
++
++ if (ksm_test_exit(mm))
++ return 0;
++
++ cond_resched();
++
++ pmd = pmd_read_atomic(pmdp);
++ if (!pmd_present(pmd))
++ return 0;
++
++ if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && pmd_leaf(pmd)) {
++ ptl = pmd_lock(mm, pmdp);
++ pmd = READ_ONCE(*pmdp);
++
++ if (!pmd_present(pmd)) {
++ goto not_found_unlock;
++ } else if (pmd_leaf(pmd)) {
++ page = vm_normal_page_pmd(vma, addr, pmd);
++ if (!page)
++ goto not_found_unlock;
++ folio = page_folio(page);
++
++ if (folio_is_zone_device(folio) || !folio_test_anon(folio))
++ goto not_found_unlock;
++
++ page += ((addr & (PMD_SIZE - 1)) >> PAGE_SHIFT);
++ goto found_unlock;
++ }
++ spin_unlock(ptl);
++ }
++
++ start_ptep = pte_offset_map_lock(mm, pmdp, addr, &ptl);
++ if (!start_ptep)
++ return 0;
++
++ for (ptep = start_ptep; addr < end; ptep++, addr += PAGE_SIZE) {
++ pte = ptep_get(ptep);
++
++ if (!pte_present(pte))
++ continue;
++
++ page = vm_normal_page(vma, addr, pte);
++ if (!page)
++ continue;
++ folio = page_folio(page);
++
++ if (folio_is_zone_device(folio) || !folio_test_anon(folio))
++ continue;
++ goto found_unlock;
++ }
++
++not_found_unlock:
++ spin_unlock(ptl);
++ if (start_ptep)
++ pte_unmap(start_ptep);
++ return 0;
++found_unlock:
++ folio_get(folio);
++ spin_unlock(ptl);
++ if (start_ptep)
++ pte_unmap(start_ptep);
++ private->page = page;
++ private->folio = folio;
++ private->addr = addr;
++ return 1;
++}
++
++static struct mm_walk_ops ksm_next_page_ops = {
++ .pmd_entry = ksm_next_page_pmd_entry,
++};
++
+ static struct ksm_rmap_item *scan_get_next_rmap_item(struct page **page)
+ {
+ struct mm_struct *mm;
+@@ -2307,32 +2396,43 @@ next_mm:
+ ksm_scan.address = vma->vm_end;
+
+ while (ksm_scan.address < vma->vm_end) {
++ struct ksm_next_page_arg ksm_next_page_arg;
++ struct page *tmp_page = NULL;
++ struct folio *folio;
++
+ if (ksm_test_exit(mm))
+ break;
+- *page = follow_page(vma, ksm_scan.address, FOLL_GET);
+- if (IS_ERR_OR_NULL(*page)) {
+- ksm_scan.address += PAGE_SIZE;
+- cond_resched();
+- continue;
++
++ int found;
++
++ found = walk_page_range_vma(vma, ksm_scan.address,
++ vma->vm_end,
++ &ksm_next_page_ops,
++ &ksm_next_page_arg);
++
++ if (found > 0) {
++ folio = ksm_next_page_arg.folio;
++ tmp_page = ksm_next_page_arg.page;
++ ksm_scan.address = ksm_next_page_arg.addr;
++ } else {
++ VM_WARN_ON_ONCE(found < 0);
++ ksm_scan.address = vma->vm_end - PAGE_SIZE;
+ }
+- if (is_zone_device_page(*page))
+- goto next_page;
+- if (PageAnon(*page)) {
+- flush_anon_page(vma, *page, ksm_scan.address);
+- flush_dcache_page(*page);
++ if (tmp_page) {
++ flush_anon_page(vma, tmp_page, ksm_scan.address);
++ flush_dcache_page(tmp_page);
+ rmap_item = get_next_rmap_item(mm_slot,
+ ksm_scan.rmap_list, ksm_scan.address);
+ if (rmap_item) {
+ ksm_scan.rmap_list =
+ &rmap_item->rmap_list;
+ ksm_scan.address += PAGE_SIZE;
++ *page = tmp_page;
+ } else
+- put_page(*page);
++ folio_put(folio);
+ mmap_read_unlock(mm);
+ return rmap_item;
+ }
+-next_page:
+- put_page(*page);
+ ksm_scan.address += PAGE_SIZE;
+ cond_resched();
+ }
--- /dev/null
+From stable+bounces-208266-greg=kroah.com@vger.kernel.org Tue Jan 13 14:22:18 2026
+From: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
+Date: Tue, 13 Jan 2026 10:01:55 -0300
+Subject: mm/pagewalk: add walk_page_range_vma()
+To: stable@vger.kernel.org
+Cc: Zhi.Yang@windriver.com, David Hildenbrand <david@redhat.com>, Andrea Arcangeli <aarcange@redhat.com>, Hugh Dickins <hughd@google.com>, Jason Gunthorpe <jgg@nvidia.com>, John Hubbard <jhubbard@nvidia.com>, Matthew Wilcox <willy@infradead.org>, Peter Xu <peterx@redhat.com>, Shuah Khan <shuah@kernel.org>, Vlastimil Babka <vbabka@suse.cz>, Andrew Morton <akpm@linux-foundation.org>, Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
+Message-ID: <20260113130156.220078-1-pedrodemargomes@gmail.com>
+
+From: David Hildenbrand <david@redhat.com>
+
+[ Upstream commit e07cda5f232fac4de0925d8a4c92e51e41fa2f6e ]
+
+Let's add walk_page_range_vma(), which is similar to walk_page_vma(),
+however, is only interested in a subset of the VMA range.
+
+To be used in KSM code to stop using follow_page() next.
+
+Link: https://lkml.kernel.org/r/20221021101141.84170-8-david@redhat.com
+Signed-off-by: David Hildenbrand <david@redhat.com>
+Cc: Andrea Arcangeli <aarcange@redhat.com>
+Cc: Hugh Dickins <hughd@google.com>
+Cc: Jason Gunthorpe <jgg@nvidia.com>
+Cc: John Hubbard <jhubbard@nvidia.com>
+Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
+Cc: Peter Xu <peterx@redhat.com>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Vlastimil Babka <vbabka@suse.cz>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Stable-dep-of: f5548c318d6 ("ksm: use range-walk function to jump over holes in scan_get_next_rmap_item")
+Signed-off-by: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/pagewalk.h | 3 +++
+ mm/pagewalk.c | 20 ++++++++++++++++++++
+ 2 files changed, 23 insertions(+)
+
+--- a/include/linux/pagewalk.h
++++ b/include/linux/pagewalk.h
+@@ -99,6 +99,9 @@ int walk_page_range_novma(struct mm_stru
+ unsigned long end, const struct mm_walk_ops *ops,
+ pgd_t *pgd,
+ void *private);
++int walk_page_range_vma(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end, const struct mm_walk_ops *ops,
++ void *private);
+ int walk_page_vma(struct vm_area_struct *vma, const struct mm_walk_ops *ops,
+ void *private);
+ int walk_page_mapping(struct address_space *mapping, pgoff_t first_index,
+--- a/mm/pagewalk.c
++++ b/mm/pagewalk.c
+@@ -517,6 +517,26 @@ int walk_page_range_novma(struct mm_stru
+ return walk_pgd_range(start, end, &walk);
+ }
+
++int walk_page_range_vma(struct vm_area_struct *vma, unsigned long start,
++ unsigned long end, const struct mm_walk_ops *ops,
++ void *private)
++{
++ struct mm_walk walk = {
++ .ops = ops,
++ .mm = vma->vm_mm,
++ .vma = vma,
++ .private = private,
++ };
++
++ if (start >= end || !walk.mm)
++ return -EINVAL;
++ if (start < vma->vm_start || end > vma->vm_end)
++ return -EINVAL;
++
++ mmap_assert_locked(walk.mm);
++ return __walk_page_range(start, end, &walk);
++}
++
+ int walk_page_vma(struct vm_area_struct *vma, const struct mm_walk_ops *ops,
+ void *private)
+ {
--- /dev/null
+From stable+bounces-208127-greg=kroah.com@vger.kernel.org Mon Jan 12 15:45:35 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Jan 2026 09:39:08 -0500
+Subject: NFS: trace: show TIMEDOUT instead of 0x6e
+To: stable@vger.kernel.org
+Cc: Chen Hanxiao <chenhx.fnst@fujitsu.com>, Jeff Layton <jlayton@kernel.org>, Chuck Lever <chuck.lever@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260112143910.714632-1-sashal@kernel.org>
+
+From: Chen Hanxiao <chenhx.fnst@fujitsu.com>
+
+[ Upstream commit cef48236dfe55fa266d505e8a497963a7bc5ef2a ]
+
+__nfs_revalidate_inode may return ETIMEDOUT.
+
+print symbol of ETIMEDOUT in nfs trace:
+
+before:
+cat-5191 [005] 119.331127: nfs_revalidate_inode_exit: error=-110 (0x6e)
+
+after:
+cat-1738 [004] 44.365509: nfs_revalidate_inode_exit: error=-110 (TIMEDOUT)
+
+Signed-off-by: Chen Hanxiao <chenhx.fnst@fujitsu.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Stable-dep-of: c6c209ceb87f ("NFSD: Remove NFSERR_EAGAIN")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/trace/misc/nfs.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/include/trace/misc/nfs.h
++++ b/include/trace/misc/nfs.h
+@@ -52,6 +52,7 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
+ { NFSERR_IO, "IO" }, \
+ { NFSERR_NXIO, "NXIO" }, \
+ { ECHILD, "CHILD" }, \
++ { ETIMEDOUT, "TIMEDOUT" }, \
+ { NFSERR_EAGAIN, "AGAIN" }, \
+ { NFSERR_ACCES, "ACCES" }, \
+ { NFSERR_EXIST, "EXIST" }, \
--- /dev/null
+From stable+bounces-208128-greg=kroah.com@vger.kernel.org Mon Jan 12 15:52:46 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Jan 2026 09:39:09 -0500
+Subject: nfs_common: factor out nfs_errtbl and nfs_stat_to_errno
+To: stable@vger.kernel.org
+Cc: Mike Snitzer <snitzer@kernel.org>, Jeff Layton <jlayton@kernel.org>, NeilBrown <neilb@suse.de>, Anna Schumaker <anna.schumaker@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260112143910.714632-2-sashal@kernel.org>
+
+From: Mike Snitzer <snitzer@kernel.org>
+
+[ Upstream commit 4806ded4c14c5e8fdc6ce885d83221a78c06a428 ]
+
+Common nfs_stat_to_errno() is used by both fs/nfs/nfs2xdr.c and
+fs/nfs/nfs3xdr.c
+
+Will also be used by fs/nfsd/localio.c
+
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Reviewed-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
+Stable-dep-of: c6c209ceb87f ("NFSD: Remove NFSERR_EAGAIN")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/Kconfig | 1
+ fs/nfs/nfs2xdr.c | 70 -----------------------------
+ fs/nfs/nfs3xdr.c | 108 ++++++++-------------------------------------
+ fs/nfs/nfs4xdr.c | 4 -
+ fs/nfs_common/Makefile | 2
+ fs/nfs_common/common.c | 67 +++++++++++++++++++++++++++
+ fs/nfsd/Kconfig | 1
+ include/linux/nfs_common.h | 16 ++++++
+ 8 files changed, 109 insertions(+), 160 deletions(-)
+ create mode 100644 fs/nfs_common/common.c
+ create mode 100644 include/linux/nfs_common.h
+
+--- a/fs/nfs/Kconfig
++++ b/fs/nfs/Kconfig
+@@ -5,6 +5,7 @@ config NFS_FS
+ select CRC32
+ select LOCKD
+ select SUNRPC
++ select NFS_COMMON
+ select NFS_ACL_SUPPORT if NFS_V3_ACL
+ help
+ Choose Y here if you want to access files residing on other
+--- a/fs/nfs/nfs2xdr.c
++++ b/fs/nfs/nfs2xdr.c
+@@ -22,14 +22,12 @@
+ #include <linux/nfs.h>
+ #include <linux/nfs2.h>
+ #include <linux/nfs_fs.h>
++#include <linux/nfs_common.h>
+ #include "nfstrace.h"
+ #include "internal.h"
+
+ #define NFSDBG_FACILITY NFSDBG_XDR
+
+-/* Mapping from NFS error code to "errno" error code. */
+-#define errno_NFSERR_IO EIO
+-
+ /*
+ * Declare the space requirements for NFS arguments and replies as
+ * number of 32bit-words
+@@ -64,8 +62,6 @@
+ #define NFS_readdirres_sz (1+NFS_pagepad_sz)
+ #define NFS_statfsres_sz (1+NFS_info_sz)
+
+-static int nfs_stat_to_errno(enum nfs_stat);
+-
+ /*
+ * Encode/decode NFSv2 basic data types
+ *
+@@ -1054,70 +1050,6 @@ out_default:
+ return nfs_stat_to_errno(status);
+ }
+
+-
+-/*
+- * We need to translate between nfs status return values and
+- * the local errno values which may not be the same.
+- */
+-static const struct {
+- int stat;
+- int errno;
+-} nfs_errtbl[] = {
+- { NFS_OK, 0 },
+- { NFSERR_PERM, -EPERM },
+- { NFSERR_NOENT, -ENOENT },
+- { NFSERR_IO, -errno_NFSERR_IO},
+- { NFSERR_NXIO, -ENXIO },
+-/* { NFSERR_EAGAIN, -EAGAIN }, */
+- { NFSERR_ACCES, -EACCES },
+- { NFSERR_EXIST, -EEXIST },
+- { NFSERR_XDEV, -EXDEV },
+- { NFSERR_NODEV, -ENODEV },
+- { NFSERR_NOTDIR, -ENOTDIR },
+- { NFSERR_ISDIR, -EISDIR },
+- { NFSERR_INVAL, -EINVAL },
+- { NFSERR_FBIG, -EFBIG },
+- { NFSERR_NOSPC, -ENOSPC },
+- { NFSERR_ROFS, -EROFS },
+- { NFSERR_MLINK, -EMLINK },
+- { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
+- { NFSERR_NOTEMPTY, -ENOTEMPTY },
+- { NFSERR_DQUOT, -EDQUOT },
+- { NFSERR_STALE, -ESTALE },
+- { NFSERR_REMOTE, -EREMOTE },
+-#ifdef EWFLUSH
+- { NFSERR_WFLUSH, -EWFLUSH },
+-#endif
+- { NFSERR_BADHANDLE, -EBADHANDLE },
+- { NFSERR_NOT_SYNC, -ENOTSYNC },
+- { NFSERR_BAD_COOKIE, -EBADCOOKIE },
+- { NFSERR_NOTSUPP, -ENOTSUPP },
+- { NFSERR_TOOSMALL, -ETOOSMALL },
+- { NFSERR_SERVERFAULT, -EREMOTEIO },
+- { NFSERR_BADTYPE, -EBADTYPE },
+- { NFSERR_JUKEBOX, -EJUKEBOX },
+- { -1, -EIO }
+-};
+-
+-/**
+- * nfs_stat_to_errno - convert an NFS status code to a local errno
+- * @status: NFS status code to convert
+- *
+- * Returns a local errno value, or -EIO if the NFS status code is
+- * not recognized. This function is used jointly by NFSv2 and NFSv3.
+- */
+-static int nfs_stat_to_errno(enum nfs_stat status)
+-{
+- int i;
+-
+- for (i = 0; nfs_errtbl[i].stat != -1; i++) {
+- if (nfs_errtbl[i].stat == (int)status)
+- return nfs_errtbl[i].errno;
+- }
+- dprintk("NFS: Unrecognized nfs status value: %u\n", status);
+- return nfs_errtbl[i].errno;
+-}
+-
+ #define PROC(proc, argtype, restype, timer) \
+ [NFSPROC_##proc] = { \
+ .p_proc = NFSPROC_##proc, \
+--- a/fs/nfs/nfs3xdr.c
++++ b/fs/nfs/nfs3xdr.c
+@@ -21,14 +21,13 @@
+ #include <linux/nfs3.h>
+ #include <linux/nfs_fs.h>
+ #include <linux/nfsacl.h>
++#include <linux/nfs_common.h>
++
+ #include "nfstrace.h"
+ #include "internal.h"
+
+ #define NFSDBG_FACILITY NFSDBG_XDR
+
+-/* Mapping from NFS error code to "errno" error code. */
+-#define errno_NFSERR_IO EIO
+-
+ /*
+ * Declare the space requirements for NFS arguments and replies as
+ * number of 32bit-words
+@@ -91,8 +90,6 @@
+ NFS3_pagepad_sz)
+ #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
+
+-static int nfs3_stat_to_errno(enum nfs_stat);
+-
+ /*
+ * Map file type to S_IFMT bits
+ */
+@@ -1406,7 +1403,7 @@ static int nfs3_xdr_dec_getattr3res(stru
+ out:
+ return error;
+ out_default:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1445,7 +1442,7 @@ static int nfs3_xdr_dec_setattr3res(stru
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1495,7 +1492,7 @@ out_default:
+ error = decode_post_op_attr(xdr, result->dir_attr, userns);
+ if (unlikely(error))
+ goto out;
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1537,7 +1534,7 @@ static int nfs3_xdr_dec_access3res(struc
+ out:
+ return error;
+ out_default:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1578,7 +1575,7 @@ static int nfs3_xdr_dec_readlink3res(str
+ out:
+ return error;
+ out_default:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1658,7 +1655,7 @@ static int nfs3_xdr_dec_read3res(struct
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1728,7 +1725,7 @@ static int nfs3_xdr_dec_write3res(struct
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1795,7 +1792,7 @@ out_default:
+ error = decode_wcc_data(xdr, result->dir_attr, userns);
+ if (unlikely(error))
+ goto out;
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1835,7 +1832,7 @@ static int nfs3_xdr_dec_remove3res(struc
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1881,7 +1878,7 @@ static int nfs3_xdr_dec_rename3res(struc
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -1926,7 +1923,7 @@ static int nfs3_xdr_dec_link3res(struct
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /**
+@@ -2101,7 +2098,7 @@ out_default:
+ error = decode_post_op_attr(xdr, result->dir_attr, rpc_rqst_userns(req));
+ if (unlikely(error))
+ goto out;
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -2167,7 +2164,7 @@ static int nfs3_xdr_dec_fsstat3res(struc
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -2243,7 +2240,7 @@ static int nfs3_xdr_dec_fsinfo3res(struc
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -2304,7 +2301,7 @@ static int nfs3_xdr_dec_pathconf3res(str
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ /*
+@@ -2350,7 +2347,7 @@ static int nfs3_xdr_dec_commit3res(struc
+ out:
+ return error;
+ out_status:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ #ifdef CONFIG_NFS_V3_ACL
+@@ -2416,7 +2413,7 @@ static int nfs3_xdr_dec_getacl3res(struc
+ out:
+ return error;
+ out_default:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
+@@ -2435,76 +2432,11 @@ static int nfs3_xdr_dec_setacl3res(struc
+ out:
+ return error;
+ out_default:
+- return nfs3_stat_to_errno(status);
++ return nfs_stat_to_errno(status);
+ }
+
+ #endif /* CONFIG_NFS_V3_ACL */
+
+-
+-/*
+- * We need to translate between nfs status return values and
+- * the local errno values which may not be the same.
+- */
+-static const struct {
+- int stat;
+- int errno;
+-} nfs_errtbl[] = {
+- { NFS_OK, 0 },
+- { NFSERR_PERM, -EPERM },
+- { NFSERR_NOENT, -ENOENT },
+- { NFSERR_IO, -errno_NFSERR_IO},
+- { NFSERR_NXIO, -ENXIO },
+-/* { NFSERR_EAGAIN, -EAGAIN }, */
+- { NFSERR_ACCES, -EACCES },
+- { NFSERR_EXIST, -EEXIST },
+- { NFSERR_XDEV, -EXDEV },
+- { NFSERR_NODEV, -ENODEV },
+- { NFSERR_NOTDIR, -ENOTDIR },
+- { NFSERR_ISDIR, -EISDIR },
+- { NFSERR_INVAL, -EINVAL },
+- { NFSERR_FBIG, -EFBIG },
+- { NFSERR_NOSPC, -ENOSPC },
+- { NFSERR_ROFS, -EROFS },
+- { NFSERR_MLINK, -EMLINK },
+- { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
+- { NFSERR_NOTEMPTY, -ENOTEMPTY },
+- { NFSERR_DQUOT, -EDQUOT },
+- { NFSERR_STALE, -ESTALE },
+- { NFSERR_REMOTE, -EREMOTE },
+-#ifdef EWFLUSH
+- { NFSERR_WFLUSH, -EWFLUSH },
+-#endif
+- { NFSERR_BADHANDLE, -EBADHANDLE },
+- { NFSERR_NOT_SYNC, -ENOTSYNC },
+- { NFSERR_BAD_COOKIE, -EBADCOOKIE },
+- { NFSERR_NOTSUPP, -ENOTSUPP },
+- { NFSERR_TOOSMALL, -ETOOSMALL },
+- { NFSERR_SERVERFAULT, -EREMOTEIO },
+- { NFSERR_BADTYPE, -EBADTYPE },
+- { NFSERR_JUKEBOX, -EJUKEBOX },
+- { -1, -EIO }
+-};
+-
+-/**
+- * nfs3_stat_to_errno - convert an NFS status code to a local errno
+- * @status: NFS status code to convert
+- *
+- * Returns a local errno value, or -EIO if the NFS status code is
+- * not recognized. This function is used jointly by NFSv2 and NFSv3.
+- */
+-static int nfs3_stat_to_errno(enum nfs_stat status)
+-{
+- int i;
+-
+- for (i = 0; nfs_errtbl[i].stat != -1; i++) {
+- if (nfs_errtbl[i].stat == (int)status)
+- return nfs_errtbl[i].errno;
+- }
+- dprintk("NFS: Unrecognized nfs status value: %u\n", status);
+- return nfs_errtbl[i].errno;
+-}
+-
+-
+ #define PROC(proc, argtype, restype, timer) \
+ [NFS3PROC_##proc] = { \
+ .p_proc = NFS3PROC_##proc, \
+--- a/fs/nfs/nfs4xdr.c
++++ b/fs/nfs/nfs4xdr.c
+@@ -52,6 +52,7 @@
+ #include <linux/nfs.h>
+ #include <linux/nfs4.h>
+ #include <linux/nfs_fs.h>
++#include <linux/nfs_common.h>
+
+ #include "nfs4_fs.h"
+ #include "nfs4trace.h"
+@@ -63,9 +64,6 @@
+
+ #define NFSDBG_FACILITY NFSDBG_XDR
+
+-/* Mapping from NFS error code to "errno" error code. */
+-#define errno_NFSERR_IO EIO
+-
+ struct compound_hdr;
+ static int nfs4_stat_to_errno(int);
+ static void encode_layoutget(struct xdr_stream *xdr,
+--- a/fs/nfs_common/Makefile
++++ b/fs/nfs_common/Makefile
+@@ -8,3 +8,5 @@ nfs_acl-objs := nfsacl.o
+
+ obj-$(CONFIG_GRACE_PERIOD) += grace.o
+ obj-$(CONFIG_NFS_V4_2_SSC_HELPER) += nfs_ssc.o
++
++obj-$(CONFIG_NFS_COMMON) += common.o
+--- /dev/null
++++ b/fs/nfs_common/common.c
+@@ -0,0 +1,67 @@
++// SPDX-License-Identifier: GPL-2.0-only
++
++#include <linux/module.h>
++#include <linux/nfs_common.h>
++
++/*
++ * We need to translate between nfs status return values and
++ * the local errno values which may not be the same.
++ */
++static const struct {
++ int stat;
++ int errno;
++} nfs_errtbl[] = {
++ { NFS_OK, 0 },
++ { NFSERR_PERM, -EPERM },
++ { NFSERR_NOENT, -ENOENT },
++ { NFSERR_IO, -errno_NFSERR_IO},
++ { NFSERR_NXIO, -ENXIO },
++/* { NFSERR_EAGAIN, -EAGAIN }, */
++ { NFSERR_ACCES, -EACCES },
++ { NFSERR_EXIST, -EEXIST },
++ { NFSERR_XDEV, -EXDEV },
++ { NFSERR_NODEV, -ENODEV },
++ { NFSERR_NOTDIR, -ENOTDIR },
++ { NFSERR_ISDIR, -EISDIR },
++ { NFSERR_INVAL, -EINVAL },
++ { NFSERR_FBIG, -EFBIG },
++ { NFSERR_NOSPC, -ENOSPC },
++ { NFSERR_ROFS, -EROFS },
++ { NFSERR_MLINK, -EMLINK },
++ { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
++ { NFSERR_NOTEMPTY, -ENOTEMPTY },
++ { NFSERR_DQUOT, -EDQUOT },
++ { NFSERR_STALE, -ESTALE },
++ { NFSERR_REMOTE, -EREMOTE },
++#ifdef EWFLUSH
++ { NFSERR_WFLUSH, -EWFLUSH },
++#endif
++ { NFSERR_BADHANDLE, -EBADHANDLE },
++ { NFSERR_NOT_SYNC, -ENOTSYNC },
++ { NFSERR_BAD_COOKIE, -EBADCOOKIE },
++ { NFSERR_NOTSUPP, -ENOTSUPP },
++ { NFSERR_TOOSMALL, -ETOOSMALL },
++ { NFSERR_SERVERFAULT, -EREMOTEIO },
++ { NFSERR_BADTYPE, -EBADTYPE },
++ { NFSERR_JUKEBOX, -EJUKEBOX },
++ { -1, -EIO }
++};
++
++/**
++ * nfs_stat_to_errno - convert an NFS status code to a local errno
++ * @status: NFS status code to convert
++ *
++ * Returns a local errno value, or -EIO if the NFS status code is
++ * not recognized. This function is used jointly by NFSv2 and NFSv3.
++ */
++int nfs_stat_to_errno(enum nfs_stat status)
++{
++ int i;
++
++ for (i = 0; nfs_errtbl[i].stat != -1; i++) {
++ if (nfs_errtbl[i].stat == (int)status)
++ return nfs_errtbl[i].errno;
++ }
++ return nfs_errtbl[i].errno;
++}
++EXPORT_SYMBOL_GPL(nfs_stat_to_errno);
+--- a/fs/nfsd/Kconfig
++++ b/fs/nfsd/Kconfig
+@@ -8,6 +8,7 @@ config NFSD
+ select LOCKD
+ select SUNRPC
+ select EXPORTFS
++ select NFS_COMMON
+ select NFS_ACL_SUPPORT if NFSD_V2_ACL
+ select NFS_ACL_SUPPORT if NFSD_V3_ACL
+ depends on MULTIUSER
+--- /dev/null
++++ b/include/linux/nfs_common.h
+@@ -0,0 +1,16 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * This file contains constants and methods used by both NFS client and server.
++ */
++#ifndef _LINUX_NFS_COMMON_H
++#define _LINUX_NFS_COMMON_H
++
++#include <linux/errno.h>
++#include <uapi/linux/nfs.h>
++
++/* Mapping from NFS error code to "errno" error code. */
++#define errno_NFSERR_IO EIO
++
++int nfs_stat_to_errno(enum nfs_stat status);
++
++#endif /* _LINUX_NFS_COMMON_H */
--- /dev/null
+From stable+bounces-208171-greg=kroah.com@vger.kernel.org Mon Jan 12 16:33:57 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Jan 2026 10:33:51 -0500
+Subject: nfsd: provide locking for v4_end_grace
+To: stable@vger.kernel.org
+Cc: NeilBrown <neil@brown.name>, Li Lingfeng <lilingfeng3@huawei.com>, Jeff Layton <jlayton@kernel.org>, Chuck Lever <chuck.lever@oracle.com>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260112153351.742670-1-sashal@kernel.org>
+
+From: NeilBrown <neil@brown.name>
+
+[ Upstream commit 2857bd59feb63fcf40fe4baf55401baea6b4feb4 ]
+
+Writing to v4_end_grace can race with server shutdown and result in
+memory being accessed after it was freed - reclaim_str_hashtbl in
+particularly.
+
+We cannot hold nfsd_mutex across the nfsd4_end_grace() call as that is
+held while client_tracking_op->init() is called and that can wait for
+an upcall to nfsdcltrack which can write to v4_end_grace, resulting in a
+deadlock.
+
+nfsd4_end_grace() is also called by the landromat work queue and this
+doesn't require locking as server shutdown will stop the work and wait
+for it before freeing anything that nfsd4_end_grace() might access.
+
+However, we must be sure that writing to v4_end_grace doesn't restart
+the work item after shutdown has already waited for it. For this we
+add a new flag protected with nn->client_lock. It is set only while it
+is safe to make client tracking calls, and v4_end_grace only schedules
+work while the flag is set with the spinlock held.
+
+So this patch adds a nfsd_net field "client_tracking_active" which is
+set as described. Another field "grace_end_forced", is set when
+v4_end_grace is written. After this is set, and providing
+client_tracking_active is set, the laundromat is scheduled.
+This "grace_end_forced" field bypasses other checks for whether the
+grace period has finished.
+
+This resolves a race which can result in use-after-free.
+
+Reported-by: Li Lingfeng <lilingfeng3@huawei.com>
+Closes: https://lore.kernel.org/linux-nfs/20250623030015.2353515-1-neil@brown.name/T/#t
+Fixes: 7f5ef2e900d9 ("nfsd: add a v4_end_grace file to /proc/fs/nfsd")
+Cc: stable@vger.kernel.org
+Signed-off-by: NeilBrown <neil@brown.name>
+Tested-by: Li Lingfeng <lilingfeng3@huawei.com>
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+[ Adjust context ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfsd/netns.h | 2 ++
+ fs/nfsd/nfs4state.c | 42 ++++++++++++++++++++++++++++++++++++++++--
+ fs/nfsd/nfsctl.c | 3 +--
+ fs/nfsd/state.h | 2 +-
+ 4 files changed, 44 insertions(+), 5 deletions(-)
+
+--- a/fs/nfsd/netns.h
++++ b/fs/nfsd/netns.h
+@@ -64,6 +64,8 @@ struct nfsd_net {
+
+ struct lock_manager nfsd4_manager;
+ bool grace_ended;
++ bool grace_end_forced;
++ bool client_tracking_active;
+ time64_t boot_time;
+
+ struct dentry *nfsd_client_dir;
+--- a/fs/nfsd/nfs4state.c
++++ b/fs/nfsd/nfs4state.c
+@@ -84,7 +84,7 @@ static u64 current_sessionid = 1;
+ /* forward declarations */
+ static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner);
+ static void nfs4_free_ol_stateid(struct nfs4_stid *stid);
+-void nfsd4_end_grace(struct nfsd_net *nn);
++static void nfsd4_end_grace(struct nfsd_net *nn);
+ static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps);
+ static void nfsd4_file_hash_remove(struct nfs4_file *fi);
+
+@@ -5882,7 +5882,7 @@ nfsd4_renew(struct svc_rqst *rqstp, stru
+ return nfs_ok;
+ }
+
+-void
++static void
+ nfsd4_end_grace(struct nfsd_net *nn)
+ {
+ /* do nothing if grace period already ended */
+@@ -5915,6 +5915,33 @@ nfsd4_end_grace(struct nfsd_net *nn)
+ */
+ }
+
++/**
++ * nfsd4_force_end_grace - forcibly end the NFSv4 grace period
++ * @nn: network namespace for the server instance to be updated
++ *
++ * Forces bypass of normal grace period completion, then schedules
++ * the laundromat to end the grace period immediately. Does not wait
++ * for the grace period to fully terminate before returning.
++ *
++ * Return values:
++ * %true: Grace termination schedule
++ * %false: No action was taken
++ */
++bool nfsd4_force_end_grace(struct nfsd_net *nn)
++{
++ if (!nn->client_tracking_ops)
++ return false;
++ spin_lock(&nn->client_lock);
++ if (nn->grace_ended || !nn->client_tracking_active) {
++ spin_unlock(&nn->client_lock);
++ return false;
++ }
++ WRITE_ONCE(nn->grace_end_forced, true);
++ mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
++ spin_unlock(&nn->client_lock);
++ return true;
++}
++
+ /*
+ * If we've waited a lease period but there are still clients trying to
+ * reclaim, wait a little longer to give them a chance to finish.
+@@ -5924,6 +5951,8 @@ static bool clients_still_reclaiming(str
+ time64_t double_grace_period_end = nn->boot_time +
+ 2 * nn->nfsd4_lease;
+
++ if (READ_ONCE(nn->grace_end_forced))
++ return false;
+ if (nn->track_reclaim_completes &&
+ atomic_read(&nn->nr_reclaim_complete) ==
+ nn->reclaim_str_hashtbl_size)
+@@ -8131,6 +8160,8 @@ static int nfs4_state_create_net(struct
+ nn->unconf_name_tree = RB_ROOT;
+ nn->boot_time = ktime_get_real_seconds();
+ nn->grace_ended = false;
++ nn->grace_end_forced = false;
++ nn->client_tracking_active = false;
+ nn->nfsd4_manager.block_opens = true;
+ INIT_LIST_HEAD(&nn->nfsd4_manager.list);
+ INIT_LIST_HEAD(&nn->client_lru);
+@@ -8207,6 +8238,10 @@ nfs4_state_start_net(struct net *net)
+ return ret;
+ locks_start_grace(net, &nn->nfsd4_manager);
+ nfsd4_client_tracking_init(net);
++ /* safe for laundromat to run now */
++ spin_lock(&nn->client_lock);
++ nn->client_tracking_active = true;
++ spin_unlock(&nn->client_lock);
+ if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0)
+ goto skip_grace;
+ printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n",
+@@ -8253,6 +8288,9 @@ nfs4_state_shutdown_net(struct net *net)
+
+ unregister_shrinker(&nn->nfsd_client_shrinker);
+ cancel_work_sync(&nn->nfsd_shrinker_work);
++ spin_lock(&nn->client_lock);
++ nn->client_tracking_active = false;
++ spin_unlock(&nn->client_lock);
+ cancel_delayed_work_sync(&nn->laundromat_work);
+ locks_end_grace(&nn->nfsd4_manager);
+
+--- a/fs/nfsd/nfsctl.c
++++ b/fs/nfsd/nfsctl.c
+@@ -1117,9 +1117,8 @@ static ssize_t write_v4_end_grace(struct
+ case 'Y':
+ case 'y':
+ case '1':
+- if (!nn->nfsd_serv)
++ if (!nfsd4_force_end_grace(nn))
+ return -EBUSY;
+- nfsd4_end_grace(nn);
+ break;
+ default:
+ return -EINVAL;
+--- a/fs/nfsd/state.h
++++ b/fs/nfsd/state.h
+@@ -719,7 +719,7 @@ static inline void get_nfs4_file(struct
+ struct nfsd_file *find_any_file(struct nfs4_file *f);
+
+ /* grace period management */
+-void nfsd4_end_grace(struct nfsd_net *nn);
++bool nfsd4_force_end_grace(struct nfsd_net *nn);
+
+ /* nfs4recover operations */
+ extern int nfsd4_client_tracking_init(struct net *net);
--- /dev/null
+From stable+bounces-208129-greg=kroah.com@vger.kernel.org Mon Jan 12 15:45:37 2026
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 12 Jan 2026 09:39:10 -0500
+Subject: NFSD: Remove NFSERR_EAGAIN
+To: stable@vger.kernel.org
+Cc: Chuck Lever <chuck.lever@oracle.com>, NeilBrown <neil@brown.name>, Jeff Layton <jlayton@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20260112143910.714632-3-sashal@kernel.org>
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+[ Upstream commit c6c209ceb87f64a6ceebe61761951dcbbf4a0baa ]
+
+I haven't found an NFSERR_EAGAIN in RFCs 1094, 1813, 7530, or 8881.
+None of these RFCs have an NFS status code that match the numeric
+value "11".
+
+Based on the meaning of the EAGAIN errno, I presume the use of this
+status in NFSD means NFS4ERR_DELAY. So replace the one usage of
+nfserr_eagain, and remove it from NFSD's NFS status conversion
+tables.
+
+As far as I can tell, NFSERR_EAGAIN has existed since the pre-git
+era, but was not actually used by any code until commit f4e44b393389
+("NFSD: delay unmount source's export after inter-server copy
+completed."), at which time it become possible for NFSD to return
+a status code of 11 (which is not valid NFS protocol).
+
+Fixes: f4e44b393389 ("NFSD: delay unmount source's export after inter-server copy completed.")
+Cc: stable@vger.kernel.org
+Reviewed-by: NeilBrown <neil@brown.name>
+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>
+---
+ fs/nfs_common/common.c | 1 -
+ fs/nfsd/nfs4proc.c | 2 +-
+ fs/nfsd/nfsd.h | 1 -
+ include/trace/misc/nfs.h | 2 --
+ include/uapi/linux/nfs.h | 1 -
+ 5 files changed, 1 insertion(+), 6 deletions(-)
+
+--- a/fs/nfs_common/common.c
++++ b/fs/nfs_common/common.c
+@@ -16,7 +16,6 @@ static const struct {
+ { NFSERR_NOENT, -ENOENT },
+ { NFSERR_IO, -errno_NFSERR_IO},
+ { NFSERR_NXIO, -ENXIO },
+-/* { NFSERR_EAGAIN, -EAGAIN }, */
+ { NFSERR_ACCES, -EACCES },
+ { NFSERR_EXIST, -EEXIST },
+ { NFSERR_XDEV, -EXDEV },
+--- a/fs/nfsd/nfs4proc.c
++++ b/fs/nfsd/nfs4proc.c
+@@ -1321,7 +1321,7 @@ try_again:
+ (schedule_timeout(20*HZ) == 0)) {
+ finish_wait(&nn->nfsd_ssc_waitq, &wait);
+ kfree(work);
+- return nfserr_eagain;
++ return nfserr_jukebox;
+ }
+ finish_wait(&nn->nfsd_ssc_waitq, &wait);
+ goto try_again;
+--- a/fs/nfsd/nfsd.h
++++ b/fs/nfsd/nfsd.h
+@@ -201,7 +201,6 @@ void nfsd_lockd_shutdown(void);
+ #define nfserr_noent cpu_to_be32(NFSERR_NOENT)
+ #define nfserr_io cpu_to_be32(NFSERR_IO)
+ #define nfserr_nxio cpu_to_be32(NFSERR_NXIO)
+-#define nfserr_eagain cpu_to_be32(NFSERR_EAGAIN)
+ #define nfserr_acces cpu_to_be32(NFSERR_ACCES)
+ #define nfserr_exist cpu_to_be32(NFSERR_EXIST)
+ #define nfserr_xdev cpu_to_be32(NFSERR_XDEV)
+--- a/include/trace/misc/nfs.h
++++ b/include/trace/misc/nfs.h
+@@ -16,7 +16,6 @@ TRACE_DEFINE_ENUM(NFSERR_PERM);
+ TRACE_DEFINE_ENUM(NFSERR_NOENT);
+ TRACE_DEFINE_ENUM(NFSERR_IO);
+ TRACE_DEFINE_ENUM(NFSERR_NXIO);
+-TRACE_DEFINE_ENUM(NFSERR_EAGAIN);
+ TRACE_DEFINE_ENUM(NFSERR_ACCES);
+ TRACE_DEFINE_ENUM(NFSERR_EXIST);
+ TRACE_DEFINE_ENUM(NFSERR_XDEV);
+@@ -53,7 +52,6 @@ TRACE_DEFINE_ENUM(NFSERR_JUKEBOX);
+ { NFSERR_NXIO, "NXIO" }, \
+ { ECHILD, "CHILD" }, \
+ { ETIMEDOUT, "TIMEDOUT" }, \
+- { NFSERR_EAGAIN, "AGAIN" }, \
+ { NFSERR_ACCES, "ACCES" }, \
+ { NFSERR_EXIST, "EXIST" }, \
+ { NFSERR_XDEV, "XDEV" }, \
+--- a/include/uapi/linux/nfs.h
++++ b/include/uapi/linux/nfs.h
+@@ -49,7 +49,6 @@
+ NFSERR_NOENT = 2, /* v2 v3 v4 */
+ NFSERR_IO = 5, /* v2 v3 v4 */
+ NFSERR_NXIO = 6, /* v2 v3 v4 */
+- NFSERR_EAGAIN = 11, /* v2 v3 */
+ NFSERR_ACCES = 13, /* v2 v3 v4 */
+ NFSERR_EXIST = 17, /* v2 v3 v4 */
+ NFSERR_XDEV = 18, /* v3 v4 */
--- /dev/null
+From ebc18e9854e5a2b62a041fb57b216a903af45b85 Mon Sep 17 00:00:00 2001
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Date: Wed, 26 Nov 2025 13:22:19 +0100
+Subject: pinctrl: qcom: lpass-lpi: mark the GPIO controller as sleeping
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+commit ebc18e9854e5a2b62a041fb57b216a903af45b85 upstream.
+
+The gpio_chip settings in this driver say the controller can't sleep
+but it actually uses a mutex for synchronization. This triggers the
+following BUG():
+
+[ 9.233659] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:281
+[ 9.233665] in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 554, name: (udev-worker)
+[ 9.233669] preempt_count: 1, expected: 0
+[ 9.233673] RCU nest depth: 0, expected: 0
+[ 9.233688] Tainted: [W]=WARN
+[ 9.233690] Hardware name: Dell Inc. Latitude 7455/0FK7MX, BIOS 2.10.1 05/20/2025
+[ 9.233694] Call trace:
+[ 9.233696] show_stack+0x24/0x38 (C)
+[ 9.233709] dump_stack_lvl+0x40/0x88
+[ 9.233716] dump_stack+0x18/0x24
+[ 9.233722] __might_resched+0x148/0x160
+[ 9.233731] __might_sleep+0x38/0x98
+[ 9.233736] mutex_lock+0x30/0xd8
+[ 9.233749] lpi_config_set+0x2e8/0x3c8 [pinctrl_lpass_lpi]
+[ 9.233757] lpi_gpio_direction_output+0x58/0x90 [pinctrl_lpass_lpi]
+[ 9.233761] gpiod_direction_output_raw_commit+0x110/0x428
+[ 9.233772] gpiod_direction_output_nonotify+0x234/0x358
+[ 9.233779] gpiod_direction_output+0x38/0xd0
+[ 9.233786] gpio_shared_proxy_direction_output+0xb8/0x2a8 [gpio_shared_proxy]
+[ 9.233792] gpiod_direction_output_raw_commit+0x110/0x428
+[ 9.233799] gpiod_direction_output_nonotify+0x234/0x358
+[ 9.233806] gpiod_configure_flags+0x2c0/0x580
+[ 9.233812] gpiod_find_and_request+0x358/0x4f8
+[ 9.233819] gpiod_get_index+0x7c/0x98
+[ 9.233826] devm_gpiod_get+0x34/0xb0
+[ 9.233829] reset_gpio_probe+0x58/0x128 [reset_gpio]
+[ 9.233836] auxiliary_bus_probe+0xb0/0xf0
+[ 9.233845] really_probe+0x14c/0x450
+[ 9.233853] __driver_probe_device+0xb0/0x188
+[ 9.233858] driver_probe_device+0x4c/0x250
+[ 9.233863] __driver_attach+0xf8/0x2a0
+[ 9.233868] bus_for_each_dev+0xf8/0x158
+[ 9.233872] driver_attach+0x30/0x48
+[ 9.233876] bus_add_driver+0x158/0x2b8
+[ 9.233880] driver_register+0x74/0x118
+[ 9.233886] __auxiliary_driver_register+0x94/0xe8
+[ 9.233893] init_module+0x34/0xfd0 [reset_gpio]
+[ 9.233898] do_one_initcall+0xec/0x300
+[ 9.233903] do_init_module+0x64/0x260
+[ 9.233910] load_module+0x16c4/0x1900
+[ 9.233915] __arm64_sys_finit_module+0x24c/0x378
+[ 9.233919] invoke_syscall+0x4c/0xe8
+[ 9.233925] el0_svc_common+0x8c/0xf0
+[ 9.233929] do_el0_svc+0x28/0x40
+[ 9.233934] el0_svc+0x38/0x100
+[ 9.233938] el0t_64_sync_handler+0x84/0x130
+[ 9.233943] el0t_64_sync+0x17c/0x180
+
+Mark the controller as sleeping.
+
+Fixes: 6e261d1090d6 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver")
+Cc: stable@vger.kernel.org
+Reported-by: Val Packett <val@packett.cool>
+Closes: https://lore.kernel.org/all/98c0f185-b0e0-49ea-896c-f3972dd011ca@packett.cool/
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Reviewed-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Linus Walleij <linusw@kernel.org>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
++++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
+@@ -435,7 +435,7 @@ int lpi_pinctrl_probe(struct platform_de
+ pctrl->chip.ngpio = data->npins;
+ pctrl->chip.label = dev_name(dev);
+ pctrl->chip.of_gpio_n_cells = 2;
+- pctrl->chip.can_sleep = false;
++ pctrl->chip.can_sleep = true;
+
+ mutex_init(&pctrl->lock);
+
net-usb-pegasus-fix-memory-leak-in-update_eth_regs_a.patch
net-enetc-fix-build-warning-when-page_size-is-greate.patch
arp-do-not-assume-dev_hard_header-does-not-change-sk.patch
+pinctrl-qcom-lpass-lpi-mark-the-gpio-controller-as-sleeping.patch
+mm-pagewalk-add-walk_page_range_vma.patch
+ksm-use-range-walk-function-to-jump-over-holes-in-scan_get_next_rmap_item.patch
+alsa-ac97bus-use-guard-for-mutex-locks.patch
+alsa-ac97-fix-a-double-free-in-snd_ac97_controller_register.patch
+nfsd-provide-locking-for-v4_end_grace.patch
+nfs-trace-show-timedout-instead-of-0x6e.patch
+nfs_common-factor-out-nfs_errtbl-and-nfs_stat_to_errno.patch
+nfsd-remove-nfserr_eagain.patch