Commit b7fa0554cf1ba6d6895cd0a5b02989a26e0bc704
Committed by
Trond Myklebust
1 parent
a257cdd0e2
Exists in
master
and in
4 other branches
[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
fs/Kconfig
... | ... | @@ -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)" |
fs/nfs/Makefile
... | ... | @@ -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 |
fs/nfs/dir.c
... | ... | @@ -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 *); |
fs/nfs/file.c
... | ... | @@ -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) |
fs/nfs/inode.c
... | ... | @@ -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)) |
fs/nfs/nfs3acl.c
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 | +} |
fs/nfs/nfs3proc.c
... | ... | @@ -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, |
fs/nfs/nfs3xdr.c
... | ... | @@ -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 */ |
fs/nfs/nfsroot.c
... | ... | @@ -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 |