Commit b7fa0554cf1ba6d6895cd0a5b02989a26e0bc704

Authored by Andreas Gruenbacher
Committed by Trond Myklebust
1 parent a257cdd0e2

[PATCH] NFS: Add support for NFSv3 ACLs

This adds acl support fo nfs clients via the NFSACL protocol extension, by
 implementing the getxattr, listxattr, setxattr, and removexattr iops for the
 system.posix_acl_access and system.posix_acl_default attributes.  This patch
 implements a dumb version that uses no caching (and thus adds some overhead).
 (Another patch in this patchset adds caching as well.)

 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 13 changed files with 601 additions and 6 deletions Side-by-side Diff

... ... @@ -1268,6 +1268,7 @@
1268 1268 depends on INET
1269 1269 select LOCKD
1270 1270 select SUNRPC
  1271 + select NFS_ACL_SUPPORT if NFS_V3_ACL
1271 1272 help
1272 1273 If you are connected to some other (usually local) Unix computer
1273 1274 (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
... ... @@ -1309,6 +1310,16 @@
1309 1310 3 of the NFS protocol.
1310 1311  
1311 1312 If unsure, say Y.
  1313 +
  1314 +config NFS_V3_ACL
  1315 + bool "Provide client support for the NFSv3 ACL protocol extension"
  1316 + depends on NFS_V3
  1317 + help
  1318 + Implement the NFSv3 ACL protocol extension for manipulating POSIX
  1319 + Access Control Lists. The server should also be compiled with
  1320 + the NFSv3 ACL protocol extension; see the CONFIG_NFSD_V3_ACL option.
  1321 +
  1322 + If unsure, say N.
1312 1323  
1313 1324 config NFS_V4
1314 1325 bool "Provide NFSv4 client support (EXPERIMENTAL)"
... ... @@ -8,6 +8,7 @@
8 8 proc.o read.o symlink.o unlink.o write.o
9 9 nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
10 10 nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
  11 +nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
11 12 nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
12 13 delegation.o idmap.o \
13 14 callback.o callback_xdr.o callback_proc.o
... ... @@ -75,6 +75,27 @@
75 75 .setattr = nfs_setattr,
76 76 };
77 77  
  78 +#ifdef CONFIG_NFS_V3
  79 +struct inode_operations nfs3_dir_inode_operations = {
  80 + .create = nfs_create,
  81 + .lookup = nfs_lookup,
  82 + .link = nfs_link,
  83 + .unlink = nfs_unlink,
  84 + .symlink = nfs_symlink,
  85 + .mkdir = nfs_mkdir,
  86 + .rmdir = nfs_rmdir,
  87 + .mknod = nfs_mknod,
  88 + .rename = nfs_rename,
  89 + .permission = nfs_permission,
  90 + .getattr = nfs_getattr,
  91 + .setattr = nfs_setattr,
  92 + .listxattr = nfs3_listxattr,
  93 + .getxattr = nfs3_getxattr,
  94 + .setxattr = nfs3_setxattr,
  95 + .removexattr = nfs3_removexattr,
  96 +};
  97 +#endif /* CONFIG_NFS_V3 */
  98 +
78 99 #ifdef CONFIG_NFS_V4
79 100  
80 101 static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
... ... @@ -71,6 +71,18 @@
71 71 .setattr = nfs_setattr,
72 72 };
73 73  
  74 +#ifdef CONFIG_NFS_V3
  75 +struct inode_operations nfs3_file_inode_operations = {
  76 + .permission = nfs_permission,
  77 + .getattr = nfs_getattr,
  78 + .setattr = nfs_setattr,
  79 + .listxattr = nfs3_listxattr,
  80 + .getxattr = nfs3_getxattr,
  81 + .setxattr = nfs3_setxattr,
  82 + .removexattr = nfs3_removexattr,
  83 +};
  84 +#endif /* CONFIG_NFS_v3 */
  85 +
