aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2005-06-22 13:16:27 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-06-22 16:07:24 -0400
commitb7fa0554cf1ba6d6895cd0a5b02989a26e0bc704 (patch)
tree83eb405f3ff78c17695999df38c99484e3aee01f /fs
parenta257cdd0e2179630d3201c32ba14d7fcb3c3a055 (diff)
[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>
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig11
-rw-r--r--fs/nfs/Makefile1
-rw-r--r--fs/nfs/dir.c21
-rw-r--r--fs/nfs/file.c12
-rw-r--r--fs/nfs/inode.c36
-rw-r--r--fs/nfs/nfs3acl.c303
-rw-r--r--fs/nfs/nfs3proc.c7
-rw-r--r--fs/nfs/nfs3xdr.c147
-rw-r--r--fs/nfs/nfsroot.c9
9 files changed, 541 insertions, 6 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index d44b04d9b0a9..a7c0cc3203cb 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1268,6 +1268,7 @@ config NFS_FS
1268 depends on INET 1268 depends on INET
1269 select LOCKD 1269 select LOCKD
1270 select SUNRPC 1270 select SUNRPC
1271 select NFS_ACL_SUPPORT if NFS_V3_ACL
1271 help 1272 help
1272 If you are connected to some other (usually local) Unix computer 1273 If you are connected to some other (usually local) Unix computer
1273 (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing 1274 (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
@@ -1310,6 +1311,16 @@ config NFS_V3
1310 1311
1311 If unsure, say Y. 1312 If unsure, say Y.
1312 1313
1314config 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.
1323
1313config NFS_V4 1324config NFS_V4
1314 bool "Provide NFSv4 client support (EXPERIMENTAL)" 1325 bool "Provide NFSv4 client support (EXPERIMENTAL)"
1315 depends on NFS_FS && EXPERIMENTAL 1326 depends on NFS_FS && EXPERIMENTAL
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index b4baa031edf4..8b3bb715d177 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \
8 proc.o read.o symlink.o unlink.o write.o 8 proc.o read.o symlink.o unlink.o write.o
9nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o 9nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
10nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o 10nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
11nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
11nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ 12nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
12 delegation.o idmap.o \ 13 delegation.o idmap.o \
13 callback.o callback_xdr.o callback_proc.o 14 callback.o callback_xdr.o callback_proc.o
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 5720537bffdd..2c6a95945684 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -75,6 +75,27 @@ struct inode_operations nfs_dir_inode_operations = {
75 .setattr = nfs_setattr, 75 .setattr = nfs_setattr,
76}; 76};
77 77
78#ifdef CONFIG_NFS_V3
79struct 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#ifdef CONFIG_NFS_V4 99#ifdef CONFIG_NFS_V4
79 100
80static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); 101static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 55c907592490..a606708264ed 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -71,6 +71,18 @@ struct inode_operations nfs_file_inode_operations = {
71 .setattr = nfs_setattr, 71 .setattr = nfs_setattr,
72}; 72};
73 73
74#ifdef CONFIG_NFS_V3
75struct 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/* Hack for future NFS swap support */ 86/* Hack for future NFS swap support */
75#ifndef IS_SWAPFILE 87#ifndef IS_SWAPFILE
76# define IS_SWAPFILE(inode) (0) 88# define IS_SWAPFILE(inode) (0)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 97b3fe7ece63..440b9cbb6f81 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -108,6 +108,21 @@ static struct rpc_program nfs_program = {
108 .pipe_dir_name = "/nfs", 108 .pipe_dir_name = "/nfs",
109}; 109};
110 110
111#ifdef CONFIG_NFS_V3_ACL
112static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
113static struct rpc_version * nfsacl_version[] = {
114 [3] = &nfsacl_version3,
115};
116
117struct 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
111static inline unsigned long 126static inline unsigned long
112nfs_fattr_to_ino_t(struct nfs_fattr *fattr) 127nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
113{ 128{
@@ -165,6 +180,9 @@ nfs_umount_begin(struct super_block *sb)
165 /* -EIO all pending I/O */ 180 /* -EIO all pending I/O */
166 if (!IS_ERR(rpc)) 181 if (!IS_ERR(rpc))
167 rpc_killall_tasks(rpc); 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
@@ -461,8 +479,17 @@ nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
461 atomic_inc(&server->client->cl_count); 479 atomic_inc(&server->client->cl_count);
462 server->client_sys = server->client; 480 server->client_sys = server->client;
463 } 481 }
464
465 if (server->flags & NFS_MOUNT_VER3) { 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 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) 493 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
467 server->namelen = NFS3_MAXNAMLEN; 494 server->namelen = NFS3_MAXNAMLEN;
468 sb->s_time_gran = 1; 495 sb->s_time_gran = 1;
@@ -546,6 +573,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
546 { NFS_MOUNT_NOCTO, ",nocto", "" }, 573 { NFS_MOUNT_NOCTO, ",nocto", "" },
547 { NFS_MOUNT_NOAC, ",noac", "" }, 574 { NFS_MOUNT_NOAC, ",noac", "" },
548 { NFS_MOUNT_NONLM, ",nolock", ",lock" }, 575 { NFS_MOUNT_NONLM, ",nolock", ",lock" },
576 { NFS_MOUNT_NOACL, ",noacl", "" },
549 { 0, NULL, NULL } 577 { 0, NULL, NULL }
550 }; 578 };
551 struct proc_nfs_info *nfs_infop; 579 struct proc_nfs_info *nfs_infop;
@@ -1452,7 +1480,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
1452 memset(server, 0, sizeof(struct nfs_server)); 1480 memset(server, 0, sizeof(struct nfs_server));
1453 /* Zero out the NFS state stuff */ 1481 /* Zero out the NFS state stuff */
1454 init_nfsv4_state(server); 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 root = &server->fh; 1485 root = &server->fh;
1458 if (data->flags & NFS_MOUNT_VER3) 1486 if (data->flags & NFS_MOUNT_VER3)
@@ -1513,6 +1541,8 @@ static void nfs_kill_super(struct super_block *s)
1513 rpc_shutdown_client(server->client); 1541 rpc_shutdown_client(server->client);
1514 if (!IS_ERR(server->client_sys)) 1542 if (!IS_ERR(server->client_sys))
1515 rpc_shutdown_client(server->client_sys); 1543 rpc_shutdown_client(server->client_sys);
1544 if (!IS_ERR(server->client_acl))
1545 rpc_shutdown_client(server->client_acl);
1516 1546
1517 if (!(server->flags & NFS_MOUNT_NONLM)) 1547 if (!(server->flags & NFS_MOUNT_NONLM))
1518 lockd_down(); /* release rpc.lockd */ 1548 lockd_down(); /* release rpc.lockd */
@@ -1794,7 +1824,7 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
1794 memset(server, 0, sizeof(struct nfs_server)); 1824 memset(server, 0, sizeof(struct nfs_server));
1795 /* Zero out the NFS state stuff */ 1825 /* Zero out the NFS state stuff */
1796 init_nfsv4_state(server); 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 p = nfs_copy_user_string(NULL, &data->hostname, 256); 1829 p = nfs_copy_user_string(NULL, &data->hostname, 256);
1800 if (IS_ERR(p)) 1830 if (IS_ERR(p))
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
new file mode 100644
index 000000000000..393ba79fc14f
--- /dev/null
+++ b/fs/nfs/nfs3acl.c
@@ -0,0 +1,303 @@
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
10ssize_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
49ssize_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
78int 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
101int 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
116struct 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
195getout:
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
206static 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 }
260out:
261 return status;
262}
263
264int 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
301fail:
302 return PTR_ERR(alloc);
303}
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 53953a775714..d03bac0cc42f 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -17,6 +17,7 @@
17#include <linux/nfs_page.h> 17#include <linux/nfs_page.h>
18#include <linux/lockd/bind.h> 18#include <linux/lockd/bind.h>
19#include <linux/smp_lock.h> 19#include <linux/smp_lock.h>
20#include <linux/nfs_mount.h>
20 21
21#define NFSDBG_FACILITY NFSDBG_PROC 22#define NFSDBG_FACILITY NFSDBG_PROC
22 23
@@ -45,7 +46,7 @@ static inline int
45nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) 46nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
46{ 47{
47 struct rpc_message msg = { 48 struct rpc_message msg = {
48 .rpc_proc = &nfs3_procedures[proc], 49 .rpc_proc = &clnt->cl_procinfo[proc],
49 .rpc_argp = argp, 50 .rpc_argp = argp,
50 .rpc_resp = resp, 51 .rpc_resp = resp,
51 }; 52 };
@@ -825,8 +826,8 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
825struct nfs_rpc_ops nfs_v3_clientops = { 826struct nfs_rpc_ops nfs_v3_clientops = {
826 .version = 3, /* protocol version */ 827 .version = 3, /* protocol version */
827 .dentry_ops = &nfs_dentry_operations, 828 .dentry_ops = &nfs_dentry_operations,
828 .dir_inode_ops = &nfs_dir_inode_operations, 829 .dir_inode_ops = &nfs3_dir_inode_operations,
829 .file_inode_ops = &nfs_file_inode_operations, 830 .file_inode_ops = &nfs3_file_inode_operations,
830 .getroot = nfs3_proc_get_root, 831 .getroot = nfs3_proc_get_root,
831 .getattr = nfs3_proc_getattr, 832 .getattr = nfs3_proc_getattr,
832 .setattr = nfs3_proc_setattr, 833 .setattr = nfs3_proc_setattr,
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index a3593d47e5ab..a4437fb177f0 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -21,6 +21,7 @@
21#include <linux/nfs.h> 21#include <linux/nfs.h>
22#include <linux/nfs3.h> 22#include <linux/nfs3.h>
23#include <linux/nfs_fs.h> 23#include <linux/nfs_fs.h>
24#include <linux/nfsacl.h>
24 25
25#define NFSDBG_FACILITY NFSDBG_XDR 26#define NFSDBG_FACILITY NFSDBG_XDR
26 27
@@ -79,6 +80,11 @@ extern int nfs_stat_to_errno(int);
79#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) 80#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
80#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) 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 * Map file type to S_IFMT bits 89 * Map file type to S_IFMT bits
84 */ 90 */
@@ -627,6 +633,74 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
627 return 0; 633 return 0;
628} 634}
629 635
636#ifdef CONFIG_NFS_V3_ACL
637/*
638 * Encode GETACL arguments
639 */
640static int
641nfs3_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 */
664static int
665nfs3_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
630/* 704/*
631 * NFS XDR decode functions 705 * NFS XDR decode functions
632 */ 706 */
@@ -978,6 +1052,54 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
978 return 0; 1052 return 0;
979} 1053}
980 1054
1055#ifdef CONFIG_NFS_V3_ACL
1056/*
1057 * Decode GETACL reply
1058 */
1059static int
1060nfs3_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 */
1091static int
1092nfs3_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#ifndef MAX 1103#ifndef MAX
982# define MAX(a, b) (((a) > (b))? (a) : (b)) 1104# define MAX(a, b) (((a) > (b))? (a) : (b))
983#endif 1105#endif
@@ -1021,3 +1143,28 @@ struct rpc_version nfs_version3 = {
1021 .procs = nfs3_procedures 1143 .procs = nfs3_procedures
1022}; 1144};
1023 1145
1146#ifdef CONFIG_NFS_V3_ACL
1147static 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
1164struct 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 */
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index fd5bc596fe8a..1b272a135a31 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -124,6 +124,7 @@ enum {
124 Opt_soft, Opt_hard, Opt_intr, 124 Opt_soft, Opt_hard, Opt_intr,
125 Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, 125 Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac,
126 Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, 126 Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
127 Opt_acl, Opt_noacl,
127 /* Error token */ 128 /* Error token */
128 Opt_err 129 Opt_err
129}; 130};
@@ -158,6 +159,8 @@ static match_table_t __initdata tokens = {
158 {Opt_udp, "udp"}, 159 {Opt_udp, "udp"},
159 {Opt_tcp, "proto=tcp"}, 160 {Opt_tcp, "proto=tcp"},
160 {Opt_tcp, "tcp"}, 161 {Opt_tcp, "tcp"},
162 {Opt_acl, "acl"},
163 {Opt_noacl, "noacl"},
161 {Opt_err, NULL} 164 {Opt_err, NULL}
162 165
163}; 166};
@@ -266,6 +269,12 @@ static int __init root_nfs_parse(char *name, char *buf)
266 case Opt_tcp: 269 case Opt_tcp:
267 nfs_data.flags |= NFS_MOUNT_TCP; 270 nfs_data.flags |= NFS_MOUNT_TCP;
268 break; 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;
277 break;
269 default : 278 default :
270 return 0; 279 return 0;
271 } 280 }