Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 May 2012 12:10:12 GMT
From:      dfilter@FreeBSD.ORG (dfilter service)
To:        freebsd-fs@FreeBSD.org
Subject:   Re: kern/165923: commit references a PR
Message-ID:  <201205121210.q4CCACtL043066@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/165923; it has been noted by GNATS.

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/165923: commit references a PR
Date: Sat, 12 May 2012 12:03:08 +0000 (UTC)

 Author: rmacklem
 Date: Sat May 12 12:02:51 2012
 New Revision: 235332
 URL: http://svn.freebsd.org/changeset/base/235332
 
 Log:
   PR# 165923 reported intermittent write failures for dirty
   memory mapped pages being written back on an NFS mount.
   Since any thread can call VOP_PUTPAGES() to write back a
   dirty page, the credentials of that thread may not have
   write access to the file on an NFS server. (Often the uid
   is 0, which may be mapped to "nobody" in the NFS server.)
   Although there is no completely correct fix for this
   (NFS servers check access on every write RPC instead of at
   open/mmap time), this patch avoids the common cases by
   holding onto a credential that recently opened the file
   for writing and uses that credential for the write RPCs
   being done by VOP_PUTPAGES() for both NFS clients.
   
   Tested by:	Joel Ray Holveck (joelh at juniper.net)
   PR:		kern/165923
   Reviewed by:	kib
   MFC after:	2 weeks
 
 Modified:
   head/sys/fs/nfsclient/nfs_clbio.c
   head/sys/fs/nfsclient/nfs_clnode.c
   head/sys/fs/nfsclient/nfs_clvnops.c
   head/sys/fs/nfsclient/nfsnode.h
   head/sys/nfsclient/nfs_bio.c
   head/sys/nfsclient/nfs_node.c
   head/sys/nfsclient/nfs_vnops.c
   head/sys/nfsclient/nfsnode.h
 
 Modified: head/sys/fs/nfsclient/nfs_clbio.c
 ==============================================================================
 --- head/sys/fs/nfsclient/nfs_clbio.c	Sat May 12 10:53:49 2012	(r235331)
 +++ head/sys/fs/nfsclient/nfs_clbio.c	Sat May 12 12:02:51 2012	(r235332)
 @@ -281,7 +281,11 @@ ncl_putpages(struct vop_putpages_args *a
  	vp = ap->a_vp;
  	np = VTONFS(vp);
  	td = curthread;				/* XXX */
 -	cred = curthread->td_ucred;		/* XXX */
 +	/* Set the cred to n_writecred for the write rpcs. */
 +	if (np->n_writecred != NULL)
 +		cred = crhold(np->n_writecred);
 +	else
 +		cred = crhold(curthread->td_ucred);	/* XXX */
  	nmp = VFSTONFS(vp->v_mount);
  	pages = ap->a_m;
  	count = ap->a_count;
 @@ -345,6 +349,7 @@ ncl_putpages(struct vop_putpages_args *a
  	    iomode = NFSWRITE_FILESYNC;
  
  	error = ncl_writerpc(vp, &uio, cred, &iomode, &must_commit, 0);
 +	crfree(cred);
  
  	pmap_qremove(kva, npages);
  	relpbuf(bp, &ncl_pbuf_freecnt);
 
 Modified: head/sys/fs/nfsclient/nfs_clnode.c
 ==============================================================================
 --- head/sys/fs/nfsclient/nfs_clnode.c	Sat May 12 10:53:49 2012	(r235331)
 +++ head/sys/fs/nfsclient/nfs_clnode.c	Sat May 12 12:02:51 2012	(r235332)
 @@ -300,6 +300,8 @@ ncl_reclaim(struct vop_reclaim_args *ap)
  			FREE((caddr_t)dp2, M_NFSDIROFF);
  		}
  	}
 +	if (np->n_writecred != NULL)
 +		crfree(np->n_writecred);
  	FREE((caddr_t)np->n_fhp, M_NFSFH);
  	if (np->n_v4 != NULL)
  		FREE((caddr_t)np->n_v4, M_NFSV4NODE);
 
 Modified: head/sys/fs/nfsclient/nfs_clvnops.c
 ==============================================================================
 --- head/sys/fs/nfsclient/nfs_clvnops.c	Sat May 12 10:53:49 2012	(r235331)
 +++ head/sys/fs/nfsclient/nfs_clvnops.c	Sat May 12 12:02:51 2012	(r235332)
 @@ -513,6 +513,7 @@ nfs_open(struct vop_open_args *ap)
  	struct vattr vattr;
  	int error;
  	int fmode = ap->a_mode;
 +	struct ucred *cred;
  
  	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
  		return (EOPNOTSUPP);
 @@ -604,7 +605,22 @@ nfs_open(struct vop_open_args *ap)
  		}
  		np->n_directio_opens++;
  	}
 +
 +	/*
 +	 * If this is an open for writing, capture a reference to the
 +	 * credentials, so they can be used by ncl_putpages(). Using
 +	 * these write credentials is preferable to the credentials of
 +	 * whatever thread happens to be doing the VOP_PUTPAGES() since
 +	 * the write RPCs are less likely to fail with EACCES.
 +	 */
 +	if ((fmode & FWRITE) != 0) {
 +		cred = np->n_writecred;
 +		np->n_writecred = crhold(ap->a_cred);
 +	} else
 +		cred = NULL;
  	mtx_unlock(&np->n_mtx);
 +	if (cred != NULL)
 +		crfree(cred);
  	vnode_create_vobject(vp, vattr.va_size, ap->a_td);
  	return (0);
  }
 
 Modified: head/sys/fs/nfsclient/nfsnode.h
 ==============================================================================
 --- head/sys/fs/nfsclient/nfsnode.h	Sat May 12 10:53:49 2012	(r235331)
 +++ head/sys/fs/nfsclient/nfsnode.h	Sat May 12 12:02:51 2012	(r235332)
 @@ -123,6 +123,7 @@ struct nfsnode {
  	int                     n_directio_asyncwr;
  	u_int64_t		 n_change;	/* old Change attribute */
  	struct nfsv4node	*n_v4;		/* extra V4 stuff */
 +	struct ucred		*n_writecred;	/* Cred. for putpages */
  };
  
  #define	n_atim		n_un1.nf_atim
 
 Modified: head/sys/nfsclient/nfs_bio.c
 ==============================================================================
 --- head/sys/nfsclient/nfs_bio.c	Sat May 12 10:53:49 2012	(r235331)
 +++ head/sys/nfsclient/nfs_bio.c	Sat May 12 12:02:51 2012	(r235332)
 @@ -275,7 +275,11 @@ nfs_putpages(struct vop_putpages_args *a
  	vp = ap->a_vp;
  	np = VTONFS(vp);
  	td = curthread;				/* XXX */
 -	cred = curthread->td_ucred;		/* XXX */
 +	/* Set the cred to n_writecred for the write rpcs. */
 +	if (np->n_writecred != NULL)
 +		cred = crhold(np->n_writecred);
 +	else
 +		cred = crhold(curthread->td_ucred);	/* XXX */
  	nmp = VFSTONFS(vp->v_mount);
  	pages = ap->a_m;
  	count = ap->a_count;
 @@ -339,6 +343,7 @@ nfs_putpages(struct vop_putpages_args *a
  	    iomode = NFSV3WRITE_FILESYNC;
  
  	error = (nmp->nm_rpcops->nr_writerpc)(vp, &uio, cred, &iomode, &must_commit);
 +	crfree(cred);
  
  	pmap_qremove(kva, npages);
  	relpbuf(bp, &nfs_pbuf_freecnt);
 
 Modified: head/sys/nfsclient/nfs_node.c
 ==============================================================================
 --- head/sys/nfsclient/nfs_node.c	Sat May 12 10:53:49 2012	(r235331)
 +++ head/sys/nfsclient/nfs_node.c	Sat May 12 12:02:51 2012	(r235332)
 @@ -270,6 +270,8 @@ nfs_reclaim(struct vop_reclaim_args *ap)
  			free((caddr_t)dp2, M_NFSDIROFF);
  		}
  	}
 +	if (np->n_writecred != NULL)
 +		crfree(np->n_writecred);
  	if (np->n_fhsize > NFS_SMALLFH) {
  		free((caddr_t)np->n_fhp, M_NFSBIGFH);
  	}
 
 Modified: head/sys/nfsclient/nfs_vnops.c
 ==============================================================================
 --- head/sys/nfsclient/nfs_vnops.c	Sat May 12 10:53:49 2012	(r235331)
 +++ head/sys/nfsclient/nfs_vnops.c	Sat May 12 12:02:51 2012	(r235332)
 @@ -507,6 +507,7 @@ nfs_open(struct vop_open_args *ap)
  	struct vattr vattr;
  	int error;
  	int fmode = ap->a_mode;
 +	struct ucred *cred;
  
  	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
  		return (EOPNOTSUPP);
 @@ -563,7 +564,22 @@ nfs_open(struct vop_open_args *ap)
  		}
  		np->n_directio_opens++;
  	}
 +
 +	/*
 +	 * If this is an open for writing, capture a reference to the
 +	 * credentials, so they can be used by nfs_putpages(). Using
 +	 * these write credentials is preferable to the credentials of
 +	 * whatever thread happens to be doing the VOP_PUTPAGES() since
 +	 * the write RPCs are less likely to fail with EACCES.
 +	 */
 +	if ((fmode & FWRITE) != 0) {
 +		cred = np->n_writecred;
 +		np->n_writecred = crhold(ap->a_cred);
 +	} else
 +		cred = NULL;
  	mtx_unlock(&np->n_mtx);
 +	if (cred != NULL)
 +		crfree(cred);
  	vnode_create_vobject(vp, vattr.va_size, ap->a_td);
  	return (0);
  }
 
 Modified: head/sys/nfsclient/nfsnode.h
 ==============================================================================
 --- head/sys/nfsclient/nfsnode.h	Sat May 12 10:53:49 2012	(r235331)
 +++ head/sys/nfsclient/nfsnode.h	Sat May 12 12:02:51 2012	(r235332)
 @@ -128,6 +128,7 @@ struct nfsnode {
  	uint32_t		n_namelen;
  	int			n_directio_opens;
  	int                     n_directio_asyncwr;
 +	struct ucred		*n_writecred;	/* Cred. for putpages */
  };
  
  #define n_atim		n_un1.nf_atim
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201205121210.q4CCACtL043066>