74 86 /* Hack for future NFS swap support */
75 87 #ifndef IS_SWAPFILE
76 88 # define IS_SWAPFILE(inode) (0)
... ... @@ -108,6 +108,21 @@
108 108 .pipe_dir_name = "/nfs",
109 109 };
110 110  
  111 +#ifdef CONFIG_NFS_V3_ACL
  112 +static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
  113 +static struct rpc_version * nfsacl_version[] = {
  114 + [3] = &nfsacl_version3,
  115 +};
  116 +
  117 +struct rpc_program nfsacl_program = {
  118 + .name = "nfsacl",
  119 + .number = NFS_ACL_PROGRAM,
  120 + .nrvers = sizeof(nfsacl_version) / sizeof(nfsacl_version[0]),
  121 + .version = nfsacl_version,
  122 + .stats = &nfsacl_rpcstat,
  123 +};
  124 +#endif /* CONFIG_NFS_V3_ACL */
  125 +
111 126 static inline unsigned long
112 127 nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
113 128 {
... ... @@ -165,6 +180,9 @@
165 180 /* -EIO all pending I/O */
166 181 if (!IS_ERR(rpc))
167 182 rpc_killall_tasks(rpc);
  183 + rpc = NFS_SB(sb)->client_acl;
  184 + if (!IS_ERR(rpc))
  185 + rpc_killall_tasks(rpc);
168 186 }
169 187  
170 188  
171 189  
... ... @@ -461,8 +479,17 @@
461 479 atomic_inc(&server->client->cl_count);
462 480 server->client_sys = server->client;
463 481 }
464   -
465 482 if (server->flags & NFS_MOUNT_VER3) {
  483 +#ifdef CONFIG_NFS_V3_ACL
  484 + if (!(server->flags & NFS_MOUNT_NOACL)) {
  485 + server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
  486 + /* No errors! Assume that Sun nfsacls are supported */
  487 + if (!IS_ERR(server->client_acl))
  488 + server->caps |= NFS_CAP_ACLS;
  489 + }
  490 +#else
  491 + server->flags &= ~NFS_MOUNT_NOACL;
  492 +#endif /* CONFIG_NFS_V3_ACL */
466 493 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
467 494 server->namelen = NFS3_MAXNAMLEN;
468 495 sb->s_time_gran = 1;
... ... @@ -546,6 +573,7 @@
546 573 { NFS_MOUNT_NOCTO, ",nocto", "" },
547 574 { NFS_MOUNT_NOAC, ",noac", "" },
548 575 { NFS_MOUNT_NONLM, ",nolock", ",lock" },
  576 + { NFS_MOUNT_NOACL, ",noacl", "" },
549 577 { 0, NULL, NULL }
550 578 };
551 579 struct proc_nfs_info *nfs_infop;
... ... @@ -1452,7 +1480,7 @@
1452 1480 memset(server, 0, sizeof(struct nfs_server));
1453 1481 /* Zero out the NFS state stuff */
1454 1482 init_nfsv4_state(server);
1455   - server->client = server->client_sys = ERR_PTR(-EINVAL);
  1483 + server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
1456 1484  
1457 1485 root = &server->fh;
1458 1486 if (data->flags & NFS_MOUNT_VER3)
... ... @@ -1513,6 +1541,8 @@
1513 1541 rpc_shutdown_client(server->client);
1514 1542 if (!IS_ERR(server->client_sys))
1515 1543 rpc_shutdown_client(server->client_sys);
  1544 + if (!IS_ERR(server->client_acl))
  1545 + rpc_shutdown_client(server->client_acl);
1516 1546  
1517 1547 if (!(server->flags & NFS_MOUNT_NONLM))
1518 1548 lockd_down(); /* release rpc.lockd */
... ... @@ -1794,7 +1824,7 @@
1794 1824 memset(server, 0, sizeof(struct nfs_server));
1795 1825 /* Zero out the NFS state stuff */
1796 1826 init_nfsv4_state(server);
1797   - server->client = server->client_sys = ERR_PTR(-EINVAL);
  1827 + server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
