Commit a257cdd0e2179630d3201c32ba14d7fcb3c3a055

Authored by Andreas Gruenbacher
Committed by Trond Myklebust
1 parent 9ba02638e4

[PATCH] NFSD: Add server support for NFSv3 ACLs.

This adds functions for encoding and decoding POSIX ACLs for the NFSACL
 protocol extension, and the GETACL and SETACL RPCs.  The implementation is
 compatible with NFSACL in Solaris.

 Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
 Acked-by: Olaf Kirch <okir@suse.de>
 Signed-off-by: Andrew Morton <akpm@osdl.org>
 Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

Showing 16 changed files with 1166 additions and 1 deletions Side-by-side Diff

... ... @@ -1353,6 +1353,7 @@
1353 1353 select LOCKD
1354 1354 select SUNRPC
1355 1355 select EXPORTFS
  1356 + select NFS_ACL_SUPPORT if NFSD_V3_ACL || NFSD_V2_ACL
1356 1357 help
1357 1358 If you want your Linux box to act as an NFS *server*, so that other
1358 1359 computers on your local network which support NFS can access certain
... ... @@ -1376,6 +1377,10 @@
1376 1377 To compile the NFS server support as a module, choose M here: the
1377 1378 module will be called nfsd. If unsure, say N.
1378 1379  
  1380 +config NFSD_V2_ACL
  1381 + bool
  1382 + depends on NFSD
  1383 +
1379 1384 config NFSD_V3
1380 1385 bool "Provide NFSv3 server support"
1381 1386 depends on NFSD
... ... @@ -1383,6 +1388,16 @@
1383 1388 If you would like to include the NFSv3 server as well as the NFSv2
1384 1389 server, say Y here. If unsure, say Y.
1385 1390  
  1391 +config NFSD_V3_ACL
  1392 + bool "Provide server support for the NFSv3 ACL protocol extension"
  1393 + depends on NFSD_V3
  1394 + select NFSD_V2_ACL
  1395 + help
  1396 + Implement the NFSv3 ACL protocol extension for manipulating POSIX
  1397 + Access Control Lists on exported file systems. NFS clients should
  1398 + be compiled with the NFSv3 ACL protocol extension; see the
  1399 + CONFIG_NFS_V3_ACL option. If unsure, say N.
  1400 +
1386 1401 config NFSD_V4
1387 1402 bool "Provide NFSv4 server support (EXPERIMENTAL)"
1388 1403 depends on NFSD_V3 && EXPERIMENTAL
... ... @@ -1426,6 +1441,15 @@
1426 1441  
1427 1442 config EXPORTFS
1428 1443 tristate
  1444 +
  1445 +config NFS_ACL_SUPPORT
  1446 + tristate
  1447 + select FS_POSIX_ACL
  1448 +
  1449 +config NFS_COMMON
  1450 + bool
  1451 + depends on NFSD || NFS_FS
  1452 + default y
1429 1453  
1430 1454 config SUNRPC
1431 1455 tristate
... ... @@ -31,6 +31,7 @@
31 31  
32 32 obj-$(CONFIG_FS_MBCACHE) += mbcache.o
33 33 obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
  34 +obj-$(CONFIG_NFS_COMMON) += nfs_common/
34 35  
35 36 obj-$(CONFIG_QUOTA) += dquot.o
36 37 obj-$(CONFIG_QFMT_V1) += quota_v1.o
fs/nfs_common/Makefile
  1 +#
  2 +# Makefile for Linux filesystem routines that are shared by client and server.
  3 +#
  4 +
  5 +obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o
  6 +
  7 +nfs_acl-objs := nfsacl.o
