1 From: Andreas Gruenbacher <agruen@suse.de>
2 Subject: NFSv4 ACLs for ext3
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.
8 Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
17 fs/ext3/inode.c | 73 ++++++++-
18 fs/ext3/namei.c | 15 +
20 fs/ext3/nfs4acl.c | 370 ++++++++++++++++++++++++++++++++++++++++++++++
21 fs/ext3/nfs4acl.h | 36 ++++
22 fs/ext3/super.c | 60 +++++--
25 include/linux/ext3_fs.h | 1
26 include/linux/ext3_fs_i.h | 3
27 16 files changed, 577 insertions(+), 26 deletions(-)
31 @@ -124,6 +124,13 @@ config EXT3_FS_POSIX_ACL
33 If you don't know what Access Control Lists are, say N
35 +config EXT3_FS_NFS4ACL
36 + bool "Native NFSv4 ACLs (EXPERIMENTAL)"
37 + depends on EXT3_FS_XATTR && EXPERIMENTAL
40 + Allow to use NFSv4 ACLs instead of POSIX ACLs.
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
54 @@ -282,7 +282,7 @@ ext3_set_acl(handle_t *handle, struct in
60 ext3_check_acl(struct inode *inode, int mask)
62 struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
63 @@ -298,12 +298,6 @@ ext3_check_acl(struct inode *inode, int
68 -ext3_permission(struct inode *inode, int mask)
70 - return generic_permission(inode, mask, ext3_check_acl);
74 * Initialize the ACLs of a new inode. Called from ext3_new_inode.
78 @@ -58,13 +58,13 @@ static inline int ext3_acl_count(size_t
79 #define EXT3_ACL_NOT_CACHED ((void *)-1)
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 *);
87 #else /* CONFIG_EXT3_FS_POSIX_ACL */
88 #include <linux/sched.h>
89 -#define ext3_permission NULL
90 +#define ext3_check_acl NULL
93 ext3_acl_chmod(struct inode *inode)
97 #include <linux/jbd.h>
98 #include <linux/ext3_fs.h>
99 #include <linux/ext3_jbd.h>
103 +#include "nfs4acl.h"
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,
110 .permission = ext3_permission,
111 + .may_create = ext3_may_create,
112 + .may_delete = ext3_may_delete,
115 --- a/fs/ext3/ialloc.c
116 +++ b/fs/ext3/ialloc.c
121 +#include "nfs4acl.h"
124 * ialloc.c contains the inodes allocation and deallocation routines
125 @@ -595,7 +596,10 @@ got:
129 - err = ext3_init_acl(handle, inode, dir);
130 + if (test_opt(sb, NFS4ACL))
131 + err = ext3_nfs4acl_init(handle, inode, dir);
133 + err = ext3_init_acl(handle, inode, dir);
137 --- a/fs/ext3/inode.c
138 +++ b/fs/ext3/inode.c
140 #include <linux/bio.h>
143 +#include "nfs4acl.h"
145 static int ext3_writepage_trans_blocks(struct inode *inode);
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;
151 +#ifdef CONFIG_EXT3_FS_NFS4ACL
152 + ei->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
154 ei->i_block_alloc_info = NULL;
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);
161 +#ifdef CONFIG_EXT3_FS_NFS4ACL
162 +static int ext3_inode_change_ok(struct inode *inode, struct iattr *attr)
164 + unsigned int ia_valid = attr->ia_valid;
166 + if (!test_opt(inode->i_sb, NFS4ACL))
167 + return inode_change_ok(inode, attr);
169 + /* If force is set do it anyway. */
170 + if (ia_valid & ATTR_FORCE)
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))
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)) &&
188 + ext3_nfs4acl_permission(inode, ACE4_WRITE_OWNER)) &&
189 + !capable(CAP_CHOWN))
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))
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;
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))
217 +# define ext3_inode_change_ok inode_change_ok
223 @@ -3006,7 +3069,7 @@ int ext3_setattr(struct dentry *dentry,
225 const unsigned int ia_valid = attr->ia_valid;
227 - error = inode_change_ok(inode, attr);
228 + error = ext3_inode_change_ok(inode, attr);
232 @@ -3063,8 +3126,12 @@ int ext3_setattr(struct dentry *dentry,
234 ext3_orphan_del(NULL, inode);
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);
242 + rc = ext3_acl_chmod(inode);
246 ext3_std_error(inode->i_sb, error);
247 --- a/fs/ext3/namei.c
248 +++ b/fs/ext3/namei.c
253 +#include "nfs4acl.h"
256 * define how far ahead to read directories while searching them.
257 @@ -2412,6 +2413,16 @@ end_rename:
261 +int ext3_permission(struct inode *inode, int mask)
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));
268 + return generic_permission(inode, mask, ext3_check_acl);
272 * directories can handle most operations...
274 @@ -2433,6 +2444,8 @@ const struct inode_operations ext3_dir_i
275 .removexattr = generic_removexattr,
277 .permission = ext3_permission,
278 + .may_create = ext3_may_create,
279 + .may_delete = ext3_may_delete,
282 const struct inode_operations ext3_special_inode_operations = {
283 @@ -2444,4 +2457,6 @@ const struct inode_operations ext3_speci
284 .removexattr = generic_removexattr,
286 .permission = ext3_permission,
287 + .may_create = ext3_may_create,
288 + .may_delete = ext3_may_delete,
290 --- a/fs/ext3/namei.h
291 +++ b/fs/ext3/namei.h
296 +extern int ext3_permission (struct inode *, int);
297 extern struct dentry *ext3_get_parent(struct dentry *child);
299 +++ b/fs/ext3/nfs4acl.c
302 + * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
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
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.
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>
322 +#include "nfs4acl.h"
324 +static inline struct nfs4acl *
325 +ext3_iget_nfs4acl(struct inode *inode)
327 + struct nfs4acl *acl = EXT3_NFS4ACL_NOT_CACHED;
328 + struct ext3_inode_info *ei = EXT3_I(inode);
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);
339 +ext3_iset_nfs4acl(struct inode *inode, struct nfs4acl *acl)
341 + struct ext3_inode_info *ei = EXT3_I(inode);
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);
350 +static struct nfs4acl *
351 +ext3_get_nfs4acl(struct inode *inode)
353 + const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
354 + void *value = NULL;
355 + struct nfs4acl *acl;
358 + if (!test_opt(inode->i_sb, NFS4ACL))
361 + acl = ext3_iget_nfs4acl(inode);
362 + if (acl != EXT3_NFS4ACL_NOT_CACHED)
364 + retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
366 + value = kmalloc(retval, GFP_KERNEL);
368 + return ERR_PTR(-ENOMEM);
369 + retval = ext3_xattr_get(inode, name_index, "", value, retval);
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)
378 + acl = ERR_PTR(retval);
382 + ext3_iset_nfs4acl(inode, acl);
388 +ext3_set_nfs4acl(handle_t *handle, struct inode *inode, struct nfs4acl *acl)
390 + const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
392 + void *value = NULL;
396 + size = nfs4acl_xattr_size(acl);
397 + value = kmalloc(size, GFP_KERNEL);
400 + nfs4acl_to_xattr(acl, value);
403 + retval = ext3_xattr_set_handle(handle, inode, name_index, "",
406 + retval = ext3_xattr_set(inode, name_index, "", value, size, 0);
410 + ext3_iset_nfs4acl(inode, acl);
416 +ext3_nfs4acl_permission(struct inode *inode, unsigned int mask)
418 + struct nfs4acl *acl;
421 + BUG_ON(!test_opt(inode->i_sb, NFS4ACL));
423 + acl = ext3_get_nfs4acl(inode);
425 + retval = nfs4acl_generic_permission(inode, mask);
426 + else if (IS_ERR(acl))
427 + retval = PTR_ERR(acl);
429 + retval = nfs4acl_permission(inode, acl, mask);
436 +int ext3_may_create(struct inode *dir, int isdir)
440 + if (test_opt(dir->i_sb, NFS4ACL)) {
441 + unsigned int mask = (isdir ? ACE4_ADD_SUBDIRECTORY : ACE4_ADD_FILE) |
444 + error = ext3_nfs4acl_permission(dir, mask);
446 + error = ext3_permission(dir, MAY_WRITE | MAY_EXEC);
451 +static int check_sticky(struct inode *dir, struct inode *inode)
453 + if (!(dir->i_mode & S_ISVTX))
455 + if (inode->i_uid == current->fsuid)
457 + if (dir->i_uid == current->fsuid)
459 + return !capable(CAP_FOWNER);
462 +int ext3_may_delete(struct inode *dir, struct inode *inode)
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))
470 + if (error && !ext3_nfs4acl_permission(inode, ACE4_DELETE))
473 + error = ext3_permission(dir, MAY_WRITE | MAY_EXEC);
474 + if (!error && check_sticky(dir, inode))
482 +ext3_nfs4acl_init(handle_t *handle, struct inode *inode, struct inode *dir)
484 + struct nfs4acl *dir_acl = NULL, *acl;
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);
493 + acl = nfs4acl_inherit(dir_acl, inode->i_mode);
494 + nfs4acl_put(dir_acl);
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);
507 +ext3_nfs4acl_chmod(struct inode *inode)
509 + struct nfs4acl *acl;
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);
519 + return PTR_ERR(acl);
520 + retval = ext3_set_nfs4acl(NULL, inode, acl);
527 +ext3_xattr_list_nfs4acl(struct inode *inode, char *list, size_t list_len,
528 + const char *name, size_t name_len)
530 + const size_t size = sizeof(NFS4ACL_XATTR);
532 + if (!test_opt(inode->i_sb, NFS4ACL))
534 + if (list && size <= list_len)
535 + memcpy(list, NFS4ACL_XATTR, size);
540 +ext3_xattr_get_nfs4acl(struct inode *inode, const char *name, void *buffer,
541 + size_t buffer_size)
543 + struct nfs4acl *acl;
546 + if (!test_opt(inode->i_sb, NFS4ACL))
547 + return -EOPNOTSUPP;
548 + if (strcmp(name, "") != 0)
551 + acl = ext3_get_nfs4acl(inode);
553 + return PTR_ERR(acl);
556 + size = nfs4acl_xattr_size(acl);
558 + if (size > buffer_size)
560 + nfs4acl_to_xattr(acl, buffer);
567 +#ifdef NFS4ACL_DEBUG
569 +ext3_xattr_list_masked_nfs4acl(struct inode *inode, char *list, size_t list_len,
570 + const char *name, size_t name_len)
576 +ext3_xattr_get_masked_nfs4acl(struct inode *inode, const char *name,
577 + void *buffer, size_t buffer_size)
579 + const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
580 + struct nfs4acl *acl;
585 + if (!test_opt(inode->i_sb, NFS4ACL))
586 + return -EOPNOTSUPP;
587 + if (strcmp(name, "") != 0)
589 + retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
592 + xattr = kmalloc(retval, GFP_KERNEL);
595 + retval = ext3_xattr_get(inode, name_index, "", xattr, retval);
598 + acl = nfs4acl_from_xattr(xattr, retval);
601 + return PTR_ERR(acl);
602 + retval = nfs4acl_apply_masks(&acl);
607 + size = nfs4acl_xattr_size(acl);
609 + if (size > buffer_size)
611 + nfs4acl_to_xattr(acl, buffer);
619 +ext3_xattr_set_nfs4acl(struct inode *inode, const char *name,
620 + const void *value, size_t size, int flags)
623 + struct nfs4acl *acl = NULL;
624 + int retval, retries = 0;
626 + if (S_ISLNK(inode->i_mode) || !test_opt(inode->i_sb, NFS4ACL))
627 + return -EOPNOTSUPP;
628 + if (strcmp(name, "") != 0)
630 + if (current->fsuid != inode->i_uid &&
631 + ext3_nfs4acl_permission(inode, ACE4_WRITE_ACL) &&
632 + !capable(CAP_FOWNER))
635 + acl = nfs4acl_from_xattr(value, size);
637 + return PTR_ERR(acl);
639 + inode->i_mode &= ~S_IRWXUGO;
640 + inode->i_mode |= nfs4acl_masks_to_mode(acl);
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))
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,
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,
672 +++ b/fs/ext3/nfs4acl.h
674 +#ifndef __FS_EXT3_NFS4ACL_H
675 +#define __FS_EXT3_NFS4ACL_H
677 +#ifdef CONFIG_EXT3_FS_NFS4ACL
679 +#include <linux/nfs4acl.h>
681 +/* Value for i_nfs4acl if NFS4ACL has not been cached */
682 +#define EXT3_NFS4ACL_NOT_CACHED ((void *)-1)
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 *);
690 +#else /* CONFIG_FS_EXT3_NFS4ACL */
692 +#define ext3_may_create NULL
693 +#define ext3_may_delete NULL
696 +ext3_nfs4acl_init(handle_t *handle, struct inode *inode, struct inode *dir)
702 +ext3_nfs4acl_chmod(struct inode *inode)
707 +#endif /* CONFIG_FS_EXT3_NFS4ACL */
709 +#endif /* __FS_EXT3_NFS4ACL_H */
710 --- a/fs/ext3/super.c
711 +++ b/fs/ext3/super.c
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>
719 #include <asm/uaccess.h>
723 +#include "nfs4acl.h"
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;
731 +#ifdef CONFIG_EXT3_FS_NFS4ACL
732 + ei->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
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;
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;
748 ext3_discard_reservation(inode);
749 EXT3_I(inode)->i_block_alloc_info = NULL;
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"},
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");
772 -#ifdef CONFIG_EXT3_FS_POSIX_ACL
774 - set_opt(sbi->s_mount_opt, POSIX_ACL);
775 + args[0].to = args[0].from;
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);
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);
792 + printk(KERN_ERR "EXT3-fs: unsupported acl "
798 clear_opt(sbi->s_mount_opt, POSIX_ACL);
799 + clear_opt(sbi->s_mount_opt, NFS4ACL);
804 - printk("EXT3 (no)acl options not supported\n");
807 case Opt_reservation:
808 set_opt(sbi->s_mount_opt, RESERVATION);
810 @@ -1607,8 +1634,11 @@ static int ext3_fill_super (struct super
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;
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");
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;
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,
845 +#ifdef CONFIG_EXT3_FS_NFS4ACL
846 + [EXT3_XATTR_INDEX_NFS4ACL] = &ext3_nfs4acl_xattr_handler,
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,
855 +#ifdef CONFIG_EXT3_FS_NFS4ACL
856 + &ext3_nfs4acl_xattr_handler,
857 +#ifdef NFS4ACL_DEBUG
858 + &ext3_masked_nfs4acl_xattr_handler,
864 --- a/fs/ext3/xattr.h
865 +++ b/fs/ext3/xattr.h
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
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;
883 extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
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 */
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;
901 +#ifdef CONFIG_EXT3_FS_NFS4ACL
902 + struct nfs4acl *i_nfs4acl;
905 struct list_head i_orphan; /* unlinked but open inodes */