1798 1828  
1799 1829 p = nfs_copy_user_string(NULL, &data->hostname, 256);
1800 1830 if (IS_ERR(p))
  1 +#include <linux/fs.h>
  2 +#include <linux/nfs.h>
  3 +#include <linux/nfs3.h>
  4 +#include <linux/nfs_fs.h>
  5 +#include <linux/xattr_acl.h>
  6 +#include <linux/nfsacl.h>
  7 +
  8 +#define NFSDBG_FACILITY NFSDBG_PROC
  9 +
  10 +ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size)
  11 +{
  12 + struct inode *inode = dentry->d_inode;
  13 + struct posix_acl *acl;
  14 + int pos=0, len=0;
  15 +
  16 +# define output(s) do { \
  17 + if (pos + sizeof(s) <= size) { \
  18 + memcpy(buffer + pos, s, sizeof(s)); \
  19 + pos += sizeof(s); \
  20 + } \
  21 + len += sizeof(s); \
  22 + } while(0)
  23 +
  24 + acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS);
  25 + if (IS_ERR(acl))
  26 + return PTR_ERR(acl);
  27 + if (acl) {
  28 + output("system.posix_acl_access");
  29 + posix_acl_release(acl);
  30 + }
  31 +
  32 + if (S_ISDIR(inode->i_mode)) {
  33 + acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT);
  34 + if (IS_ERR(acl))
  35 + return PTR_ERR(acl);
  36 + if (acl) {
  37 + output("system.posix_acl_default");
  38 + posix_acl_release(acl);
  39 + }
  40 + }
  41 +
  42 +# undef output
  43 +
  44 + if (!buffer || len <= size)
  45 + return len;
  46 + return -ERANGE;
  47 +}
  48 +
  49 +ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
  50 + void *buffer, size_t size)
  51 +{
  52 + struct inode *inode = dentry->d_inode;
  53 + struct posix_acl *acl;
  54 + int type, error = 0;
  55 +
  56 + if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
  57 + type = ACL_TYPE_ACCESS;
  58 + else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
  59 + type = ACL_TYPE_DEFAULT;
  60 + else
  61 + return -EOPNOTSUPP;
  62 +
  63 + acl = nfs3_proc_getacl(inode, type);
  64 + if (IS_ERR(acl))
  65 + return PTR_ERR(acl);
  66 + else if (acl) {
  67 + if (type == ACL_TYPE_ACCESS && acl->a_count == 0)
  68 + error = -ENODATA;
  69 + else
  70 + error = posix_acl_to_xattr(acl, buffer, size);
  71 + posix_acl_release(acl);
  72 + } else
  73 + error = -ENODATA;
  74 +
  75 + return error;
  76 +}
  77 +
  78 +int nfs3_setxattr(struct dentry *dentry, const char *name,
  79 + const void *value, size_t size, int flags)
  80 +{
  81 + struct inode *inode = dentry->d_inode;
  82 + struct posix_acl *acl;
  83 + int type, error;
  84 +
  85 + if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
  86 + type = ACL_TYPE_ACCESS;
  87 + else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
  88 + type = ACL_TYPE_DEFAULT;
  89 + else
  90 + return -EOPNOTSUPP;
  91 +
  92 + acl = posix_acl_from_xattr(value, size);
  93 + if (IS_ERR(acl))
  94 + return PTR_ERR(acl);
  95 + error = nfs3_proc_setacl(inode, type, acl);
  96 + posix_acl_release(acl);
  97 +
  98 + return error;
  99 +}
  100 +
  101 +int nfs3_removexattr(struct dentry *dentry, const char *name)
  102 +{
  103 + struct inode *inode = dentry->d_inode;
  104 + int type;
  105 +
  106 + if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
  107 + type = ACL_TYPE_ACCESS;
  108 + else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
  109 + type = ACL_TYPE_DEFAULT;
  110 + else
  111 + return -EOPNOTSUPP;
  112 +
  113 + return nfs3_proc_setacl(inode, type, NULL);
  114 +}
  115 +
  116 +struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
  117 +{
  118 + struct nfs_server *server = NFS_SERVER(inode);
  119 + struct nfs_fattr fattr;
  120 + struct page *pages[NFSACL_MAXPAGES] = { };
  121 + struct nfs3_getaclargs args = {
  122 + .fh = NFS_FH(inode),
  123 + /* The xdr layer may allocate pages here. */
  124 + .pages = pages,
  125 + };
  126 + struct nfs3_getaclres res = {
  127 + .fattr = &fattr,
  128 + };
  129 + struct posix_acl *acl = NULL;
  130 + int status, count;
  131 +
  132 + if (!nfs_server_capable(inode, NFS_CAP_ACLS))
  133 + return ERR_PTR(-EOPNOTSUPP);
  134 +
  135 + switch (type) {
  136 + case ACL_TYPE_ACCESS:
  137 + args.mask = NFS_ACLCNT|NFS_ACL;
  138 + break;
  139 +
  140 + case ACL_TYPE_DEFAULT:
  141 + if (!S_ISDIR(inode->i_mode))
  142 + return NULL;
  143 + args.mask = NFS_DFACLCNT|NFS_DFACL;
  144 + break;
  145 +
  146 + default:
  147 + return ERR_PTR(-EINVAL);
  148 + }
  149 +
  150 + dprintk("NFS call getacl\n");
  151 + status = rpc_call(server->client_acl, ACLPROC3_GETACL,
  152 + &args, &res, 0);
  153 + dprintk("NFS reply getacl: %d\n", status);
  154 +
  155 + /* pages may have been allocated at the xdr layer. */
  156 + for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
  157 + __free_page(args.pages[count]);
  158 +
  159 + switch (status) {
  160 + case 0:
  161 + status = nfs_refresh_inode(inode, &fattr);
  162 + break;
  163 + case -EPFNOSUPPORT:
  164 + case -EPROTONOSUPPORT:
  165 + dprintk("NFS_V3_ACL extension not supported; disabling\n");
  166 + server->caps &= ~NFS_CAP_ACLS;
  167 + case -ENOTSUPP:
  168 + status = -EOPNOTSUPP;
  169 + default:
  170 + goto getout;
  171 + }
  172 + if ((args.mask & res.mask) != args.mask) {
  173 + status = -EIO;
  174 + goto getout;
  175 + }
  176 +
  177 + if (res.acl_access != NULL) {
  178 + if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) {
  179 + posix_acl_release(res.acl_access);
  180 + res.acl_access = NULL;
  181 + }
  182 + }
  183 +
  184 + switch(type) {
  185 + case ACL_TYPE_ACCESS:
  186 + acl = res.acl_access;
  187 + res.acl_access = NULL;
  188 + break;
  189 +
  190 + case ACL_TYPE_DEFAULT:
  191 + acl = res.acl_default;
  192 + res.acl_default = NULL;
  193 + }
  194 +
  195 +getout:
  196 + posix_acl_release(res.acl_access);
  197 + posix_acl_release(res.acl_default);
  198 +
  199 + if (status != 0) {
  200 + posix_acl_release(acl);
  201 + acl = ERR_PTR(status);
  202 + }
  203 + return acl;
  204 +}
  205 +
  206 +static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
  207 + struct posix_acl *dfacl)
  208 +{
  209 + struct nfs_server *server = NFS_SERVER(inode);
  210 + struct nfs_fattr fattr;
  211 + struct page *pages[NFSACL_MAXPAGES] = { };
  212 + struct nfs3_setaclargs args = {
  213 + .inode = inode,
  214 + .mask = NFS_ACL,
  215 + .acl_access = acl,
  216 + .pages = pages,
  217 + };
  218 + int status, count;
  219 +
  220 + status = -EOPNOTSUPP;
  221 + if (!nfs_server_capable(inode, NFS_CAP_ACLS))
  222 + goto out;
  223 +
  224 + /* We are doing this here, because XDR marshalling can only
  225 + return -ENOMEM. */
  226 + status = -ENOSPC;
  227 + if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
  228 + goto out;
  229 + if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES)
  230 + goto out;
  231 + if (S_ISDIR(inode->i_mode)) {
  232 + args.mask |= NFS_DFACL;
  233 + args.acl_default = dfacl;
  234 + }
  235 +
  236 + dprintk("NFS call setacl\n");
  237 + nfs_begin_data_update(inode);
  238 + status = rpc_call(server->client_acl, ACLPROC3_SETACL,
  239 + &args, &fattr, 0);
  240 + NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS;
  241 + nfs_end_data_update(inode);
  242 + dprintk("NFS reply setacl: %d\n", status);
  243 +
  244 + /* pages may have been allocated at the xdr layer. */
  245 + for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
  246 + __free_page(args.pages[count]);
  247 +
  248 + switch (status) {
  249 + case 0:
  250 + status = nfs_refresh_inode(inode, &fattr);
  251 + break;
  252 + case -EPFNOSUPPORT:
  253 + case -EPROTONOSUPPORT:
  254 + dprintk("NFS_V3_ACL SETACL RPC not supported"
  255 + "(will not retry)\n");
  256 + server->caps &= ~NFS_CAP_ACLS;
  257 + case -ENOTSUPP:
  258 + status = -EOPNOTSUPP;
  259 + }
  260 +out:
  261 + return status;
  262 +}
  263 +
  264 +int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl)
  265 +{
  266 + struct posix_acl *alloc = NULL, *dfacl = NULL;
  267 + int status;
  268 +
  269 + if (S_ISDIR(inode->i_mode)) {
  270 + switch(type) {
  271 + case ACL_TYPE_ACCESS:
  272 + alloc = dfacl = nfs3_proc_getacl(inode,
  273 + ACL_TYPE_DEFAULT);
  274 + if (IS_ERR(alloc))
  275 + goto fail;
  276 + break;
  277 +
  278 + case ACL_TYPE_DEFAULT:
  279 + dfacl = acl;
  280 + alloc = acl = nfs3_proc_getacl(inode,
  281 + ACL_TYPE_ACCESS);
  282 + if (IS_ERR(alloc))
  283 + goto fail;
  284 + break;
  285 +
  286 + default:
  287 + return -EINVAL;
  288 + }
  289 + } else if (type != ACL_TYPE_ACCESS)
  290 + return -EINVAL;
  291 +
  292 + if (acl == NULL) {
  293 + alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
  294 + if (IS_ERR(alloc))
  295 + goto fail;
  296 + }
  297 + status = nfs3_proc_setacls(inode, acl, dfacl);
  298 + posix_acl_release(alloc);
  299 + return status;
  300 +
  301 +fail:
  302 + return PTR_ERR(alloc);
  303 +}