fs/nfs_common/nfsacl.c
  1 +/*
  2 + * fs/nfs_common/nfsacl.c
  3 + *
  4 + * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
  5 + */
  6 +
  7 +/*
  8 + * The Solaris nfsacl protocol represents some ACLs slightly differently
  9 + * than POSIX 1003.1e draft 17 does (and we do):
  10 + *
  11 + * - Minimal ACLs always have an ACL_MASK entry, so they have
  12 + * four instead of three entries.
  13 + * - The ACL_MASK entry in such minimal ACLs always has the same
  14 + * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs
  15 + * the ACL_MASK and ACL_GROUP_OBJ entries may differ.)
  16 + * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ
  17 + * entries contain the identifiers of the owner and owning group.
  18 + * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID).
  19 + * - ACL entries in the kernel are kept sorted in ascending order
  20 + * of (e_tag, e_id). Solaris ACLs are unsorted.
  21 + */
  22 +
  23 +#include <linux/module.h>
  24 +#include <linux/fs.h>
  25 +#include <linux/sunrpc/xdr.h>
  26 +#include <linux/nfsacl.h>
  27 +#include <linux/nfs3.h>
  28 +#include <linux/sort.h>
  29 +
  30 +MODULE_LICENSE("GPL");
  31 +
  32 +EXPORT_SYMBOL(nfsacl_encode);
  33 +EXPORT_SYMBOL(nfsacl_decode);
  34 +
  35 +struct nfsacl_encode_desc {
  36 + struct xdr_array2_desc desc;
  37 + unsigned int count;
  38 + struct posix_acl *acl;
  39 + int typeflag;
  40 + uid_t uid;
  41 + gid_t gid;
  42 +};
  43 +
  44 +static int
  45 +xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
  46 +{
  47 + struct nfsacl_encode_desc *nfsacl_desc =
  48 + (struct nfsacl_encode_desc *) desc;
  49 + u32 *p = (u32 *) elem;
  50 +
  51 + if (nfsacl_desc->count < nfsacl_desc->acl->a_count) {
  52 + struct posix_acl_entry *entry =
  53 + &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
  54 +
  55 + *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag);
  56 + switch(entry->e_tag) {
  57 + case ACL_USER_OBJ:
  58 + *p++ = htonl(nfsacl_desc->uid);
  59 + break;
  60 + case ACL_GROUP_OBJ:
  61 + *p++ = htonl(nfsacl_desc->gid);
  62 + break;
  63 + case ACL_USER:
  64 + case ACL_GROUP:
  65 + *p++ = htonl(entry->e_id);
  66 + break;
  67 + default: /* Solaris depends on that! */
  68 + *p++ = 0;
  69 + break;
  70 + }
  71 + *p++ = htonl(entry->e_perm & S_IRWXO);
  72 + } else {
  73 + const struct posix_acl_entry *pa, *pe;
  74 + int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE;
  75 +
  76 + FOREACH_ACL_ENTRY(pa, nfsacl_desc->acl, pe) {
  77 + if (pa->e_tag == ACL_GROUP_OBJ) {
  78 + group_obj_perm = pa->e_perm & S_IRWXO;
  79 + break;
  80 + }
  81 + }
  82 + /* fake up ACL_MASK entry */
  83 + *p++ = htonl(ACL_MASK | nfsacl_desc->typeflag);
  84 + *p++ = htonl(0);
  85 + *p++ = htonl(group_obj_perm);
  86 + }
  87 +
  88 + return 0;
  89 +}
  90 +
  91 +unsigned int
  92 +nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
  93 + struct posix_acl *acl, int encode_entries, int typeflag)
  94 +{
  95 + int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
  96 + struct nfsacl_encode_desc nfsacl_desc = {
  97 + .desc = {
  98 + .elem_size = 12,
  99 + .array_len = encode_entries ? entries : 0,
  100 + .xcode = xdr_nfsace_encode,
  101 + },
  102 + .acl = acl,
  103 + .typeflag = typeflag,
  104 + .uid = inode->i_uid,
  105 + .gid = inode->i_gid,
  106 + };
  107 + int err;
  108 +
  109 + if (entries > NFS_ACL_MAX_ENTRIES ||
  110 + xdr_encode_word(buf, base, entries))
  111 + return -EINVAL;
  112 + err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
  113 + if (!err)
  114 + err = 8 + nfsacl_desc.desc.elem_size *
  115 + nfsacl_desc.desc.array_len;
  116 + return err;
  117 +}
  118 +
  119 +struct nfsacl_decode_desc {
  120 + struct xdr_array2_desc desc;
  121 + unsigned int count;
  122 + struct posix_acl *acl;
  123 +};
  124 +
  125 +static int
  126 +xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem)
  127 +{
  128 + struct nfsacl_decode_desc *nfsacl_desc =
  129 + (struct nfsacl_decode_desc *) desc;
  130 + u32 *p = (u32 *) elem;
  131 + struct posix_acl_entry *entry;
  132 +
  133 + if (!nfsacl_desc->acl) {
  134 + if (desc->array_len > NFS_ACL_MAX_ENTRIES)
  135 + return -EINVAL;
  136 + nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL);
  137 + if (!nfsacl_desc->acl)
  138 + return -ENOMEM;
  139 + nfsacl_desc->count = 0;
  140 + }
  141 +
  142 + entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
  143 + entry->e_tag = ntohl(*p++) & ~NFS_ACL_DEFAULT;
  144 + entry->e_id = ntohl(*p++);
  145 + entry->e_perm = ntohl(*p++);
  146 +
  147 + switch(entry->e_tag) {
  148 + case ACL_USER_OBJ:
  149 + case ACL_USER:
  150 + case ACL_GROUP_OBJ:
  151 + case ACL_GROUP:
  152 + case ACL_OTHER:
  153 + if (entry->e_perm & ~S_IRWXO)
  154 + return -EINVAL;
  155 + break;
  156 + case ACL_MASK:
  157 + /* Solaris sometimes sets additonal bits in the mask */
  158 + entry->e_perm &= S_IRWXO;
  159 + break;
  160 + default:
  161 + return -EINVAL;
  162 + }
  163 +
  164 + return 0;
  165 +}
  166 +
  167 +static int
  168 +cmp_acl_entry(const void *x, const void *y)
  169 +{
  170 + const struct posix_acl_entry *a = x, *b = y;
  171 +
  172 + if (a->e_tag != b->e_tag)
  173 + return a->e_tag - b->e_tag;
  174 + else if (a->e_id > b->e_id)
  175 + return 1;
  176 + else if (a->e_id < b->e_id)
  177 + return -1;
  178 + else
  179 + return 0;
  180 +}
  181 +
  182 +/*
  183 + * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL.
  184 + */
  185 +static int
  186 +posix_acl_from_nfsacl(struct posix_acl *acl)
  187 +{
  188 + struct posix_acl_entry *pa, *pe,
  189 + *group_obj = NULL, *mask = NULL;
  190 +
  191 + if (!acl)
  192 + return 0;
  193 +
  194 + sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry),
  195 + cmp_acl_entry, NULL);
  196 +
  197 + /* Clear undefined identifier fields and find the ACL_GROUP_OBJ
  198 + and ACL_MASK entries. */
  199 + FOREACH_ACL_ENTRY(pa, acl, pe) {
  200 + switch(pa->e_tag) {
  201 + case ACL_USER_OBJ:
  202 + pa->e_id = ACL_UNDEFINED_ID;
  203 + break;
  204 + case ACL_GROUP_OBJ:
  205 + pa->e_id = ACL_UNDEFINED_ID;
  206 + group_obj = pa;
  207 + break;
  208 + case ACL_MASK:
  209 + mask = pa;
  210 + /* fall through */
  211 + case ACL_OTHER:
  212 + pa->e_id = ACL_UNDEFINED_ID;
  213 + break;
  214 + }
  215 + }
  216 + if (acl->a_count == 4 && group_obj && mask &&
  217 + mask->e_perm == group_obj->e_perm) {
  218 + /* remove bogus ACL_MASK entry */
  219 + memmove(mask, mask+1, (3 - (mask - acl->a_entries)) *
  220 + sizeof(struct posix_acl_entry));
  221 + acl->a_count = 3;
  222 + }
  223 + return 0;
  224 +}
  225 +
  226 +unsigned int
  227 +nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
  228 + struct posix_acl **pacl)
  229 +{
  230 + struct nfsacl_decode_desc nfsacl_desc = {
  231 + .desc = {
  232 + .elem_size = 12,
  233 + .xcode = pacl ? xdr_nfsace_decode : NULL,
  234 + },
  235 + };
  236 + u32 entries;
  237 + int err;
  238 +
  239 + if (xdr_decode_word(buf, base, &entries) ||
  240 + entries > NFS_ACL_MAX_ENTRIES)
  241 + return -EINVAL;
  242 + err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc);
  243 + if (err)
  244 + return err;
  245 + if (pacl) {
  246 + if (entries != nfsacl_desc.desc.array_len ||
  247 + posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) {
  248 + posix_acl_release(nfsacl_desc.acl);
  249 + return -EINVAL;
  250 + }
  251 + *pacl = nfsacl_desc.acl;
  252 + }
  253 + if (aclcnt)
  254 + *aclcnt = entries;
  255 + return 8 + nfsacl_desc.desc.elem_size *
  256 + nfsacl_desc.desc.array_len;
  257 +}
