Commit aa53ed54 authored by Jeff Layton's avatar Jeff Layton Committed by Trond Myklebust

NFS4: on a O_EXCL OPEN make sure SETATTR sets the fields holding the verifier

The Linux NFS4 client simply skips over the bitmask in an O_EXCL open
call and so it doesn't bother to reset any fields that may be holding
the verifier. This patch has us save the first two words of the bitmask
(which is all the current client has #defines for). The client then
later checks this bitmask and turns on the appropriate flags in the
sattr->ia_verify field for the following SETATTR call.

This patch only currently checks to see if the server used the atime
and mtime slots for the verifier (which is what the Linux server uses
for this). I'm not sure of what other fields the server could
reasonably use, but adding checks for others should be trivial.
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent fc6ae3cf
...@@ -942,6 +942,22 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st ...@@ -942,6 +942,22 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st
return res; return res;
} }
/*
* on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-*
* fields corresponding to attributes that were used to store the verifier.
* Make sure we clobber those fields in the later setattr call
*/
static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr)
{
if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) &&
!(sattr->ia_valid & ATTR_ATIME_SET))
sattr->ia_valid |= ATTR_ATIME;
if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) &&
!(sattr->ia_valid & ATTR_MTIME_SET))
sattr->ia_valid |= ATTR_MTIME;
}
/* /*
* Returns a referenced nfs4_state * Returns a referenced nfs4_state
*/ */
...@@ -973,6 +989,9 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct ...@@ -973,6 +989,9 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct
if (status != 0) if (status != 0)
goto err_opendata_free; goto err_opendata_free;
if (opendata->o_arg.open_flags & O_EXCL)
nfs4_exclusive_attrset(opendata, sattr);
status = -ENOMEM; status = -ENOMEM;
state = nfs4_opendata_to_nfs4_state(opendata); state = nfs4_opendata_to_nfs4_state(opendata);
if (state == NULL) if (state == NULL)
...@@ -1784,6 +1803,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ...@@ -1784,6 +1803,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = nfs4_do_setattr(state->inode, &fattr, sattr, state); status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
if (status == 0) if (status == 0)
nfs_setattr_update_inode(state->inode, sattr); nfs_setattr_update_inode(state->inode, sattr);
nfs_post_op_update_inode(state->inode, &fattr);
} }
if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
status = nfs4_intent_set_file(nd, &path, state); status = nfs4_intent_set_file(nd, &path, state);
......
...@@ -3269,7 +3269,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) ...@@ -3269,7 +3269,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{ {
__be32 *p; __be32 *p;
uint32_t bmlen; uint32_t savewords, bmlen, i;
int status; int status;
status = decode_op_hdr(xdr, OP_OPEN); status = decode_op_hdr(xdr, OP_OPEN);
...@@ -3287,7 +3287,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) ...@@ -3287,7 +3287,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
goto xdr_error; goto xdr_error;
READ_BUF(bmlen << 2); READ_BUF(bmlen << 2);
p += bmlen; savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
for (i = 0; i < savewords; ++i)
READ32(res->attrset[i]);
for (; i < NFS4_BITMAP_SIZE; i++)
res->attrset[i] = 0;
return decode_delegation(xdr, res); return decode_delegation(xdr, res);
xdr_error: xdr_error:
dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen); dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/types.h> #include <linux/types.h>
#define NFS4_BITMAP_SIZE 2
#define NFS4_VERIFIER_SIZE 8 #define NFS4_VERIFIER_SIZE 8
#define NFS4_STATEID_SIZE 16 #define NFS4_STATEID_SIZE 16
#define NFS4_FHSIZE 128 #define NFS4_FHSIZE 128
......
...@@ -144,6 +144,7 @@ struct nfs_openres { ...@@ -144,6 +144,7 @@ struct nfs_openres {
nfs4_stateid delegation; nfs4_stateid delegation;
__u32 do_recall; __u32 do_recall;
__u64 maxsize; __u64 maxsize;
__u32 attrset[NFS4_BITMAP_SIZE];
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment