aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2007-06-05 14:49:03 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-10 23:40:25 -0400
commitaa53ed541a1fec78a78d02afc8b042d040cc080d (patch)
tree04d4c66b643e4ec9ec1277f3ad642b18f3f94990
parentfc6ae3cf482c385a6fe87ba119d399bb85aa670b (diff)
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: Jeff Layton <jlayton@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/nfs4proc.c20
-rw-r--r--fs/nfs/nfs4xdr.c9
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs_xdr.h1
4 files changed, 29 insertions, 2 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 3cc75445a68..fee2d14b158 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -943,6 +943,22 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st
943} 943}
944 944
945/* 945/*
946 * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-*
947 * fields corresponding to attributes that were used to store the verifier.
948 * Make sure we clobber those fields in the later setattr call
949 */
950static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr)
951{
952 if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) &&
953 !(sattr->ia_valid & ATTR_ATIME_SET))
954 sattr->ia_valid |= ATTR_ATIME;
955
956 if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) &&
957 !(sattr->ia_valid & ATTR_MTIME_SET))
958 sattr->ia_valid |= ATTR_MTIME;
959}
960
961/*
946 * Returns a referenced nfs4_state 962 * Returns a referenced nfs4_state
947 */ 963 */
948static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) 964static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
@@ -973,6 +989,9 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct
973 if (status != 0) 989 if (status != 0)
974 goto err_opendata_free; 990 goto err_opendata_free;
975 991
992 if (opendata->o_arg.open_flags & O_EXCL)
993 nfs4_exclusive_attrset(opendata, sattr);
994
976 status = -ENOMEM; 995 status = -ENOMEM;
977 state = nfs4_opendata_to_nfs4_state(opendata); 996 state = nfs4_opendata_to_nfs4_state(opendata);
978 if (state == NULL) 997 if (state == NULL)
@@ -1784,6 +1803,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
1784 status = nfs4_do_setattr(state->inode, &fattr, sattr, state); 1803 status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
1785 if (status == 0) 1804 if (status == 0)
1786 nfs_setattr_update_inode(state->inode, sattr); 1805 nfs_setattr_update_inode(state->inode, sattr);
1806 nfs_post_op_update_inode(state->inode, &fattr);
1787 } 1807 }
1788 if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) 1808 if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
1789 status = nfs4_intent_set_file(nd, &path, state); 1809 status = nfs4_intent_set_file(nd, &path, state);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 8003c91ccb9..1fcca516e6e 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -3269,7 +3269,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
3269static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) 3269static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
3270{ 3270{
3271 __be32 *p; 3271 __be32 *p;
3272 uint32_t bmlen; 3272 uint32_t savewords, bmlen, i;
3273 int status; 3273 int status;
3274 3274
3275 status = decode_op_hdr(xdr, OP_OPEN); 3275 status = decode_op_hdr(xdr, OP_OPEN);
@@ -3287,7 +3287,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
3287 goto xdr_error; 3287 goto xdr_error;
3288 3288
3289 READ_BUF(bmlen << 2); 3289 READ_BUF(bmlen << 2);
3290 p += bmlen; 3290 savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
3291 for (i = 0; i < savewords; ++i)
3292 READ32(res->attrset[i]);
3293 for (; i < NFS4_BITMAP_SIZE; i++)
3294 res->attrset[i] = 0;
3295
3291 return decode_delegation(xdr, res); 3296 return decode_delegation(xdr, res);
3292xdr_error: 3297xdr_error:
3293 dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen); 3298 dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen);
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 7e7f33a38fc..8726491de15 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -15,6 +15,7 @@
15 15
16#include <linux/types.h> 16#include <linux/types.h>
17 17
18#define NFS4_BITMAP_SIZE 2
18#define NFS4_VERIFIER_SIZE 8 19#define NFS4_VERIFIER_SIZE 8
19#define NFS4_STATEID_SIZE 16 20#define NFS4_STATEID_SIZE 16
20#define NFS4_FHSIZE 128 21#define NFS4_FHSIZE 128
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 10c26ed0db7..f7100df3a69 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -144,6 +144,7 @@ struct nfs_openres {
144 nfs4_stateid delegation; 144 nfs4_stateid delegation;
145 __u32 do_recall; 145 __u32 do_recall;
146 __u64 maxsize; 146 __u64 maxsize;
147 __u32 attrset[NFS4_BITMAP_SIZE];
147}; 148};
148 149
149/* 150/*