Date: Wed, 3 Jan 2001 23:54:30 -0800 (PST) From: Matt Dillon <dillon@earth.backplane.com> To: Marc Culler <culler@math.uic.edu>, freebsd-stable@FreeBSD.ORG Subject: NFSv3 O_EXCL file create - protocol spec & solution (was Re: Bug in NFSv3 client) Message-ID: <200101040754.f047sUW55674@earth.backplane.com> References: <20010103155533.B71238@math.uic.edu> <200101032243.f03Mhar51440@earth.backplane.com> <200101032308.f03N84f51776@earth.backplane.com> <200101032322.f03NMTK51973@earth.backplane.com>
next in thread | previous in thread | raw e-mail | index | archive | help
The RFC (1813) says that the exclusive-file-create NFS op passes a
verifier. It says, and I quote:
"One aspect of the NFS version 3 protocol CREATE procedure
warrants particularly careful consideration: the mechanism
introduced to support the reliable exclusive creation of
regular files. The mechanism comes into play when how.mode
is EXCLUSIVE. In this case, how.verf contains a verifier
that can reasonably be expected to be unique. A
combination of a client identifier, perhaps the client
network address, and a unique number generated by the
client, perhaps the RPC transaction identifier, may be
appropriate."
What that means is that the verifier can be anything.
Here's why the FreeBSD server was storing the verifier as the
file access time:
"verifier must be stored in stable storage to prevent
erroneous failure on retransmission of the request. It is
assumed that an exclusive create is being performed
because exclusive semantics are critical to the
application. Because of the expected usage, exclusive
CREATE does not rely solely on the normally volatile
duplicate request cache for storage of the verifier. The
duplicate request cache in volatile storage does not
survive a crash and may actually flush on a long network
partition, opening failure windows. In the UNIX local
file system environment, the expected storage location for
the verifier on creation is the metadata (time stamps) of
the file. For this reason, an exclusive file create may
not include initial attributes because the server would
have nowhere to store the verifier."
Ahhh, so now we know why FreeBSD is passing the IP address of
the interface plus a 'unique' number! Or trying anyway.
And also:
"Once the client has performed a successful exclusive
create, it must issue a SETATTR to set the correct file
attributes. Until it does so, it should not rely upon any
of the file attributes, since the server implementation
may need to overload file metadata to store the verifier."
What this means is that the FreeBSD client is supposed to call
SETATTR to set the correct file attributes after the O_EXCL open
succeeds. It is in fact doing this, but the 'atime' attribute
in the 'vap' structure is not initialized, so the SETATTR call
never actually fixes up the access time.
Solaris probably shouldn't be generating an error for the 'bogus'
time specification, as that can race with an O_EXCL create, but
I think fixing the FreeBSD clients to do the proper SETATTR
should solve the problem.
I've included the patch below. The patch will fix FreeBSD
clients. I will commit it to -current now and to -stable in
two days if there aren't any problems. (Throw away any previous
patches you might have applied).
-Matt
Index: nfs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/nfs_vnops.c,v
retrieving revision 1.150
diff -u -r1.150 nfs_vnops.c
--- nfs_vnops.c 2000/01/05 00:32:18 1.150
+++ nfs_vnops.c 2001/01/04 07:48:37
@@ -1436,8 +1436,21 @@
}
if (newvp)
vput(newvp);
- } else if (v3 && (fmode & O_EXCL))
+ } else if (v3 && (fmode & O_EXCL)) {
+ /*
+ * We are normally called with only a partially initialized
+ * VAP. Since the NFSv3 spec says that server may use the
+ * file attributes to store the verifier, the spec requires
+ * us to do a SETATTR RPC. FreeBSD servers store the verifier
+ * in atime, but we can't really assume that all servers will
+ * so we ensure that our SETATTR sets both atime and mtime.
+ */
+ if (vap->va_mtime.tv_sec == VNOVAL)
+ vfs_timestamp(&vap->va_mtime);
+ if (vap->va_atime.tv_sec == VNOVAL)
+ vap->va_atime = vap->va_mtime;
error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
+ }
if (!error) {
if (cnp->cn_flags & MAKEENTRY)
cache_enter(dvp, newvp, cnp);
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-stable" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200101040754.f047sUW55674>