... ... @@ -6,7 +6,9 @@
6 6  
7 7 nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
8 8 export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
  9 +nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
9 10 nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
  11 +nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
10 12 nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
11 13 nfs4acl.o nfs4callback.o
12 14 nfsd-objs := $(nfsd-y)
  1 +/*
  2 + * linux/fs/nfsd/nfsacl.c
  3 + *
  4 + * Process version 2 NFSACL requests.
  5 + *
  6 + * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
  7 + */
  8 +
  9 +#include <linux/sunrpc/svc.h>
  10 +#include <linux/nfs.h>
  11 +#include <linux/nfsd/nfsd.h>
  12 +#include <linux/nfsd/cache.h>
  13 +#include <linux/nfsd/xdr.h>
  14 +#include <linux/nfsd/xdr3.h>
  15 +#include <linux/posix_acl.h>
  16 +#include <linux/nfsacl.h>
  17 +
  18 +#define NFSDDBG_FACILITY NFSDDBG_PROC
  19 +#define RETURN_STATUS(st) { resp->status = (st); return (st); }
  20 +
  21 +/*
  22 + * NULL call.
  23 + */
  24 +static int
  25 +nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
  26 +{
  27 + return nfs_ok;
  28 +}
  29 +
  30 +/*
  31 + * Get the Access and/or Default ACL of a file.
  32 + */
  33 +static int nfsacld_proc_getacl(struct svc_rqst * rqstp,
  34 + struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
  35 +{
  36 + svc_fh *fh;
  37 + struct posix_acl *acl;
  38 + int nfserr = 0;
  39 +
  40 + dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
  41 +
  42 + fh = fh_copy(&resp->fh, &argp->fh);
  43 + if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP)))
  44 + RETURN_STATUS(nfserr_inval);
  45 +
  46 + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
  47 + RETURN_STATUS(nfserr_inval);
  48 + resp->mask = argp->mask;
  49 +
  50 + if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
  51 + acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
  52 + if (IS_ERR(acl)) {
  53 + int err = PTR_ERR(acl);
  54 +
  55 + if (err == -ENODATA || err == -EOPNOTSUPP)
  56 + acl = NULL;
  57 + else {
  58 + nfserr = nfserrno(err);
  59 + goto fail;
  60 + }
  61 + }
  62 + if (acl == NULL) {
  63 + /* Solaris returns the inode's minimum ACL. */
  64 +
  65 + struct inode *inode = fh->fh_dentry->d_inode;
  66 + acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
  67 + }
  68 + resp->acl_access = acl;
  69 + }
  70 + if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
  71 + /* Check how Solaris handles requests for the Default ACL
  72 + of a non-directory! */
  73 +
  74 + acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
  75 + if (IS_ERR(acl)) {
  76 + int err = PTR_ERR(acl);
  77 +
  78 + if (err == -ENODATA || err == -EOPNOTSUPP)
  79 + acl = NULL;
  80 + else {
  81 + nfserr = nfserrno(err);
  82 + goto fail;
  83 + }
  84 + }
  85 + resp->acl_default = acl;
  86 + }
  87 +
  88 + /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
  89 + RETURN_STATUS(0);
  90 +
  91 +fail:
  92 + posix_acl_release(resp->acl_access);
  93 + posix_acl_release(resp->acl_default);
  94 + RETURN_STATUS(nfserr);
  95 +}
  96 +
  97 +/*
  98 + * Set the Access and/or Default ACL of a file.
  99 + */
  100 +static int nfsacld_proc_setacl(struct svc_rqst * rqstp,
  101 + struct nfsd3_setaclargs *argp,
  102 + struct nfsd_attrstat *resp)
  103 +{
  104 + svc_fh *fh;
  105 + int nfserr = 0;
  106 +
  107 + dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
  108 +
  109 + fh = fh_copy(&resp->fh, &argp->fh);
  110 + nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
  111 +
  112 + if (!nfserr) {
  113 + nfserr = nfserrno( nfsd_set_posix_acl(
  114 + fh, ACL_TYPE_ACCESS, argp->acl_access) );
  115 + }
  116 + if (!nfserr) {
  117 + nfserr = nfserrno( nfsd_set_posix_acl(
  118 + fh, ACL_TYPE_DEFAULT, argp->acl_default) );
  119 + }
  120 +
  121 + /* argp->acl_{access,default} may have been allocated in
  122 + nfssvc_decode_setaclargs. */
  123 + posix_acl_release(argp->acl_access);
  124 + posix_acl_release(argp->acl_default);
  125 + return nfserr;
  126 +}
  127 +
  128 +/*
  129 + * Check file attributes
  130 + */
  131 +static int nfsacld_proc_getattr(struct svc_rqst * rqstp,
  132 + struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
  133 +{
  134 + dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
  135 +
  136 + fh_copy(&resp->fh, &argp->fh);
  137 + return fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
  138 +}
  139 +
  140 +/*
  141 + * Check file access
  142 + */
  143 +static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
  144 + struct nfsd3_accessres *resp)
  145 +{
  146 + int nfserr;
  147 +
  148 + dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
  149 + SVCFH_fmt(&argp->fh),
  150 + argp->access);
  151 +
  152 + fh_copy(&resp->fh, &argp->fh);
  153 + resp->access = argp->access;
  154 + nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
  155 + return nfserr;
  156 +}
  157 +
  158 +/*
  159 + * XDR decode functions
  160 + */
  161 +static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
  162 + struct nfsd3_getaclargs *argp)
  163 +{
  164 + if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
  165 + return 0;
  166 + argp->mask = ntohl(*p); p++;
  167 +
  168 + return xdr_argsize_check(rqstp, p);
  169 +}
  170 +
  171 +
  172 +static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
  173 + struct nfsd3_setaclargs *argp)
  174 +{
  175 + struct kvec *head = rqstp->rq_arg.head;
  176 + unsigned int base;
  177 + int n;
  178 +
  179 + if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
  180 + return 0;
  181 + argp->mask = ntohl(*p++);
  182 + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) ||
  183 + !xdr_argsize_check(rqstp, p))
  184 + return 0;
  185 +
  186 + base = (char *)p - (char *)head->iov_base;
  187 + n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
  188 + (argp->mask & NFS_ACL) ?
  189 + &argp->acl_access : NULL);
  190 + if (n > 0)
  191 + n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
  192 + (argp->mask & NFS_DFACL) ?
  193 + &argp->acl_default : NULL);
  194 + return (n > 0);
  195 +}
  196 +
  197 +static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p,
  198 + struct nfsd_fhandle *argp)
  199 +{
  200 + if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
  201 + return 0;
  202 + return xdr_argsize_check(rqstp, p);
  203 +}
  204 +
  205 +static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
  206 + struct nfsd3_accessargs *argp)
  207 +{
  208 + if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
  209 + return 0;
  210 + argp->access = ntohl(*p++);
  211 +
  212 + return xdr_argsize_check(rqstp, p);
  213 +}
  214 +
  215 +/*
  216 + * XDR encode functions
  217 + */
  218 +
  219 +/* GETACL */
  220 +static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
  221 + struct nfsd3_getaclres *resp)
  222 +{
  223 + struct dentry *dentry = resp->fh.fh_dentry;
  224 + struct inode *inode = dentry->d_inode;
  225 + int w = nfsacl_size(
  226 + (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
  227 + (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
  228 + struct kvec *head = rqstp->rq_res.head;
  229 + unsigned int base;
  230 + int n;
  231 +
  232 + if (dentry == NULL || dentry->d_inode == NULL)
  233 + return 0;
  234 + inode = dentry->d_inode;
  235 +
  236 + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
  237 + *p++ = htonl(resp->mask);
  238 + if (!xdr_ressize_check(rqstp, p))
  239 + return 0;
  240 + base = (char *)p - (char *)head->iov_base;
  241 +
  242 + rqstp->rq_res.page_len = w;
  243 + while (w > 0) {
  244 + if (!svc_take_res_page(rqstp))
  245 + return 0;
  246 + w -= PAGE_SIZE;
  247 + }
  248 +
  249 + n = nfsacl_encode(&rqstp->rq_res, base, inode,
  250 + resp->acl_access,
  251 + resp->mask & NFS_ACL, 0);
  252 + if (n > 0)
  253 + n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
  254 + resp->acl_default,
  255 + resp->mask & NFS_DFACL,
  256 + NFS_ACL_DEFAULT);
  257 + if (n <= 0)
  258 + return 0;
  259 + return 1;
  260 +}
  261 +
  262 +static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p,
  263 + struct nfsd_attrstat *resp)
  264 +{
  265 + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
  266 + return xdr_ressize_check(rqstp, p);
  267 +}
  268 +
  269 +/* ACCESS */
  270 +static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
  271 + struct nfsd3_accessres *resp)
  272 +{
  273 + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
  274 + *p++ = htonl(resp->access);
  275 + return xdr_ressize_check(rqstp, p);
  276 +}
  277 +
  278 +/*
  279 + * XDR release functions
  280 + */
  281 +static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p,
  282 + struct nfsd3_getaclres *resp)
  283 +{
  284 + fh_put(&resp->fh);
  285 + posix_acl_release(resp->acl_access);
  286 + posix_acl_release(resp->acl_default);
  287 + return 1;
  288 +}
  289 +
  290 +static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
  291 + struct nfsd_fhandle *resp)
  292 +{
  293 + fh_put(&resp->fh);
  294 + return 1;
  295 +}
  296 +
  297 +#define nfsaclsvc_decode_voidargs NULL
  298 +#define nfsaclsvc_encode_voidres NULL
  299 +#define nfsaclsvc_release_void NULL
  300 +#define nfsd3_fhandleargs nfsd_fhandle
  301 +#define nfsd3_attrstatres nfsd_attrstat
  302 +#define nfsd3_voidres nfsd3_voidargs
  303 +struct nfsd3_voidargs { int dummy; };
  304 +
  305 +#define PROC(name, argt, rest, relt, cache, respsize) \
  306 + { (svc_procfunc) nfsacld_proc_##name, \
  307 + (kxdrproc_t) nfsaclsvc_decode_##argt##args, \
  308 + (kxdrproc_t) nfsaclsvc_encode_##rest##res, \
  309 + (kxdrproc_t) nfsaclsvc_release_##relt, \
  310 + sizeof(struct nfsd3_##argt##args), \
  311 + sizeof(struct nfsd3_##rest##res), \
  312 + 0, \
  313 + cache, \
  314 + respsize, \
  315 + }
  316 +
  317 +#define ST 1 /* status*/
  318 +#define AT 21 /* attributes */
  319 +#define pAT (1+AT) /* post attributes - conditional */
  320 +#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
  321 +
  322 +static struct svc_procedure nfsd_acl_procedures2[] = {
  323 + PROC(null, void, void, void, RC_NOCACHE, ST),
  324 + PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
  325 + PROC(setacl, setacl, attrstat, fhandle, RC_NOCACHE, ST+AT),
  326 + PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT),
  327 + PROC(access, access, access, fhandle, RC_NOCACHE, ST+AT+1),
  328 +};
  329 +
  330 +struct svc_version nfsd_acl_version2 = {
  331 + .vs_vers = 2,
  332 + .vs_nproc = 5,
  333 + .vs_proc = nfsd_acl_procedures2,
  334 + .vs_dispatch = nfsd_dispatch,
  335 + .vs_xdrsize = NFS3_SVC_XDRSIZE,
  336 +};
  1 +/*
  2 + * linux/fs/nfsd/nfs3acl.c
  3 + *
  4 + * Process version 3 NFSACL requests.
  5 + *
  6 + * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
  7 + */
  8 +
  9 +#include <linux/sunrpc/svc.h>
  10 +#include <linux/nfs3.h>
  11 +#include <linux/nfsd/nfsd.h>
  12 +#include <linux/nfsd/cache.h>
  13 +#include <linux/nfsd/xdr3.h>
  14 +#include <linux/posix_acl.h>
  15 +#include <linux/nfsacl.h>
  16 +
  17 +#define RETURN_STATUS(st) { resp->status = (st); return (st); }
  18 +
  19 +/*
  20 + * NULL call.
  21 + */
  22 +static int
  23 +nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
  24 +{
  25 + return nfs_ok;
  26 +}
  27 +
  28 +/*
  29 + * Get the Access and/or Default ACL of a file.
  30 + */
  31 +static int nfsd3_proc_getacl(struct svc_rqst * rqstp,
  32 + struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
  33 +{
  34 + svc_fh *fh;
  35 + struct posix_acl *acl;
  36 + int nfserr = 0;
  37 +
  38 + fh = fh_copy(&resp->fh, &argp->fh);
  39 + if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP)))
  40 + RETURN_STATUS(nfserr_inval);
  41 +
  42 + if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
  43 + RETURN_STATUS(nfserr_inval);
  44 + resp->mask = argp->mask;
  45 +
  46 + if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
  47 + acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
  48 + if (IS_ERR(acl)) {
  49 + int err = PTR_ERR(acl);
  50 +
  51 + if (err == -ENODATA || err == -EOPNOTSUPP)
  52 + acl = NULL;
  53 + else {
  54 + nfserr = nfserrno(err);
  55 + goto fail;
  56 + }
  57 + }
  58 + if (acl == NULL) {
  59 + /* Solaris returns the inode's minimum ACL. */
  60 +
  61 + struct inode *inode = fh->fh_dentry->d_inode;
  62 + acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
  63 + }
  64 + resp->acl_access = acl;
  65 + }
  66 + if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
  67 + /* Check how Solaris handles requests for the Default ACL
  68 + of a non-directory! */
  69 +
  70 + acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
  71 + if (IS_ERR(acl)) {
  72 + int err = PTR_ERR(acl);
  73 +
  74 + if (err == -ENODATA || err == -EOPNOTSUPP)
  75 + acl = NULL;
  76 + else {
  77 + nfserr = nfserrno(err);
  78 + goto fail;
  79 + }
  80 + }
  81 + resp->acl_default = acl;
  82 + }
  83 +
  84 + /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */
  85 + RETURN_STATUS(0);
  86 +
  87 +fail:
  88 + posix_acl_release(resp->acl_access);
  89 + posix_acl_release(resp->acl_default);
  90 + RETURN_STATUS(nfserr);
  91 +}
  92 +
  93 +/*
  94 + * Set the Access and/or Default ACL of a file.
  95 + */
  96 +static int nfsd3_proc_setacl(struct svc_rqst * rqstp,
  97 + struct nfsd3_setaclargs *argp,
  98 + struct nfsd3_attrstat *resp)
  99 +{
  100 + svc_fh *fh;
  101 + int nfserr = 0;
  102 +
  103 + fh = fh_copy(&resp->fh, &argp->fh);
  104 + nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
  105 +
  106 + if (!nfserr) {
  107 + nfserr = nfserrno( nfsd_set_posix_acl(
  108 + fh, ACL_TYPE_ACCESS, argp->acl_access) );
  109 + }
  110 + if (!nfserr) {
  111 + nfserr = nfserrno( nfsd_set_posix_acl(
  112 + fh, ACL_TYPE_DEFAULT, argp->acl_default) );
  113 + }
  114 +
  115 + /* argp->acl_{access,default} may have been allocated in
  116 + nfs3svc_decode_setaclargs. */
  117 + posix_acl_release(argp->acl_access);
  118 + posix_acl_release(argp->acl_default);
  119 + RETURN_STATUS(nfserr);
  120 +}
  121 +
  122 +/*
  123 + * XDR decode functions
  124 + */
  125 +static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
  126 + struct nfsd3_getaclargs *args)
  127 +{
  128 + if (!(p = nfs3svc_decode_fh(p, &args->fh)))
  129 + return 0;
  130 + args->mask = ntohl(*p); p++;
  131 +
  132 + return xdr_argsize_check(rqstp, p);
  133 +}
  134 +
  135 +
  136 +static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
  137 + struct nfsd3_setaclargs *args)
  138 +{
  139 + struct kvec *head = rqstp->rq_arg.head;
  140 + unsigned int base;
  141 + int n;
  142 +
  143 + if (!(p = nfs3svc_decode_fh(p, &args->fh)))
  144 + return 0;
  145 + args->mask = ntohl(*p++);
  146 + if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) ||
  147 + !xdr_argsize_check(rqstp, p))
  148 + return 0;
  149 +
  150 + base = (char *)p - (char *)head->iov_base;
  151 + n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
  152 + (args->mask & NFS_ACL) ?
  153 + &args->acl_access : NULL);
  154 + if (n > 0)
  155 + n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
  156 + (args->mask & NFS_DFACL) ?
  157 + &args->acl_default : NULL);
  158 + return (n > 0);
  159 +}
  160 +
  161 +/*
  162 + * XDR encode functions
  163 + */
  164 +
  165 +/* GETACL */
  166 +static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
  167 + struct nfsd3_getaclres *resp)
  168 +{
  169 + struct dentry *dentry = resp->fh.fh_dentry;
  170 +
  171 + p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
  172 + if (resp->status == 0 && dentry && dentry->d_inode) {
  173 + struct inode *inode = dentry->d_inode;
  174 + int w = nfsacl_size(
  175 + (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
  176 + (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
  177 + struct kvec *head = rqstp->rq_res.head;
  178 + unsigned int base;
  179 + int n;
  180 +
  181 + *p++ = htonl(resp->mask);
  182 + if (!xdr_ressize_check(rqstp, p))
  183 + return 0;
  184 + base = (char *)p - (char *)head->iov_base;
  185 +
  186 + rqstp->rq_res.page_len = w;
  187 + while (w > 0) {
  188 + if (!svc_take_res_page(rqstp))
  189 + return 0;
  190 + w -= PAGE_SIZE;
  191 + }
  192 +
  193 + n = nfsacl_encode(&rqstp->rq_res, base, inode,
  194 + resp->acl_access,
  195 + resp->mask & NFS_ACL, 0);
  196 + if (n > 0)
  197 + n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
  198 + resp->acl_default,
  199 + resp->mask & NFS_DFACL,
  200 + NFS_ACL_DEFAULT);
  201 + if (n <= 0)
  202 + return 0;
  203 + } else
  204 + if (!xdr_ressize_check(rqstp, p))
  205 + return 0;
  206 +
  207 + return 1;
  208 +}
  209 +
  210 +/* SETACL */
  211 +static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p,
  212 + struct nfsd3_attrstat *resp)
  213 +{
  214 + p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
  215 +
  216 + return xdr_ressize_check(rqstp, p);
  217 +}
  218 +
  219 +/*
  220 + * XDR release functions
  221 + */
  222 +static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p,
  223 + struct nfsd3_getaclres *resp)
  224 +{
  225 + fh_put(&resp->fh);
  226 + posix_acl_release(resp->acl_access);
  227 + posix_acl_release(resp->acl_default);
  228 + return 1;
  229 +}
  230 +
  231 +#define nfs3svc_decode_voidargs NULL
  232 +#define nfs3svc_release_void NULL
  233 +#define nfsd3_setaclres nfsd3_attrstat
  234 +#define nfsd3_voidres nfsd3_voidargs
  235 +struct nfsd3_voidargs { int dummy; };
  236 +
  237 +#define PROC(name, argt, rest, relt, cache, respsize) \
  238 + { (svc_procfunc) nfsd3_proc_##name, \
  239 + (kxdrproc_t) nfs3svc_decode_##argt##args, \
  240 + (kxdrproc_t) nfs3svc_encode_##rest##res, \
  241 + (kxdrproc_t) nfs3svc_release_##relt, \
  242 + sizeof(struct nfsd3_##argt##args), \
  243 + sizeof(struct nfsd3_##rest##res), \
  244 + 0, \
  245 + cache, \
  246 + respsize, \
  247 + }
  248 +
  249 +#define ST 1 /* status*/
  250 +#define AT 21 /* attributes */
  251 +#define pAT (1+AT) /* post attributes - conditional */
  252 +#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
  253 +
  254 +static struct svc_procedure nfsd_acl_procedures3[] = {
  255 + PROC(null, void, void, void, RC_NOCACHE, ST),
  256 + PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
  257 + PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT),
  258 +};
  259 +
  260 +struct svc_version nfsd_acl_version3 = {
  261 + .vs_vers = 3,
  262 + .vs_nproc = 3,
  263 + .vs_proc = nfsd_acl_procedures3,
  264 + .vs_dispatch = nfsd_dispatch,
  265 + .vs_xdrsize = NFS3_SVC_XDRSIZE,
  266 +};
... ... @@ -71,6 +71,12 @@
71 71 return p + XDR_QUADLEN(size);
72 72 }
73 73  
  74 +/* Helper function for NFSv3 ACL code */
  75 +u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp)
  76 +{
  77 + return decode_fh(p, fhp);
  78 +}
  79 +