... ... @@ -17,6 +17,7 @@
17 17 #include <linux/nfs_page.h>
18 18 #include <linux/lockd/bind.h>
19 19 #include <linux/smp_lock.h>
  20 +#include <linux/nfs_mount.h>
20 21  
21 22 #define NFSDBG_FACILITY NFSDBG_PROC
22 23  
... ... @@ -45,7 +46,7 @@
45 46 nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
46 47 {
47 48 struct rpc_message msg = {
48   - .rpc_proc = &nfs3_procedures[proc],
  49 + .rpc_proc = &clnt->cl_procinfo[proc],
49 50 .rpc_argp = argp,
50 51 .rpc_resp = resp,
51 52 };
... ... @@ -825,8 +826,8 @@
825 826 struct nfs_rpc_ops nfs_v3_clientops = {
826 827 .version = 3, /* protocol version */
827 828 .dentry_ops = &nfs_dentry_operations,
828   - .dir_inode_ops = &nfs_dir_inode_operations,
829   - .file_inode_ops = &nfs_file_inode_operations,
  829 + .dir_inode_ops = &nfs3_dir_inode_operations,
  830 + .file_inode_ops = &nfs3_file_inode_operations,
830 831 .getroot = nfs3_proc_get_root,
831 832 .getattr = nfs3_proc_getattr,
832 833 .setattr = nfs3_proc_setattr,
... ... @@ -21,6 +21,7 @@
21 21 #include <linux/nfs.h>
22 22 #include <linux/nfs3.h>
23 23 #include <linux/nfs_fs.h>
  24 +#include <linux/nfsacl.h>
24 25  
25 26 #define NFSDBG_FACILITY NFSDBG_XDR
26 27  
... ... @@ -79,6 +80,11 @@
79 80 #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
80 81 #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
81 82  
  83 +#define ACL3_getaclargs_sz (NFS3_fh_sz+1)
  84 +#define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3))
  85 +#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
  86 +#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
  87 +
82 88 /*
83 89 * Map file type to S_IFMT bits
84 90 */
85 91  
... ... @@ -627,7 +633,75 @@
627 633 return 0;
628 634 }
629 635  
  636 +#ifdef CONFIG_NFS_V3_ACL
630 637 /*
  638 + * Encode GETACL arguments
  639 + */
  640 +static int
  641 +nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
  642 + struct nfs3_getaclargs *args)
  643 +{
  644 + struct rpc_auth *auth = req->rq_task->tk_auth;
  645 + unsigned int replen;
  646 +
  647 + p = xdr_encode_fhandle(p, args->fh);
  648 + *p++ = htonl(args->mask);
  649 + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  650 +
  651 + if (args->mask & (NFS_ACL | NFS_DFACL)) {
  652 + /* Inline the page array */
  653 + replen = (RPC_REPHDRSIZE + auth->au_rslack +
  654 + ACL3_getaclres_sz) << 2;
  655 + xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
  656 + NFSACL_MAXPAGES << PAGE_SHIFT);
  657 + }
  658 + return 0;
  659 +}
  660 +
  661 +/*
  662 + * Encode SETACL arguments
  663 + */
  664 +static int
  665 +nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
  666 + struct nfs3_setaclargs *args)
  667 +{
  668 + struct xdr_buf *buf = &req->rq_snd_buf;
  669 + unsigned int base, len_in_head, len = nfsacl_size(
  670 + (args->mask & NFS_ACL) ? args->acl_access : NULL,
  671 + (args->mask & NFS_DFACL) ? args->acl_default : NULL);
  672 + int count, err;
  673 +
  674 + p = xdr_encode_fhandle(p, NFS_FH(args->inode));
  675 + *p++ = htonl(args->mask);
  676 + base = (char *)p - (char *)buf->head->iov_base;
  677 + /* put as much of the acls into head as possible. */
  678 + len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
  679 + len -= len_in_head;
  680 + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + len_in_head);
  681 +
  682 + for (count = 0; (count << PAGE_SHIFT) < len; count++) {
  683 + args->pages[count] = alloc_page(GFP_KERNEL);
  684 + if (!args->pages[count]) {
  685 + while (count)
  686 + __free_page(args->pages[--count]);
  687 + return -ENOMEM;
  688 + }
  689 + }
  690 + xdr_encode_pages(buf, args->pages, 0, len);
  691 +
  692 + err = nfsacl_encode(buf, base, args->inode,
  693 + (args->mask & NFS_ACL) ?
  694 + args->acl_access : NULL, 1, 0);
  695 + if (err > 0)
  696 + err = nfsacl_encode(buf, base + err, args->inode,
  697 + (args->mask & NFS_DFACL) ?
  698 + args->acl_default : NULL, 1,
  699 + NFS_ACL_DEFAULT);
  700 + return (err > 0) ? 0 : err;
  701 +}
  702 +#endif /* CONFIG_NFS_V3_ACL */
  703 +
  704 +/*
631 705 * NFS XDR decode functions
632 706 */
633 707  
... ... @@ -978,6 +1052,54 @@
978 1052 return 0;
979 1053 }
980 1054  
  1055 +#ifdef CONFIG_NFS_V3_ACL
  1056 +/*
  1057 + * Decode GETACL reply
  1058 + */
  1059 +static int
  1060 +nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
  1061 + struct nfs3_getaclres *res)
  1062 +{
  1063 + struct xdr_buf *buf = &req->rq_rcv_buf;
  1064 + int status = ntohl(*p++);
  1065 + struct posix_acl **acl;
  1066 + unsigned int *aclcnt;
  1067 + int err, base;
  1068 +
  1069 + if (status != 0)
  1070 + return -nfs_stat_to_errno(status);
  1071 + p = xdr_decode_post_op_attr(p, res->fattr);
  1072 + res->mask = ntohl(*p++);
  1073 + if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
  1074 + return -EINVAL;
  1075 + base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
  1076 +
  1077 + acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
  1078 + aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
  1079 + err = nfsacl_decode(buf, base, aclcnt, acl);
  1080 +
  1081 + acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
  1082 + aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
  1083 + if (err > 0)
  1084 + err = nfsacl_decode(buf, base + err, aclcnt, acl);
  1085 + return (err > 0) ? 0 : err;
  1086 +}
  1087 +
  1088 +/*
  1089 + * Decode setacl reply.
  1090 + */
  1091 +static int
  1092 +nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
  1093 +{
  1094 + int status = ntohl(*p++);
  1095 +
  1096 + if (status)
  1097 + return -nfs_stat_to_errno(status);
  1098 + xdr_decode_post_op_attr(p, fattr);
  1099 + return 0;
  1100 +}
  1101 +#endif /* CONFIG_NFS_V3_ACL */
  1102 +
