aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/dir.c7
-rw-r--r--fs/nfs/nfs4proc.c16
-rw-r--r--fs/nfs/nfs4xdr.c36
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs_xdr.h2
5 files changed, 45 insertions, 17 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 7483722162fa..cb22a9f9ae7e 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1529,8 +1529,13 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
return -ENAMETOOLONG;
if (open_flags & O_CREAT) {
+ struct nfs_server *server = NFS_SERVER(dir);
+
+ if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
+ mode &= ~current_umask();
+
attr.ia_valid |= ATTR_MODE;
- attr.ia_mode = mode & ~current_umask();
+ attr.ia_mode = mode;
}
if (open_flags & O_TRUNC) {
attr.ia_valid |= ATTR_SIZE;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c5a508669655..d33242c8d95d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1224,6 +1224,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
atomic_inc(&sp->so_count);
p->o_arg.open_flags = flags;
p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
+ p->o_arg.umask = current_umask();
p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
p->o_arg.share_access = nfs4_map_atomic_open_share(server,
fmode, flags);
@@ -3337,7 +3338,7 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
#define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
#define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL)
-#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_SECURITY_LABEL - 1UL)
+#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_MODE_UMASK - 1UL)
static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
{
@@ -4010,6 +4011,7 @@ static int
nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
int flags)
{
+ struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_label l, *ilabel = NULL;
struct nfs_open_context *ctx;
struct nfs4_state *state;
@@ -4021,7 +4023,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
- sattr->ia_mode &= ~current_umask();
+ if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
+ sattr->ia_mode &= ~current_umask();
state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, NULL);
if (IS_ERR(state)) {
status = PTR_ERR(state);
@@ -4229,6 +4232,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
data->arg.attrs = sattr;
data->arg.ftype = ftype;
data->arg.bitmask = nfs4_bitmask(server, data->label);
+ data->arg.umask = current_umask();
data->res.server = server;
data->res.fh = &data->fh;
data->res.fattr = &data->fattr;
@@ -4326,13 +4330,15 @@ out:
static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
struct iattr *sattr)
{
+ struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_exception exception = { };
struct nfs4_label l, *label = NULL;
int err;
label = nfs4_label_init_security(dir, dentry, sattr, &l);
- sattr->ia_mode &= ~current_umask();
+ if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
+ sattr->ia_mode &= ~current_umask();
do {
err = _nfs4_proc_mkdir(dir, dentry, sattr, label);
trace_nfs4_mkdir(dir, &dentry->d_name, err);
@@ -4435,13 +4441,15 @@ out:
static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
struct iattr *sattr, dev_t rdev)
{
+ struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_exception exception = { };
struct nfs4_label l, *label = NULL;
int err;
label = nfs4_label_init_security(dir, dentry, sattr, &l);
- sattr->ia_mode &= ~current_umask();
+ if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
+ sattr->ia_mode &= ~current_umask();
do {
err = _nfs4_proc_mknod(dir, dentry, sattr, label, rdev);
trace_nfs4_mknod(dir, &dentry->d_name, err);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 1c1768a8fcd1..1af6268a7d8c 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -52,6 +52,7 @@
#include <linux/nfs.h>
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
+#include <linux/fs_struct.h>
#include "nfs4_fs.h"
#include "internal.h"
@@ -1008,7 +1009,7 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
const struct nfs4_label *label,
const struct nfs_server *server,
- bool excl_check)
+ bool excl_check, const umode_t *umask)
{
char owner_name[IDMAP_NAMESZ];
char owner_group[IDMAP_NAMESZ];
@@ -1022,18 +1023,21 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
/*
* We reserve enough space to write the entire attribute buffer at once.
- * In the worst-case, this would be
- * 16(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
- * = 40 bytes, plus any contribution from variable-length fields
- * such as owner/group.
*/
if (iap->ia_valid & ATTR_SIZE) {
bmval[0] |= FATTR4_WORD0_SIZE;
len += 8;
}
+ if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
+ umask = NULL;
if (iap->ia_valid & ATTR_MODE) {
- bmval[1] |= FATTR4_WORD1_MODE;
- len += 4;
+ if (umask) {
+ bmval[2] |= FATTR4_WORD2_MODE_UMASK;
+ len += 8;
+ } else {
+ bmval[1] |= FATTR4_WORD1_MODE;
+ len += 4;
+ }
}
if (iap->ia_valid & ATTR_UID) {
owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
@@ -1134,6 +1138,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
*p++ = cpu_to_be32(label->len);
p = xdr_encode_opaque_fixed(p, label->label, label->len);
}
+ if (bmval[2] & FATTR4_WORD2_MODE_UMASK) {
+ *p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
+ *p++ = cpu_to_be32(*umask);
+ }
/* out: */
}
@@ -1188,7 +1196,8 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
}
encode_string(xdr, create->name->len, create->name->name);
- encode_attrs(xdr, create->attrs, create->label, create->server, false);
+ encode_attrs(xdr, create->attrs, create->label, create->server, false,
+ &create->umask);
}
static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
@@ -1408,11 +1417,13 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
switch(arg->createmode) {
case NFS4_CREATE_UNCHECKED:
*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
- encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false);
+ encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false,
+ &arg->umask);
break;
case NFS4_CREATE_GUARDED:
*p = cpu_to_be32(NFS4_CREATE_GUARDED);
- encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false);
+ encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false,
+ &arg->umask);
break;
case NFS4_CREATE_EXCLUSIVE:
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
@@ -1421,7 +1432,8 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
case NFS4_CREATE_EXCLUSIVE4_1:
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
encode_nfs4_verifier(xdr, &arg->u.verifier);
- encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, true);
+ encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, true,
+ &arg->umask);
}
}
@@ -1677,7 +1689,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
{
encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
encode_nfs4_stateid(xdr, &arg->stateid);
- encode_attrs(xdr, arg->iap, arg->label, server, false);
+ encode_attrs(xdr, arg->iap, arg->label, server, false, NULL);
}
static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 9094faf0699d..bca536341d1a 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -440,6 +440,7 @@ enum lock_type4 {
#define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4)
#define FATTR4_WORD2_CLONE_BLKSIZE (1UL << 13)
#define FATTR4_WORD2_SECURITY_LABEL (1UL << 16)
+#define FATTR4_WORD2_MODE_UMASK (1UL << 17)
/* MDS threshold bitmap bits */
#define THRESHOLD_RD (1UL << 0)
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 617cfaa20ffc..348f7c158084 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -433,6 +433,7 @@ struct nfs_openargs {
enum open_claim_type4 claim;
enum createmode4 createmode;
const struct nfs4_label *label;
+ umode_t umask;
};
struct nfs_openres {
@@ -958,6 +959,7 @@ struct nfs4_create_arg {
const struct nfs_fh * dir_fh;
const u32 * bitmask;
const struct nfs4_label *label;
+ umode_t umask;
};
struct nfs4_create_res {