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;

Reply via email to