--- /dev/null
+From 3af870aedbff10bfed220e280b57a405e972229f Mon Sep 17 00:00:00 2001
+From: Mike Snitzer <snitzer@kernel.org>
+Date: Wed, 26 Nov 2025 01:01:25 -0500
+Subject: nfs/localio: fix regression due to out-of-order __put_cred
+
+From: Mike Snitzer <snitzer@kernel.org>
+
+commit 3af870aedbff10bfed220e280b57a405e972229f upstream.
+
+Commit f2060bdc21d7 ("nfs/localio: add refcounting for each iocb IO
+associated with NFS pgio header") inadvertantly reintroduced the same
+potential for __put_cred() triggering BUG_ON(cred == current->cred) that
+commit 992203a1fba5 ("nfs/localio: restore creds before releasing pageio
+data") fixed.
+
+Fix this by saving and restoring the cred around each {read,write}_iter
+call within the respective for loop of nfs_local_call_{read,write} using
+scoped_with_creds().
+
+NOTE: this fix started by first reverting the following commits:
+
+ 94afb627dfc2 ("nfs: use credential guards in nfs_local_call_read()")
+ bff3c841f7bd ("nfs: use credential guards in nfs_local_call_write()")
+ 1d18101a644e ("Merge tag 'kernel-6.19-rc1.cred' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs")
+
+followed by narrowly fixing the cred lifetime issue by using
+scoped_with_creds(). In doing so, this commit's changes appear more
+extensive than they really are (as evidenced by comparing to v6.18's
+fs/nfs/localio.c).
+
+Reported-by: Zorro Lang <zlang@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@kernel.org>
+Acked-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Reviewed-by: Christian Brauner <brauner@kernel.org>
+Link: https://lore.kernel.org/linux-next/20251205111942.4150b06f@canb.auug.org.au/
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/localio.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/fs/nfs/localio.c
++++ b/fs/nfs/localio.c
+@@ -623,8 +623,6 @@ static void nfs_local_call_read(struct w
+ ssize_t status;
+ int n_iters;
+
+- save_cred = override_creds(filp->f_cred);
+-
+ n_iters = atomic_read(&iocb->n_iters);
+ for (int i = 0; i < n_iters ; i++) {
+ if (iocb->iter_is_dio_aligned[i]) {
+@@ -637,7 +635,10 @@ static void nfs_local_call_read(struct w
+ } else
+ iocb->kiocb.ki_flags &= ~IOCB_DIRECT;
+
++ save_cred = override_creds(filp->f_cred);
+ status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]);
++ revert_creds(save_cred);
++
+ if (status != -EIOCBQUEUED) {
+ if (unlikely(status >= 0 && status < iocb->iters[i].count))
+ force_done = true; /* Partial read */
+@@ -647,8 +648,6 @@ static void nfs_local_call_read(struct w
+ }
+ }
+ }
+-
+- revert_creds(save_cred);
+ }
+
+ static int
+@@ -830,7 +829,6 @@ static void nfs_local_call_write(struct
+ int n_iters;
+
+ current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO;
+- save_cred = override_creds(filp->f_cred);
+
+ file_start_write(filp);
+ n_iters = atomic_read(&iocb->n_iters);
+@@ -845,7 +843,10 @@ static void nfs_local_call_write(struct
+ } else
+ iocb->kiocb.ki_flags &= ~IOCB_DIRECT;
+
++ save_cred = override_creds(filp->f_cred);
+ status = filp->f_op->write_iter(&iocb->kiocb, &iocb->iters[i]);
++ revert_creds(save_cred);
++
+ if (status != -EIOCBQUEUED) {
+ if (unlikely(status >= 0 && status < iocb->iters[i].count))
+ force_done = true; /* Partial write */
+@@ -857,7 +858,6 @@ static void nfs_local_call_write(struct
+ }
+ file_end_write(filp);
+
+- revert_creds(save_cred);
+ current->flags = old_flags;
+ }
+