aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/Makefile2
-rw-r--r--fs/nfsd/nfs2acl.c336
-rw-r--r--fs/nfsd/nfs3acl.c267
-rw-r--r--fs/nfsd/nfs3xdr.c13
-rw-r--r--fs/nfsd/nfssvc.c27
-rw-r--r--fs/nfsd/nfsxdr.c11
-rw-r--r--fs/nfsd/vfs.c107
7 files changed, 762 insertions, 1 deletions
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index b8680a247f8b..9f043f44c92f 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -6,7 +6,9 @@ obj-$(CONFIG_NFSD) += nfsd.o
6 6
7nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ 7nfsd-y := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
8 export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o 8 export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
9nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
9nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o 10nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
11nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
10nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ 12nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
11 nfs4acl.o nfs4callback.o 13 nfs4acl.o nfs4callback.o
12nfsd-objs := $(nfsd-y) 14nfsd-objs := $(nfsd-y)
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
new file mode 100644
index 000000000000..7cbf0682b2f0
--- /dev/null
+++ b/fs/nfsd/nfs2acl.c
@@ -0,0 +1,336 @@
1/*
2 * linux/fs/nfsd/nfsacl.c
3 *
4 * Process version 2 NFSACL requests.
5 *
6 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
7 */
8
9#include <linux/sunrpc/svc.h>
10#include <linux/nfs.h>
11#include <linux/nfsd/nfsd.h>
12#include <linux/nfsd/cache.h>
13#include <linux/nfsd/xdr.h>
14#include <linux/nfsd/xdr3.h>
15#include <linux/posix_acl.h>
16#include <linux/nfsacl.h>
17
18#define NFSDDBG_FACILITY NFSDDBG_PROC
19#define RETURN_STATUS(st) { resp->status = (st); return (st); }
20
21/*
22 * NULL call.
23 */
24static int
25nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
26{
27 return nfs_ok;
28}
29
30/*
31 * Get the Access and/or Default ACL of a file.
32 */
33static int nfsacld_proc_getacl(struct svc_rqst * rqstp,
34 struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
35{
36 svc_fh *fh;
37 struct posix_acl *acl;
38 int nfserr = 0;
39
40 dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
41
42 fh = fh_copy(&resp->fh, &argp->fh);
43 if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP)))
44 RETURN_STATUS(nfserr_inval);
45
46 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
47 RETURN_STATUS(nfserr_inval);
48 resp->mask = argp->mask;
49
50 if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
51 acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
52 if (IS_ERR(acl)) {
53 int err = PTR_ERR(acl);
54
55 if (err == -ENODATA || err == -EOPNOTSUPP)
56 acl = NULL;
57 else {
58 nfserr = nfserrno(err);
59 goto fail;
60 }
61 }
62 if (acl == NULL) {
63 /* Solaris returns the inode's minimum ACL. */
64
65 struct inode *inode = fh->fh_dentry->d_inode;
66 acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
67 }
68 resp->acl_access = acl;
69 }
70 if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
71 /* Check how Solaris handles requests for the Default ACL
72 of a non-directory! */
73
74 acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
75 if (IS_ERR(acl)) {
76 int err = PTR_ERR(acl);
77
78 if (err == -ENODATA || err == -EOPNOTSUPP)
79 acl = NULL;
80 else {
81 nfserr = nfserrno(err);
82 goto fail;
83 }
84 }
85 resp->acl_default = acl;
86 }
87
88 /* resp->acl_{access,default} are released in nfssvc_release_getacl. */
89 RETURN_STATUS(0);
90
91fail:
92 posix_acl_release(resp->acl_access);
93 posix_acl_release(resp->acl_default);
94 RETURN_STATUS(nfserr);
95}
96
97/*
98 * Set the Access and/or Default ACL of a file.
99 */
100static int nfsacld_proc_setacl(struct svc_rqst * rqstp,
101 struct nfsd3_setaclargs *argp,
102 struct nfsd_attrstat *resp)
103{
104 svc_fh *fh;
105 int nfserr = 0;
106
107 dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
108
109 fh = fh_copy(&resp->fh, &argp->fh);
110 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
111
112 if (!nfserr) {
113 nfserr = nfserrno( nfsd_set_posix_acl(
114 fh, ACL_TYPE_ACCESS, argp->acl_access) );
115 }
116 if (!nfserr) {
117 nfserr = nfserrno( nfsd_set_posix_acl(
118 fh, ACL_TYPE_DEFAULT, argp->acl_default) );
119 }
120
121 /* argp->acl_{access,default} may have been allocated in
122 nfssvc_decode_setaclargs. */
123 posix_acl_release(argp->acl_access);
124 posix_acl_release(argp->acl_default);
125 return nfserr;
126}
127
128/*
129 * Check file attributes
130 */
131static int nfsacld_proc_getattr(struct svc_rqst * rqstp,
132 struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
133{
134 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
135
136 fh_copy(&resp->fh, &argp->fh);
137 return fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
138}
139
140/*
141 * Check file access
142 */
143static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
144 struct nfsd3_accessres *resp)
145{
146 int nfserr;
147
148 dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
149 SVCFH_fmt(&argp->fh),
150 argp->access);
151
152 fh_copy(&resp->fh, &argp->fh);
153 resp->access = argp->access;
154 nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
155 return nfserr;
156}
157
158/*
159 * XDR decode functions
160 */
161static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
162 struct nfsd3_getaclargs *argp)
163{
164 if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
165 return 0;
166 argp->mask = ntohl(*p); p++;
167
168 return xdr_argsize_check(rqstp, p);
169}
170
171
172static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
173 struct nfsd3_setaclargs *argp)
174{
175 struct kvec *head = rqstp->rq_arg.head;
176 unsigned int base;
177 int n;
178
179 if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
180 return 0;
181 argp->mask = ntohl(*p++);
182 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) ||
183 !xdr_argsize_check(rqstp, p))
184 return 0;
185
186 base = (char *)p - (char *)head->iov_base;
187 n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
188 (argp->mask & NFS_ACL) ?
189 &argp->acl_access : NULL);
190 if (n > 0)
191 n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
192 (argp->mask & NFS_DFACL) ?
193 &argp->acl_default : NULL);
194 return (n > 0);
195}
196
197static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p,
198 struct nfsd_fhandle *argp)
199{
200 if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
201 return 0;
202 return xdr_argsize_check(rqstp, p);
203}
204
205static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
206 struct nfsd3_accessargs *argp)
207{
208 if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
209 return 0;
210 argp->access = ntohl(*p++);
211
212 return xdr_argsize_check(rqstp, p);
213}
214
215/*
216 * XDR encode functions
217 */
218
219/* GETACL */
220static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
221 struct nfsd3_getaclres *resp)
222{
223 struct dentry *dentry = resp->fh.fh_dentry;
224 struct inode *inode = dentry->d_inode;
225 int w = nfsacl_size(
226 (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
227 (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
228 struct kvec *head = rqstp->rq_res.head;
229 unsigned int base;
230 int n;
231
232 if (dentry == NULL || dentry->d_inode == NULL)
233 return 0;
234 inode = dentry->d_inode;
235
236 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
237 *p++ = htonl(resp->mask);
238 if (!xdr_ressize_check(rqstp, p))
239 return 0;
240 base = (char *)p - (char *)head->iov_base;
241
242 rqstp->rq_res.page_len = w;
243 while (w > 0) {
244 if (!svc_take_res_page(rqstp))
245 return 0;
246 w -= PAGE_SIZE;
247 }
248
249 n = nfsacl_encode(&rqstp->rq_res, base, inode,
250 resp->acl_access,
251 resp->mask & NFS_ACL, 0);
252 if (n > 0)
253 n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
254 resp->acl_default,
255 resp->mask & NFS_DFACL,
256 NFS_ACL_DEFAULT);
257 if (n <= 0)
258 return 0;
259 return 1;
260}
261
262static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p,
263 struct nfsd_attrstat *resp)
264{
265 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
266 return xdr_ressize_check(rqstp, p);
267}
268
269/* ACCESS */
270static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
271 struct nfsd3_accessres *resp)
272{
273 p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
274 *p++ = htonl(resp->access);
275 return xdr_ressize_check(rqstp, p);
276}
277
278/*
279 * XDR release functions
280 */
281static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p,
282 struct nfsd3_getaclres *resp)
283{
284 fh_put(&resp->fh);
285 posix_acl_release(resp->acl_access);
286 posix_acl_release(resp->acl_default);
287 return 1;
288}
289
290static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
291 struct nfsd_fhandle *resp)
292{
293 fh_put(&resp->fh);
294 return 1;
295}
296
297#define nfsaclsvc_decode_voidargs NULL
298#define nfsaclsvc_encode_voidres NULL
299#define nfsaclsvc_release_void NULL
300#define nfsd3_fhandleargs nfsd_fhandle
301#define nfsd3_attrstatres nfsd_attrstat
302#define nfsd3_voidres nfsd3_voidargs
303struct nfsd3_voidargs { int dummy; };
304
305#define PROC(name, argt, rest, relt, cache, respsize) \
306 { (svc_procfunc) nfsacld_proc_##name, \
307 (kxdrproc_t) nfsaclsvc_decode_##argt##args, \
308 (kxdrproc_t) nfsaclsvc_encode_##rest##res, \
309 (kxdrproc_t) nfsaclsvc_release_##relt, \
310 sizeof(struct nfsd3_##argt##args), \
311 sizeof(struct nfsd3_##rest##res), \
312 0, \
313 cache, \
314 respsize, \
315 }
316
317#define ST 1 /* status*/
318#define AT 21 /* attributes */
319#define pAT (1+AT) /* post attributes - conditional */
320#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
321
322static struct svc_procedure nfsd_acl_procedures2[] = {
323 PROC(null, void, void, void, RC_NOCACHE, ST),
324 PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
325 PROC(setacl, setacl, attrstat, fhandle, RC_NOCACHE, ST+AT),
326 PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT),
327 PROC(access, access, access, fhandle, RC_NOCACHE, ST+AT+1),
328};
329
330struct svc_version nfsd_acl_version2 = {
331 .vs_vers = 2,
332 .vs_nproc = 5,
333 .vs_proc = nfsd_acl_procedures2,
334 .vs_dispatch = nfsd_dispatch,
335 .vs_xdrsize = NFS3_SVC_XDRSIZE,
336};
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
new file mode 100644
index 000000000000..64ba40572fea
--- /dev/null
+++ b/fs/nfsd/nfs3acl.c
@@ -0,0 +1,267 @@
1/*
2 * linux/fs/nfsd/nfs3acl.c
3 *
4 * Process version 3 NFSACL requests.
5 *
6 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
7 */
8
9#include <linux/sunrpc/svc.h>
10#include <linux/nfs3.h>
11#include <linux/nfsd/nfsd.h>
12#include <linux/nfsd/cache.h>
13#include <linux/nfsd/xdr3.h>
14#include <linux/posix_acl.h>
15#include <linux/nfsacl.h>
16
17#define RETURN_STATUS(st) { resp->status = (st); return (st); }
18
19/*
20 * NULL call.
21 */
22static int
23nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
24{
25 return nfs_ok;
26}
27
28/*
29 * Get the Access and/or Default ACL of a file.
30 */
31static int nfsd3_proc_getacl(struct svc_rqst * rqstp,
32 struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
33{
34 svc_fh *fh;
35 struct posix_acl *acl;
36 int nfserr = 0;
37
38 fh = fh_copy(&resp->fh, &argp->fh);
39 if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP)))
40 RETURN_STATUS(nfserr_inval);
41
42 if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
43 RETURN_STATUS(nfserr_inval);
44 resp->mask = argp->mask;
45
46 if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
47 acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
48 if (IS_ERR(acl)) {
49 int err = PTR_ERR(acl);
50
51 if (err == -ENODATA || err == -EOPNOTSUPP)
52 acl = NULL;
53 else {
54 nfserr = nfserrno(err);
55 goto fail;
56 }
57 }
58 if (acl == NULL) {
59 /* Solaris returns the inode's minimum ACL. */
60
61 struct inode *inode = fh->fh_dentry->d_inode;
62 acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
63 }
64 resp->acl_access = acl;
65 }
66 if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
67 /* Check how Solaris handles requests for the Default ACL
68 of a non-directory! */
69
70 acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
71 if (IS_ERR(acl)) {
72 int err = PTR_ERR(acl);
73
74 if (err == -ENODATA || err == -EOPNOTSUPP)
75 acl = NULL;
76 else {
77 nfserr = nfserrno(err);
78 goto fail;
79 }
80 }
81 resp->acl_default = acl;
82 }
83
84 /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */
85 RETURN_STATUS(0);
86
87fail:
88 posix_acl_release(resp->acl_access);
89 posix_acl_release(resp->acl_default);
90 RETURN_STATUS(nfserr);
91}
92
93/*
94 * Set the Access and/or Default ACL of a file.
95 */
96static int nfsd3_proc_setacl(struct svc_rqst * rqstp,
97 struct nfsd3_setaclargs *argp,
98 struct nfsd3_attrstat *resp)
99{
100 svc_fh *fh;
101 int nfserr = 0;
102
103 fh = fh_copy(&resp->fh, &argp->fh);
104 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
105
106 if (!nfserr) {
107 nfserr = nfserrno( nfsd_set_posix_acl(
108 fh, ACL_TYPE_ACCESS, argp->acl_access) );
109 }
110 if (!nfserr) {
111 nfserr = nfserrno( nfsd_set_posix_acl(
112 fh, ACL_TYPE_DEFAULT, argp->acl_default) );
113 }
114
115 /* argp->acl_{access,default} may have been allocated in
116 nfs3svc_decode_setaclargs. */
117 posix_acl_release(argp->acl_access);
118 posix_acl_release(argp->acl_default);
119 RETURN_STATUS(nfserr);
120}
121
122/*
123 * XDR decode functions
124 */
125static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
126 struct nfsd3_getaclargs *args)
127{
128 if (!(p = nfs3svc_decode_fh(p, &args->fh)))
129 return 0;
130 args->mask = ntohl(*p); p++;
131
132 return xdr_argsize_check(rqstp, p);
133}
134
135
136static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
137 struct nfsd3_setaclargs *args)
138{
139 struct kvec *head = rqstp->rq_arg.head;
140 unsigned int base;
141 int n;
142
143 if (!(p = nfs3svc_decode_fh(p, &args->fh)))
144 return 0;
145 args->mask = ntohl(*p++);
146 if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) ||
147 !xdr_argsize_check(rqstp, p))
148 return 0;
149
150 base = (char *)p - (char *)head->iov_base;
151 n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
152 (args->mask & NFS_ACL) ?
153 &args->acl_access : NULL);
154 if (n > 0)
155 n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
156 (args->mask & NFS_DFACL) ?
157 &args->acl_default : NULL);
158 return (n > 0);
159}
160
161/*
162 * XDR encode functions
163 */
164
165/* GETACL */
166static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
167 struct nfsd3_getaclres *resp)
168{
169 struct dentry *dentry = resp->fh.fh_dentry;
170
171 p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
172 if (resp->status == 0 && dentry && dentry->d_inode) {
173 struct inode *inode = dentry->d_inode;
174 int w = nfsacl_size(
175 (resp->mask & NFS_ACL) ? resp->acl_access : NULL,
176 (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
177 struct kvec *head = rqstp->rq_res.head;
178 unsigned int base;
179 int n;
180
181 *p++ = htonl(resp->mask);
182 if (!xdr_ressize_check(rqstp, p))
183 return 0;
184 base = (char *)p - (char *)head->iov_base;
185
186 rqstp->rq_res.page_len = w;
187 while (w > 0) {
188 if (!svc_take_res_page(rqstp))
189 return 0;
190 w -= PAGE_SIZE;
191 }
192
193 n = nfsacl_encode(&rqstp->rq_res, base, inode,
194 resp->acl_access,
195 resp->mask & NFS_ACL, 0);
196 if (n > 0)
197 n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
198 resp->acl_default,
199 resp->mask & NFS_DFACL,
200 NFS_ACL_DEFAULT);
201 if (n <= 0)
202 return 0;
203 } else
204 if (!xdr_ressize_check(rqstp, p))
205 return 0;
206
207 return 1;
208}
209
210/* SETACL */
211static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p,
212 struct nfsd3_attrstat *resp)
213{
214 p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
215
216 return xdr_ressize_check(rqstp, p);
217}
218
219/*
220 * XDR release functions
221 */
222static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p,
223 struct nfsd3_getaclres *resp)
224{
225 fh_put(&resp->fh);
226 posix_acl_release(resp->acl_access);
227 posix_acl_release(resp->acl_default);
228 return 1;
229}
230
231#define nfs3svc_decode_voidargs NULL
232#define nfs3svc_release_void NULL
233#define nfsd3_setaclres nfsd3_attrstat
234#define nfsd3_voidres nfsd3_voidargs
235struct nfsd3_voidargs { int dummy; };
236
237#define PROC(name, argt, rest, relt, cache, respsize) \
238 { (svc_procfunc) nfsd3_proc_##name, \
239 (kxdrproc_t) nfs3svc_decode_##argt##args, \
240 (kxdrproc_t) nfs3svc_encode_##rest##res, \
241 (kxdrproc_t) nfs3svc_release_##relt, \
242 sizeof(struct nfsd3_##argt##args), \
243 sizeof(struct nfsd3_##rest##res), \
244 0, \
245 cache, \
246 respsize, \
247 }
248
249#define ST 1 /* status*/
250#define AT 21 /* attributes */
251#define pAT (1+AT) /* post attributes - conditional */
252#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
253
254static struct svc_procedure nfsd_acl_procedures3[] = {
255 PROC(null, void, void, void, RC_NOCACHE, ST),
256 PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
257 PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT),
258};
259
260struct svc_version nfsd_acl_version3 = {
261 .vs_vers = 3,
262 .vs_nproc = 3,
263 .vs_proc = nfsd_acl_procedures3,
264 .vs_dispatch = nfsd_dispatch,
265 .vs_xdrsize = NFS3_SVC_XDRSIZE,
266};
267
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 11f806835c5a..e0e134d6baba 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -71,6 +71,12 @@ decode_fh(u32 *p, struct svc_fh *fhp)
71 return p + XDR_QUADLEN(size); 71 return p + XDR_QUADLEN(size);
72} 72}
73 73
74/* Helper function for NFSv3 ACL code */
75u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp)
76{
77 return decode_fh(p, fhp);
78}
79
74static inline u32 * 80static inline u32 *
75encode_fh(u32 *p, struct svc_fh *fhp) 81encode_fh(u32 *p, struct svc_fh *fhp)
76{ 82{
@@ -233,6 +239,13 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
233 return p; 239 return p;
234} 240}
235 241
242/* Helper for NFSv3 ACLs */
243u32 *
244nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
245{
246 return encode_post_op_attr(rqstp, p, fhp);
247}
248
236/* 249/*
237 * Enocde weak cache consistency data 250 * Enocde weak cache consistency data
238 */ 251 */
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 02ded7cfbdcf..79b25b19fec8 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -31,6 +31,7 @@
31#include <linux/nfsd/stats.h> 31#include <linux/nfsd/stats.h>
32#include <linux/nfsd/cache.h> 32#include <linux/nfsd/cache.h>
33#include <linux/lockd/bind.h> 33#include <linux/lockd/bind.h>
34#include <linux/nfsacl.h>
34 35
35#define NFSDDBG_FACILITY NFSDDBG_SVC 36#define NFSDDBG_FACILITY NFSDDBG_SVC
36 37
@@ -362,6 +363,31 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
362 return 1; 363 return 1;
363} 364}
364 365
366#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
367static struct svc_stat nfsd_acl_svcstats;
368static struct svc_version * nfsd_acl_version[] = {
369 [2] = &nfsd_acl_version2,
370 [3] = &nfsd_acl_version3,
371};
372
373#define NFSD_ACL_NRVERS (sizeof(nfsd_acl_version)/sizeof(nfsd_acl_version[0]))
374static struct svc_program nfsd_acl_program = {
375 .pg_prog = NFS_ACL_PROGRAM,
376 .pg_nvers = NFSD_ACL_NRVERS,
377 .pg_vers = nfsd_acl_version,
378 .pg_name = "nfsd",
379 .pg_stats = &nfsd_acl_svcstats,
380};
381
382static struct svc_stat nfsd_acl_svcstats = {
383 .program = &nfsd_acl_program,
384};
385
386#define nfsd_acl_program_p &nfsd_acl_program
387#else
388#define nfsd_acl_program_p NULL
389#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
390
365extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; 391extern struct svc_version nfsd_version2, nfsd_version3, nfsd_version4;
366 392
367static struct svc_version * nfsd_version[] = { 393static struct svc_version * nfsd_version[] = {
@@ -376,6 +402,7 @@ static struct svc_version * nfsd_version[] = {
376 402
377#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0])) 403#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
378struct svc_program nfsd_program = { 404struct svc_program nfsd_program = {
405 .pg_next = nfsd_acl_program_p,
379 .pg_prog = NFS_PROGRAM, /* program number */ 406 .pg_prog = NFS_PROGRAM, /* program number */
380 .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */ 407 .pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
381 .pg_vers = nfsd_version, /* version table */ 408 .pg_vers = nfsd_version, /* version table */
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 948b08287c99..b45999ff33e6 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -49,6 +49,12 @@ decode_fh(u32 *p, struct svc_fh *fhp)
49 return p + (NFS_FHSIZE >> 2); 49 return p + (NFS_FHSIZE >> 2);
50} 50}
51 51
52/* Helper function for NFSv2 ACL code */
53u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp)
54{
55 return decode_fh(p, fhp);
56}
57
52static inline u32 * 58static inline u32 *
53encode_fh(u32 *p, struct svc_fh *fhp) 59encode_fh(u32 *p, struct svc_fh *fhp)
54{ 60{
@@ -190,6 +196,11 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
190 return p; 196 return p;
191} 197}
192 198
199/* Helper function for NFSv2 ACL code */
200u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
201{
202 return encode_fattr(rqstp, p, fhp);
203}
193 204
194/* 205/*
195 * XDR decode functions 206 * XDR decode functions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index e3e9d217236e..ae3940dc85cc 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -46,8 +46,9 @@
46#include <linux/nfsd/nfsfh.h> 46#include <linux/nfsd/nfsfh.h>
47#include <linux/quotaops.h> 47#include <linux/quotaops.h>
48#include <linux/dnotify.h> 48#include <linux/dnotify.h>
49#ifdef CONFIG_NFSD_V4 49#include <linux/xattr_acl.h>
50#include <linux/posix_acl.h> 50#include <linux/posix_acl.h>
51#ifdef CONFIG_NFSD_V4
51#include <linux/posix_acl_xattr.h> 52#include <linux/posix_acl_xattr.h>
52#include <linux/xattr_acl.h> 53#include <linux/xattr_acl.h>
53#include <linux/xattr.h> 54#include <linux/xattr.h>
@@ -1857,3 +1858,107 @@ nfsd_racache_init(int cache_size)
1857 nfsdstats.ra_size = cache_size; 1858 nfsdstats.ra_size = cache_size;
1858 return 0; 1859 return 0;
1859} 1860}
1861
1862#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
1863struct posix_acl *
1864nfsd_get_posix_acl(struct svc_fh *fhp, int type)
1865{
1866 struct inode *inode = fhp->fh_dentry->d_inode;
1867 char *name;
1868 void *value = NULL;
1869 ssize_t size;
1870 struct posix_acl *acl;
1871
1872 if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr)
1873 return ERR_PTR(-EOPNOTSUPP);
1874 switch(type) {
1875 case ACL_TYPE_ACCESS:
1876 name = XATTR_NAME_ACL_ACCESS;
1877 break;
1878 case ACL_TYPE_DEFAULT:
1879 name = XATTR_NAME_ACL_DEFAULT;
1880 break;
1881 default:
1882 return ERR_PTR(-EOPNOTSUPP);
1883 }
1884
1885 size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0);
1886
1887 if (size < 0) {
1888 acl = ERR_PTR(size);
1889 goto getout;
1890 } else if (size > 0) {
1891 value = kmalloc(size, GFP_KERNEL);
1892 if (!value) {
1893 acl = ERR_PTR(-ENOMEM);
1894 goto getout;
1895 }
1896 size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size);
1897 if (size < 0) {
1898 acl = ERR_PTR(size);
1899 goto getout;
1900 }
1901 }
1902 acl = posix_acl_from_xattr(value, size);
1903
1904getout:
1905 kfree(value);
1906 return acl;
1907}
1908
1909int
1910nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
1911{
1912 struct inode *inode = fhp->fh_dentry->d_inode;
1913 char *name;
1914 void *value = NULL;
1915 size_t size;
1916 int error;
1917
1918 if (!IS_POSIXACL(inode) || !inode->i_op ||
1919 !inode->i_op->setxattr || !inode->i_op->removexattr)
1920 return -EOPNOTSUPP;
1921 switch(type) {
1922 case ACL_TYPE_ACCESS:
1923 name = XATTR_NAME_ACL_ACCESS;
1924 break;
1925 case ACL_TYPE_DEFAULT:
1926 name = XATTR_NAME_ACL_DEFAULT;
1927 break;
1928 default:
1929 return -EOPNOTSUPP;
1930 }
1931
1932 if (acl && acl->a_count) {
1933 size = xattr_acl_size(acl->a_count);
1934 value = kmalloc(size, GFP_KERNEL);
1935 if (!value)
1936 return -ENOMEM;
1937 size = posix_acl_to_xattr(acl, value, size);
1938 if (size < 0) {
1939 error = size;
1940 goto getout;
1941 }
1942 } else
1943 size = 0;
1944
1945 if (!fhp->fh_locked)
1946 fh_lock(fhp); /* unlocking is done automatically */
1947 if (size)
1948 error = inode->i_op->setxattr(fhp->fh_dentry, name,
1949 value, size, 0);
1950 else {
1951 if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
1952 error = 0;
1953 else {
1954 error = inode->i_op->removexattr(fhp->fh_dentry, name);
1955 if (error == -ENODATA)
1956 error = 0;
1957 }
1958 }
1959
1960getout:
1961 kfree(value);
1962 return error;
1963}
1964#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */