nfs: add support for the umask attribute
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>
This commit is contained in:
parent
d9152114f7
commit
dff25ddb48
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue