]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.suse/nfs4acl-ext3.diff
Add ignored *.diff files of the xen patches
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.suse / nfs4acl-ext3.diff
1 From: Andreas Gruenbacher <agruen@suse.de>
2 Subject: NFSv4 ACLs for ext3
3
4 With the acl=nfs4 mount option, ext3 will use NFSv4 ACLs instead of
5 POSIX ACLs. See http://www.suse.de/~agruen/nfs4acl/ for some
6 documentation and examples.
7
8 Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
9
10 ---
11 fs/Kconfig | 7
12 fs/ext3/Makefile | 1
13 fs/ext3/acl.c | 8
14 fs/ext3/acl.h | 4
15 fs/ext3/file.c | 4
16 fs/ext3/ialloc.c | 6
17 fs/ext3/inode.c | 73 ++++++++-
18 fs/ext3/namei.c | 15 +
19 fs/ext3/namei.h | 1
20 fs/ext3/nfs4acl.c | 370 ++++++++++++++++++++++++++++++++++++++++++++++
21 fs/ext3/nfs4acl.h | 36 ++++
22 fs/ext3/super.c | 60 +++++--
23 fs/ext3/xattr.c | 9 +
24 fs/ext3/xattr.h | 5
25 include/linux/ext3_fs.h | 1
26 include/linux/ext3_fs_i.h | 3
27 16 files changed, 577 insertions(+), 26 deletions(-)
28
29 --- a/fs/Kconfig
30 +++ b/fs/Kconfig
31 @@ -124,6 +124,13 @@ config EXT3_FS_POSIX_ACL
32
33 If you don't know what Access Control Lists are, say N
34
35 +config EXT3_FS_NFS4ACL
36 + bool "Native NFSv4 ACLs (EXPERIMENTAL)"
37 + depends on EXT3_FS_XATTR && EXPERIMENTAL
38 + select FS_NFS4ACL
39 + help
40 + Allow to use NFSv4 ACLs instead of POSIX ACLs.
41 +
42 config EXT3_FS_SECURITY
43 bool "Ext3 Security Labels"
44 depends on EXT3_FS_XATTR
45 --- a/fs/ext3/Makefile
46 +++ b/fs/ext3/Makefile
47 @@ -10,3 +10,4 @@ ext3-y := balloc.o bitmap.o dir.o file.o
48 ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
49 ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
50 ext3-$(CONFIG_EXT3_FS_SECURITY) += xattr_security.o
51 +ext3-$(CONFIG_EXT3_FS_NFS4ACL) += nfs4acl.o
52 --- a/fs/ext3/acl.c
53 +++ b/fs/ext3/acl.c
54 @@ -282,7 +282,7 @@ ext3_set_acl(handle_t *handle, struct in
55 return error;
56 }
57
58 -static int
59 +int
60 ext3_check_acl(struct inode *inode, int mask)
61 {
62 struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
63 @@ -298,12 +298,6 @@ ext3_check_acl(struct inode *inode, int
64 return -EAGAIN;
65 }
66
67 -int
68 -ext3_permission(struct inode *inode, int mask)
69 -{
70 - return generic_permission(inode, mask, ext3_check_acl);
71 -}
72 -
73 /*
74 * Initialize the ACLs of a new inode. Called from ext3_new_inode.
75 *
76 --- a/fs/ext3/acl.h
77 +++ b/fs/ext3/acl.h
78 @@ -58,13 +58,13 @@ static inline int ext3_acl_count(size_t
79 #define EXT3_ACL_NOT_CACHED ((void *)-1)
80
81 /* acl.c */
82 -extern int ext3_permission (struct inode *, int);
83 +extern int ext3_check_acl (struct inode *, int);
84 extern int ext3_acl_chmod (struct inode *);
85 extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
86
87 #else /* CONFIG_EXT3_FS_POSIX_ACL */
88 #include <linux/sched.h>
89 -#define ext3_permission NULL
90 +#define ext3_check_acl NULL
91
92 static inline int
93 ext3_acl_chmod(struct inode *inode)
94 --- a/fs/ext3/file.c
95 +++ b/fs/ext3/file.c
96 @@ -23,8 +23,10 @@
97 #include <linux/jbd.h>
98 #include <linux/ext3_fs.h>
99 #include <linux/ext3_jbd.h>
100 +#include "namei.h"
101 #include "xattr.h"
102 #include "acl.h"
103 +#include "nfs4acl.h"
104
105 /*
106 * Called when an inode is released. Note that this is different
107 @@ -134,5 +136,7 @@ const struct inode_operations ext3_file_
108 .removexattr = generic_removexattr,
109 #endif
110 .permission = ext3_permission,
111 + .may_create = ext3_may_create,
112 + .may_delete = ext3_may_delete,
113 };
114
115 --- a/fs/ext3/ialloc.c
116 +++ b/fs/ext3/ialloc.c
117 @@ -28,6 +28,7 @@
118
119 #include "xattr.h"
120 #include "acl.h"
121 +#include "nfs4acl.h"
122
123 /*
124 * ialloc.c contains the inodes allocation and deallocation routines
125 @@ -595,7 +596,10 @@ got:
126 goto fail_drop;
127 }
128
129 - err = ext3_init_acl(handle, inode, dir);
130 + if (test_opt(sb, NFS4ACL))
131 + err = ext3_nfs4acl_init(handle, inode, dir);
132 + else
133 + err = ext3_init_acl(handle, inode, dir);
134 if (err)
135 goto fail_free_drop;
136
137 --- a/fs/ext3/inode.c
138 +++ b/fs/ext3/inode.c
139 @@ -38,6 +38,7 @@
140 #include <linux/bio.h>
141 #include "xattr.h"
142 #include "acl.h"
143 +#include "nfs4acl.h"
144
145 static int ext3_writepage_trans_blocks(struct inode *inode);
146
147 @@ -2684,6 +2685,9 @@ struct inode *ext3_iget(struct super_blo
148 ei->i_acl = EXT3_ACL_NOT_CACHED;
149 ei->i_default_acl = EXT3_ACL_NOT_CACHED;
150 #endif
151 +#ifdef CONFIG_EXT3_FS_NFS4ACL
152 + ei->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
153 +#endif
154 ei->i_block_alloc_info = NULL;
155
156 ret = __ext3_get_inode_loc(inode, &iloc, 0);
157 @@ -2983,6 +2987,65 @@ int ext3_write_inode(struct inode *inode
158 return ext3_force_commit(inode->i_sb);
159 }
160
161 +#ifdef CONFIG_EXT3_FS_NFS4ACL
162 +static int ext3_inode_change_ok(struct inode *inode, struct iattr *attr)
163 +{
164 + unsigned int ia_valid = attr->ia_valid;
165 +
166 + if (!test_opt(inode->i_sb, NFS4ACL))
167 + return inode_change_ok(inode, attr);
168 +
169 + /* If force is set do it anyway. */
170 + if (ia_valid & ATTR_FORCE)
171 + return 0;
172 +
173 + /* Make sure a caller can chown. */
174 + if ((ia_valid & ATTR_UID) &&
175 + (current->fsuid != inode->i_uid ||
176 + attr->ia_uid != inode->i_uid) &&
177 + (current->fsuid != attr->ia_uid ||
178 + ext3_nfs4acl_permission(inode, ACE4_WRITE_OWNER)) &&
179 + !capable(CAP_CHOWN))
180 + goto error;
181 +
182 + /* Make sure caller can chgrp. */
183 + if ((ia_valid & ATTR_GID)) {
184 + int in_group = in_group_p(attr->ia_gid);
185 + if ((current->fsuid != inode->i_uid ||
186 + (!in_group && attr->ia_gid != inode->i_gid)) &&
187 + (!in_group ||
188 + ext3_nfs4acl_permission(inode, ACE4_WRITE_OWNER)) &&
189 + !capable(CAP_CHOWN))
190 + goto error;
191 + }
192 +
193 + /* Make sure a caller can chmod. */
194 + if (ia_valid & ATTR_MODE) {
195 + if (current->fsuid != inode->i_uid &&
196 + ext3_nfs4acl_permission(inode, ACE4_WRITE_ACL) &&
197 + !capable(CAP_FOWNER))
198 + goto error;
199 + /* Also check the setgid bit! */
200 + if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
201 + inode->i_gid) && !capable(CAP_FSETID))
202 + attr->ia_mode &= ~S_ISGID;
203 + }
204 +
205 + /* Check for setting the inode time. */
206 + if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
207 + if (current->fsuid != inode->i_uid &&
208 + ext3_nfs4acl_permission(inode, ACE4_WRITE_ATTRIBUTES) &&
209 + !capable(CAP_FOWNER))
210 + goto error;
211 + }
212 + return 0;
213 +error:
214 + return -EPERM;
215 +}
216 +#else
217 +# define ext3_inode_change_ok inode_change_ok
218 +#endif
219 +
220 /*
221 * ext3_setattr()
222 *
223 @@ -3006,7 +3069,7 @@ int ext3_setattr(struct dentry *dentry,
224 int error, rc = 0;
225 const unsigned int ia_valid = attr->ia_valid;
226
227 - error = inode_change_ok(inode, attr);
228 + error = ext3_inode_change_ok(inode, attr);
229 if (error)
230 return error;
231
232 @@ -3063,8 +3126,12 @@ int ext3_setattr(struct dentry *dentry,
233 if (inode->i_nlink)
234 ext3_orphan_del(NULL, inode);
235
236 - if (!rc && (ia_valid & ATTR_MODE))
237 - rc = ext3_acl_chmod(inode);
238 + if (!rc && (ia_valid & ATTR_MODE)) {
239 + if (test_opt(inode->i_sb, NFS4ACL))
240 + rc = ext3_nfs4acl_chmod(inode);
241 + else
242 + rc = ext3_acl_chmod(inode);
243 + }
244
245 err_out:
246 ext3_std_error(inode->i_sb, error);
247 --- a/fs/ext3/namei.c
248 +++ b/fs/ext3/namei.c
249 @@ -40,6 +40,7 @@
250 #include "namei.h"
251 #include "xattr.h"
252 #include "acl.h"
253 +#include "nfs4acl.h"
254
255 /*
256 * define how far ahead to read directories while searching them.
257 @@ -2412,6 +2413,16 @@ end_rename:
258 return retval;
259 }
260
261 +int ext3_permission(struct inode *inode, int mask)
262 +{
263 +#ifdef CONFIG_EXT3_FS_NFS4ACL
264 + if (test_opt(inode->i_sb, NFS4ACL))
265 + return ext3_nfs4acl_permission(inode, nfs4acl_want_to_mask(mask));
266 + else
267 +#endif
268 + return generic_permission(inode, mask, ext3_check_acl);
269 +}
270 +
271 /*
272 * directories can handle most operations...
273 */
274 @@ -2433,6 +2444,8 @@ const struct inode_operations ext3_dir_i
275 .removexattr = generic_removexattr,
276 #endif
277 .permission = ext3_permission,
278 + .may_create = ext3_may_create,
279 + .may_delete = ext3_may_delete,
280 };
281
282 const struct inode_operations ext3_special_inode_operations = {
283 @@ -2444,4 +2457,6 @@ const struct inode_operations ext3_speci
284 .removexattr = generic_removexattr,
285 #endif
286 .permission = ext3_permission,
287 + .may_create = ext3_may_create,
288 + .may_delete = ext3_may_delete,
289 };
290 --- a/fs/ext3/namei.h
291 +++ b/fs/ext3/namei.h
292 @@ -5,4 +5,5 @@
293 *
294 */
295
296 +extern int ext3_permission (struct inode *, int);
297 extern struct dentry *ext3_get_parent(struct dentry *child);
298 --- /dev/null
299 +++ b/fs/ext3/nfs4acl.c
300 @@ -0,0 +1,370 @@
301 +/*
302 + * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
303 + *
304 + * This program is free software; you can redistribute it and/or modify it
305 + * under the terms of the GNU General Public License as published by the
306 + * Free Software Foundation; either version 2, or (at your option) any
307 + * later version.
308 + *
309 + * This program is distributed in the hope that it will be useful, but
310 + * WITHOUT ANY WARRANTY; without even the implied warranty of
311 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
312 + * General Public License for more details.
313 + */
314 +
315 +#include <linux/kernel.h>
316 +#include <linux/fs.h>
317 +#include <linux/ext3_jbd.h>
318 +#include <linux/ext3_fs.h>
319 +#include <linux/nfs4acl_xattr.h>
320 +#include "namei.h"
321 +#include "xattr.h"
322 +#include "nfs4acl.h"
323 +
324 +static inline struct nfs4acl *
325 +ext3_iget_nfs4acl(struct inode *inode)
326 +{
327 + struct nfs4acl *acl = EXT3_NFS4ACL_NOT_CACHED;
328 + struct ext3_inode_info *ei = EXT3_I(inode);
329 +
330 + spin_lock(&inode->i_lock);
331 + if (ei->i_nfs4acl != EXT3_NFS4ACL_NOT_CACHED)
332 + acl = nfs4acl_get(ei->i_nfs4acl);
333 + spin_unlock(&inode->i_lock);
334 +
335 + return acl;
336 +}
337 +
338 +static inline void
339 +ext3_iset_nfs4acl(struct inode *inode, struct nfs4acl *acl)
340 +{
341 + struct ext3_inode_info *ei = EXT3_I(inode);
342 +
343 + spin_lock(&inode->i_lock);
344 + if (ei->i_nfs4acl != EXT3_NFS4ACL_NOT_CACHED)
345 + nfs4acl_put(ei->i_nfs4acl);
346 + ei->i_nfs4acl = nfs4acl_get(acl);
347 + spin_unlock(&inode->i_lock);
348 +}
349 +
350 +static struct nfs4acl *
351 +ext3_get_nfs4acl(struct inode *inode)
352 +{
353 + const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
354 + void *value = NULL;
355 + struct nfs4acl *acl;
356 + int retval;
357 +
358 + if (!test_opt(inode->i_sb, NFS4ACL))
359 + return NULL;
360 +
361 + acl = ext3_iget_nfs4acl(inode);
362 + if (acl != EXT3_NFS4ACL_NOT_CACHED)
363 + return acl;
364 + retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
365 + if (retval > 0) {
366 + value = kmalloc(retval, GFP_KERNEL);
367 + if (!value)
368 + return ERR_PTR(-ENOMEM);
369 + retval = ext3_xattr_get(inode, name_index, "", value, retval);
370 + }
371 + if (retval > 0) {
372 + acl = nfs4acl_from_xattr(value, retval);
373 + if (acl == ERR_PTR(-EINVAL))
374 + acl = ERR_PTR(-EIO);
375 + } else if (retval == -ENODATA || retval == -ENOSYS)
376 + acl = NULL;
377 + else
378 + acl = ERR_PTR(retval);
379 + kfree(value);
380 +
381 + if (!IS_ERR(acl))
382 + ext3_iset_nfs4acl(inode, acl);
383 +
384 + return acl;
385 +}
386 +
387 +static int
388 +ext3_set_nfs4acl(handle_t *handle, struct inode *inode, struct nfs4acl *acl)
389 +{
390 + const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
391 + size_t size = 0;
392 + void *value = NULL;
393 + int retval;
394 +
395 + if (acl) {
396 + size = nfs4acl_xattr_size(acl);
397 + value = kmalloc(size, GFP_KERNEL);
398 + if (!value)
399 + return -ENOMEM;
400 + nfs4acl_to_xattr(acl, value);
401 + }
402 + if (handle)
403 + retval = ext3_xattr_set_handle(handle, inode, name_index, "",
404 + value, size, 0);
405 + else
406 + retval = ext3_xattr_set(inode, name_index, "", value, size, 0);
407 + if (value)
408 + kfree(value);
409 + if (!retval)
410 + ext3_iset_nfs4acl(inode, acl);
411 +
412 + return retval;
413 +}
414 +
415 +int
416 +ext3_nfs4acl_permission(struct inode *inode, unsigned int mask)
417 +{
418 + struct nfs4acl *acl;
419 + int retval;
420 +
421 + BUG_ON(!test_opt(inode->i_sb, NFS4ACL));
422 +
423 + acl = ext3_get_nfs4acl(inode);
424 + if (!acl)
425 + retval = nfs4acl_generic_permission(inode, mask);
426 + else if (IS_ERR(acl))
427 + retval = PTR_ERR(acl);
428 + else {
429 + retval = nfs4acl_permission(inode, acl, mask);
430 + nfs4acl_put(acl);
431 + }
432 +
433 + return retval;
434 +}
435 +
436 +int ext3_may_create(struct inode *dir, int isdir)
437 +{
438 + int error;
439 +
440 + if (test_opt(dir->i_sb, NFS4ACL)) {
441 + unsigned int mask = (isdir ? ACE4_ADD_SUBDIRECTORY : ACE4_ADD_FILE) |
442 + ACE4_EXECUTE;
443 +
444 + error = ext3_nfs4acl_permission(dir, mask);
445 + } else
446 + error = ext3_permission(dir, MAY_WRITE | MAY_EXEC);
447 +
448 + return error;
449 +}
450 +
451 +static int check_sticky(struct inode *dir, struct inode *inode)
452 +{
453 + if (!(dir->i_mode & S_ISVTX))
454 + return 0;
455 + if (inode->i_uid == current->fsuid)
456 + return 0;
457 + if (dir->i_uid == current->fsuid)
458 + return 0;
459 + return !capable(CAP_FOWNER);
460 +}
461 +
462 +int ext3_may_delete(struct inode *dir, struct inode *inode)
463 +{
464 + int error;
465 +
466 + if (test_opt(inode->i_sb, NFS4ACL)) {
467 + error = ext3_nfs4acl_permission(dir, ACE4_DELETE_CHILD | ACE4_EXECUTE);
468 + if (!error && check_sticky(dir, inode))
469 + error = -EPERM;
470 + if (error && !ext3_nfs4acl_permission(inode, ACE4_DELETE))
471 + error = 0;
472 + } else {
473 + error = ext3_permission(dir, MAY_WRITE | MAY_EXEC);
474 + if (!error && check_sticky(dir, inode))
475 + error = -EPERM;
476 + }
477 +
478 + return error;
479 +}
480 +
481 +int
482 +ext3_nfs4acl_init(handle_t *handle, struct inode *inode, struct inode *dir)
483 +{
484 + struct nfs4acl *dir_acl = NULL, *acl;
485 + int retval;
486 +
487 + if (!S_ISLNK(inode->i_mode))
488 + dir_acl = ext3_get_nfs4acl(dir);
489 + if (!dir_acl || IS_ERR(dir_acl)) {
490 + inode->i_mode &= ~current->fs->umask;
491 + return PTR_ERR(dir_acl);
492 + }
493 + acl = nfs4acl_inherit(dir_acl, inode->i_mode);
494 + nfs4acl_put(dir_acl);
495 +
496 + retval = PTR_ERR(acl);
497 + if (acl && !IS_ERR(acl)) {
498 + retval = ext3_set_nfs4acl(handle, inode, acl);
499 + inode->i_mode = (inode->i_mode & ~S_IRWXUGO) |
500 + nfs4acl_masks_to_mode(acl);
501 + nfs4acl_put(acl);
502 + }
503 + return retval;
504 +}
505 +
506 +int
507 +ext3_nfs4acl_chmod(struct inode *inode)
508 +{
509 + struct nfs4acl *acl;
510 + int retval;
511 +
512 + if (S_ISLNK(inode->i_mode))
513 + return -EOPNOTSUPP;
514 + acl = ext3_get_nfs4acl(inode);
515 + if (!acl || IS_ERR(acl))
516 + return PTR_ERR(acl);
517 + acl = nfs4acl_chmod(acl, inode->i_mode);
518 + if (IS_ERR(acl))
519 + return PTR_ERR(acl);
520 + retval = ext3_set_nfs4acl(NULL, inode, acl);
521 + nfs4acl_put(acl);
522 +
523 + return retval;
524 +}
525 +
526 +static size_t
527 +ext3_xattr_list_nfs4acl(struct inode *inode, char *list, size_t list_len,
528 + const char *name, size_t name_len)
529 +{
530 + const size_t size = sizeof(NFS4ACL_XATTR);
531 +
532 + if (!test_opt(inode->i_sb, NFS4ACL))
533 + return 0;
534 + if (list && size <= list_len)
535 + memcpy(list, NFS4ACL_XATTR, size);
536 + return size;
537 +}
538 +
539 +static int
540 +ext3_xattr_get_nfs4acl(struct inode *inode, const char *name, void *buffer,
541 + size_t buffer_size)
542 +{
543 + struct nfs4acl *acl;
544 + size_t size;
545 +
546 + if (!test_opt(inode->i_sb, NFS4ACL))
547 + return -EOPNOTSUPP;
548 + if (strcmp(name, "") != 0)
549 + return -EINVAL;
550 +
551 + acl = ext3_get_nfs4acl(inode);
552 + if (IS_ERR(acl))
553 + return PTR_ERR(acl);
554 + if (acl == NULL)
555 + return -ENODATA;
556 + size = nfs4acl_xattr_size(acl);
557 + if (buffer) {
558 + if (size > buffer_size)
559 + return -ERANGE;
560 + nfs4acl_to_xattr(acl, buffer);
561 + }
562 + nfs4acl_put(acl);
563 +
564 + return size;
565 +}
566 +
567 +#ifdef NFS4ACL_DEBUG
568 +static size_t
569 +ext3_xattr_list_masked_nfs4acl(struct inode *inode, char *list, size_t list_len,
570 + const char *name, size_t name_len)
571 +{
572 + return 0;
573 +}
574 +
575 +static int
576 +ext3_xattr_get_masked_nfs4acl(struct inode *inode, const char *name,
577 + void *buffer, size_t buffer_size)
578 +{
579 + const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
580 + struct nfs4acl *acl;
581 + void *xattr;
582 + size_t size;
583 + int retval;
584 +
585 + if (!test_opt(inode->i_sb, NFS4ACL))
586 + return -EOPNOTSUPP;
587 + if (strcmp(name, "") != 0)
588 + return -EINVAL;
589 + retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
590 + if (retval <= 0)
591 + return retval;
592 + xattr = kmalloc(retval, GFP_KERNEL);
593 + if (!xattr)
594 + return -ENOMEM;
595 + retval = ext3_xattr_get(inode, name_index, "", xattr, retval);
596 + if (retval <= 0)
597 + return retval;
598 + acl = nfs4acl_from_xattr(xattr, retval);
599 + kfree(xattr);
600 + if (IS_ERR(acl))
601 + return PTR_ERR(acl);
602 + retval = nfs4acl_apply_masks(&acl);
603 + if (retval) {
604 + nfs4acl_put(acl);
605 + return retval;
606 + }
607 + size = nfs4acl_xattr_size(acl);
608 + if (buffer) {
609 + if (size > buffer_size)
610 + return -ERANGE;
611 + nfs4acl_to_xattr(acl, buffer);
612 + }
613 + nfs4acl_put(acl);
614 + return size;
615 +}
616 +#endif
617 +
618 +static int
619 +ext3_xattr_set_nfs4acl(struct inode *inode, const char *name,
620 + const void *value, size_t size, int flags)
621 +{
622 + handle_t *handle;
623 + struct nfs4acl *acl = NULL;
624 + int retval, retries = 0;
625 +
626 + if (S_ISLNK(inode->i_mode) || !test_opt(inode->i_sb, NFS4ACL))
627 + return -EOPNOTSUPP;
628 + if (strcmp(name, "") != 0)
629 + return -EINVAL;
630 + if (current->fsuid != inode->i_uid &&
631 + ext3_nfs4acl_permission(inode, ACE4_WRITE_ACL) &&
632 + !capable(CAP_FOWNER))
633 + return -EPERM;
634 + if (value) {
635 + acl = nfs4acl_from_xattr(value, size);
636 + if (IS_ERR(acl))
637 + return PTR_ERR(acl);
638 +
639 + inode->i_mode &= ~S_IRWXUGO;
640 + inode->i_mode |= nfs4acl_masks_to_mode(acl);
641 + }
642 +
643 +retry:
644 + handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
645 + if (IS_ERR(handle))
646 + return PTR_ERR(handle);
647 + ext3_mark_inode_dirty(handle, inode);
648 + retval = ext3_set_nfs4acl(handle, inode, acl);
649 + ext3_journal_stop(handle);
650 + if (retval == ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
651 + goto retry;
652 + nfs4acl_put(acl);
653 + return retval;
654 +}
655 +
656 +struct xattr_handler ext3_nfs4acl_xattr_handler = {
657 + .prefix = NFS4ACL_XATTR,
658 + .list = ext3_xattr_list_nfs4acl,
659 + .get = ext3_xattr_get_nfs4acl,
660 + .set = ext3_xattr_set_nfs4acl,
661 +};
662 +
663 +#ifdef NFS4ACL_DEBUG
664 +struct xattr_handler ext3_masked_nfs4acl_xattr_handler = {
665 + .prefix = "system.masked-nfs4acl",
666 + .list = ext3_xattr_list_masked_nfs4acl,
667 + .get = ext3_xattr_get_masked_nfs4acl,
668 + .set = ext3_xattr_set_nfs4acl,
669 +};
670 +#endif
671 --- /dev/null
672 +++ b/fs/ext3/nfs4acl.h
673 @@ -0,0 +1,36 @@
674 +#ifndef __FS_EXT3_NFS4ACL_H
675 +#define __FS_EXT3_NFS4ACL_H
676 +
677 +#ifdef CONFIG_EXT3_FS_NFS4ACL
678 +
679 +#include <linux/nfs4acl.h>
680 +
681 +/* Value for i_nfs4acl if NFS4ACL has not been cached */
682 +#define EXT3_NFS4ACL_NOT_CACHED ((void *)-1)
683 +
684 +extern int ext3_nfs4acl_permission(struct inode *, unsigned int);
685 +extern int ext3_may_create(struct inode *, int);
686 +extern int ext3_may_delete(struct inode *, struct inode *);
687 +extern int ext3_nfs4acl_init(handle_t *, struct inode *, struct inode *);
688 +extern int ext3_nfs4acl_chmod(struct inode *);
689 +
690 +#else /* CONFIG_FS_EXT3_NFS4ACL */
691 +
692 +#define ext3_may_create NULL
693 +#define ext3_may_delete NULL
694 +
695 +static inline int
696 +ext3_nfs4acl_init(handle_t *handle, struct inode *inode, struct inode *dir)
697 +{
698 + return 0;
699 +}
700 +
701 +static inline int
702 +ext3_nfs4acl_chmod(struct inode *inode)
703 +{
704 + return 0;
705 +}
706 +
707 +#endif /* CONFIG_FS_EXT3_NFS4ACL */
708 +
709 +#endif /* __FS_EXT3_NFS4ACL_H */
710 --- a/fs/ext3/super.c
711 +++ b/fs/ext3/super.c
712 @@ -36,12 +36,14 @@
713 #include <linux/namei.h>
714 #include <linux/quotaops.h>
715 #include <linux/seq_file.h>
716 +#include <linux/nfs4acl.h>
717 #include <linux/log2.h>
718
719 #include <asm/uaccess.h>
720
721 #include "xattr.h"
722 #include "acl.h"
723 +#include "nfs4acl.h"
724 #include "namei.h"
725
726 static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
727 @@ -454,6 +456,9 @@ static struct inode *ext3_alloc_inode(st
728 ei->i_acl = EXT3_ACL_NOT_CACHED;
729 ei->i_default_acl = EXT3_ACL_NOT_CACHED;
730 #endif
731 +#ifdef CONFIG_EXT3_FS_NFS4ACL
732 + ei->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
733 +#endif
734 ei->i_block_alloc_info = NULL;
735 ei->vfs_inode.i_version = 1;
736 return &ei->vfs_inode;
737 @@ -516,6 +521,13 @@ static void ext3_clear_inode(struct inod
738 EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
739 }
740 #endif
741 +#ifdef CONFIG_EXT3_FS_NFS4ACL
742 + if (EXT3_I(inode)->i_nfs4acl &&
743 + EXT3_I(inode)->i_nfs4acl != EXT3_NFS4ACL_NOT_CACHED) {
744 + nfs4acl_put(EXT3_I(inode)->i_nfs4acl);
745 + EXT3_I(inode)->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
746 + }
747 +#endif
748 ext3_discard_reservation(inode);
749 EXT3_I(inode)->i_block_alloc_info = NULL;
750 if (unlikely(rsv))
751 @@ -750,7 +762,7 @@ enum {
752 Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
753 Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
754 Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
755 - Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
756 + Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_acl_flavor, Opt_noacl,
757 Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
758 Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
759 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
760 @@ -782,6 +794,7 @@ static match_table_t tokens = {
761 {Opt_user_xattr, "user_xattr"},
762 {Opt_nouser_xattr, "nouser_xattr"},
763 {Opt_acl, "acl"},
764 + {Opt_acl_flavor, "acl=%s"},
765 {Opt_noacl, "noacl"},
766 {Opt_reservation, "reservation"},
767 {Opt_noreservation, "noreservation"},
768 @@ -925,19 +938,33 @@ static int parse_options (char *options,
769 printk("EXT3 (no)user_xattr options not supported\n");
770 break;
771 #endif
772 -#ifdef CONFIG_EXT3_FS_POSIX_ACL
773 case Opt_acl:
774 - set_opt(sbi->s_mount_opt, POSIX_ACL);
775 + args[0].to = args[0].from;
776 + /* fall through */
777 + case Opt_acl_flavor:
778 +#ifdef CONFIG_EXT3_FS_POSIX_ACL
779 + if (match_string(&args[0], "") ||
780 + match_string(&args[0], "posix")) {
781 + set_opt(sbi->s_mount_opt, POSIX_ACL);
782 + clear_opt(sbi->s_mount_opt, NFS4ACL);
783 + } else
784 +#endif
785 +#ifdef CONFIG_EXT3_FS_NFS4ACL
786 + if (match_string(&args[0], "nfs4")) {
787 + clear_opt(sbi->s_mount_opt, POSIX_ACL);
788 + set_opt(sbi->s_mount_opt, NFS4ACL);
789 + } else
790 +#endif
791 + {
792 + printk(KERN_ERR "EXT3-fs: unsupported acl "
793 + "flavor\n");
794 + return 0;
795 + }
796 break;
797 case Opt_noacl:
798 clear_opt(sbi->s_mount_opt, POSIX_ACL);
799 + clear_opt(sbi->s_mount_opt, NFS4ACL);
800 break;
801 -#else
802 - case Opt_acl:
803 - case Opt_noacl:
804 - printk("EXT3 (no)acl options not supported\n");
805 - break;
806 -#endif
807 case Opt_reservation:
808 set_opt(sbi->s_mount_opt, RESERVATION);
809 break;
810 @@ -1607,8 +1634,11 @@ static int ext3_fill_super (struct super
811 NULL, 0))
812 goto failed_mount;
813
814 - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
815 - ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
816 + sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
817 + if (sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL)
818 + sb->s_flags |= MS_POSIXACL;
819 + if (sbi->s_mount_opt & EXT3_MOUNT_NFS4ACL)
820 + sb->s_flags |= MS_POSIXACL | MS_WITHAPPEND;
821
822 if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV &&
823 (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
824 @@ -2451,8 +2481,12 @@ static int ext3_remount (struct super_bl
825 if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
826 ext3_abort(sb, __func__, "Abort forced by user");
827
828 - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
829 - ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
830 + sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
831 + if (sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL)
832 + sb->s_flags |= MS_POSIXACL;
833 + if (sbi->s_mount_opt & EXT3_MOUNT_NFS4ACL)
834 + sb->s_flags |= MS_POSIXACL;
835 +
836
837 es = sbi->s_es;
838
839 --- a/fs/ext3/xattr.c
840 +++ b/fs/ext3/xattr.c
841 @@ -114,6 +114,9 @@ static struct xattr_handler *ext3_xattr_
842 #ifdef CONFIG_EXT3_FS_SECURITY
843 [EXT3_XATTR_INDEX_SECURITY] = &ext3_xattr_security_handler,
844 #endif
845 +#ifdef CONFIG_EXT3_FS_NFS4ACL
846 + [EXT3_XATTR_INDEX_NFS4ACL] = &ext3_nfs4acl_xattr_handler,
847 +#endif
848 };
849
850 struct xattr_handler *ext3_xattr_handlers[] = {
851 @@ -126,6 +129,12 @@ struct xattr_handler *ext3_xattr_handler
852 #ifdef CONFIG_EXT3_FS_SECURITY
853 &ext3_xattr_security_handler,
854 #endif
855 +#ifdef CONFIG_EXT3_FS_NFS4ACL
856 + &ext3_nfs4acl_xattr_handler,
857 +#ifdef NFS4ACL_DEBUG
858 + &ext3_masked_nfs4acl_xattr_handler,
859 +#endif
860 +#endif
861 NULL
862 };
863
864 --- a/fs/ext3/xattr.h
865 +++ b/fs/ext3/xattr.h
866 @@ -21,6 +21,7 @@
867 #define EXT3_XATTR_INDEX_TRUSTED 4
868 #define EXT3_XATTR_INDEX_LUSTRE 5
869 #define EXT3_XATTR_INDEX_SECURITY 6
870 +#define EXT3_XATTR_INDEX_NFS4ACL 7
871
872 struct ext3_xattr_header {
873 __le32 h_magic; /* magic number for identification */
874 @@ -63,6 +64,10 @@ extern struct xattr_handler ext3_xattr_t
875 extern struct xattr_handler ext3_xattr_acl_access_handler;
876 extern struct xattr_handler ext3_xattr_acl_default_handler;
877 extern struct xattr_handler ext3_xattr_security_handler;
878 +extern struct xattr_handler ext3_nfs4acl_xattr_handler;
879 +#ifdef NFS4ACL_DEBUG
880 +extern struct xattr_handler ext3_masked_nfs4acl_xattr_handler;
881 +#endif
882
883 extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
884
885 --- a/include/linux/ext3_fs.h
886 +++ b/include/linux/ext3_fs.h
887 @@ -380,6 +380,7 @@ struct ext3_inode {
888 #define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */
889 #define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
890 #define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
891 +#define EXT3_MOUNT_NFS4ACL 0x400000 /* NFS version 4 ACLs */
892
893 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
894 #ifndef _LINUX_EXT2_FS_H
895 --- a/include/linux/ext3_fs_i.h
896 +++ b/include/linux/ext3_fs_i.h
897 @@ -107,6 +107,9 @@ struct ext3_inode_info {
898 struct posix_acl *i_acl;
899 struct posix_acl *i_default_acl;
900 #endif
901 +#ifdef CONFIG_EXT3_FS_NFS4ACL
902 + struct nfs4acl *i_nfs4acl;
903 +#endif
904
905 struct list_head i_orphan; /* unlinked but open inodes */
906