nfs: add support for the umask attribute
authorAndreas Gruenbacher <agruenba@redhat.com>
Sat, 3 Dec 2016 03:53:30 +0000 (22:53 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Sat, 10 Dec 2016 04:47:10 +0000 (23:47 -0500)
Clients can set the umask attribute when creating files to cause the
server to apply it always except when inheriting permissions from the
parent directory.  That way, the new files will end up with the same
permissions as files created locally.

See https://tools.ietf.org/html/draft-ietf-nfsv4-umask-02 for more details.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/dir.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4xdr.c
include/linux/nfs4.h
include/linux/nfs_xdr.h

index 7483722162fa0591e8ad2de2ac88687aed2d431e..cb22a9f9ae7e3694db1532a683ae34d4d313e787 100644 (file)
@@ -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;
index c5a5086696555c8039bb3953d8e50078e345c369..d33242c8d95d58a5366a4a57283005702852c29b 100644 (file)
@@ -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);
index 1c1768a8fcd15ef5cc606686b49ee33f30223f39..1af6268a7d8c4c71779d3b64f7ce087b431df723 100644 (file)
@@ -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)
index 9094faf0699d61b7b07bc5b9b0d0e9f76dc67742..bca536341d1ae51781981906f069a96f612cf52f 100644 (file)
@@ -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)
index 617cfaa20ffc96e87030dbadca821a56efe0aae0..348f7c158084b8de71c2a0a2f6941b0db7bf2c3b 100644 (file)
@@ -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 {