Skip to content

Commit 3af870a

Browse files
Mike Snitzertorvalds
authored andcommitted
nfs/localio: fix regression due to out-of-order __put_cred
Commit f2060bd ("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 992203a ("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: 94afb62 ("nfs: use credential guards in nfs_local_call_read()") bff3c84 ("nfs: use credential guards in nfs_local_call_write()") 1d18101 ("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>
1 parent 11efc1c commit 3af870a

1 file changed

Lines changed: 17 additions & 31 deletions

File tree

fs/nfs/localio.c

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -615,8 +615,11 @@ static void nfs_local_read_aio_complete(struct kiocb *kiocb, long ret)
615615
nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_read_aio_complete_work */
616616
}
617617

618-
static void do_nfs_local_call_read(struct nfs_local_kiocb *iocb, struct file *filp)
618+
static void nfs_local_call_read(struct work_struct *work)
619619
{
620+
struct nfs_local_kiocb *iocb =
621+
container_of(work, struct nfs_local_kiocb, work);
622+
struct file *filp = iocb->kiocb.ki_filp;
620623
bool force_done = false;
621624
ssize_t status;
622625
int n_iters;
@@ -633,7 +636,9 @@ static void do_nfs_local_call_read(struct nfs_local_kiocb *iocb, struct file *fi
633636
} else
634637
iocb->kiocb.ki_flags &= ~IOCB_DIRECT;
635638

636-
status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]);
639+
scoped_with_creds(filp->f_cred)
640+
status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]);
641+
637642
if (status != -EIOCBQUEUED) {
638643
if (unlikely(status >= 0 && status < iocb->iters[i].count))
639644
force_done = true; /* Partial read */
@@ -645,16 +650,6 @@ static void do_nfs_local_call_read(struct nfs_local_kiocb *iocb, struct file *fi
645650
}
646651
}
647652

648-
static void nfs_local_call_read(struct work_struct *work)
649-
{
650-
struct nfs_local_kiocb *iocb =
651-
container_of(work, struct nfs_local_kiocb, work);
652-
struct file *filp = iocb->kiocb.ki_filp;
653-
654-
scoped_with_creds(filp->f_cred)
655-
do_nfs_local_call_read(iocb, filp);
656-
}
657-
658653
static int
659654
nfs_local_do_read(struct nfs_local_kiocb *iocb,
660655
const struct rpc_call_ops *call_ops)
@@ -822,13 +817,18 @@ static void nfs_local_write_aio_complete(struct kiocb *kiocb, long ret)
822817
nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_write_aio_complete_work */
823818
}
824819

825-
static ssize_t do_nfs_local_call_write(struct nfs_local_kiocb *iocb,
826-
struct file *filp)
820+
static void nfs_local_call_write(struct work_struct *work)
827821
{
822+
struct nfs_local_kiocb *iocb =
823+
container_of(work, struct nfs_local_kiocb, work);
824+
struct file *filp = iocb->kiocb.ki_filp;
825+
unsigned long old_flags = current->flags;
828826
bool force_done = false;
829827
ssize_t status;
830828
int n_iters;
831829

830+
current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO;
831+
832832
file_start_write(filp);
833833
n_iters = atomic_read(&iocb->n_iters);
834834
for (int i = 0; i < n_iters ; i++) {
@@ -842,7 +842,9 @@ static ssize_t do_nfs_local_call_write(struct nfs_local_kiocb *iocb,
842842
} else
843843
iocb->kiocb.ki_flags &= ~IOCB_DIRECT;
844844

845-
status = filp->f_op->write_iter(&iocb->kiocb, &iocb->iters[i]);
845+
scoped_with_creds(filp->f_cred)
846+
status = filp->f_op->write_iter(&iocb->kiocb, &iocb->iters[i]);
847+
846848
if (status != -EIOCBQUEUED) {
847849
if (unlikely(status >= 0 && status < iocb->iters[i].count))
848850
force_done = true; /* Partial write */
@@ -854,22 +856,6 @@ static ssize_t do_nfs_local_call_write(struct nfs_local_kiocb *iocb,
854856
}
855857
file_end_write(filp);
856858

857-
return status;
858-
}
859-
860-
static void nfs_local_call_write(struct work_struct *work)
861-
{
862-
struct nfs_local_kiocb *iocb =
863-
container_of(work, struct nfs_local_kiocb, work);
864-
struct file *filp = iocb->kiocb.ki_filp;
865-
unsigned long old_flags = current->flags;
866-
ssize_t status;
867-
868-
current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO;
869-
870-
scoped_with_creds(filp->f_cred)
871-
status = do_nfs_local_call_write(iocb, filp);
872-
873859
current->flags = old_flags;
874860
}
875861

0 commit comments

Comments
 (0)