981 1103 #ifndef MAX
982 1104 # define MAX(a, b) (((a) > (b))? (a) : (b))
983 1105 #endif
... ... @@ -1020,4 +1142,30 @@
1020 1142 .nrprocs = sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1021 1143 .procs = nfs3_procedures
1022 1144 };
  1145 +
  1146 +#ifdef CONFIG_NFS_V3_ACL
  1147 +static struct rpc_procinfo nfs3_acl_procedures[] = {
  1148 + [ACLPROC3_GETACL] = {
  1149 + .p_proc = ACLPROC3_GETACL,
  1150 + .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
  1151 + .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
  1152 + .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
  1153 + .p_timer = 1,
  1154 + },
  1155 + [ACLPROC3_SETACL] = {
  1156 + .p_proc = ACLPROC3_SETACL,
  1157 + .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
  1158 + .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
  1159 + .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
  1160 + .p_timer = 0,
  1161 + },
  1162 +};
  1163 +
  1164 +struct rpc_version nfsacl_version3 = {
  1165 + .number = 3,
  1166 + .nrprocs = sizeof(nfs3_acl_procedures)/
  1167 + sizeof(nfs3_acl_procedures[0]),
  1168 + .procs = nfs3_acl_procedures,
  1169 +};
  1170 +#endif /* CONFIG_NFS_V3_ACL */
