From owner-svn-src-head@FreeBSD.ORG Sun Jan 2 19:58:39 2011 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 989CE1065670; Sun, 2 Jan 2011 19:58:39 +0000 (UTC) (envelope-from rmacklem@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 86E5B8FC08; Sun, 2 Jan 2011 19:58:39 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p02JwdwM056662; Sun, 2 Jan 2011 19:58:39 GMT (envelope-from rmacklem@svn.freebsd.org) Received: (from rmacklem@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p02JwdtC056657; Sun, 2 Jan 2011 19:58:39 GMT (envelope-from rmacklem@svn.freebsd.org) Message-Id: <201101021958.p02JwdtC056657@svn.freebsd.org> From: Rick Macklem Date: Sun, 2 Jan 2011 19:58:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r216893 - head/sys/fs/nfsserver X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 02 Jan 2011 19:58:39 -0000 Author: rmacklem Date: Sun Jan 2 19:58:39 2011 New Revision: 216893 URL: http://svn.freebsd.org/changeset/base/216893 Log: Add checks for VI_DOOMED and vn_lock() failures to the experimental NFS server, to handle the case where an exported file system is forced dismounted while an RPC is in progress. Further commits will fix the cases where a mount point is used when the associated vnode isn't locked. Reviewed by: kib MFC after: 2 weeks Modified: head/sys/fs/nfsserver/nfs_nfsdport.c head/sys/fs/nfsserver/nfs_nfsdserv.c head/sys/fs/nfsserver/nfs_nfsdsocket.c head/sys/fs/nfsserver/nfs_nfsdstate.c Modified: head/sys/fs/nfsserver/nfs_nfsdport.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdport.c Sun Jan 2 15:06:07 2011 (r216892) +++ head/sys/fs/nfsserver/nfs_nfsdport.c Sun Jan 2 19:58:39 2011 (r216893) @@ -153,6 +153,10 @@ nfsvno_accchk(struct vnode *vp, accmode_ struct vattr vattr; int error = 0, getret = 0; + if (vpislocked == 0) { + if (vn_lock(vp, LK_SHARED) != 0) + return (EPERM); + } if (accmode & VWRITE) { /* Just vn_writechk() changed to check rdonly */ /* @@ -166,7 +170,7 @@ nfsvno_accchk(struct vnode *vp, accmode_ case VREG: case VDIR: case VLNK: - return (EROFS); + error = EROFS; default: break; } @@ -176,11 +180,14 @@ nfsvno_accchk(struct vnode *vp, accmode_ * the inode, try to free it up once. If * we fail, we can't allow writing. */ - if (vp->v_vflag & VV_TEXT) - return (ETXTBSY); + if ((vp->v_vflag & VV_TEXT) != 0 && error == 0) + error = ETXTBSY; + } + if (error != 0) { + if (vpislocked == 0) + VOP_UNLOCK(vp, 0); + return (error); } - if (vpislocked == 0) - vn_lock(vp, LK_SHARED | LK_RETRY); /* * Should the override still be applied when ACLs are enabled? @@ -1097,9 +1104,11 @@ nfsvno_rename(struct nameidata *fromndp, goto out; } if (ndflag & ND_NFSV4) { - NFSVOPLOCK(fvp, LK_EXCLUSIVE | LK_RETRY, p); - error = nfsrv_checkremove(fvp, 0, p); - NFSVOPUNLOCK(fvp, 0, p); + if (vn_lock(fvp, LK_EXCLUSIVE) == 0) { + error = nfsrv_checkremove(fvp, 0, p); + VOP_UNLOCK(fvp, 0); + } else + error = EPERM; if (tvp && !error) error = nfsrv_checkremove(tvp, 1, p); } else { @@ -1156,13 +1165,16 @@ nfsvno_link(struct nameidata *ndp, struc error = EXDEV; } if (!error) { - NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); - error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + if ((vp->v_iflag & VI_DOOMED) == 0) + error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd); + else + error = EPERM; if (ndp->ni_dvp == vp) vrele(ndp->ni_dvp); else vput(ndp->ni_dvp); - NFSVOPUNLOCK(vp, 0, p); + VOP_UNLOCK(vp, 0); } else { if (ndp->ni_dvp == ndp->ni_vp) vrele(ndp->ni_dvp); @@ -2793,6 +2805,11 @@ nfsvno_advlock(struct vnode *vp, int fty if (nfsrv_dolocallocks == 0) return (0); + + /* Check for VI_DOOMED here, so that VOP_ADVLOCK() isn't performed. */ + if ((vp->v_iflag & VI_DOOMED) != 0) + return (EPERM); + fl.l_whence = SEEK_SET; fl.l_type = ftype; fl.l_start = (off_t)first; Modified: head/sys/fs/nfsserver/nfs_nfsdserv.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdserv.c Sun Jan 2 15:06:07 2011 (r216892) +++ head/sys/fs/nfsserver/nfs_nfsdserv.c Sun Jan 2 19:58:39 2011 (r216893) @@ -2676,9 +2676,12 @@ nfsrvd_open(struct nfsrv_descript *nd, _ }; stp->ls_flags |= NFSLCK_RECLAIM; vp = dp; - NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); - nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp, - nd, p, nd->nd_repstat); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + if ((vp->v_iflag & VI_DOOMED) == 0) + nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, + stp, vp, nd, p, nd->nd_repstat); + else + nd->nd_repstat = NFSERR_PERM; } else { nd->nd_repstat = NFSERR_BADXDR; vrele(dp); Modified: head/sys/fs/nfsserver/nfs_nfsdsocket.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdsocket.c Sun Jan 2 15:06:07 2011 (r216892) +++ head/sys/fs/nfsserver/nfs_nfsdsocket.c Sun Jan 2 19:58:39 2011 (r216893) @@ -902,13 +902,15 @@ nfsrvd_compound(struct nfsrv_descript *n nd->nd_repstat = NFSERR_XDEV; break; } - VREF(vp); - VREF(savevp); if (nfsv4_opflag[op].modifyfs) NFS_STARTWRITE(NULL, &mp); - NFSVOPLOCK(savevp, LK_EXCLUSIVE | LK_RETRY, p); - error = (*(nfsrv4_ops2[op]))(nd, isdgram, savevp, - vp, p, &savevpnes, &vpnes); + if (vn_lock(savevp, LK_EXCLUSIVE) == 0) { + VREF(vp); + VREF(savevp); + error = (*(nfsrv4_ops2[op]))(nd, isdgram, + savevp, vp, p, &savevpnes, &vpnes); + } else + nd->nd_repstat = NFSERR_PERM; if (nfsv4_opflag[op].modifyfs) NFS_ENDWRITE(mp); } else { @@ -916,12 +918,15 @@ nfsrvd_compound(struct nfsrv_descript *n panic("nfsrvd_compound"); if (nfsv4_opflag[op].needscfh) { if (vp != NULL) { + if (nfsv4_opflag[op].modifyfs) + NFS_STARTWRITE(NULL, &mp); if (vn_lock(vp, nfsv4_opflag[op].lktype) - != 0) + == 0) + VREF(vp); + else nd->nd_repstat = NFSERR_PERM; - } else + } else { nd->nd_repstat = NFSERR_NOFILEHANDLE; - if (nd->nd_repstat != 0) { if (op == NFSV4OP_SETATTR) { /* * Setattr reply requires a @@ -934,11 +939,9 @@ nfsrvd_compound(struct nfsrv_descript *n } break; } - VREF(vp); - if (nfsv4_opflag[op].modifyfs) - NFS_STARTWRITE(NULL, &mp); - error = (*(nfsrv4_ops0[op]))(nd, isdgram, vp, - p, &vpnes); + if (nd->nd_repstat == 0) + error = (*(nfsrv4_ops0[op]))(nd, + isdgram, vp, p, &vpnes); if (nfsv4_opflag[op].modifyfs) NFS_ENDWRITE(mp); } else { Modified: head/sys/fs/nfsserver/nfs_nfsdstate.c ============================================================================== --- head/sys/fs/nfsserver/nfs_nfsdstate.c Sun Jan 2 15:06:07 2011 (r216892) +++ head/sys/fs/nfsserver/nfs_nfsdstate.c Sun Jan 2 19:58:39 2011 (r216893) @@ -1659,7 +1659,7 @@ tryagain: if (new_stp->ls_flags & bits & NFSLCK_ACCESSBITS) { ret = nfsrv_clientconflict(tstp->ls_clp, &haslock, vp, p); - if (ret) { + if (ret == 1) { /* * nfsrv_clientconflict unlocks state * when it returns non-zero. @@ -1667,13 +1667,17 @@ tryagain: lckstp = NULL; goto tryagain; } - NFSUNLOCKSTATE(); + if (ret == 0) + NFSUNLOCKSTATE(); if (haslock) { NFSLOCKV4ROOTMUTEX(); nfsv4_unlock(&nfsv4rootfs_lock, 1); NFSUNLOCKV4ROOTMUTEX(); } - return (NFSERR_OPENMODE); + if (ret == 2) + return (NFSERR_PERM); + else + return (NFSERR_OPENMODE); } } } @@ -1826,7 +1830,7 @@ tryagain: other_lop = NULL; } ret = nfsrv_clientconflict(lop->lo_stp->ls_clp,&haslock,vp,p); - if (ret) { + if (ret == 1) { if (filestruct_locked != 0) { /* Roll back local locks. */ nfsrv_locallock_rollback(vp, lfp, p); @@ -1845,7 +1849,7 @@ tryagain: * Found a conflicting lock, so record the conflict and * return the error. */ - if (cfp) { + if (cfp != NULL && ret == 0) { cfp->cl_clientid.lval[0]=lop->lo_stp->ls_stateid.other[0]; cfp->cl_clientid.lval[1]=lop->lo_stp->ls_stateid.other[1]; cfp->cl_first = lop->lo_first; @@ -1855,20 +1859,23 @@ tryagain: NFSBCOPY(lop->lo_stp->ls_owner, cfp->cl_owner, cfp->cl_ownerlen); } - if (new_stp->ls_flags & NFSLCK_RECLAIM) + if (ret == 2) + error = NFSERR_PERM; + else if (new_stp->ls_flags & NFSLCK_RECLAIM) error = NFSERR_RECLAIMCONFLICT; else if (new_stp->ls_flags & NFSLCK_CHECK) error = NFSERR_LOCKED; else error = NFSERR_DENIED; - if (filestruct_locked != 0) { + if (filestruct_locked != 0 && ret == 0) { /* Roll back local locks. */ NFSUNLOCKSTATE(); nfsrv_locallock_rollback(vp, lfp, p); NFSLOCKSTATE(); nfsrv_unlocklf(lfp); } - NFSUNLOCKSTATE(); + if (ret == 0) + NFSUNLOCKSTATE(); if (haslock) { NFSLOCKV4ROOTMUTEX(); nfsv4_unlock(&nfsv4rootfs_lock, 1); @@ -2120,18 +2127,21 @@ tryagain: ((stp->ls_flags & NFSLCK_ACCESSBITS) & ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS)))){ ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p); - if (ret) { + if (ret == 1) { /* * nfsrv_clientconflict() unlocks * state when it returns non-zero. */ goto tryagain; } - if (new_stp->ls_flags & NFSLCK_RECLAIM) + if (ret == 2) + error = NFSERR_PERM; + else if (new_stp->ls_flags & NFSLCK_RECLAIM) error = NFSERR_RECLAIMCONFLICT; else error = NFSERR_SHAREDENIED; - NFSUNLOCKSTATE(); + if (ret == 0) + NFSUNLOCKSTATE(); if (haslock) { NFSLOCKV4ROOTMUTEX(); nfsv4_unlock(&nfsv4rootfs_lock, 1); @@ -2394,7 +2404,7 @@ tryagain: ((stp->ls_flags & NFSLCK_ACCESSBITS) & ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS))){ ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p); - if (ret) { + if (ret == 1) { /* * nfsrv_clientconflict() unlocks state * when it returns non-zero. @@ -2404,11 +2414,14 @@ tryagain: openstp = NULL; goto tryagain; } - if (new_stp->ls_flags & NFSLCK_RECLAIM) + if (ret == 2) + error = NFSERR_PERM; + else if (new_stp->ls_flags & NFSLCK_RECLAIM) error = NFSERR_RECLAIMCONFLICT; else error = NFSERR_SHAREDENIED; - NFSUNLOCKSTATE(); + if (ret == 0) + NFSUNLOCKSTATE(); if (haslock) { NFSLOCKV4ROOTMUTEX(); nfsv4_unlock(&nfsv4rootfs_lock, 1); @@ -4080,10 +4093,13 @@ nfsrv_updatestable(NFSPROC_T *p) NFSVNO_SETATTRVAL(&nva, size, 0); vp = NFSFPVNODE(sf->nsf_fp); NFS_STARTWRITE(vp, &mp); - NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); - error = nfsvno_setattr(vp, &nva, NFSFPCRED(sf->nsf_fp), p, NULL); + if (vn_lock(vp, LK_EXCLUSIVE) == 0) { + error = nfsvno_setattr(vp, &nva, NFSFPCRED(sf->nsf_fp), p, + NULL); + VOP_UNLOCK(vp, 0); + } else + error = EPERM; NFS_ENDWRITE(mp); - NFSVOPUNLOCK(vp, 0, p); if (!error) error = NFSD_RDWR(UIO_WRITE, vp, (caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), (off_t)0, @@ -4211,10 +4227,11 @@ nfsrv_checkstable(struct nfsclient *clp) * Return 0 to indicate the conflict can't be revoked and 1 to indicate * the revocation worked and the conflicting client is "bye, bye", so it * can be tried again. + * Return 2 to indicate that the vnode is VI_DOOMED after vn_lock(). * Unlocks State before a non-zero value is returned. */ static int -nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, __unused vnode_t vp, +nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, vnode_t vp, NFSPROC_T *p) { int gotlock, lktype; @@ -4238,7 +4255,10 @@ nfsrv_clientconflict(struct nfsclient *c NFSUNLOCKV4ROOTMUTEX(); *haslockp = 1; vn_lock(vp, lktype | LK_RETRY); - return (1); + if ((vp->v_iflag & VI_DOOMED) != 0) + return (2); + else + return (1); } NFSUNLOCKSTATE(); @@ -4254,7 +4274,6 @@ nfsrv_clientconflict(struct nfsclient *c return (1); } - /* * Resolve a delegation conflict. * Returns 0 to indicate the conflict was resolved without sleeping. @@ -4403,6 +4422,13 @@ nfsrv_delegconflict(struct nfsstate *stp NFSUNLOCKV4ROOTMUTEX(); *haslockp = 1; vn_lock(vp, lktype | LK_RETRY); + if ((vp->v_iflag & VI_DOOMED) != 0) { + *haslockp = 0; + NFSLOCKV4ROOTMUTEX(); + nfsv4_unlock(&nfsv4rootfs_lock, 1); + NFSUNLOCKV4ROOTMUTEX(); + return (NFSERR_PERM); + } return (-1); } @@ -4594,12 +4620,11 @@ nfsd_recalldelegation(vnode_t vp, NFSPRO NFSGETNANOTIME(&mytime); starttime = (u_int32_t)mytime.tv_sec; do { - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); - if ((vp->v_iflag & VI_DOOMED) == 0) + if (vn_lock(vp, LK_EXCLUSIVE) == 0) { error = nfsrv_checkremove(vp, 0, p); - else + VOP_UNLOCK(vp, 0); + } else error = EPERM; - VOP_UNLOCK(vp, 0); if (error == NFSERR_DELAY) { NFSGETNANOTIME(&mytime); if (((u_int32_t)mytime.tv_sec - starttime) >