74 80 static inline u32 *
75 81 encode_fh(u32 *p, struct svc_fh *fhp)
76 82 {
... ... @@ -231,6 +237,13 @@
231 237 }
232 238 *p++ = xdr_zero;
233 239 return p;
  240 +}
  241 +
  242 +/* Helper for NFSv3 ACLs */
  243 +u32 *
  244 +nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  245 +{
  246 + return encode_post_op_attr(rqstp, p, fhp);
234 247 }
235 248  
236 249 /*
... ... @@ -31,6 +31,7 @@
31 31 #include <linux/nfsd/stats.h>
32 32 #include <linux/nfsd/cache.h>
33 33 #include <linux/lockd/bind.h>
  34 +#include <linux/nfsacl.h>
34 35  
35 36 #define NFSDDBG_FACILITY NFSDDBG_SVC
36 37  
... ... @@ -362,6 +363,31 @@
362 363 return 1;
363 364 }
364 365  
  366 +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  367 +static struct svc_stat nfsd_acl_svcstats;
  368 +static struct svc_version * nfsd_acl_version[] = {
  369 + [2] = &nfsd_acl_version2,
  370 + [3] = &nfsd_acl_version3,
  371 +};
  372 +
  373 +#define NFSD_ACL_NRVERS (sizeof(nfsd_acl_version)/sizeof(nfsd_acl_version[0]))
  374 +static struct svc_program nfsd_acl_program = {
  375 + .pg_prog = NFS_ACL_PROGRAM,
  376 + .pg_nvers = NFSD_ACL_NRVERS,
  377 + .pg_vers = nfsd_acl_version,
  378 + .pg_name = "nfsd",
  379 + .pg_stats = &nfsd_acl_svcstats,
  380 +};
  381 +
  382 +static struct svc_stat nfsd_acl_svcstats = {
  383 + .program = &nfsd_acl_program,
  384 +};
  385 +
  386 +#define nfsd_acl_program_p &nfsd_acl_program
  387 +#else
  388 +#define nfsd_acl_program_p NULL
  389 +#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
  390 +
365 391 extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4;
366 392  
367 393 static struct svc_version * nfsd_version[] = {
... ... @@ -376,6 +402,7 @@
376 402  
377 403 #define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
378 404 struct svc_program nfsd_program = {
  405 + .pg_next = nfsd_acl_program_p,
379 406 .pg_prog = NFS_PROGRAM, /* program number */
380 407 .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
381 408 .pg_vers = nfsd_version, /* version table */
... ... @@ -49,6 +49,12 @@
49 49 return p + (NFS_FHSIZE >> 2);
50 50 }
51 51  
  52 +/* Helper function for NFSv2 ACL code */
  53 +u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp)
  54 +{
  55 + return decode_fh(p, fhp);
  56 +}
  57 +