... ... @@ -124,6 +124,7 @@
124 124 Opt_soft, Opt_hard, Opt_intr,
125 125 Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac,
126 126 Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
  127 + Opt_acl, Opt_noacl,
127 128 /* Error token */
128 129 Opt_err
129 130 };
... ... @@ -158,6 +159,8 @@
158 159 {Opt_udp, "udp"},
159 160 {Opt_tcp, "proto=tcp"},
160 161 {Opt_tcp, "tcp"},
  162 + {Opt_acl, "acl"},
  163 + {Opt_noacl, "noacl"},
161 164 {Opt_err, NULL}
162 165  
163 166 };
... ... @@ -265,6 +268,12 @@
265 268 break;
266 269 case Opt_tcp:
267 270 nfs_data.flags |= NFS_MOUNT_TCP;
  271 + break;
  272 + case Opt_acl:
  273 + nfs_data.flags &= ~NFS_MOUNT_NOACL;
  274 + break;
  275 + case Opt_noacl:
  276 + nfs_data.flags |= NFS_MOUNT_NOACL;
268 277 break;
269 278 default :
270 279 return 0;
include/linux/nfs_fs.h
... ... @@ -301,6 +301,9 @@
301 301 * linux/fs/nfs/file.c
302 302 */
303 303 extern struct inode_operations nfs_file_inode_operations;
  304 +#ifdef CONFIG_NFS_V3
  305 +extern struct inode_operations nfs3_file_inode_operations;
  306 +#endif /* CONFIG_NFS_V3 */
