summaryrefslogtreecommitdiff
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c49
1 files changed, 33 insertions, 16 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 3eb53d7784e2..b71757e85066 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2750,27 +2750,40 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
* 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,
+static unsigned nfs4_exclusive_attrset(struct nfs4_opendata *opendata,
struct iattr *sattr, struct nfs4_label **label)
{
- const u32 *attrset = opendata->o_res.attrset;
+ const __u32 *bitmask = opendata->o_arg.server->exclcreat_bitmask;
+ __u32 attrset[3];
+ unsigned ret;
+ unsigned i;
- if ((attrset[1] & FATTR4_WORD1_TIME_ACCESS) &&
- !(sattr->ia_valid & ATTR_ATIME_SET))
- sattr->ia_valid |= ATTR_ATIME;
+ for (i = 0; i < ARRAY_SIZE(attrset); i++) {
+ attrset[i] = opendata->o_res.attrset[i];
+ if (opendata->o_arg.createmode == NFS4_CREATE_EXCLUSIVE4_1)
+ attrset[i] &= ~bitmask[i];
+ }
+
+ ret = (opendata->o_arg.createmode == NFS4_CREATE_EXCLUSIVE) ?
+ sattr->ia_valid : 0;
- if ((attrset[1] & FATTR4_WORD1_TIME_MODIFY) &&
- !(sattr->ia_valid & ATTR_MTIME_SET))
- sattr->ia_valid |= ATTR_MTIME;
+ if ((attrset[1] & (FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET))) {
+ if (sattr->ia_valid & ATTR_ATIME_SET)
+ ret |= ATTR_ATIME_SET;
+ else
+ ret |= ATTR_ATIME;
+ }
- /* Except MODE, it seems harmless of setting twice. */
- if (opendata->o_arg.createmode != NFS4_CREATE_EXCLUSIVE &&
- (attrset[1] & FATTR4_WORD1_MODE ||
- attrset[2] & FATTR4_WORD2_MODE_UMASK))
- sattr->ia_valid &= ~ATTR_MODE;
+ if ((attrset[1] & (FATTR4_WORD1_TIME_MODIFY|FATTR4_WORD1_TIME_MODIFY_SET))) {
+ if (sattr->ia_valid & ATTR_MTIME_SET)
+ ret |= ATTR_MTIME_SET;
+ else
+ ret |= ATTR_MTIME;
+ }
- if (attrset[2] & FATTR4_WORD2_SECURITY_LABEL)
+ if (!(attrset[2] & FATTR4_WORD2_SECURITY_LABEL))
*label = NULL;
+ return ret;
}
static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
@@ -2899,12 +2912,15 @@ static int _nfs4_do_open(struct inode *dir,
if ((opendata->o_arg.open_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) &&
(opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) {
- nfs4_exclusive_attrset(opendata, sattr, &label);
+ unsigned attrs = nfs4_exclusive_attrset(opendata, sattr, &label);
/*
* send create attributes which was not set by open
* with an extra setattr.
*/
- if (sattr->ia_valid & NFS4_VALID_ATTRS) {
+ if (attrs || label) {
+ unsigned ia_old = sattr->ia_valid;
+
+ sattr->ia_valid = attrs;
nfs_fattr_init(opendata->o_res.f_attr);
status = nfs4_do_setattr(state->inode, cred,
opendata->o_res.f_attr, sattr,
@@ -2914,6 +2930,7 @@ static int _nfs4_do_open(struct inode *dir,
opendata->o_res.f_attr);
nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
}
+ sattr->ia_valid = ia_old;
}
}
if (opened && opendata->file_created)