aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
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/nfs
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/nfs')
-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
8 files changed, 530 insertions, 6 deletions
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 }