52 58 static inline u32 *
53 59 encode_fh(u32 *p, struct svc_fh *fhp)
54 60 {
... ... @@ -190,6 +196,11 @@
190 196 return p;
191 197 }
192 198  
  199 +/* Helper function for NFSv2 ACL code */
  200 +u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  201 +{
  202 + return encode_fattr(rqstp, p, fhp);
  203 +}
193 204  
194 205 /*
195 206 * XDR decode functions
... ... @@ -46,8 +46,9 @@
46 46 #include <linux/nfsd/nfsfh.h>
47 47 #include <linux/quotaops.h>
48 48 #include <linux/dnotify.h>
49   -#ifdef CONFIG_NFSD_V4
  49 +#include <linux/xattr_acl.h>
50 50 #include <linux/posix_acl.h>
  51 +#ifdef CONFIG_NFSD_V4
51 52 #include <linux/posix_acl_xattr.h>
52 53 #include <linux/xattr_acl.h>
53 54 #include <linux/xattr.h>
... ... @@ -1857,4 +1858,108 @@
1857 1858 nfsdstats.ra_size = cache_size;
1858 1859 return 0;
1859 1860 }
  1861 +
  1862 +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  1863 +struct posix_acl *
  1864 +nfsd_get_posix_acl(struct svc_fh *fhp, int type)
  1865 +{
  1866 + struct inode *inode = fhp->fh_dentry->d_inode;
  1867 + char *name;
  1868 + void *value = NULL;
  1869 + ssize_t size;
  1870 + struct posix_acl *acl;
  1871 +
  1872 + if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr)
  1873 + return ERR_PTR(-EOPNOTSUPP);
  1874 + switch(type) {
  1875 + case ACL_TYPE_ACCESS:
  1876 + name = XATTR_NAME_ACL_ACCESS;
  1877 + break;
  1878 + case ACL_TYPE_DEFAULT:
  1879 + name = XATTR_NAME_ACL_DEFAULT;
  1880 + break;
  1881 + default:
  1882 + return ERR_PTR(-EOPNOTSUPP);
  1883 + }
  1884 +
  1885 + size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0);
  1886 +
  1887 + if (size < 0) {
  1888 + acl = ERR_PTR(size);
  1889 + goto getout;
  1890 + } else if (size > 0) {
  1891 + value = kmalloc(size, GFP_KERNEL);
  1892 + if (!value) {
  1893 + acl = ERR_PTR(-ENOMEM);
  1894 + goto getout;
  1895 + }
  1896 + size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size);
  1897 + if (size < 0) {
  1898 + acl = ERR_PTR(size);
  1899 + goto getout;
  1900 + }
  1901 + }
  1902 + acl = posix_acl_from_xattr(value, size);
  1903 +
  1904 +getout:
  1905 + kfree(value);
  1906 + return acl;
  1907 +}
  1908 +
  1909 +int
  1910 +nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
  1911 +{
  1912 + struct inode *inode = fhp->fh_dentry->d_inode;
  1913 + char *name;
  1914 + void *value = NULL;
  1915 + size_t size;
  1916 + int error;
  1917 +
  1918 + if (!IS_POSIXACL(inode) || !inode->i_op ||
  1919 + !inode->i_op->setxattr || !inode->i_op->removexattr)
  1920 + return -EOPNOTSUPP;
  1921 + switch(type) {
  1922 + case ACL_TYPE_ACCESS:
  1923 + name = XATTR_NAME_ACL_ACCESS;
  1924 + break;
  1925 + case ACL_TYPE_DEFAULT:
  1926 + name = XATTR_NAME_ACL_DEFAULT;
  1927 + break;
  1928 + default:
  1929 + return -EOPNOTSUPP;
  1930 + }
  1931 +
  1932 + if (acl && acl->a_count) {
  1933 + size = xattr_acl_size(acl->a_count);
  1934 + value = kmalloc(size, GFP_KERNEL);
  1935 + if (!value)
  1936 + return -ENOMEM;
  1937 + size = posix_acl_to_xattr(acl, value, size);
  1938 + if (size < 0) {
  1939 + error = size;
  1940 + goto getout;
  1941 + }
  1942 + } else
  1943 + size = 0;
  1944 +
  1945 + if (!fhp->fh_locked)
  1946 + fh_lock(fhp); /* unlocking is done automatically */
  1947 + if (size)
  1948 + error = inode->i_op->setxattr(fhp->fh_dentry, name,
  1949 + value, size, 0);
  1950 + else {
  1951 + if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
  1952 + error = 0;
  1953 + else {
  1954 + error = inode->i_op->removexattr(fhp->fh_dentry, name);
  1955 + if (error == -ENODATA)
  1956 + error = 0;
  1957 + }
  1958 + }
  1959 +
  1960 +getout:
  1961 + kfree(value);
  1962 + return error;
  1963 +}
  1964 +#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
include/linux/nfsacl.h
  1 +/*
  2 + * File: linux/nfsacl.h
  3 + *
  4 + * (C) 2003 Andreas Gruenbacher <agruen@suse.de>
  5 + */
  6 +#ifndef __LINUX_NFSACL_H
  7 +#define __LINUX_NFSACL_H
  8 +
  9 +#define NFS_ACL_PROGRAM 100227
  10 +
  11 +#define ACLPROC2_GETACL 1
  12 +#define ACLPROC2_SETACL 2
  13 +#define ACLPROC2_GETATTR 3
  14 +#define ACLPROC2_ACCESS 4
  15 +
  16 +#define ACLPROC3_GETACL 1
  17 +#define ACLPROC3_SETACL 2
  18 +
  19 +
  20 +/* Flags for the getacl/setacl mode */
  21 +#define NFS_ACL 0x0001
  22 +#define NFS_ACLCNT 0x0002
  23 +#define NFS_DFACL 0x0004
  24 +#define NFS_DFACLCNT 0x0008
  25 +
  26 +/* Flag for Default ACL entries */
  27 +#define NFS_ACL_DEFAULT 0x1000
  28 +
  29 +#ifdef __KERNEL__
  30 +
  31 +#include <linux/posix_acl.h>
  32 +
  33 +/* Maximum number of ACL entries over NFS */
  34 +#define NFS_ACL_MAX_ENTRIES 1024
  35 +
  36 +#define NFSACL_MAXWORDS (2*(2+3*NFS_ACL_MAX_ENTRIES))
  37 +#define NFSACL_MAXPAGES ((2*(8+12*NFS_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \
  38 + >> PAGE_SHIFT)
  39 +
  40 +static inline unsigned int
  41 +nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
  42 +{
  43 + unsigned int w = 16;
  44 + w += max(acl_access ? (int)acl_access->a_count : 3, 4) * 12;
  45 + if (acl_default)
  46 + w += max((int)acl_default->a_count, 4) * 12;
  47 + return w;
  48 +}
  49 +
  50 +extern unsigned int
  51 +nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
  52 + struct posix_acl *acl, int encode_entries, int typeflag);
  53 +extern unsigned int
  54 +nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
  55 + struct posix_acl **pacl);
  56 +
  57 +#endif /* __KERNEL__ */
  58 +#endif /* __LINUX_NFSACL_H */
