Date: Sun, 2 Jan 2011 19:58:39 +0000 (UTC) From: Rick Macklem <rmacklem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r216893 - head/sys/fs/nfsserver Message-ID: <201101021958.p02JwdtC056657@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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) >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101021958.p02JwdtC056657>