Commit 28e05dd8 authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Linus Torvalds

[PATCH] knfsd: nfsd4: represent nfsv4 acl with array instead of linked list

Simplify the memory management and code a bit by representing acls with an
array instead of a linked list.
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 575a6290
...@@ -128,74 +128,58 @@ struct ace_container { ...@@ -128,74 +128,58 @@ struct ace_container {
}; };
static short ace2type(struct nfs4_ace *); static short ace2type(struct nfs4_ace *);
static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int); static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); unsigned int);
void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
struct nfs4_acl * struct nfs4_acl *
nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
unsigned int flags) unsigned int flags)
{ {
struct nfs4_acl *acl; struct nfs4_acl *acl;
int error = -EINVAL; int size = 0;
if ((pacl != NULL && if (pacl) {
(posix_acl_valid(pacl) < 0 || pacl->a_count == 0)) || if (posix_acl_valid(pacl) < 0)
(dpacl != NULL && return ERR_PTR(-EINVAL);
(posix_acl_valid(dpacl) < 0 || dpacl->a_count == 0))) size += 2*pacl->a_count;
goto out_err;
acl = nfs4_acl_new();
if (acl == NULL) {
error = -ENOMEM;
goto out_err;
} }
if (dpacl) {
if (pacl != NULL) { if (posix_acl_valid(dpacl) < 0)
error = _posix_to_nfsv4_one(pacl, acl, return ERR_PTR(-EINVAL);
flags & ~NFS4_ACL_TYPE_DEFAULT); size += 2*dpacl->a_count;
if (error < 0)
goto out_acl;
} }
if (dpacl != NULL) { /* Allocate for worst case: one (deny, allow) pair each: */
error = _posix_to_nfsv4_one(dpacl, acl, acl = nfs4_acl_new(size);
flags | NFS4_ACL_TYPE_DEFAULT); if (acl == NULL)
if (error < 0) return ERR_PTR(-ENOMEM);
goto out_acl;
}
return acl; if (pacl)
_posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
out_acl: if (dpacl)
nfs4_acl_free(acl); _posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT);
out_err:
acl = ERR_PTR(error);
return acl; return acl;
} }
static int static void
nfs4_acl_add_pair(struct nfs4_acl *acl, int eflag, u32 mask, int whotype, nfs4_acl_add_pair(struct nfs4_acl *acl, int eflag, u32 mask, int whotype,
uid_t owner, unsigned int flags) uid_t owner, unsigned int flags)
{ {
int error; nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
eflag, mask, whotype, owner); eflag, mask, whotype, owner);
if (error < 0) nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
return error;
error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
eflag, deny_mask(mask, flags), whotype, owner); eflag, deny_mask(mask, flags), whotype, owner);
return error;
} }
/* We assume the acl has been verified with posix_acl_valid. */ /* We assume the acl has been verified with posix_acl_valid. */
static int static void
_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
unsigned int flags) unsigned int flags)
{ {
struct posix_acl_entry *pa, *pe, *group_owner_entry; struct posix_acl_entry *pa, *pe, *group_owner_entry;
int error = -EINVAL;
u32 mask, mask_mask; u32 mask, mask_mask;
int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ? int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ?
NFS4_INHERITANCE_FLAGS : 0); NFS4_INHERITANCE_FLAGS : 0);
...@@ -211,23 +195,16 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, ...@@ -211,23 +195,16 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
pa = pacl->a_entries; pa = pacl->a_entries;
BUG_ON(pa->e_tag != ACL_USER_OBJ); BUG_ON(pa->e_tag != ACL_USER_OBJ);
mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER);
error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_OWNER, 0, flags); nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_OWNER, 0, flags);
if (error < 0)
goto out;
pa++; pa++;
while (pa->e_tag == ACL_USER) { while (pa->e_tag == ACL_USER) {
mask = mask_from_posix(pa->e_perm, flags); mask = mask_from_posix(pa->e_perm, flags);
error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
eflag, mask_mask, NFS4_ACL_WHO_NAMED, pa->e_id); eflag, mask_mask, NFS4_ACL_WHO_NAMED, pa->e_id);
if (error < 0)
goto out;
nfs4_acl_add_pair(acl, eflag, mask,
error = nfs4_acl_add_pair(acl, eflag, mask,
NFS4_ACL_WHO_NAMED, pa->e_id, flags); NFS4_ACL_WHO_NAMED, pa->e_id, flags);
if (error < 0)
goto out;
pa++; pa++;
} }
...@@ -238,34 +215,25 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, ...@@ -238,34 +215,25 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
if (pacl->a_count > 3) { if (pacl->a_count > 3) {
BUG_ON(pa->e_tag != ACL_GROUP_OBJ); BUG_ON(pa->e_tag != ACL_GROUP_OBJ);
error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask, NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask,
NFS4_ACL_WHO_GROUP, 0); NFS4_ACL_WHO_GROUP, 0);
if (error < 0)
goto out;
} }
group_owner_entry = pa; group_owner_entry = pa;
mask = mask_from_posix(pa->e_perm, flags); mask = mask_from_posix(pa->e_perm, flags);
error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, NFS4_ACE_IDENTIFIER_GROUP | eflag, mask,
NFS4_ACL_WHO_GROUP, 0); NFS4_ACL_WHO_GROUP, 0);
if (error < 0)
goto out;
pa++; pa++;
while (pa->e_tag == ACL_GROUP) { while (pa->e_tag == ACL_GROUP) {
mask = mask_from_posix(pa->e_perm, flags); mask = mask_from_posix(pa->e_perm, flags);
error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask, NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask,
NFS4_ACL_WHO_NAMED, pa->e_id); NFS4_ACL_WHO_NAMED, pa->e_id);
if (error < 0) nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
goto out;
error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, NFS4_ACE_IDENTIFIER_GROUP | eflag, mask,
NFS4_ACL_WHO_NAMED, pa->e_id); NFS4_ACL_WHO_NAMED, pa->e_id);
if (error < 0)
goto out;
pa++; pa++;
} }
...@@ -273,19 +241,15 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, ...@@ -273,19 +241,15 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
pa = group_owner_entry; pa = group_owner_entry;
mask = mask_from_posix(pa->e_perm, flags); mask = mask_from_posix(pa->e_perm, flags);
error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
NFS4_ACE_IDENTIFIER_GROUP | eflag, NFS4_ACE_IDENTIFIER_GROUP | eflag,
deny_mask(mask, flags), NFS4_ACL_WHO_GROUP, 0); deny_mask(mask, flags), NFS4_ACL_WHO_GROUP, 0);
if (error < 0)
goto out;
pa++; pa++;
while (pa->e_tag == ACL_GROUP) { while (pa->e_tag == ACL_GROUP) {
mask = mask_from_posix(pa->e_perm, flags); mask = mask_from_posix(pa->e_perm, flags);
error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
NFS4_ACE_IDENTIFIER_GROUP | eflag, NFS4_ACE_IDENTIFIER_GROUP | eflag,
deny_mask(mask, flags), NFS4_ACL_WHO_NAMED, pa->e_id); deny_mask(mask, flags), NFS4_ACL_WHO_NAMED, pa->e_id);
if (error < 0)
goto out;
pa++; pa++;
} }
...@@ -293,10 +257,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, ...@@ -293,10 +257,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
pa++; pa++;
BUG_ON(pa->e_tag != ACL_OTHER); BUG_ON(pa->e_tag != ACL_OTHER);
mask = mask_from_posix(pa->e_perm, flags); mask = mask_from_posix(pa->e_perm, flags);
error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_EVERYONE, 0, flags); nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_EVERYONE, 0, flags);
out:
return error;
} }
static void static void
...@@ -640,7 +601,7 @@ int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, ...@@ -640,7 +601,7 @@ int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
if (ret) if (ret)
goto out_estate; goto out_estate;
ret = -EINVAL; ret = -EINVAL;
list_for_each_entry(ace, &acl->ace_head, l_ace) { for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE && if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE) ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
goto out_dstate; goto out_dstate;
...@@ -705,48 +666,22 @@ EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4); ...@@ -705,48 +666,22 @@ EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4);
EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix); EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix);
struct nfs4_acl * struct nfs4_acl *
nfs4_acl_new(void) nfs4_acl_new(int n)
{ {
struct nfs4_acl *acl; struct nfs4_acl *acl;
if ((acl = kmalloc(sizeof(*acl), GFP_KERNEL)) == NULL) acl = kmalloc(sizeof(*acl) + n*sizeof(struct nfs4_ace), GFP_KERNEL);
if (acl == NULL)
return NULL; return NULL;
acl->naces = 0; acl->naces = 0;
INIT_LIST_HEAD(&acl->ace_head);
return acl; return acl;
} }
void void
nfs4_acl_free(struct nfs4_acl *acl)
{
struct list_head *h;
struct nfs4_ace *ace;
if (!acl)
return;
while (!list_empty(&acl->ace_head)) {
h = acl->ace_head.next;
list_del(h);
ace = list_entry(h, struct nfs4_ace, l_ace);
kfree(ace);
}
kfree(acl);
return;
}
int
nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask, nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
int whotype, uid_t who) int whotype, uid_t who)
{ {
struct nfs4_ace *ace; struct nfs4_ace *ace = acl->aces + acl->naces;
if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL)
return -ENOMEM;
ace->type = type; ace->type = type;
ace->flag = flag; ace->flag = flag;
...@@ -754,10 +689,7 @@ nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask, ...@@ -754,10 +689,7 @@ nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
ace->whotype = whotype; ace->whotype = whotype;
ace->who = who; ace->who = who;
list_add_tail(&ace->l_ace, &acl->ace_head);
acl->naces++; acl->naces++;
return 0;
} }
static struct { static struct {
...@@ -811,7 +743,6 @@ nfs4_acl_write_who(int who, char *p) ...@@ -811,7 +743,6 @@ nfs4_acl_write_who(int who, char *p)
} }
EXPORT_SYMBOL(nfs4_acl_new); EXPORT_SYMBOL(nfs4_acl_new);
EXPORT_SYMBOL(nfs4_acl_free);
EXPORT_SYMBOL(nfs4_acl_add_ace); EXPORT_SYMBOL(nfs4_acl_add_ace);
EXPORT_SYMBOL(nfs4_acl_get_whotype); EXPORT_SYMBOL(nfs4_acl_get_whotype);
EXPORT_SYMBOL(nfs4_acl_write_who); EXPORT_SYMBOL(nfs4_acl_write_who);
...@@ -273,42 +273,42 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia ...@@ -273,42 +273,42 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
iattr->ia_valid |= ATTR_SIZE; iattr->ia_valid |= ATTR_SIZE;
} }
if (bmval[0] & FATTR4_WORD0_ACL) { if (bmval[0] & FATTR4_WORD0_ACL) {
int nace, i; int nace;
struct nfs4_ace ace; struct nfs4_ace *ace;
READ_BUF(4); len += 4; READ_BUF(4); len += 4;
READ32(nace); READ32(nace);
*acl = nfs4_acl_new(); if (nace > NFS4_ACL_MAX)
return nfserr_resource;
*acl = nfs4_acl_new(nace);
if (*acl == NULL) { if (*acl == NULL) {
host_err = -ENOMEM; host_err = -ENOMEM;
goto out_nfserr; goto out_nfserr;
} }
defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl); defer_free(argp, kfree, *acl);
for (i = 0; i < nace; i++) { (*acl)->naces = nace;
for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {
READ_BUF(16); len += 16; READ_BUF(16); len += 16;
READ32(ace.type); READ32(ace->type);
READ32(ace.flag); READ32(ace->flag);
READ32(ace.access_mask); READ32(ace->access_mask);
READ32(dummy32); READ32(dummy32);
READ_BUF(dummy32); READ_BUF(dummy32);
len += XDR_QUADLEN(dummy32) << 2; len += XDR_QUADLEN(dummy32) << 2;
READMEM(buf, dummy32); READMEM(buf, dummy32);
ace.whotype = nfs4_acl_get_whotype(buf, dummy32); ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
host_err = 0; host_err = 0;
if (ace.whotype != NFS4_ACL_WHO_NAMED) if (ace->whotype != NFS4_ACL_WHO_NAMED)
ace.who = 0; ace->who = 0;
else if (ace.flag & NFS4_ACE_IDENTIFIER_GROUP) else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
host_err = nfsd_map_name_to_gid(argp->rqstp, host_err = nfsd_map_name_to_gid(argp->rqstp,
buf, dummy32, &ace.who); buf, dummy32, &ace->who);
else else
host_err = nfsd_map_name_to_uid(argp->rqstp, host_err = nfsd_map_name_to_uid(argp->rqstp,
buf, dummy32, &ace.who); buf, dummy32, &ace->who);
if (host_err)
goto out_nfserr;
host_err = nfs4_acl_add_ace(*acl, ace.type, ace.flag,
ace.access_mask, ace.whotype, ace.who);
if (host_err) if (host_err)
goto out_nfserr; goto out_nfserr;
} }
...@@ -1596,7 +1596,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, ...@@ -1596,7 +1596,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
} }
if (bmval0 & FATTR4_WORD0_ACL) { if (bmval0 & FATTR4_WORD0_ACL) {
struct nfs4_ace *ace; struct nfs4_ace *ace;
struct list_head *h;
if (acl == NULL) { if (acl == NULL) {
if ((buflen -= 4) < 0) if ((buflen -= 4) < 0)
...@@ -1609,9 +1608,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, ...@@ -1609,9 +1608,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
goto out_resource; goto out_resource;
WRITE32(acl->naces); WRITE32(acl->naces);
list_for_each(h, &acl->ace_head) { for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
ace = list_entry(h, struct nfs4_ace, l_ace);
if ((buflen -= 4*3) < 0) if ((buflen -= 4*3) < 0)
goto out_resource; goto out_resource;
WRITE32(ace->type); WRITE32(ace->type);
...@@ -1821,7 +1818,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, ...@@ -1821,7 +1818,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
status = nfs_ok; status = nfs_ok;
out: out:
nfs4_acl_free(acl); kfree(acl);
if (fhp == &tempfh) if (fhp == &tempfh)
fh_put(&tempfh); fh_put(&tempfh);
return status; return status;
......
...@@ -105,12 +105,11 @@ struct nfs4_ace { ...@@ -105,12 +105,11 @@ struct nfs4_ace {
uint32_t access_mask; uint32_t access_mask;
int whotype; int whotype;
uid_t who; uid_t who;
struct list_head l_ace;
}; };
struct nfs4_acl { struct nfs4_acl {
uint32_t naces; uint32_t naces;
struct list_head ace_head; struct nfs4_ace aces[0];
}; };
typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier; typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
......
...@@ -39,9 +39,12 @@ ...@@ -39,9 +39,12 @@
#include <linux/posix_acl.h> #include <linux/posix_acl.h>
struct nfs4_acl *nfs4_acl_new(void); /* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to
void nfs4_acl_free(struct nfs4_acl *); * fit in a page: */
int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); #define NFS4_ACL_MAX 170
struct nfs4_acl *nfs4_acl_new(int);
void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
int nfs4_acl_get_whotype(char *, u32); int nfs4_acl_get_whotype(char *, u32);
int nfs4_acl_write_who(int who, char *p); int nfs4_acl_write_who(int who, char *p);
int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group, int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment