svn commit: r185586 - head/sys/nfsserver

Alexander Kabaev kan at FreeBSD.org
Wed Dec 3 09:54:10 PST 2008


Author: kan
Date: Wed Dec  3 17:54:09 2008
New Revision: 185586
URL: http://svn.freebsd.org/changeset/base/185586

Log:
  Change nfsserver slightly so that it does not trip over the timestamp
  validation code on ZFS.
  
  Problem: when opening file with O_CREAT|O_EXCL NFS has to jump through
  extra hoops to ensure O_EXCL semantics. Namely, client supplies of 8
  bytes (NFSX_V3CREATEVERF) bytes of verification data to uniquely
  identify this create request. Server then creates a new file with access
  mode 0, copies received 8 bytes into va_atime member of struct vattr and
  attempt to set the atime on file using VOP_SETATTR. If that succeeds, it
  fetches file attributes with VOP_GETATTR and verifies that atime
  timestamps match.  If timestamps do not match, NFS server concludes it
  has probbaly lost the race to another process creating the file with the
  same name and bails with EEXIST.
  
  This scheme works OK when exported FS is FFS, but if underlying
  filesystem is ZFS _and_ server is running 64bit kernel, it breaks down
  due to sanity checking in zfs_setattr function, which refuses to accept
  any timestamps which have tv_sec that cannot be represented as 32bit
  int. Since struct timespec fields are 64 bit integers on 64bit platforms
  and server just copies NFSX_V3CREATEVERF bytes info va_atime, all eight
  bytes supplied by client end up in va_atime.tv_sec, forcing it out of
  valid 32bit range.
  
  The solution this change implements is simple: it treats
  NFSX_V3CREATEVERF as two 32bit integers and unpacks them separately into
  va_atime.tv_sec and va_atime.tv_nsec respectively, thus guaranteeing
  that tv_sec remains in 32 bit range and ZFS remains happy.
  
  Reviewed by: kib

Modified:
  head/sys/nfsserver/nfs_serv.c

Modified: head/sys/nfsserver/nfs_serv.c
==============================================================================
--- head/sys/nfsserver/nfs_serv.c	Wed Dec  3 17:30:36 2008	(r185585)
+++ head/sys/nfsserver/nfs_serv.c	Wed Dec  3 17:54:09 2008	(r185586)
@@ -1669,13 +1669,12 @@ nfsrv_create(struct nfsrv_descript *nfsd
 	caddr_t bpos;
 	int error = 0, rdev, len, tsize, dirfor_ret = 1, diraft_ret = 1;
 	int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
-	caddr_t cp;
 	struct mbuf *mb, *mreq;
 	struct vnode *dirp = NULL;
 	nfsfh_t nfh;
 	fhandle_t *fhp;
 	u_quad_t tempsize;
-	u_char cverf[NFSX_V3CREATEVERF];
+	struct timespec cverf;
 	struct mount *mp = NULL;
 	int tvfslocked;
 	int vfslocked;
@@ -1754,8 +1753,11 @@ nfsrv_create(struct nfsrv_descript *nfsd
 			nfsm_srvsattr(vap);
 			break;
 		case NFSV3CREATE_EXCLUSIVE:
-			cp = nfsm_dissect_nonblock(caddr_t, NFSX_V3CREATEVERF);
-			bcopy(cp, cverf, NFSX_V3CREATEVERF);
+			tl = nfsm_dissect_nonblock(u_int32_t *,
+			    NFSX_V3CREATEVERF);
+			/* Unique bytes, endianness is not important. */
+			cverf.tv_sec  = tl[0];
+			cverf.tv_nsec = tl[1];
 			exclusive_flag = 1;
 			break;
 		};
@@ -1801,8 +1803,7 @@ nfsrv_create(struct nfsrv_descript *nfsd
 				if (exclusive_flag) {
 					exclusive_flag = 0;
 					VATTR_NULL(vap);
-					bcopy(cverf, (caddr_t)&vap->va_atime,
-						NFSX_V3CREATEVERF);
+					vap->va_atime = cverf;
 					error = VOP_SETATTR(nd.ni_vp, vap,
 					    cred);
 				}
@@ -1886,7 +1887,7 @@ nfsrv_create(struct nfsrv_descript *nfsd
 	}
 	if (v3) {
 		if (exclusive_flag && !error &&
-			bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
+		    bcmp(&cverf, &vap->va_atime, sizeof (cverf)))
 			error = EEXIST;
 		if (dirp == nd.ni_dvp)
 			diraft_ret = VOP_GETATTR(dirp, &diraft, cred);


More information about the svn-src-all mailing list