include/linux/nfsd/nfsd.h
... ... @@ -15,6 +15,7 @@
15 15 #include <linux/unistd.h>
16 16 #include <linux/dirent.h>
17 17 #include <linux/fs.h>
  18 +#include <linux/posix_acl.h>
18 19 #include <linux/mount.h>
19 20  
20 21 #include <linux/nfsd/debug.h>
... ... @@ -123,6 +124,21 @@
123 124  
124 125 int nfsd_notify_change(struct inode *, struct iattr *);
125 126 int nfsd_permission(struct svc_export *, struct dentry *, int);
  127 +
  128 +#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
  129 +#ifdef CONFIG_NFSD_V2_ACL
  130 +extern struct svc_version nfsd_acl_version2;
  131 +#else
  132 +#define nfsd_acl_version2 NULL
  133 +#endif
  134 +#ifdef CONFIG_NFSD_V3_ACL
  135 +extern struct svc_version nfsd_acl_version3;
  136 +#else
  137 +#define nfsd_acl_version3 NULL
  138 +#endif
  139 +struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
  140 +int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
  141 +#endif
126 142  
127 143  
128 144 /*
include/linux/nfsd/xdr.h
... ... @@ -169,5 +169,9 @@
169 169  
170 170 int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
171 171  
  172 +/* Helper functions for NFSv2 ACL code */
  173 +u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp);
  174 +u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp);
  175 +
