FWIW, this is the diff I used to simulate the race condition (only for
testing):
Index: kern/vfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.260
diff -u -p -r1.260 vfs_syscalls.c
--- kern/vfs_syscalls.c 3 Jul 2016 04:36:08 -0000 1.260
+++ kern/vfs_syscalls.c 3 Jul 2016 19:09:24 -0000
@@ -1233,9 +1233,12 @@ domknodat(struct proc *p, int fd, const
if ((error = namei(&nd)) != 0)
return (error);
vp = nd.ni_vp;
- if (vp != NULL)
- error = EEXIST;
- else {
+ if (vp != NULL) {
+ /* error = EEXIST; */
+ error = 0;
+ vrele(vp);
+ }
+ /* else { */
VATTR_NULL(&vattr);
vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
if ((p->p_p->ps_flags & PS_PLEDGE))
@@ -1267,7 +1270,7 @@ domknodat(struct proc *p, int fd, const
error = EINVAL;
break;
}
- }
+ /* } */
if (!error) {
error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
} else {
On Sun, Jul 03, 2016 at 09:16:26PM +0200, Martin Natano wrote:
> When perfoming a mknod operation over NFS it can happen that another
> client creates a file with the same name between the namei() and
> VOP_MKNOD() calls in domknod(). This leads to an error path in
> nfsrv_mknod() being triggered. In that error path there is a
> vput(nd.ni_np) missing, resulting in the vnode getting stuck with a
> stale reference and lock, while it shouldn't have either.
>
> Ok?
>
> natano
>
>
> Index: nfs/nfs_serv.c
> ===================================================================
> RCS file: /cvs/src/sys/nfs/nfs_serv.c,v
> retrieving revision 1.108
> diff -u -p -r1.108 nfs_serv.c
> --- nfs/nfs_serv.c 29 Apr 2016 14:40:36 -0000 1.108
> +++ nfs/nfs_serv.c 3 Jul 2016 18:00:54 -0000
> @@ -1163,7 +1163,12 @@ nfsrv_mknod(struct nfsrv_descript *nfsd,
> pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
> error = NFSERR_BADTYPE;
> VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
> - vput(nd.ni_dvp);
> + if (nd.ni_dvp == nd.ni_vp)
> + vrele(nd.ni_dvp);
> + else
> + vput(nd.ni_dvp);
> + if (nd.ni_vp)
> + vput(nd.ni_vp);
> goto out;
> }
> VATTR_NULL(&va);
> @@ -1185,7 +1190,11 @@ nfsrv_mknod(struct nfsrv_descript *nfsd,
> pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
> error = EEXIST;
> VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
> - vput(nd.ni_dvp);
> + if (nd.ni_dvp == nd.ni_vp)
> + vrele(nd.ni_dvp);
> + else
> + vput(nd.ni_dvp);
> + vput(nd.ni_vp);
> goto out;
> }
> va.va_type = vtyp;