304 307 extern struct file_operations nfs_file_operations;
305 308 extern struct address_space_operations nfs_file_aops;
306 309  
... ... @@ -316,6 +319,22 @@
316 319 }
317 320  
318 321 /*
  322 + * linux/fs/nfs/xattr.c
  323 + */
  324 +#ifdef CONFIG_NFS_V3_ACL
  325 +extern ssize_t nfs3_listxattr(struct dentry *, char *, size_t);
  326 +extern ssize_t nfs3_getxattr(struct dentry *, const char *, void *, size_t);
  327 +extern int nfs3_setxattr(struct dentry *, const char *,
  328 + const void *, size_t, int);
  329 +extern int nfs3_removexattr (struct dentry *, const char *name);
  330 +#else
  331 +# define nfs3_listxattr NULL
  332 +# define nfs3_getxattr NULL
  333 +# define nfs3_setxattr NULL
  334 +# define nfs3_removexattr NULL
  335 +#endif
  336 +
  337 +/*
319 338 * linux/fs/nfs/direct.c
320 339 */
321 340 extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
... ... @@ -329,6 +348,9 @@
329 348 * linux/fs/nfs/dir.c
330 349 */
331 350 extern struct inode_operations nfs_dir_inode_operations;
  351 +#ifdef CONFIG_NFS_V3
  352 +extern struct inode_operations nfs3_dir_inode_operations;
  353 +#endif /* CONFIG_NFS_V3 */