172 176 #endif /* LINUX_NFSD_H */
include/linux/nfsd/xdr3.h
... ... @@ -110,6 +110,19 @@
110 110 __u32 count;
111 111 };
112 112  
  113 +struct nfsd3_getaclargs {
  114 + struct svc_fh fh;
  115 + int mask;
  116 +};
  117 +
  118 +struct posix_acl;
  119 +struct nfsd3_setaclargs {
  120 + struct svc_fh fh;
  121 + int mask;
  122 + struct posix_acl *acl_access;
  123 + struct posix_acl *acl_default;
  124 +};
  125 +
113 126 struct nfsd3_attrstat {
114 127 __u32 status;
115 128 struct svc_fh fh;
... ... @@ -209,6 +222,14 @@
209 222 struct svc_fh fh;
210 223 };
211 224  
  225 +struct nfsd3_getaclres {
  226 + __u32 status;
  227 + struct svc_fh fh;
  228 + int mask;
  229 + struct posix_acl *acl_access;
  230 + struct posix_acl *acl_default;
  231 +};
  232 +
212 233 /* dummy type for release */
213 234 struct nfsd3_fhandle_pair {
214 235 __u32 dummy;
... ... @@ -241,6 +262,7 @@
241 262 struct nfsd3_fsinfores fsinfores;
242 263 struct nfsd3_pathconfres pathconfres;
243 264 struct nfsd3_commitres commitres;
  265 + struct nfsd3_getaclres getaclres;
244 266 };
245 267  
246 268 #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore)
... ... @@ -316,6 +338,10 @@
316 338 int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name,
317 339 int namlen, loff_t offset, ino_t ino,
318 340 unsigned int);
  341 +/* Helper functions for NFSv3 ACL code */
  342 +u32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p,
  343 + struct svc_fh *fhp);
  344 +u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp);
319 345  
320 346  
321 347 #endif /* _LINUX_NFSD_XDR3_H */
include/linux/sunrpc/svc.h
... ... @@ -185,6 +185,17 @@
185 185 return vec->iov_len <= PAGE_SIZE;
186 186 }
187 187  
  188 +static inline struct page *
  189 +svc_take_res_page(struct svc_rqst *rqstp)
  190 +{
  191 + if (rqstp->rq_arghi <= rqstp->rq_argused)
  192 + return NULL;
  193 + rqstp->rq_arghi--;
  194 + rqstp->rq_respages[rqstp->rq_resused] =
  195 + rqstp->rq_argpages[rqstp->rq_arghi];
  196 + return rqstp->rq_respages[rqstp->rq_resused++];
  197 +}
  198 +
188 199 static inline int svc_take_page(struct svc_rqst *rqstp)
189 200 {
190 201 if (rqstp->rq_arghi <= rqstp->rq_argused)