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);