Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

nfs/localio: fix regression due to out-of-order __put_cred

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>

authored by

Mike Snitzer and committed by
Linus Torvalds
3af870ae 11efc1cb

+17 -31
+17 -31
fs/nfs/localio.c
··· 615 615 nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_read_aio_complete_work */ 616 616 } 617 617 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) 619 619 { 620 + struct nfs_local_kiocb *iocb = 621 + container_of(work, struct nfs_local_kiocb, work); 622 + struct file *filp = iocb->kiocb.ki_filp; 620 623 bool force_done = false; 621 624 ssize_t status; 622 625 int n_iters; ··· 636 633 } else 637 634 iocb->kiocb.ki_flags &= ~IOCB_DIRECT; 638 635 639 - status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]); 636 + scoped_with_creds(filp->f_cred) 637 + status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]); 638 + 640 639 if (status != -EIOCBQUEUED) { 641 640 if (unlikely(status >= 0 && status < iocb->iters[i].count)) 642 641 force_done = true; /* Partial read */ ··· 648 643 } 649 644 } 650 645 } 651 - } 652 - 653 - static void nfs_local_call_read(struct work_struct *work) 654 - { 655 - struct nfs_local_kiocb *iocb = 656 - container_of(work, struct nfs_local_kiocb, work); 657 - struct file *filp = iocb->kiocb.ki_filp; 658 - 659 - scoped_with_creds(filp->f_cred) 660 - do_nfs_local_call_read(iocb, filp); 661 646 } 662 647 663 648 static int ··· 817 822 nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_write_aio_complete_work */ 818 823 } 819 824 820 - static ssize_t do_nfs_local_call_write(struct nfs_local_kiocb *iocb, 821 - struct file *filp) 825 + static void nfs_local_call_write(struct work_struct *work) 822 826 { 827 + struct nfs_local_kiocb *iocb = 828 + container_of(work, struct nfs_local_kiocb, work); 829 + struct file *filp = iocb->kiocb.ki_filp; 830 + unsigned long old_flags = current->flags; 823 831 bool force_done = false; 824 832 ssize_t status; 825 833 int n_iters; 834 + 835 + current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO; 826 836 827 837 file_start_write(filp); 828 838 n_iters = atomic_read(&iocb->n_iters); ··· 842 842 } else 843 843 iocb->kiocb.ki_flags &= ~IOCB_DIRECT; 844 844 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 + 846 848 if (status != -EIOCBQUEUED) { 847 849 if (unlikely(status >= 0 && status < iocb->iters[i].count)) 848 850 force_done = true; /* Partial write */ ··· 855 853 } 856 854 } 857 855 file_end_write(filp); 858 - 859 - return status; 860 - } 861 - 862 - static void nfs_local_call_write(struct work_struct *work) 863 - { 864 - struct nfs_local_kiocb *iocb = 865 - container_of(work, struct nfs_local_kiocb, work); 866 - struct file *filp = iocb->kiocb.ki_filp; 867 - unsigned long old_flags = current->flags; 868 - ssize_t status; 869 - 870 - current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO; 871 - 872 - scoped_with_creds(filp->f_cred) 873 - status = do_nfs_local_call_write(iocb, filp); 874 856 875 857 current->flags = old_flags; 876 858 }