Message ID | 1441448856-13478-30-git-send-email-agruenba@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Sat, Sep 05, 2015 at 12:27:24PM +0200, Andreas Gruenbacher wrote: > When converting from NFSv4 ACLs to POSIX ACLs, nfsd so far was using > struct nfs4_acl as its internal representation. This representation is a > subset of richacls, so get rid of struct nfs4_acl. Richacls even have a > more compact in-memory representation, so a few more ACL entries can > easily be supported. Looks good to me, ACK. --b. > > Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> > --- > fs/Kconfig | 6 + > fs/nfs_common/Makefile | 1 + > fs/nfs_common/nfs4acl.c | 44 ++++++ > fs/nfsd/Kconfig | 1 + > fs/nfsd/acl.h | 24 ++-- > fs/nfsd/nfs4acl.c | 367 ++++++++++++++++++++++-------------------------- > fs/nfsd/nfs4proc.c | 15 +- > fs/nfsd/nfs4xdr.c | 64 +++------ > fs/nfsd/xdr4.h | 6 +- > include/linux/nfs4.h | 23 --- > include/linux/nfs4acl.h | 7 + > 11 files changed, 273 insertions(+), 285 deletions(-) > create mode 100644 fs/nfs_common/nfs4acl.c > create mode 100644 include/linux/nfs4acl.h > > diff --git a/fs/Kconfig b/fs/Kconfig > index 3e09c06..dd3f2d6 100644 > --- a/fs/Kconfig > +++ b/fs/Kconfig > @@ -268,6 +268,12 @@ config NFS_COMMON > depends on NFSD || NFS_FS || LOCKD > default y > > +config NFS_RICHACL > + bool > + depends on NFSD_V4 || NFS_V4 > + select FS_RICHACL > + default y > + > source "net/sunrpc/Kconfig" > source "fs/ceph/Kconfig" > source "fs/cifs/Kconfig" > diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile > index d153ca3..e055139 100644 > --- a/fs/nfs_common/Makefile > +++ b/fs/nfs_common/Makefile > @@ -4,5 +4,6 @@ > > obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o > nfs_acl-objs := nfsacl.o > +obj-$(CONFIG_NFS_RICHACL) += nfs4acl.o > > obj-$(CONFIG_GRACE_PERIOD) += grace.o > diff --git a/fs/nfs_common/nfs4acl.c b/fs/nfs_common/nfs4acl.c > new file mode 100644 > index 0000000..02df064 > --- /dev/null > +++ b/fs/nfs_common/nfs4acl.c > @@ -0,0 +1,44 @@ > +#include <linux/fs.h> > +#include <linux/richacl.h> > +#include <linux/nfs4acl.h> > + > +static struct special_id { > + char *who; > + int len; > +} special_who_map[] = { > + [RICHACE_OWNER_SPECIAL_ID] = { > + .who = "OWNER@", > + .len = sizeof("OWNER@") - 1 }, > + [RICHACE_GROUP_SPECIAL_ID] = { > + .who = "GROUP@", > + .len = sizeof("GROUP@") - 1 }, > + [RICHACE_EVERYONE_SPECIAL_ID] = { > + .who = "EVERYONE@", > + .len = sizeof("EVERYONE@") - 1 } > +}; > + > +int nfs4acl_who_to_special_id(const char *who, u32 len) > +{ > + int n; > + > + for (n = 0; n < ARRAY_SIZE(special_who_map); n++) { > + if (len == special_who_map[n].len && > + !memcmp(who, special_who_map[n].who, len)) > + return n; > + } > + return -1; > +} > +EXPORT_SYMBOL(nfs4acl_who_to_special_id); > + > +bool nfs4acl_special_id_to_who(unsigned int special_who, > + const char **who, unsigned int *len) > +{ > + struct special_id *special = &special_who_map[special_who]; > + > + if (special_who > ARRAY_SIZE(special_who_map) || !special->len) > + return false; > + *who = special->who; > + *len = special->len; > + return true; > +} > +EXPORT_SYMBOL(nfs4acl_special_id_to_who); > diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig > index a0b77fc..811379a 100644 > --- a/fs/nfsd/Kconfig > +++ b/fs/nfsd/Kconfig > @@ -70,6 +70,7 @@ config NFSD_V4 > depends on NFSD && PROC_FS > select NFSD_V3 > select FS_POSIX_ACL > + select FS_RICHACL > select SUNRPC_GSS > select CRYPTO > select GRACE_PERIOD > diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h > index 4cd7c69..1c5deb5 100644 > --- a/fs/nfsd/acl.h > +++ b/fs/nfsd/acl.h > @@ -35,25 +35,27 @@ > #ifndef LINUX_NFS4_ACL_H > #define LINUX_NFS4_ACL_H > > -struct nfs4_acl; > +struct richacl; > +struct richace; > struct svc_fh; > struct svc_rqst; > > /* > * Maximum ACL we'll accept from a client; chosen (somewhat > * arbitrarily) so that kmalloc'ing the ACL shouldn't require a > - * high-order allocation. This allows 204 ACEs on x86_64: > + * high-order allocation. This allows 339 ACEs on x86_64: > */ > -#define NFS4_ACL_MAX ((PAGE_SIZE - sizeof(struct nfs4_acl)) \ > - / sizeof(struct nfs4_ace)) > +#define NFSD4_ACL_MAX ((PAGE_SIZE - sizeof(struct richacl)) \ > + / sizeof(struct richace)) > > -int nfs4_acl_bytes(int entries); > -int nfs4_acl_get_whotype(char *, u32); > -__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who); > +__be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp, > + char *who, u32 len); > +__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp, > + struct richace *ace); > > -int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, > - struct nfs4_acl **acl); > -__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, > - struct nfs4_acl *acl); > +int nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry, > + struct richacl **acl); > +__be32 nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, > + struct richacl *acl); > > #endif /* LINUX_NFS4_ACL_H */ > diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c > index eb5accf..582f772 100644 > --- a/fs/nfsd/nfs4acl.c > +++ b/fs/nfsd/nfs4acl.c > @@ -36,45 +36,48 @@ > > #include <linux/slab.h> > #include <linux/nfs_fs.h> > +#include <linux/richacl_compat.h> > +#include <linux/nfs4acl.h> > #include "nfsfh.h" > #include "nfsd.h" > +#include "idmap.h" > #include "acl.h" > #include "vfs.h" > > -#define NFS4_ACL_TYPE_DEFAULT 0x01 > -#define NFS4_ACL_DIR 0x02 > -#define NFS4_ACL_OWNER 0x04 > +#define FLAG_DEFAULT_ACL 0x01 > +#define FLAG_DIRECTORY 0x02 > +#define FLAG_OWNER 0x04 > > /* mode bit translations: */ > -#define NFS4_READ_MODE (NFS4_ACE_READ_DATA) > -#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA) > -#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE > -#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE) > -#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL) > +#define RICHACE_READ_MODE (RICHACE_READ_DATA) > +#define RICHACE_WRITE_MODE (RICHACE_WRITE_DATA | RICHACE_APPEND_DATA) > +#define RICHACE_EXECUTE_MODE RICHACE_EXECUTE > +#define RICHACE_ANYONE_MODE (RICHACE_READ_ATTRIBUTES | RICHACE_READ_ACL | RICHACE_SYNCHRONIZE) > +#define RICHACE_OWNER_MODE (RICHACE_WRITE_ATTRIBUTES | RICHACE_WRITE_ACL) > > /* flags used to simulate posix default ACLs */ > -#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \ > - | NFS4_ACE_DIRECTORY_INHERIT_ACE) > - > -#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \ > - | NFS4_ACE_INHERIT_ONLY_ACE \ > - | NFS4_ACE_IDENTIFIER_GROUP) > +#define RICHACE_SUPPORTED_FLAGS ( \ > + RICHACE_FILE_INHERIT_ACE | \ > + RICHACE_DIRECTORY_INHERIT_ACE | \ > + RICHACE_INHERIT_ONLY_ACE | \ > + RICHACE_IDENTIFIER_GROUP | \ > + RICHACE_SPECIAL_WHO) > > static u32 > mask_from_posix(unsigned short perm, unsigned int flags) > { > - int mask = NFS4_ANYONE_MODE; > + int mask = RICHACE_ANYONE_MODE; > > - if (flags & NFS4_ACL_OWNER) > - mask |= NFS4_OWNER_MODE; > + if (flags & FLAG_OWNER) > + mask |= RICHACE_OWNER_MODE; > if (perm & ACL_READ) > - mask |= NFS4_READ_MODE; > + mask |= RICHACE_READ_MODE; > if (perm & ACL_WRITE) > - mask |= NFS4_WRITE_MODE; > - if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) > - mask |= NFS4_ACE_DELETE_CHILD; > + mask |= RICHACE_WRITE_MODE; > + if ((perm & ACL_WRITE) && (flags & FLAG_DIRECTORY)) > + mask |= RICHACE_DELETE_CHILD; > if (perm & ACL_EXECUTE) > - mask |= NFS4_EXECUTE_MODE; > + mask |= RICHACE_EXECUTE_MODE; > return mask; > } > > @@ -84,13 +87,13 @@ deny_mask_from_posix(unsigned short perm, u32 flags) > u32 mask = 0; > > if (perm & ACL_READ) > - mask |= NFS4_READ_MODE; > + mask |= RICHACE_READ_MODE; > if (perm & ACL_WRITE) > - mask |= NFS4_WRITE_MODE; > - if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) > - mask |= NFS4_ACE_DELETE_CHILD; > + mask |= RICHACE_WRITE_MODE; > + if ((perm & ACL_WRITE) && (flags & FLAG_DIRECTORY)) > + mask |= RICHACE_DELETE_CHILD; > if (perm & ACL_EXECUTE) > - mask |= NFS4_EXECUTE_MODE; > + mask |= RICHACE_EXECUTE_MODE; > return mask; > } > > @@ -106,32 +109,33 @@ deny_mask_from_posix(unsigned short perm, u32 flags) > static void > low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) > { > - u32 write_mode = NFS4_WRITE_MODE; > + u32 write_mode = RICHACE_WRITE_MODE; > > - if (flags & NFS4_ACL_DIR) > - write_mode |= NFS4_ACE_DELETE_CHILD; > + if (flags & FLAG_DIRECTORY) > + write_mode |= RICHACE_DELETE_CHILD; > *mode = 0; > - if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE) > + if ((perm & RICHACE_READ_MODE) == RICHACE_READ_MODE) > *mode |= ACL_READ; > if ((perm & write_mode) == write_mode) > *mode |= ACL_WRITE; > - if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE) > + if ((perm & RICHACE_EXECUTE_MODE) == RICHACE_EXECUTE_MODE) > *mode |= ACL_EXECUTE; > } > > -static short ace2type(struct nfs4_ace *); > -static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, > +static short ace2type(struct richace *); > +static void _posix_to_richacl_one(struct posix_acl *, struct richacl_alloc *, > unsigned int); > > int > -nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, > - struct nfs4_acl **acl) > +nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry, > + struct richacl **acl) > { > struct inode *inode = d_inode(dentry); > int error = 0; > struct posix_acl *pacl = NULL, *dpacl = NULL; > + struct richacl_alloc alloc; > unsigned int flags = 0; > - int size = 0; > + int count; > > pacl = get_acl(inode, ACL_TYPE_ACCESS); > if (!pacl) > @@ -141,10 +145,10 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, > return PTR_ERR(pacl); > > /* allocate for worst case: one (deny, allow) pair each: */ > - size += 2 * pacl->a_count; > + count = 2 * pacl->a_count; > > if (S_ISDIR(inode->i_mode)) { > - flags = NFS4_ACL_DIR; > + flags = FLAG_DIRECTORY; > dpacl = get_acl(inode, ACL_TYPE_DEFAULT); > if (IS_ERR(dpacl)) { > error = PTR_ERR(dpacl); > @@ -152,20 +156,20 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, > } > > if (dpacl) > - size += 2 * dpacl->a_count; > + count += 2 * dpacl->a_count; > } > > - *acl = kmalloc(nfs4_acl_bytes(size), GFP_KERNEL); > - if (*acl == NULL) { > + if (!richacl_prepare(&alloc, count)) { > error = -ENOMEM; > goto out; > } > - (*acl)->naces = 0; > > - _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT); > + _posix_to_richacl_one(pacl, &alloc, flags); > > if (dpacl) > - _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT); > + _posix_to_richacl_one(dpacl, &alloc, flags | FLAG_DEFAULT_ACL); > + > + *acl = alloc.acl; > > out: > posix_acl_release(dpacl); > @@ -228,21 +232,22 @@ summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) > > /* We assume the acl has been verified with posix_acl_valid. */ > static void > -_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, > - unsigned int flags) > +_posix_to_richacl_one(struct posix_acl *pacl, struct richacl_alloc *alloc, > + unsigned int flags) > { > struct posix_acl_entry *pa, *group_owner_entry; > - struct nfs4_ace *ace; > + struct richace *ace; > struct posix_acl_summary pas; > unsigned short deny; > - int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ? > - NFS4_INHERITANCE_FLAGS | NFS4_ACE_INHERIT_ONLY_ACE : 0); > + int e_flags = ((flags & FLAG_DEFAULT_ACL) ? > + (RICHACE_FILE_INHERIT_ACE | > + RICHACE_DIRECTORY_INHERIT_ACE | > + RICHACE_INHERIT_ONLY_ACE) : 0); > > BUG_ON(pacl->a_count < 3); > summarize_posix_acl(pacl, &pas); > > pa = pacl->a_entries; > - ace = acl->aces + acl->naces; > > /* We could deny everything not granted by the owner: */ > deny = ~pas.owner; > @@ -252,42 +257,35 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, > */ > deny &= pas.users | pas.group | pas.groups | pas.other; > if (deny) { > - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; > - ace->flag = eflag; > - ace->access_mask = deny_mask_from_posix(deny, flags); > - ace->whotype = NFS4_ACL_WHO_OWNER; > - ace++; > - acl->naces++; > + ace = richacl_append_entry(alloc); > + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; > + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; > + ace->e_mask = deny_mask_from_posix(deny, flags); > + ace->e_id.special = RICHACE_OWNER_SPECIAL_ID; > } > > - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; > - ace->flag = eflag; > - ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); > - ace->whotype = NFS4_ACL_WHO_OWNER; > - ace++; > - acl->naces++; > + ace = richacl_append_entry(alloc); > + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; > + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; > + ace->e_mask = mask_from_posix(pa->e_perm, flags | FLAG_OWNER); > + ace->e_id.special = RICHACE_OWNER_SPECIAL_ID; > pa++; > > while (pa->e_tag == ACL_USER) { > deny = ~(pa->e_perm & pas.mask); > deny &= pas.groups | pas.group | pas.other; > if (deny) { > - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; > - ace->flag = eflag; > - ace->access_mask = deny_mask_from_posix(deny, flags); > - ace->whotype = NFS4_ACL_WHO_NAMED; > - ace->who_uid = pa->e_uid; > - ace++; > - acl->naces++; > + ace = richacl_append_entry(alloc); > + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; > + ace->e_flags = e_flags; > + ace->e_mask = deny_mask_from_posix(deny, flags); > + ace->e_id.uid = pa->e_uid; > } > - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; > - ace->flag = eflag; > - ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, > - flags); > - ace->whotype = NFS4_ACL_WHO_NAMED; > - ace->who_uid = pa->e_uid; > - ace++; > - acl->naces++; > + ace = richacl_append_entry(alloc); > + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; > + ace->e_flags = e_flags; > + ace->e_mask = mask_from_posix(pa->e_perm & pas.mask, flags); > + ace->e_id.uid = pa->e_uid; > pa++; > } > > @@ -298,23 +296,19 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, > > group_owner_entry = pa; > > - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; > - ace->flag = eflag; > - ace->access_mask = mask_from_posix(pas.group, flags); > - ace->whotype = NFS4_ACL_WHO_GROUP; > - ace++; > - acl->naces++; > + ace = richacl_append_entry(alloc); > + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; > + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; > + ace->e_mask = mask_from_posix(pas.group, flags); > + ace->e_id.special = RICHACE_GROUP_SPECIAL_ID; > pa++; > > while (pa->e_tag == ACL_GROUP) { > - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; > - ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; > - ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, > - flags); > - ace->whotype = NFS4_ACL_WHO_NAMED; > - ace->who_gid = pa->e_gid; > - ace++; > - acl->naces++; > + ace = richacl_append_entry(alloc); > + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; > + ace->e_flags = e_flags | RICHACE_IDENTIFIER_GROUP; > + ace->e_mask = mask_from_posix(pa->e_perm & pas.mask, flags); > + ace->e_id.gid = pa->e_gid; > pa++; > } > > @@ -324,12 +318,11 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, > > deny = ~pas.group & pas.other; > if (deny) { > - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; > - ace->flag = eflag; > - ace->access_mask = deny_mask_from_posix(deny, flags); > - ace->whotype = NFS4_ACL_WHO_GROUP; > - ace++; > - acl->naces++; > + ace = richacl_append_entry(alloc); > + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; > + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; > + ace->e_mask = deny_mask_from_posix(deny, flags); > + ace->e_id.special = RICHACE_GROUP_SPECIAL_ID; > } > pa++; > > @@ -337,24 +330,22 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, > deny = ~(pa->e_perm & pas.mask); > deny &= pas.other; > if (deny) { > - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; > - ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; > - ace->access_mask = deny_mask_from_posix(deny, flags); > - ace->whotype = NFS4_ACL_WHO_NAMED; > - ace->who_gid = pa->e_gid; > - ace++; > - acl->naces++; > + ace = richacl_append_entry(alloc); > + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; > + ace->e_flags = e_flags | RICHACE_IDENTIFIER_GROUP; > + ace->e_mask = deny_mask_from_posix(deny, flags); > + ace->e_id.gid = pa->e_gid; > } > pa++; > } > > if (pa->e_tag == ACL_MASK) > pa++; > - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; > - ace->flag = eflag; > - ace->access_mask = mask_from_posix(pa->e_perm, flags); > - ace->whotype = NFS4_ACL_WHO_EVERYONE; > - acl->naces++; > + ace = richacl_append_entry(alloc); > + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; > + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; > + ace->e_mask = mask_from_posix(pa->e_perm, flags); > + ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID; > } > > static bool > @@ -498,7 +489,7 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) > * and effective cases: when there are no inheritable ACEs, > * calls ->set_acl with a NULL ACL structure. > */ > - if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) > + if (state->empty && (flags & FLAG_DEFAULT_ACL)) > return NULL; > > /* > @@ -617,24 +608,24 @@ static void allow_bits_array(struct posix_ace_state_array *a, u32 mask) > } > > static void process_one_v4_ace(struct posix_acl_state *state, > - struct nfs4_ace *ace) > + struct richace *ace) > { > - u32 mask = ace->access_mask; > + u32 mask = ace->e_mask; > int i; > > state->empty = 0; > > switch (ace2type(ace)) { > case ACL_USER_OBJ: > - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { > + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { > allow_bits(&state->owner, mask); > } else { > deny_bits(&state->owner, mask); > } > break; > case ACL_USER: > - i = find_uid(state, ace->who_uid); > - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { > + i = find_uid(state, ace->e_id.uid); > + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { > allow_bits(&state->users->aces[i].perms, mask); > } else { > deny_bits(&state->users->aces[i].perms, mask); > @@ -643,7 +634,7 @@ static void process_one_v4_ace(struct posix_acl_state *state, > } > break; > case ACL_GROUP_OBJ: > - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { > + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { > allow_bits(&state->group, mask); > } else { > deny_bits(&state->group, mask); > @@ -655,8 +646,8 @@ static void process_one_v4_ace(struct posix_acl_state *state, > } > break; > case ACL_GROUP: > - i = find_gid(state, ace->who_gid); > - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { > + i = find_gid(state, ace->e_id.gid); > + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { > allow_bits(&state->groups->aces[i].perms, mask); > } else { > deny_bits(&state->groups->aces[i].perms, mask); > @@ -669,7 +660,7 @@ static void process_one_v4_ace(struct posix_acl_state *state, > } > break; > case ACL_OTHER: > - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { > + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { > allow_bits(&state->owner, mask); > allow_bits(&state->group, mask); > allow_bits(&state->other, mask); > @@ -687,32 +678,33 @@ static void process_one_v4_ace(struct posix_acl_state *state, > } > } > > -static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, > +static int nfs4_richacl_to_posix(struct richacl *acl, > struct posix_acl **pacl, struct posix_acl **dpacl, > unsigned int flags) > { > struct posix_acl_state effective_acl_state, default_acl_state; > - struct nfs4_ace *ace; > + struct richace *ace; > int ret; > > - ret = init_state(&effective_acl_state, acl->naces); > + ret = init_state(&effective_acl_state, acl->a_count); > if (ret) > return ret; > - ret = init_state(&default_acl_state, acl->naces); > + ret = init_state(&default_acl_state, acl->a_count); > if (ret) > goto out_estate; > ret = -EINVAL; > - for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { > - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && > - ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) > + richacl_for_each_entry(ace, acl) { > + if (ace->e_type != RICHACE_ACCESS_ALLOWED_ACE_TYPE && > + ace->e_type != RICHACE_ACCESS_DENIED_ACE_TYPE) > goto out_dstate; > - if (ace->flag & ~NFS4_SUPPORTED_FLAGS) > + if (ace->e_flags & ~RICHACE_SUPPORTED_FLAGS) > goto out_dstate; > - if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) { > + if ((ace->e_flags & (RICHACE_FILE_INHERIT_ACE | > + RICHACE_DIRECTORY_INHERIT_ACE)) == 0) { > process_one_v4_ace(&effective_acl_state, ace); > continue; > } > - if (!(flags & NFS4_ACL_DIR)) > + if (!(flags & FLAG_DIRECTORY)) > goto out_dstate; > /* > * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT > @@ -721,7 +713,7 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, > */ > process_one_v4_ace(&default_acl_state, ace); > > - if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE)) > + if (!(ace->e_flags & RICHACE_INHERIT_ONLY_ACE)) > process_one_v4_ace(&effective_acl_state, ace); > } > *pacl = posix_state_to_acl(&effective_acl_state, flags); > @@ -731,7 +723,7 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, > goto out_dstate; > } > *dpacl = posix_state_to_acl(&default_acl_state, > - flags | NFS4_ACL_TYPE_DEFAULT); > + flags | FLAG_DEFAULT_ACL); > if (IS_ERR(*dpacl)) { > ret = PTR_ERR(*dpacl); > *dpacl = NULL; > @@ -750,8 +742,7 @@ out_estate: > } > > __be32 > -nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, > - struct nfs4_acl *acl) > +nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl) > { > __be32 error; > int host_error; > @@ -772,9 +763,9 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, > return nfserr_attrnotsupp; > > if (S_ISDIR(inode->i_mode)) > - flags = NFS4_ACL_DIR; > + flags = FLAG_DIRECTORY; > > - host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); > + host_error = nfs4_richacl_to_posix(acl, &pacl, &dpacl, flags); > if (host_error == -EINVAL) > return nfserr_attrnotsupp; > if (host_error < 0) > @@ -801,82 +792,62 @@ out_nfserr: > > > static short > -ace2type(struct nfs4_ace *ace) > +ace2type(struct richace *ace) > { > - switch (ace->whotype) { > - case NFS4_ACL_WHO_NAMED: > - return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ? > - ACL_GROUP : ACL_USER); > - case NFS4_ACL_WHO_OWNER: > + if (ace->e_flags & RICHACE_SPECIAL_WHO) { > + switch (ace->e_id.special) { > + case RICHACE_OWNER_SPECIAL_ID: > return ACL_USER_OBJ; > - case NFS4_ACL_WHO_GROUP: > + case RICHACE_GROUP_SPECIAL_ID: > return ACL_GROUP_OBJ; > - case NFS4_ACL_WHO_EVERYONE: > + case RICHACE_EVERYONE_SPECIAL_ID: > return ACL_OTHER; > + default: > + BUG(); > + } > } > - BUG(); > - return -1; > -} > - > -/* > - * return the size of the struct nfs4_acl required to represent an acl > - * with @entries entries. > - */ > -int nfs4_acl_bytes(int entries) > -{ > - return sizeof(struct nfs4_acl) + entries * sizeof(struct nfs4_ace); > + return ace->e_flags & RICHACE_IDENTIFIER_GROUP ? ACL_GROUP : ACL_USER; > } > > -static struct { > - char *string; > - int stringlen; > - int type; > -} s2t_map[] = { > - { > - .string = "OWNER@", > - .stringlen = sizeof("OWNER@") - 1, > - .type = NFS4_ACL_WHO_OWNER, > - }, > - { > - .string = "GROUP@", > - .stringlen = sizeof("GROUP@") - 1, > - .type = NFS4_ACL_WHO_GROUP, > - }, > - { > - .string = "EVERYONE@", > - .stringlen = sizeof("EVERYONE@") - 1, > - .type = NFS4_ACL_WHO_EVERYONE, > - }, > -}; > - > -int > -nfs4_acl_get_whotype(char *p, u32 len) > +__be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp, > + char *who, u32 len) > { > - int i; > - > - for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { > - if (s2t_map[i].stringlen == len && > - 0 == memcmp(s2t_map[i].string, p, len)) > - return s2t_map[i].type; > + int special_id; > + > + special_id = nfs4acl_who_to_special_id(who, len); > + if (special_id >= 0) { > + ace->e_flags |= RICHACE_SPECIAL_WHO; > + ace->e_flags &= ~RICHACE_IDENTIFIER_GROUP; > + ace->e_id.special = special_id; > + return nfs_ok; > } > - return NFS4_ACL_WHO_NAMED; > + if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) > + return nfsd_map_name_to_gid(rqstp, who, len, &ace->e_id.gid); > + else > + return nfsd_map_name_to_uid(rqstp, who, len, &ace->e_id.uid); > } > > -__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who) > +__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp, > + struct richace *ace) > { > - __be32 *p; > - int i; > - > - for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { > - if (s2t_map[i].type != who) > - continue; > - p = xdr_reserve_space(xdr, s2t_map[i].stringlen + 4); > + if (ace->e_flags & RICHACE_SPECIAL_WHO) { > + unsigned int special_id = ace->e_id.special; > + const char *who; > + unsigned int len; > + __be32 *p; > + > + if (!nfs4acl_special_id_to_who(special_id, &who, &len)) { > + WARN_ON_ONCE(1); > + return nfserr_serverfault; > + } > + p = xdr_reserve_space(xdr, len + 4); > if (!p) > return nfserr_resource; > - p = xdr_encode_opaque(p, s2t_map[i].string, > - s2t_map[i].stringlen); > + p = xdr_encode_opaque(p, who, len); > return 0; > } > - WARN_ON_ONCE(1); > - return nfserr_serverfault; > + if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) > + return nfsd4_encode_group(xdr, rqstp, ace->e_id.gid); > + else > + return nfsd4_encode_user(xdr, rqstp, ace->e_id.uid); > } > diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c > index 90cfda7..8c2cb16 100644 > --- a/fs/nfsd/nfs4proc.c > +++ b/fs/nfsd/nfs4proc.c > @@ -159,12 +159,12 @@ is_create_with_attrs(struct nfsd4_open *open) > * in the returned attr bitmap. > */ > static void > -do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, > - struct nfs4_acl *acl, u32 *bmval) > +do_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl, > + u32 *bmval) > { > __be32 status; > > - status = nfsd4_set_nfs4_acl(rqstp, fhp, acl); > + status = nfsd4_set_acl(rqstp, fhp, acl); > if (status) > /* > * We should probably fail the whole open at this point, > @@ -299,7 +299,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru > goto out; > > if (is_create_with_attrs(open) && open->op_acl != NULL) > - do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval); > + do_set_acl(rqstp, *resfh, open->op_acl, open->op_bmval); > > nfsd4_set_open_owner_reply_cache(cstate, open, *resfh); > accmode = NFSD_MAY_NOP; > @@ -674,8 +674,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); > > if (create->cr_acl != NULL) > - do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, > - create->cr_bmval); > + do_set_acl(rqstp, &resfh, create->cr_acl, create->cr_bmval); > > fh_unlock(&cstate->current_fh); > set_change_info(&create->cr_cinfo, &cstate->current_fh); > @@ -940,8 +939,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, > goto out; > > if (setattr->sa_acl != NULL) > - status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, > - setattr->sa_acl); > + status = nfsd4_set_acl(rqstp, &cstate->current_fh, > + setattr->sa_acl); > if (status) > goto out; > if (setattr->sa_label.len) > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c > index 0768251..465f82a 100644 > --- a/fs/nfsd/nfs4xdr.c > +++ b/fs/nfsd/nfs4xdr.c > @@ -303,7 +303,7 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) > > static __be32 > nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, > - struct iattr *iattr, struct nfs4_acl **acl, > + struct iattr *iattr, struct richacl **acl, > struct xdr_netobj *label) > { > int expected_len, len = 0; > @@ -326,38 +326,31 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, > } > if (bmval[0] & FATTR4_WORD0_ACL) { > u32 nace; > - struct nfs4_ace *ace; > + struct richace *ace; > > READ_BUF(4); len += 4; > nace = be32_to_cpup(p++); > > - if (nace > NFS4_ACL_MAX) > + if (nace > NFSD4_ACL_MAX) > return nfserr_fbig; > > - *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace)); > + *acl = svcxdr_alloc_richacl(argp, nace); > if (*acl == NULL) > return nfserr_jukebox; > > - (*acl)->naces = nace; > - for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { > + richacl_for_each_entry(ace, *acl) { > READ_BUF(16); len += 16; > - ace->type = be32_to_cpup(p++); > - ace->flag = be32_to_cpup(p++); > - ace->access_mask = be32_to_cpup(p++); > + ace->e_type = be32_to_cpup(p++); > + ace->e_flags = be32_to_cpup(p++); > + ace->e_mask = be32_to_cpup(p++); > + if (ace->e_flags & RICHACE_SPECIAL_WHO) > + return nfserr_inval; > dummy32 = be32_to_cpup(p++); > READ_BUF(dummy32); > len += XDR_QUADLEN(dummy32) << 2; > READMEM(buf, dummy32); > - ace->whotype = nfs4_acl_get_whotype(buf, dummy32); > - status = nfs_ok; > - if (ace->whotype != NFS4_ACL_WHO_NAMED) > - ; > - else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) > - status = nfsd_map_name_to_gid(argp->rqstp, > - buf, dummy32, &ace->who_gid); > - else > - status = nfsd_map_name_to_uid(argp->rqstp, > - buf, dummy32, &ace->who_uid); > + status = nfsd4_decode_ace_who(ace, argp->rqstp, > + buf, dummy32); > if (status) > return status; > } > @@ -2147,18 +2140,6 @@ static u32 nfs4_file_type(umode_t mode) > }; > } > > -static inline __be32 > -nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp, > - struct nfs4_ace *ace) > -{ > - if (ace->whotype != NFS4_ACL_WHO_NAMED) > - return nfs4_acl_write_who(xdr, ace->whotype); > - else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) > - return nfsd4_encode_group(xdr, rqstp, ace->who_gid); > - else > - return nfsd4_encode_user(xdr, rqstp, ace->who_uid); > -} > - > #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ > FATTR4_WORD0_RDATTR_ERROR) > #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID > @@ -2249,7 +2230,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, > u32 rdattr_err = 0; > __be32 status; > int err; > - struct nfs4_acl *acl = NULL; > + struct richacl *acl = NULL; > void *context = NULL; > int contextlen; > bool contextsupport = false; > @@ -2295,7 +2276,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, > fhp = tempfh; > } > if (bmval0 & FATTR4_WORD0_ACL) { > - err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); > + err = nfsd4_get_acl(rqstp, dentry, &acl); > if (err == -EOPNOTSUPP) > bmval0 &= ~FATTR4_WORD0_ACL; > else if (err == -EINVAL) { > @@ -2469,7 +2450,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, > *p++ = cpu_to_be32(rdattr_err); > } > if (bmval0 & FATTR4_WORD0_ACL) { > - struct nfs4_ace *ace; > + struct richace *ace; > > if (acl == NULL) { > p = xdr_reserve_space(xdr, 4); > @@ -2482,17 +2463,16 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, > p = xdr_reserve_space(xdr, 4); > if (!p) > goto out_resource; > - *p++ = cpu_to_be32(acl->naces); > + *p++ = cpu_to_be32(acl->a_count); > > - for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { > + richacl_for_each_entry(ace, acl) { > p = xdr_reserve_space(xdr, 4*3); > if (!p) > goto out_resource; > - *p++ = cpu_to_be32(ace->type); > - *p++ = cpu_to_be32(ace->flag); > - *p++ = cpu_to_be32(ace->access_mask & > - NFS4_ACE_MASK_ALL); > - status = nfsd4_encode_aclname(xdr, rqstp, ace); > + *p++ = cpu_to_be32(ace->e_type); > + *p++ = cpu_to_be32(ace->e_flags & ~RICHACE_SPECIAL_WHO); > + *p++ = cpu_to_be32(ace->e_mask & NFS4_ACE_MASK_ALL); > + status = nfsd4_encode_ace_who(xdr, rqstp, ace); > if (status) > goto out; > } > @@ -2755,7 +2735,7 @@ out: > if (context) > security_release_secctx(context, contextlen); > #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ > - kfree(acl); > + richacl_put(acl); > if (tempfh) { > fh_put(tempfh); > kfree(tempfh); > diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h > index b698585..c311066 100644 > --- a/fs/nfsd/xdr4.h > +++ b/fs/nfsd/xdr4.h > @@ -118,7 +118,7 @@ struct nfsd4_create { > u32 cr_bmval[3]; /* request */ > struct iattr cr_iattr; /* request */ > struct nfsd4_change_info cr_cinfo; /* response */ > - struct nfs4_acl *cr_acl; > + struct richacl *cr_acl; > struct xdr_netobj cr_label; > }; > #define cr_datalen u.link.datalen > @@ -248,7 +248,7 @@ struct nfsd4_open { > struct nfs4_file *op_file; /* used during processing */ > struct nfs4_ol_stateid *op_stp; /* used during processing */ > struct nfs4_clnt_odstate *op_odstate; /* used during processing */ > - struct nfs4_acl *op_acl; > + struct richacl *op_acl; > struct xdr_netobj op_label; > }; > > @@ -332,7 +332,7 @@ struct nfsd4_setattr { > stateid_t sa_stateid; /* request */ > u32 sa_bmval[3]; /* request */ > struct iattr sa_iattr; /* request */ > - struct nfs4_acl *sa_acl; > + struct richacl *sa_acl; > struct xdr_netobj sa_label; > }; > > diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h > index b8e72aa..992ddc4 100644 > --- a/include/linux/nfs4.h > +++ b/include/linux/nfs4.h > @@ -16,29 +16,6 @@ > #include <linux/uidgid.h> > #include <uapi/linux/nfs4.h> > > -enum nfs4_acl_whotype { > - NFS4_ACL_WHO_NAMED = 0, > - NFS4_ACL_WHO_OWNER, > - NFS4_ACL_WHO_GROUP, > - NFS4_ACL_WHO_EVERYONE, > -}; > - > -struct nfs4_ace { > - uint32_t type; > - uint32_t flag; > - uint32_t access_mask; > - int whotype; > - union { > - kuid_t who_uid; > - kgid_t who_gid; > - }; > -}; > - > -struct nfs4_acl { > - uint32_t naces; > - struct nfs4_ace aces[0]; > -}; > - > #define NFS4_MAXLABELLEN 2048 > > struct nfs4_label { > diff --git a/include/linux/nfs4acl.h b/include/linux/nfs4acl.h > new file mode 100644 > index 0000000..db9f9a6 > --- /dev/null > +++ b/include/linux/nfs4acl.h > @@ -0,0 +1,7 @@ > +#ifndef __LINUX_NFS4ACL_H > +#define __LINUX_NFS4ACL_H > + > +int nfs4acl_who_to_special_id(const char *, u32); > +bool nfs4acl_special_id_to_who(unsigned int, const char **, unsigned int *); > + > +#endif > -- > 2.4.3 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/fs/Kconfig b/fs/Kconfig index 3e09c06..dd3f2d6 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -268,6 +268,12 @@ config NFS_COMMON depends on NFSD || NFS_FS || LOCKD default y +config NFS_RICHACL + bool + depends on NFSD_V4 || NFS_V4 + select FS_RICHACL + default y + source "net/sunrpc/Kconfig" source "fs/ceph/Kconfig" source "fs/cifs/Kconfig" diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile index d153ca3..e055139 100644 --- a/fs/nfs_common/Makefile +++ b/fs/nfs_common/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o nfs_acl-objs := nfsacl.o +obj-$(CONFIG_NFS_RICHACL) += nfs4acl.o obj-$(CONFIG_GRACE_PERIOD) += grace.o diff --git a/fs/nfs_common/nfs4acl.c b/fs/nfs_common/nfs4acl.c new file mode 100644 index 0000000..02df064 --- /dev/null +++ b/fs/nfs_common/nfs4acl.c @@ -0,0 +1,44 @@ +#include <linux/fs.h> +#include <linux/richacl.h> +#include <linux/nfs4acl.h> + +static struct special_id { + char *who; + int len; +} special_who_map[] = { + [RICHACE_OWNER_SPECIAL_ID] = { + .who = "OWNER@", + .len = sizeof("OWNER@") - 1 }, + [RICHACE_GROUP_SPECIAL_ID] = { + .who = "GROUP@", + .len = sizeof("GROUP@") - 1 }, + [RICHACE_EVERYONE_SPECIAL_ID] = { + .who = "EVERYONE@", + .len = sizeof("EVERYONE@") - 1 } +}; + +int nfs4acl_who_to_special_id(const char *who, u32 len) +{ + int n; + + for (n = 0; n < ARRAY_SIZE(special_who_map); n++) { + if (len == special_who_map[n].len && + !memcmp(who, special_who_map[n].who, len)) + return n; + } + return -1; +} +EXPORT_SYMBOL(nfs4acl_who_to_special_id); + +bool nfs4acl_special_id_to_who(unsigned int special_who, + const char **who, unsigned int *len) +{ + struct special_id *special = &special_who_map[special_who]; + + if (special_who > ARRAY_SIZE(special_who_map) || !special->len) + return false; + *who = special->who; + *len = special->len; + return true; +} +EXPORT_SYMBOL(nfs4acl_special_id_to_who); diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index a0b77fc..811379a 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -70,6 +70,7 @@ config NFSD_V4 depends on NFSD && PROC_FS select NFSD_V3 select FS_POSIX_ACL + select FS_RICHACL select SUNRPC_GSS select CRYPTO select GRACE_PERIOD diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h index 4cd7c69..1c5deb5 100644 --- a/fs/nfsd/acl.h +++ b/fs/nfsd/acl.h @@ -35,25 +35,27 @@ #ifndef LINUX_NFS4_ACL_H #define LINUX_NFS4_ACL_H -struct nfs4_acl; +struct richacl; +struct richace; struct svc_fh; struct svc_rqst; /* * Maximum ACL we'll accept from a client; chosen (somewhat * arbitrarily) so that kmalloc'ing the ACL shouldn't require a - * high-order allocation. This allows 204 ACEs on x86_64: + * high-order allocation. This allows 339 ACEs on x86_64: */ -#define NFS4_ACL_MAX ((PAGE_SIZE - sizeof(struct nfs4_acl)) \ - / sizeof(struct nfs4_ace)) +#define NFSD4_ACL_MAX ((PAGE_SIZE - sizeof(struct richacl)) \ + / sizeof(struct richace)) -int nfs4_acl_bytes(int entries); -int nfs4_acl_get_whotype(char *, u32); -__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who); +__be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp, + char *who, u32 len); +__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp, + struct richace *ace); -int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, - struct nfs4_acl **acl); -__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, - struct nfs4_acl *acl); +int nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct richacl **acl); +__be32 nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct richacl *acl); #endif /* LINUX_NFS4_ACL_H */ diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index eb5accf..582f772 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -36,45 +36,48 @@ #include <linux/slab.h> #include <linux/nfs_fs.h> +#include <linux/richacl_compat.h> +#include <linux/nfs4acl.h> #include "nfsfh.h" #include "nfsd.h" +#include "idmap.h" #include "acl.h" #include "vfs.h" -#define NFS4_ACL_TYPE_DEFAULT 0x01 -#define NFS4_ACL_DIR 0x02 -#define NFS4_ACL_OWNER 0x04 +#define FLAG_DEFAULT_ACL 0x01 +#define FLAG_DIRECTORY 0x02 +#define FLAG_OWNER 0x04 /* mode bit translations: */ -#define NFS4_READ_MODE (NFS4_ACE_READ_DATA) -#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA) -#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE -#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE) -#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL) +#define RICHACE_READ_MODE (RICHACE_READ_DATA) +#define RICHACE_WRITE_MODE (RICHACE_WRITE_DATA | RICHACE_APPEND_DATA) +#define RICHACE_EXECUTE_MODE RICHACE_EXECUTE +#define RICHACE_ANYONE_MODE (RICHACE_READ_ATTRIBUTES | RICHACE_READ_ACL | RICHACE_SYNCHRONIZE) +#define RICHACE_OWNER_MODE (RICHACE_WRITE_ATTRIBUTES | RICHACE_WRITE_ACL) /* flags used to simulate posix default ACLs */ -#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \ - | NFS4_ACE_DIRECTORY_INHERIT_ACE) - -#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \ - | NFS4_ACE_INHERIT_ONLY_ACE \ - | NFS4_ACE_IDENTIFIER_GROUP) +#define RICHACE_SUPPORTED_FLAGS ( \ + RICHACE_FILE_INHERIT_ACE | \ + RICHACE_DIRECTORY_INHERIT_ACE | \ + RICHACE_INHERIT_ONLY_ACE | \ + RICHACE_IDENTIFIER_GROUP | \ + RICHACE_SPECIAL_WHO) static u32 mask_from_posix(unsigned short perm, unsigned int flags) { - int mask = NFS4_ANYONE_MODE; + int mask = RICHACE_ANYONE_MODE; - if (flags & NFS4_ACL_OWNER) - mask |= NFS4_OWNER_MODE; + if (flags & FLAG_OWNER) + mask |= RICHACE_OWNER_MODE; if (perm & ACL_READ) - mask |= NFS4_READ_MODE; + mask |= RICHACE_READ_MODE; if (perm & ACL_WRITE) - mask |= NFS4_WRITE_MODE; - if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) - mask |= NFS4_ACE_DELETE_CHILD; + mask |= RICHACE_WRITE_MODE; + if ((perm & ACL_WRITE) && (flags & FLAG_DIRECTORY)) + mask |= RICHACE_DELETE_CHILD; if (perm & ACL_EXECUTE) - mask |= NFS4_EXECUTE_MODE; + mask |= RICHACE_EXECUTE_MODE; return mask; } @@ -84,13 +87,13 @@ deny_mask_from_posix(unsigned short perm, u32 flags) u32 mask = 0; if (perm & ACL_READ) - mask |= NFS4_READ_MODE; + mask |= RICHACE_READ_MODE; if (perm & ACL_WRITE) - mask |= NFS4_WRITE_MODE; - if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR)) - mask |= NFS4_ACE_DELETE_CHILD; + mask |= RICHACE_WRITE_MODE; + if ((perm & ACL_WRITE) && (flags & FLAG_DIRECTORY)) + mask |= RICHACE_DELETE_CHILD; if (perm & ACL_EXECUTE) - mask |= NFS4_EXECUTE_MODE; + mask |= RICHACE_EXECUTE_MODE; return mask; } @@ -106,32 +109,33 @@ deny_mask_from_posix(unsigned short perm, u32 flags) static void low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags) { - u32 write_mode = NFS4_WRITE_MODE; + u32 write_mode = RICHACE_WRITE_MODE; - if (flags & NFS4_ACL_DIR) - write_mode |= NFS4_ACE_DELETE_CHILD; + if (flags & FLAG_DIRECTORY) + write_mode |= RICHACE_DELETE_CHILD; *mode = 0; - if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE) + if ((perm & RICHACE_READ_MODE) == RICHACE_READ_MODE) *mode |= ACL_READ; if ((perm & write_mode) == write_mode) *mode |= ACL_WRITE; - if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE) + if ((perm & RICHACE_EXECUTE_MODE) == RICHACE_EXECUTE_MODE) *mode |= ACL_EXECUTE; } -static short ace2type(struct nfs4_ace *); -static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, +static short ace2type(struct richace *); +static void _posix_to_richacl_one(struct posix_acl *, struct richacl_alloc *, unsigned int); int -nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, - struct nfs4_acl **acl) +nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct richacl **acl) { struct inode *inode = d_inode(dentry); int error = 0; struct posix_acl *pacl = NULL, *dpacl = NULL; + struct richacl_alloc alloc; unsigned int flags = 0; - int size = 0; + int count; pacl = get_acl(inode, ACL_TYPE_ACCESS); if (!pacl) @@ -141,10 +145,10 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, return PTR_ERR(pacl); /* allocate for worst case: one (deny, allow) pair each: */ - size += 2 * pacl->a_count; + count = 2 * pacl->a_count; if (S_ISDIR(inode->i_mode)) { - flags = NFS4_ACL_DIR; + flags = FLAG_DIRECTORY; dpacl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(dpacl)) { error = PTR_ERR(dpacl); @@ -152,20 +156,20 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, } if (dpacl) - size += 2 * dpacl->a_count; + count += 2 * dpacl->a_count; } - *acl = kmalloc(nfs4_acl_bytes(size), GFP_KERNEL); - if (*acl == NULL) { + if (!richacl_prepare(&alloc, count)) { error = -ENOMEM; goto out; } - (*acl)->naces = 0; - _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT); + _posix_to_richacl_one(pacl, &alloc, flags); if (dpacl) - _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT); + _posix_to_richacl_one(dpacl, &alloc, flags | FLAG_DEFAULT_ACL); + + *acl = alloc.acl; out: posix_acl_release(dpacl); @@ -228,21 +232,22 @@ summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) /* We assume the acl has been verified with posix_acl_valid. */ static void -_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, - unsigned int flags) +_posix_to_richacl_one(struct posix_acl *pacl, struct richacl_alloc *alloc, + unsigned int flags) { struct posix_acl_entry *pa, *group_owner_entry; - struct nfs4_ace *ace; + struct richace *ace; struct posix_acl_summary pas; unsigned short deny; - int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ? - NFS4_INHERITANCE_FLAGS | NFS4_ACE_INHERIT_ONLY_ACE : 0); + int e_flags = ((flags & FLAG_DEFAULT_ACL) ? + (RICHACE_FILE_INHERIT_ACE | + RICHACE_DIRECTORY_INHERIT_ACE | + RICHACE_INHERIT_ONLY_ACE) : 0); BUG_ON(pacl->a_count < 3); summarize_posix_acl(pacl, &pas); pa = pacl->a_entries; - ace = acl->aces + acl->naces; /* We could deny everything not granted by the owner: */ deny = ~pas.owner; @@ -252,42 +257,35 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, */ deny &= pas.users | pas.group | pas.groups | pas.other; if (deny) { - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = deny_mask_from_posix(deny, flags); - ace->whotype = NFS4_ACL_WHO_OWNER; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = deny_mask_from_posix(deny, flags); + ace->e_id.special = RICHACE_OWNER_SPECIAL_ID; } - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); - ace->whotype = NFS4_ACL_WHO_OWNER; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = mask_from_posix(pa->e_perm, flags | FLAG_OWNER); + ace->e_id.special = RICHACE_OWNER_SPECIAL_ID; pa++; while (pa->e_tag == ACL_USER) { deny = ~(pa->e_perm & pas.mask); deny &= pas.groups | pas.group | pas.other; if (deny) { - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = deny_mask_from_posix(deny, flags); - ace->whotype = NFS4_ACL_WHO_NAMED; - ace->who_uid = pa->e_uid; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; + ace->e_flags = e_flags; + ace->e_mask = deny_mask_from_posix(deny, flags); + ace->e_id.uid = pa->e_uid; } - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, - flags); - ace->whotype = NFS4_ACL_WHO_NAMED; - ace->who_uid = pa->e_uid; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags; + ace->e_mask = mask_from_posix(pa->e_perm & pas.mask, flags); + ace->e_id.uid = pa->e_uid; pa++; } @@ -298,23 +296,19 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, group_owner_entry = pa; - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = mask_from_posix(pas.group, flags); - ace->whotype = NFS4_ACL_WHO_GROUP; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = mask_from_posix(pas.group, flags); + ace->e_id.special = RICHACE_GROUP_SPECIAL_ID; pa++; while (pa->e_tag == ACL_GROUP) { - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; - ace->access_mask = mask_from_posix(pa->e_perm & pas.mask, - flags); - ace->whotype = NFS4_ACL_WHO_NAMED; - ace->who_gid = pa->e_gid; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_IDENTIFIER_GROUP; + ace->e_mask = mask_from_posix(pa->e_perm & pas.mask, flags); + ace->e_id.gid = pa->e_gid; pa++; } @@ -324,12 +318,11 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, deny = ~pas.group & pas.other; if (deny) { - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = deny_mask_from_posix(deny, flags); - ace->whotype = NFS4_ACL_WHO_GROUP; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = deny_mask_from_posix(deny, flags); + ace->e_id.special = RICHACE_GROUP_SPECIAL_ID; } pa++; @@ -337,24 +330,22 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, deny = ~(pa->e_perm & pas.mask); deny &= pas.other; if (deny) { - ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; - ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; - ace->access_mask = deny_mask_from_posix(deny, flags); - ace->whotype = NFS4_ACL_WHO_NAMED; - ace->who_gid = pa->e_gid; - ace++; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_IDENTIFIER_GROUP; + ace->e_mask = deny_mask_from_posix(deny, flags); + ace->e_id.gid = pa->e_gid; } pa++; } if (pa->e_tag == ACL_MASK) pa++; - ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE; - ace->flag = eflag; - ace->access_mask = mask_from_posix(pa->e_perm, flags); - ace->whotype = NFS4_ACL_WHO_EVERYONE; - acl->naces++; + ace = richacl_append_entry(alloc); + ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE; + ace->e_flags = e_flags | RICHACE_SPECIAL_WHO; + ace->e_mask = mask_from_posix(pa->e_perm, flags); + ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID; } static bool @@ -498,7 +489,7 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags) * and effective cases: when there are no inheritable ACEs, * calls ->set_acl with a NULL ACL structure. */ - if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT)) + if (state->empty && (flags & FLAG_DEFAULT_ACL)) return NULL; /* @@ -617,24 +608,24 @@ static void allow_bits_array(struct posix_ace_state_array *a, u32 mask) } static void process_one_v4_ace(struct posix_acl_state *state, - struct nfs4_ace *ace) + struct richace *ace) { - u32 mask = ace->access_mask; + u32 mask = ace->e_mask; int i; state->empty = 0; switch (ace2type(ace)) { case ACL_USER_OBJ: - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->owner, mask); } else { deny_bits(&state->owner, mask); } break; case ACL_USER: - i = find_uid(state, ace->who_uid); - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + i = find_uid(state, ace->e_id.uid); + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->users->aces[i].perms, mask); } else { deny_bits(&state->users->aces[i].perms, mask); @@ -643,7 +634,7 @@ static void process_one_v4_ace(struct posix_acl_state *state, } break; case ACL_GROUP_OBJ: - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->group, mask); } else { deny_bits(&state->group, mask); @@ -655,8 +646,8 @@ static void process_one_v4_ace(struct posix_acl_state *state, } break; case ACL_GROUP: - i = find_gid(state, ace->who_gid); - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + i = find_gid(state, ace->e_id.gid); + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->groups->aces[i].perms, mask); } else { deny_bits(&state->groups->aces[i].perms, mask); @@ -669,7 +660,7 @@ static void process_one_v4_ace(struct posix_acl_state *state, } break; case ACL_OTHER: - if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) { + if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) { allow_bits(&state->owner, mask); allow_bits(&state->group, mask); allow_bits(&state->other, mask); @@ -687,32 +678,33 @@ static void process_one_v4_ace(struct posix_acl_state *state, } } -static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, +static int nfs4_richacl_to_posix(struct richacl *acl, struct posix_acl **pacl, struct posix_acl **dpacl, unsigned int flags) { struct posix_acl_state effective_acl_state, default_acl_state; - struct nfs4_ace *ace; + struct richace *ace; int ret; - ret = init_state(&effective_acl_state, acl->naces); + ret = init_state(&effective_acl_state, acl->a_count); if (ret) return ret; - ret = init_state(&default_acl_state, acl->naces); + ret = init_state(&default_acl_state, acl->a_count); if (ret) goto out_estate; ret = -EINVAL; - for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { - if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && - ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) + richacl_for_each_entry(ace, acl) { + if (ace->e_type != RICHACE_ACCESS_ALLOWED_ACE_TYPE && + ace->e_type != RICHACE_ACCESS_DENIED_ACE_TYPE) goto out_dstate; - if (ace->flag & ~NFS4_SUPPORTED_FLAGS) + if (ace->e_flags & ~RICHACE_SUPPORTED_FLAGS) goto out_dstate; - if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) { + if ((ace->e_flags & (RICHACE_FILE_INHERIT_ACE | + RICHACE_DIRECTORY_INHERIT_ACE)) == 0) { process_one_v4_ace(&effective_acl_state, ace); continue; } - if (!(flags & NFS4_ACL_DIR)) + if (!(flags & FLAG_DIRECTORY)) goto out_dstate; /* * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT @@ -721,7 +713,7 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, */ process_one_v4_ace(&default_acl_state, ace); - if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE)) + if (!(ace->e_flags & RICHACE_INHERIT_ONLY_ACE)) process_one_v4_ace(&effective_acl_state, ace); } *pacl = posix_state_to_acl(&effective_acl_state, flags); @@ -731,7 +723,7 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, goto out_dstate; } *dpacl = posix_state_to_acl(&default_acl_state, - flags | NFS4_ACL_TYPE_DEFAULT); + flags | FLAG_DEFAULT_ACL); if (IS_ERR(*dpacl)) { ret = PTR_ERR(*dpacl); *dpacl = NULL; @@ -750,8 +742,7 @@ out_estate: } __be32 -nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, - struct nfs4_acl *acl) +nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl) { __be32 error; int host_error; @@ -772,9 +763,9 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, return nfserr_attrnotsupp; if (S_ISDIR(inode->i_mode)) - flags = NFS4_ACL_DIR; + flags = FLAG_DIRECTORY; - host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); + host_error = nfs4_richacl_to_posix(acl, &pacl, &dpacl, flags); if (host_error == -EINVAL) return nfserr_attrnotsupp; if (host_error < 0) @@ -801,82 +792,62 @@ out_nfserr: static short -ace2type(struct nfs4_ace *ace) +ace2type(struct richace *ace) { - switch (ace->whotype) { - case NFS4_ACL_WHO_NAMED: - return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ? - ACL_GROUP : ACL_USER); - case NFS4_ACL_WHO_OWNER: + if (ace->e_flags & RICHACE_SPECIAL_WHO) { + switch (ace->e_id.special) { + case RICHACE_OWNER_SPECIAL_ID: return ACL_USER_OBJ; - case NFS4_ACL_WHO_GROUP: + case RICHACE_GROUP_SPECIAL_ID: return ACL_GROUP_OBJ; - case NFS4_ACL_WHO_EVERYONE: + case RICHACE_EVERYONE_SPECIAL_ID: return ACL_OTHER; + default: + BUG(); + } } - BUG(); - return -1; -} - -/* - * return the size of the struct nfs4_acl required to represent an acl - * with @entries entries. - */ -int nfs4_acl_bytes(int entries) -{ - return sizeof(struct nfs4_acl) + entries * sizeof(struct nfs4_ace); + return ace->e_flags & RICHACE_IDENTIFIER_GROUP ? ACL_GROUP : ACL_USER; } -static struct { - char *string; - int stringlen; - int type; -} s2t_map[] = { - { - .string = "OWNER@", - .stringlen = sizeof("OWNER@") - 1, - .type = NFS4_ACL_WHO_OWNER, - }, - { - .string = "GROUP@", - .stringlen = sizeof("GROUP@") - 1, - .type = NFS4_ACL_WHO_GROUP, - }, - { - .string = "EVERYONE@", - .stringlen = sizeof("EVERYONE@") - 1, - .type = NFS4_ACL_WHO_EVERYONE, - }, -}; - -int -nfs4_acl_get_whotype(char *p, u32 len) +__be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp, + char *who, u32 len) { - int i; - - for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { - if (s2t_map[i].stringlen == len && - 0 == memcmp(s2t_map[i].string, p, len)) - return s2t_map[i].type; + int special_id; + + special_id = nfs4acl_who_to_special_id(who, len); + if (special_id >= 0) { + ace->e_flags |= RICHACE_SPECIAL_WHO; + ace->e_flags &= ~RICHACE_IDENTIFIER_GROUP; + ace->e_id.special = special_id; + return nfs_ok; } - return NFS4_ACL_WHO_NAMED; + if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) + return nfsd_map_name_to_gid(rqstp, who, len, &ace->e_id.gid); + else + return nfsd_map_name_to_uid(rqstp, who, len, &ace->e_id.uid); } -__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who) +__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp, + struct richace *ace) { - __be32 *p; - int i; - - for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { - if (s2t_map[i].type != who) - continue; - p = xdr_reserve_space(xdr, s2t_map[i].stringlen + 4); + if (ace->e_flags & RICHACE_SPECIAL_WHO) { + unsigned int special_id = ace->e_id.special; + const char *who; + unsigned int len; + __be32 *p; + + if (!nfs4acl_special_id_to_who(special_id, &who, &len)) { + WARN_ON_ONCE(1); + return nfserr_serverfault; + } + p = xdr_reserve_space(xdr, len + 4); if (!p) return nfserr_resource; - p = xdr_encode_opaque(p, s2t_map[i].string, - s2t_map[i].stringlen); + p = xdr_encode_opaque(p, who, len); return 0; } - WARN_ON_ONCE(1); - return nfserr_serverfault; + if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) + return nfsd4_encode_group(xdr, rqstp, ace->e_id.gid); + else + return nfsd4_encode_user(xdr, rqstp, ace->e_id.uid); } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 90cfda7..8c2cb16 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -159,12 +159,12 @@ is_create_with_attrs(struct nfsd4_open *open) * in the returned attr bitmap. */ static void -do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, - struct nfs4_acl *acl, u32 *bmval) +do_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl, + u32 *bmval) { __be32 status; - status = nfsd4_set_nfs4_acl(rqstp, fhp, acl); + status = nfsd4_set_acl(rqstp, fhp, acl); if (status) /* * We should probably fail the whole open at this point, @@ -299,7 +299,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru goto out; if (is_create_with_attrs(open) && open->op_acl != NULL) - do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval); + do_set_acl(rqstp, *resfh, open->op_acl, open->op_bmval); nfsd4_set_open_owner_reply_cache(cstate, open, *resfh); accmode = NFSD_MAY_NOP; @@ -674,8 +674,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); if (create->cr_acl != NULL) - do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, - create->cr_bmval); + do_set_acl(rqstp, &resfh, create->cr_acl, create->cr_bmval); fh_unlock(&cstate->current_fh); set_change_info(&create->cr_cinfo, &cstate->current_fh); @@ -940,8 +939,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; if (setattr->sa_acl != NULL) - status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, - setattr->sa_acl); + status = nfsd4_set_acl(rqstp, &cstate->current_fh, + setattr->sa_acl); if (status) goto out; if (setattr->sa_label.len) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 0768251..465f82a 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -303,7 +303,7 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) static __be32 nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, - struct iattr *iattr, struct nfs4_acl **acl, + struct iattr *iattr, struct richacl **acl, struct xdr_netobj *label) { int expected_len, len = 0; @@ -326,38 +326,31 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, } if (bmval[0] & FATTR4_WORD0_ACL) { u32 nace; - struct nfs4_ace *ace; + struct richace *ace; READ_BUF(4); len += 4; nace = be32_to_cpup(p++); - if (nace > NFS4_ACL_MAX) + if (nace > NFSD4_ACL_MAX) return nfserr_fbig; - *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace)); + *acl = svcxdr_alloc_richacl(argp, nace); if (*acl == NULL) return nfserr_jukebox; - (*acl)->naces = nace; - for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { + richacl_for_each_entry(ace, *acl) { READ_BUF(16); len += 16; - ace->type = be32_to_cpup(p++); - ace->flag = be32_to_cpup(p++); - ace->access_mask = be32_to_cpup(p++); + ace->e_type = be32_to_cpup(p++); + ace->e_flags = be32_to_cpup(p++); + ace->e_mask = be32_to_cpup(p++); + if (ace->e_flags & RICHACE_SPECIAL_WHO) + return nfserr_inval; dummy32 = be32_to_cpup(p++); READ_BUF(dummy32); len += XDR_QUADLEN(dummy32) << 2; READMEM(buf, dummy32); - ace->whotype = nfs4_acl_get_whotype(buf, dummy32); - status = nfs_ok; - if (ace->whotype != NFS4_ACL_WHO_NAMED) - ; - else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) - status = nfsd_map_name_to_gid(argp->rqstp, - buf, dummy32, &ace->who_gid); - else - status = nfsd_map_name_to_uid(argp->rqstp, - buf, dummy32, &ace->who_uid); + status = nfsd4_decode_ace_who(ace, argp->rqstp, + buf, dummy32); if (status) return status; } @@ -2147,18 +2140,6 @@ static u32 nfs4_file_type(umode_t mode) }; } -static inline __be32 -nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp, - struct nfs4_ace *ace) -{ - if (ace->whotype != NFS4_ACL_WHO_NAMED) - return nfs4_acl_write_who(xdr, ace->whotype); - else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) - return nfsd4_encode_group(xdr, rqstp, ace->who_gid); - else - return nfsd4_encode_user(xdr, rqstp, ace->who_uid); -} - #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ FATTR4_WORD0_RDATTR_ERROR) #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID @@ -2249,7 +2230,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, u32 rdattr_err = 0; __be32 status; int err; - struct nfs4_acl *acl = NULL; + struct richacl *acl = NULL; void *context = NULL; int contextlen; bool contextsupport = false; @@ -2295,7 +2276,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, fhp = tempfh; } if (bmval0 & FATTR4_WORD0_ACL) { - err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl); + err = nfsd4_get_acl(rqstp, dentry, &acl); if (err == -EOPNOTSUPP) bmval0 &= ~FATTR4_WORD0_ACL; else if (err == -EINVAL) { @@ -2469,7 +2450,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, *p++ = cpu_to_be32(rdattr_err); } if (bmval0 & FATTR4_WORD0_ACL) { - struct nfs4_ace *ace; + struct richace *ace; if (acl == NULL) { p = xdr_reserve_space(xdr, 4); @@ -2482,17 +2463,16 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, p = xdr_reserve_space(xdr, 4); if (!p) goto out_resource; - *p++ = cpu_to_be32(acl->naces); + *p++ = cpu_to_be32(acl->a_count); - for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) { + richacl_for_each_entry(ace, acl) { p = xdr_reserve_space(xdr, 4*3); if (!p) goto out_resource; - *p++ = cpu_to_be32(ace->type); - *p++ = cpu_to_be32(ace->flag); - *p++ = cpu_to_be32(ace->access_mask & - NFS4_ACE_MASK_ALL); - status = nfsd4_encode_aclname(xdr, rqstp, ace); + *p++ = cpu_to_be32(ace->e_type); + *p++ = cpu_to_be32(ace->e_flags & ~RICHACE_SPECIAL_WHO); + *p++ = cpu_to_be32(ace->e_mask & NFS4_ACE_MASK_ALL); + status = nfsd4_encode_ace_who(xdr, rqstp, ace); if (status) goto out; } @@ -2755,7 +2735,7 @@ out: if (context) security_release_secctx(context, contextlen); #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ - kfree(acl); + richacl_put(acl); if (tempfh) { fh_put(tempfh); kfree(tempfh); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index b698585..c311066 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -118,7 +118,7 @@ struct nfsd4_create { u32 cr_bmval[3]; /* request */ struct iattr cr_iattr; /* request */ struct nfsd4_change_info cr_cinfo; /* response */ - struct nfs4_acl *cr_acl; + struct richacl *cr_acl; struct xdr_netobj cr_label; }; #define cr_datalen u.link.datalen @@ -248,7 +248,7 @@ struct nfsd4_open { struct nfs4_file *op_file; /* used during processing */ struct nfs4_ol_stateid *op_stp; /* used during processing */ struct nfs4_clnt_odstate *op_odstate; /* used during processing */ - struct nfs4_acl *op_acl; + struct richacl *op_acl; struct xdr_netobj op_label; }; @@ -332,7 +332,7 @@ struct nfsd4_setattr { stateid_t sa_stateid; /* request */ u32 sa_bmval[3]; /* request */ struct iattr sa_iattr; /* request */ - struct nfs4_acl *sa_acl; + struct richacl *sa_acl; struct xdr_netobj sa_label; }; diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index b8e72aa..992ddc4 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -16,29 +16,6 @@ #include <linux/uidgid.h> #include <uapi/linux/nfs4.h> -enum nfs4_acl_whotype { - NFS4_ACL_WHO_NAMED = 0, - NFS4_ACL_WHO_OWNER, - NFS4_ACL_WHO_GROUP, - NFS4_ACL_WHO_EVERYONE, -}; - -struct nfs4_ace { - uint32_t type; - uint32_t flag; - uint32_t access_mask; - int whotype; - union { - kuid_t who_uid; - kgid_t who_gid; - }; -}; - -struct nfs4_acl { - uint32_t naces; - struct nfs4_ace aces[0]; -}; - #define NFS4_MAXLABELLEN 2048 struct nfs4_label { diff --git a/include/linux/nfs4acl.h b/include/linux/nfs4acl.h new file mode 100644 index 0000000..db9f9a6 --- /dev/null +++ b/include/linux/nfs4acl.h @@ -0,0 +1,7 @@ +#ifndef __LINUX_NFS4ACL_H +#define __LINUX_NFS4ACL_H + +int nfs4acl_who_to_special_id(const char *, u32); +bool nfs4acl_special_id_to_who(unsigned int, const char **, unsigned int *); + +#endif
When converting from NFSv4 ACLs to POSIX ACLs, nfsd so far was using struct nfs4_acl as its internal representation. This representation is a subset of richacls, so get rid of struct nfs4_acl. Richacls even have a more compact in-memory representation, so a few more ACL entries can easily be supported. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> --- fs/Kconfig | 6 + fs/nfs_common/Makefile | 1 + fs/nfs_common/nfs4acl.c | 44 ++++++ fs/nfsd/Kconfig | 1 + fs/nfsd/acl.h | 24 ++-- fs/nfsd/nfs4acl.c | 367 ++++++++++++++++++++++-------------------------- fs/nfsd/nfs4proc.c | 15 +- fs/nfsd/nfs4xdr.c | 64 +++------ fs/nfsd/xdr4.h | 6 +- include/linux/nfs4.h | 23 --- include/linux/nfs4acl.h | 7 + 11 files changed, 273 insertions(+), 285 deletions(-) create mode 100644 fs/nfs_common/nfs4acl.c create mode 100644 include/linux/nfs4acl.h