This diff puts more fields of struct vnode under splbio(). splbio()
looks necessary with the fields that are modified through the buffer
cache because the access can happen in an interrupt context.

Wrapping LIST_EMPTY() with splbio() is probably overzealous.
However, the added splbio() calls might serve as hints for locking.

OK?

Index: kern/vfs_bio.c
===================================================================
RCS file: src/sys/kern/vfs_bio.c,v
retrieving revision 1.208
diff -u -p -r1.208 vfs_bio.c
--- kern/vfs_bio.c      12 Dec 2021 09:14:59 -0000      1.208
+++ kern/vfs_bio.c      26 Jul 2022 15:36:42 -0000
@@ -1554,7 +1554,10 @@ bufcache_getcleanbuf(int cachenum, int d
 
 
 void
-discard_buffer(struct buf *bp) {
+discard_buffer(struct buf *bp)
+{
+       splassert(IPL_BIO);
+
        bufcache_take(bp);
        if (bp->b_vp) {
                RBT_REMOVE(buf_rb_bufs,
Index: kern/vfs_subr.c
===================================================================
RCS file: src/sys/kern/vfs_subr.c,v
retrieving revision 1.315
diff -u -p -r1.315 vfs_subr.c
--- kern/vfs_subr.c     27 Mar 2022 16:19:39 -0000      1.315
+++ kern/vfs_subr.c     26 Jul 2022 15:36:42 -0000
@@ -662,16 +662,16 @@ vget(struct vnode *vp, int flags)
        }
        mtx_leave(&vnode_mtx);
 
+       s = splbio();
        onfreelist = vp->v_bioflag & VBIOONFREELIST;
        if (vp->v_usecount == 0 && onfreelist) {
-               s = splbio();
                if (vp->v_holdcnt > 0)
                        TAILQ_REMOVE(&vnode_hold_list, vp, v_freelist);
                else
                        TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
                vp->v_bioflag &= ~VBIOONFREELIST;
-               splx(s);
        }
+       splx(s);
 
        vp->v_usecount++;
        if (flags & LK_TYPE_MASK) {
@@ -749,6 +749,7 @@ void
 vput(struct vnode *vp)
 {
        struct proc *p = curproc;
+       int s;
 
 #ifdef DIAGNOSTIC
        if (vp == NULL)
@@ -777,8 +778,10 @@ vput(struct vnode *vp)
 
        VOP_INACTIVE(vp, p);
 
+       s = splbio();
        if (vp->v_usecount == 0 && !(vp->v_bioflag & VBIOONFREELIST))
                vputonfreelist(vp);
+       splx(s);
 }
 
 /*
@@ -790,6 +793,7 @@ int
 vrele(struct vnode *vp)
 {
        struct proc *p = curproc;
+       int s;
 
 #ifdef DIAGNOSTIC
        if (vp == NULL)
@@ -822,8 +826,10 @@ vrele(struct vnode *vp)
 
        VOP_INACTIVE(vp, p);
 
+       s = splbio();
        if (vp->v_usecount == 0 && !(vp->v_bioflag & VBIOONFREELIST))
                vputonfreelist(vp);
+       splx(s);
        return (1);
 }
 
@@ -831,6 +837,10 @@ vrele(struct vnode *vp)
 void
 vhold(struct vnode *vp)
 {
+       int s;
+
+       s = splbio();
+
        /*
         * If it is on the freelist and the hold count is currently
         * zero, move it to the hold list.
@@ -841,12 +851,18 @@ vhold(struct vnode *vp)
                TAILQ_INSERT_TAIL(&vnode_hold_list, vp, v_freelist);
        }
        vp->v_holdcnt++;
+
+       splx(s);
 }
 
 /* Lose interest in a vnode. */
 void
 vdrop(struct vnode *vp)
 {
+       int s;
+
+       s = splbio();
+
 #ifdef DIAGNOSTIC
        if (vp->v_holdcnt == 0)
                panic("vdrop: zero holdcnt");
@@ -863,6 +879,8 @@ vdrop(struct vnode *vp)
                TAILQ_REMOVE(&vnode_hold_list, vp, v_freelist);
                TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
        }
+
+       splx(s);
 }
 
 /*
@@ -909,6 +927,7 @@ vflush_vnode(struct vnode *vp, void *arg
 {
        struct vflush_args *va = arg;
        struct proc *p = curproc;
+       int empty, s;
 
        if (vp == va->skipvp) {
                return (0);
@@ -958,8 +977,11 @@ vflush_vnode(struct vnode *vp, void *arg
         * XXX Might be nice to check per-fs "inode" flags, but
         * generally the filesystem is sync'd already, right?
         */
-       if ((va->flags & IGNORECLEAN) &&
-           LIST_EMPTY(&vp->v_dirtyblkhd))
+       s = splbio();
+       empty = (va->flags & IGNORECLEAN) && LIST_EMPTY(&vp->v_dirtyblkhd);
+       splx(s);
+
+       if (empty)
                return (0);
 
 #ifdef DEBUG_SYSCTL
@@ -992,6 +1014,7 @@ void
 vclean(struct vnode *vp, int flags, struct proc *p)
 {
        int active, do_wakeup = 0;
+       int s;
 
        /*
         * Check to see if the vnode is in use.
@@ -1066,9 +1089,11 @@ vclean(struct vnode *vp, int flags, stru
        if (active) {
                vp->v_usecount--;
                if (vp->v_usecount == 0) {
+                       s = splbio();
                        if (vp->v_holdcnt > 0)
                                panic("vclean: not clean");
                        vputonfreelist(vp);
+                       splx(s);
                }
        }
        cache_purge(vp);
@@ -1125,6 +1150,7 @@ vgonel(struct vnode *vp, struct proc *p)
 {
        struct vnode *vq;
        struct vnode *vx;
+       int s;
 
        KASSERT(vp->v_uvcount == 0);
 
@@ -1192,12 +1218,9 @@ vgonel(struct vnode *vp, struct proc *p)
         * Move onto the free list, unless we were called from
         * getnewvnode and we're not on any free list
         */
+       s = splbio();
        if (vp->v_usecount == 0 &&
            (vp->v_bioflag & VBIOONFREELIST)) {
-               int s;
-
-               s = splbio();
-
                if (vp->v_holdcnt > 0)
                        panic("vgonel: not clean");
 
@@ -1205,8 +1228,8 @@ vgonel(struct vnode *vp, struct proc *p)
                        TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
                        TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
                }
-               splx(s);
        }
+       splx(s);
 }
 
 /*
Index: msdosfs/msdosfs_vfsops.c
===================================================================
RCS file: src/sys/msdosfs/msdosfs_vfsops.c,v
retrieving revision 1.95
diff -u -p -r1.95 msdosfs_vfsops.c
--- msdosfs/msdosfs_vfsops.c    13 Nov 2021 18:18:59 -0000      1.95
+++ msdosfs/msdosfs_vfsops.c    26 Jul 2022 15:36:42 -0000
@@ -640,16 +640,22 @@ int
 msdosfs_sync_vnode(struct vnode *vp, void *arg)
 {
        struct msdosfs_sync_arg *msa = arg;
-       int error;
        struct denode *dep;
+       int error;
+       int s, skip = 0;
 
        dep = VTODE(vp);
+       s = splbio();
        if (vp->v_type == VNON ||
            ((dep->de_flag & (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) 
== 0
              && LIST_EMPTY(&vp->v_dirtyblkhd)) ||
            msa->waitfor == MNT_LAZY) {
-               return (0);
+               skip = 1;
        }
+       splx(s);
+
+       if (skip)
+               return (0);
 
        if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT))
                return (0);
Index: nfs/nfs_vfsops.c
===================================================================
RCS file: src/sys/nfs/nfs_vfsops.c,v
retrieving revision 1.126
diff -u -p -r1.126 nfs_vfsops.c
--- nfs/nfs_vfsops.c    2 Jan 2021 02:41:42 -0000       1.126
+++ nfs/nfs_vfsops.c    26 Jul 2022 15:36:42 -0000
@@ -793,7 +793,8 @@ int
 nfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct 
proc *p)
 {
        struct vnode *vp;
-       int error, allerror = 0;
+       int allerror = 0;
+       int empty, error, s;
 
        /*
         * Don't traverse the vnode list if we want to skip all of them.
@@ -812,7 +813,12 @@ loop:
                 */
                if (vp->v_mount != mp)
                        goto loop;
-               if (VOP_ISLOCKED(vp) || LIST_EMPTY(&vp->v_dirtyblkhd))
+               if (VOP_ISLOCKED(vp))
+                       continue;
+               s = splbio();
+               empty = LIST_EMPTY(&vp->v_dirtyblkhd);
+               splx(s);
+               if (empty)
                        continue;
                if (vget(vp, LK_EXCLUSIVE))
                        goto loop;
Index: nfs/nfs_vnops.c
===================================================================
RCS file: src/sys/nfs/nfs_vnops.c,v
retrieving revision 1.189
diff -u -p -r1.189 nfs_vnops.c
--- nfs/nfs_vnops.c     26 Jun 2022 05:20:42 -0000      1.189
+++ nfs/nfs_vnops.c     26 Jul 2022 15:36:42 -0000
@@ -2849,7 +2849,7 @@ nfs_flush(struct vnode *vp, struct ucred
        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
        uint64_t slptimeo = INFSLP;
        int s, error = 0, slpflag = 0, retv, bvecpos;
-       int passone = 1;
+       int dirty, passone = 1;
        u_quad_t off = (u_quad_t)-1, endoff = 0, toff;
 #ifndef NFS_COMMITBVECSIZ
 #define NFS_COMMITBVECSIZ      20
@@ -2982,8 +2982,8 @@ loop:
  loop2:
                s = splbio();
                error = vwaitforio(vp, slpflag, "nfs_fsync", slptimeo);
-               splx(s);
                if (error) {
+                       splx(s);
                        if (nfs_sigintr(nmp, NULL, p))
                                return (EINTR);
                        if (slpflag == PCATCH) {
@@ -2992,8 +2992,9 @@ loop:
                        }
                        goto loop2;
                }
-
-               if (!LIST_EMPTY(&vp->v_dirtyblkhd) && commit) {
+               dirty = (!LIST_EMPTY(&vp->v_dirtyblkhd) && commit);
+               splx(s);
+               if (dirty) {
 #if 0
                        vprint("nfs_fsync: dirty", vp);
 #endif
Index: sys/vnode.h
===================================================================
RCS file: src/sys/sys/vnode.h,v
retrieving revision 1.166
diff -u -p -r1.166 vnode.h
--- sys/vnode.h 26 Jun 2022 05:20:42 -0000      1.166
+++ sys/vnode.h 26 Jul 2022 15:36:42 -0000
@@ -104,18 +104,17 @@ struct vnode {
        u_int   v_writecount;           /* reference count of writers */
        u_int   v_lockcount;            /* [V] # threads waiting on lock */
 
-       /* Flags that can be read/written in interrupts */
-       u_int   v_bioflag;
-       u_int   v_holdcnt;                      /* buffer references */
+       u_int   v_bioflag;              /* [B] flags accessed in interrupts */
+       u_int   v_holdcnt;              /* [B] buffer references */
        u_int   v_id;                           /* capability identifier */
        struct  mount *v_mount;                 /* ptr to vfs we are in */
-       TAILQ_ENTRY(vnode) v_freelist;          /* vnode freelist */
+       TAILQ_ENTRY(vnode) v_freelist;  /* [B] vnode freelist */
        TAILQ_ENTRY(vnode) v_mntvnodes;         /* vnodes for mount point */
-       struct  buf_rb_bufs v_bufs_tree;        /* lookup of all bufs */
-       struct  buflists v_cleanblkhd;          /* clean blocklist head */
-       struct  buflists v_dirtyblkhd;          /* dirty blocklist head */
+       struct  buf_rb_bufs v_bufs_tree;/* [B] lookup of all bufs */
+       struct  buflists v_cleanblkhd;  /* [B] clean blocklist head */
+       struct  buflists v_dirtyblkhd;  /* [B] dirty blocklist head */
        u_int   v_numoutput;            /* [B] num of writes in progress */
-       LIST_ENTRY(vnode) v_synclist;           /* vnode with dirty buffers */
+       LIST_ENTRY(vnode) v_synclist;   /* [B] vnode with dirty buffers */
        union {
                struct mount    *vu_mountedhere;/* ptr to mounted vfs (VDIR) */
                struct socket   *vu_socket;     /* unix ipc (VSOCK) */
Index: ufs/ext2fs/ext2fs_inode.c
===================================================================
RCS file: src/sys/ufs/ext2fs/ext2fs_inode.c,v
retrieving revision 1.65
diff -u -p -r1.65 ext2fs_inode.c
--- ufs/ext2fs/ext2fs_inode.c   12 Dec 2021 09:14:59 -0000      1.65
+++ ufs/ext2fs/ext2fs_inode.c   26 Jul 2022 15:36:42 -0000
@@ -387,10 +387,15 @@ done:
        for (i = 0; i < NDADDR; i++)
                if (newblks[i] != oip->i_e2fs_blocks[i])
                        panic("ext2fs_truncate2");
-       if (length == 0 &&
-           (!LIST_EMPTY(&ovp->v_cleanblkhd) ||
-            !LIST_EMPTY(&ovp->v_dirtyblkhd)))
-               panic("ext2fs_truncate3");
+       if (length == 0) {
+               int s;
+
+               s = splbio();
+               if (!LIST_EMPTY(&ovp->v_cleanblkhd) ||
+                   !LIST_EMPTY(&ovp->v_dirtyblkhd))
+                       panic("ext2fs_truncate3");
+               splx(s);
+       }
 #endif /* DIAGNOSTIC */
        /*
         * Put back the real size.
Index: ufs/ext2fs/ext2fs_vfsops.c
===================================================================
RCS file: src/sys/ufs/ext2fs/ext2fs_vfsops.c,v
retrieving revision 1.116
diff -u -p -r1.116 ext2fs_vfsops.c
--- ufs/ext2fs/ext2fs_vfsops.c  4 Oct 2021 08:11:02 -0000       1.116
+++ ufs/ext2fs/ext2fs_vfsops.c  26 Jul 2022 15:36:42 -0000
@@ -713,6 +713,7 @@ ext2fs_sync_vnode(struct vnode *vp, void
        struct ext2fs_sync_args *esa = args;
        struct inode *ip;
        int error, nlink0 = 0;
+       int s, skip = 0;
 
        if (vp->v_type == VNON)
                return (0);
@@ -722,10 +723,15 @@ ext2fs_sync_vnode(struct vnode *vp, void
        if (ip->i_e2fs_nlink == 0)
                nlink0 = 1;
 
+       s = splbio();
        if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 
0 &&
            LIST_EMPTY(&vp->v_dirtyblkhd)) {
-               goto end;
+               skip = 1;
        }
+       splx(s);
+
+       if (skip)
+               goto end;
 
        if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT)) {
                esa->inflight = MIN(esa->inflight+1, 65536);
Index: ufs/ffs/ffs_vfsops.c
===================================================================
RCS file: src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.192
diff -u -p -r1.192 ffs_vfsops.c
--- ufs/ffs/ffs_vfsops.c        20 Oct 2021 06:35:39 -0000      1.192
+++ ufs/ffs/ffs_vfsops.c        26 Jul 2022 15:36:42 -0000
@@ -1159,6 +1159,7 @@ ffs_sync_vnode(struct vnode *vp, void *a
        struct ffs_sync_args *fsa = arg;
        struct inode *ip;
        int error, nlink0 = 0;
+       int s, skip = 0;
 
        if (vp->v_type == VNON)
                return (0);
@@ -1177,11 +1178,16 @@ ffs_sync_vnode(struct vnode *vp, void *a
        if (ip->i_effnlink == 0)
                nlink0 = 1;
 
+       s = splbio();
        if ((ip->i_flag &
            (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
            LIST_EMPTY(&vp->v_dirtyblkhd)) {
-               goto end;
+               skip = 1;
        }
+       splx(s);
+
+       if (skip)
+               goto end;
 
        if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT)) {
                fsa->inflight = MIN(fsa->inflight+1, 65536);

Reply via email to