aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--include/linux/nfs_fs.h31
-rw-r--r--include/linux/nfs_fs_sb.h1
-rw-r--r--include/linux/nfs_mount.h1
-rw-r--r--include/linux/nfs_xdr.h27
13 files changed, 601 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 }
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index d2b5d7e0e85a..3a5e442ac776 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -301,6 +301,9 @@ extern u32 root_nfs_parse_addr(char *name); /*__init*/
301 * linux/fs/nfs/file.c 301 * linux/fs/nfs/file.c
302 */ 302 */
303extern struct inode_operations nfs_file_inode_operations; 303extern struct inode_operations nfs_file_inode_operations;
304#ifdef CONFIG_NFS_V3
305extern struct inode_operations nfs3_file_inode_operations;
306#endif /* CONFIG_NFS_V3 */
304extern struct file_operations nfs_file_operations; 307extern struct file_operations nfs_file_operations;
305extern struct address_space_operations nfs_file_aops; 308extern struct address_space_operations nfs_file_aops;
306 309
@@ -316,6 +319,22 @@ static inline struct rpc_cred *nfs_file_cred(struct file *file)
316} 319}
317 320
318/* 321/*
322 * linux/fs/nfs/xattr.c
323 */
324#ifdef CONFIG_NFS_V3_ACL
325extern ssize_t nfs3_listxattr(struct dentry *, char *, size_t);
326extern ssize_t nfs3_getxattr(struct dentry *, const char *, void *, size_t);
327extern int nfs3_setxattr(struct dentry *, const char *,
328 const void *, size_t, int);
329extern 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 * linux/fs/nfs/direct.c 338 * linux/fs/nfs/direct.c
320 */ 339 */
321extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t, 340extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
@@ -329,6 +348,9 @@ extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf,
329 * linux/fs/nfs/dir.c 348 * linux/fs/nfs/dir.c
330 */ 349 */
331extern struct inode_operations nfs_dir_inode_operations; 350extern struct inode_operations nfs_dir_inode_operations;
351#ifdef CONFIG_NFS_V3
352extern struct inode_operations nfs3_dir_inode_operations;
353#endif /* CONFIG_NFS_V3 */
332extern struct file_operations nfs_dir_operations; 354extern struct file_operations nfs_dir_operations;
333extern struct dentry_operations nfs_dentry_operations; 355extern struct dentry_operations nfs_dentry_operations;
334 356
@@ -450,6 +472,15 @@ static inline void nfs_readdata_free(struct nfs_read_data *p)
450extern void nfs_readdata_release(struct rpc_task *task); 472extern void nfs_readdata_release(struct rpc_task *task);
451 473
452/* 474/*
475 * linux/fs/nfs3proc.c
476 */
477#ifdef CONFIG_NFS_V3_ACL
478extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type);
479extern int nfs3_proc_setacl(struct inode *inode, int type,
480 struct posix_acl *acl);
481#endif /* CONFIG_NFS_V3_ACL */
482
483/*
453 * linux/fs/mount_clnt.c 484 * linux/fs/mount_clnt.c
454 * (Used only by nfsroot module) 485 * (Used only by nfsroot module)
455 */ 486 */
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index fc51645d61ee..3d3a305488cf 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -10,6 +10,7 @@
10struct nfs_server { 10struct nfs_server {
11 struct rpc_clnt * client; /* RPC client handle */ 11 struct rpc_clnt * client; /* RPC client handle */
12 struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */ 12 struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */
13 struct rpc_clnt * client_acl; /* ACL RPC client handle */
13 struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */ 14 struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */
14 struct backing_dev_info backing_dev_info; 15 struct backing_dev_info backing_dev_info;
15 int flags; /* various flags */ 16 int flags; /* various flags */
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
index 0071428231f9..659c75438454 100644
--- a/include/linux/nfs_mount.h
+++ b/include/linux/nfs_mount.h
@@ -58,6 +58,7 @@ struct nfs_mount_data {
58#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ 58#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
59#define NFS_MOUNT_NONLM 0x0200 /* 3 */ 59#define NFS_MOUNT_NONLM 0x0200 /* 3 */
60#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ 60#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */
61#define NFS_MOUNT_NOACL 0x0800 /* 4 */
61#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ 62#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
62#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ 63#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
63#define NFS_MOUNT_FLAGMASK 0xFFFF 64#define NFS_MOUNT_FLAGMASK 0xFFFF
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 46b206b460c0..a2bf6914ff1b 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -2,6 +2,7 @@
2#define _LINUX_NFS_XDR_H 2#define _LINUX_NFS_XDR_H
3 3
4#include <linux/sunrpc/xprt.h> 4#include <linux/sunrpc/xprt.h>
5#include <linux/nfsacl.h>
5 6
6struct nfs4_fsid { 7struct nfs4_fsid {
7 __u64 major; 8 __u64 major;
@@ -368,6 +369,20 @@ struct nfs_readdirargs {
368 struct page ** pages; 369 struct page ** pages;
369}; 370};
370 371
372struct nfs3_getaclargs {
373 struct nfs_fh * fh;
374 int mask;
375 struct page ** pages;
376};
377
378struct 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
371struct nfs_diropok { 386struct nfs_diropok {
372 struct nfs_fh * fh; 387 struct nfs_fh * fh;
373 struct nfs_fattr * fattr; 388 struct nfs_fattr * fattr;
@@ -491,6 +506,15 @@ struct nfs3_readdirres {
491 int plus; 506 int plus;
492}; 507};
493 508
509struct 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#ifdef CONFIG_NFS_V4 518#ifdef CONFIG_NFS_V4
495 519
496typedef u64 clientid4; 520typedef u64 clientid4;
@@ -748,4 +772,7 @@ extern struct rpc_version nfs_version2;
748extern struct rpc_version nfs_version3; 772extern struct rpc_version nfs_version3;
749extern struct rpc_version nfs_version4; 773extern struct rpc_version nfs_version4;
750 774
775extern struct rpc_version nfsacl_version3;
776extern struct rpc_program nfsacl_program;
777
751#endif 778#endif