332 354 extern struct file_operations nfs_dir_operations;
333 355 extern struct dentry_operations nfs_dentry_operations;
334 356  
... ... @@ -448,6 +470,15 @@
448 470 }
449 471  
450 472 extern void nfs_readdata_release(struct rpc_task *task);
  473 +
  474 +/*
  475 + * linux/fs/nfs3proc.c
  476 + */
  477 +#ifdef CONFIG_NFS_V3_ACL
  478 +extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type);
  479 +extern int nfs3_proc_setacl(struct inode *inode, int type,
  480 + struct posix_acl *acl);
  481 +#endif /* CONFIG_NFS_V3_ACL */
451 482  
452 483 /*
453 484 * linux/fs/mount_clnt.c
include/linux/nfs_fs_sb.h
... ... @@ -10,6 +10,7 @@
10 10 struct nfs_server {
11 11 struct rpc_clnt * client; /* RPC client handle */
12 12 struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */
  13 + struct rpc_clnt * client_acl; /* ACL RPC client handle */
13 14 struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */
14 15 struct backing_dev_info backing_dev_info;
15 16 int flags; /* various flags */
include/linux/nfs_mount.h
... ... @@ -58,6 +58,7 @@
58 58 #define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
59 59 #define NFS_MOUNT_NONLM 0x0200 /* 3 */
60 60 #define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */
  61 +#define NFS_MOUNT_NOACL 0x0800 /* 4 */
61 62 #define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
62 63 #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
63 64 #define NFS_MOUNT_FLAGMASK 0xFFFF
include/linux/nfs_xdr.h
... ... @@ -2,6 +2,7 @@
2 2 #define _LINUX_NFS_XDR_H
3 3  
4 4 #include <linux/sunrpc/xprt.h>
  5 +#include <linux/nfsacl.h>
5 6  
6 7 struct nfs4_fsid {
7 8 __u64 major;
... ... @@ -368,6 +369,20 @@
368 369 struct page ** pages;
369 370 };
370 371  
  372 +struct nfs3_getaclargs {
  373 + struct nfs_fh * fh;
  374 + int mask;
  375 + struct page ** pages;
  376 +};
  377 +
  378 +struct nfs3_setaclargs {
  379 + struct inode * inode;
  380 + int mask;
  381 + struct posix_acl * acl_access;
  382 + struct posix_acl * acl_default;
  383 + struct page ** pages;
  384 +};
  385 +
371 386 struct nfs_diropok {
372 387 struct nfs_fh * fh;
373 388 struct nfs_fattr * fattr;
... ... @@ -491,6 +506,15 @@
491 506 int plus;
492 507 };
493 508  
  509 +struct nfs3_getaclres {
  510 + struct nfs_fattr * fattr;
  511 + int mask;
  512 + unsigned int acl_access_count;
  513 + unsigned int acl_default_count;
  514 + struct posix_acl * acl_access;
  515 + struct posix_acl * acl_default;
  516 +};
  517 +
494 518 #ifdef CONFIG_NFS_V4
495 519  
496 520 typedef u64 clientid4;
... ... @@ -747,6 +771,9 @@
747 771 extern struct rpc_version nfs_version2;
748 772 extern struct rpc_version nfs_version3;
749 773 extern struct rpc_version nfs_version4;
  774 +
  775 +extern struct rpc_version nfsacl_version3;
  776 +extern struct rpc_program nfsacl_program;
750 777  
751 778 #endif