Skip site navigation (1)Skip section navigation (2)
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>