]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.suse/nfs4acl-ext3.diff
Added missing Xen Kernel Patches which were not commited because
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.suse / nfs4acl-ext3.diff
diff --git a/src/patches/suse-2.6.27.31/patches.suse/nfs4acl-ext3.diff b/src/patches/suse-2.6.27.31/patches.suse/nfs4acl-ext3.diff
new file mode 100644 (file)
index 0000000..938643e
--- /dev/null
@@ -0,0 +1,906 @@
+From: Andreas Gruenbacher <agruen@suse.de>
+Subject: NFSv4 ACLs for ext3
+    
+With the acl=nfs4 mount option, ext3 will use NFSv4 ACLs instead of
+POSIX ACLs.  See http://www.suse.de/~agruen/nfs4acl/ for some
+documentation and examples.
+
+Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+
+---
+ fs/Kconfig                |    7 
+ fs/ext3/Makefile          |    1 
+ fs/ext3/acl.c             |    8 
+ fs/ext3/acl.h             |    4 
+ fs/ext3/file.c            |    4 
+ fs/ext3/ialloc.c          |    6 
+ fs/ext3/inode.c           |   73 ++++++++-
+ fs/ext3/namei.c           |   15 +
+ fs/ext3/namei.h           |    1 
+ fs/ext3/nfs4acl.c         |  370 ++++++++++++++++++++++++++++++++++++++++++++++
+ fs/ext3/nfs4acl.h         |   36 ++++
+ fs/ext3/super.c           |   60 +++++--
+ fs/ext3/xattr.c           |    9 +
+ fs/ext3/xattr.h           |    5 
+ include/linux/ext3_fs.h   |    1 
+ include/linux/ext3_fs_i.h |    3 
+ 16 files changed, 577 insertions(+), 26 deletions(-)
+
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -124,6 +124,13 @@ config EXT3_FS_POSIX_ACL
+         If you don't know what Access Control Lists are, say N
++config EXT3_FS_NFS4ACL
++      bool "Native NFSv4 ACLs (EXPERIMENTAL)"
++      depends on EXT3_FS_XATTR && EXPERIMENTAL
++      select FS_NFS4ACL
++      help
++        Allow to use NFSv4 ACLs instead of POSIX ACLs.
++
+ config EXT3_FS_SECURITY
+       bool "Ext3 Security Labels"
+       depends on EXT3_FS_XATTR
+--- a/fs/ext3/Makefile
++++ b/fs/ext3/Makefile
+@@ -10,3 +10,4 @@ ext3-y       := balloc.o bitmap.o dir.o file.o
+ ext3-$(CONFIG_EXT3_FS_XATTR)   += xattr.o xattr_user.o xattr_trusted.o
+ ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
+ ext3-$(CONFIG_EXT3_FS_SECURITY)        += xattr_security.o
++ext3-$(CONFIG_EXT3_FS_NFS4ACL)         += nfs4acl.o
+--- a/fs/ext3/acl.c
++++ b/fs/ext3/acl.c
+@@ -282,7 +282,7 @@ ext3_set_acl(handle_t *handle, struct in
+       return error;
+ }
+-static int
++int
+ ext3_check_acl(struct inode *inode, int mask)
+ {
+       struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
+@@ -298,12 +298,6 @@ ext3_check_acl(struct inode *inode, int
+       return -EAGAIN;
+ }
+-int
+-ext3_permission(struct inode *inode, int mask)
+-{
+-      return generic_permission(inode, mask, ext3_check_acl);
+-}
+-
+ /*
+  * Initialize the ACLs of a new inode. Called from ext3_new_inode.
+  *
+--- a/fs/ext3/acl.h
++++ b/fs/ext3/acl.h
+@@ -58,13 +58,13 @@ static inline int ext3_acl_count(size_t
+ #define EXT3_ACL_NOT_CACHED ((void *)-1)
+ /* acl.c */
+-extern int ext3_permission (struct inode *, int);
++extern int ext3_check_acl (struct inode *, int);
+ extern int ext3_acl_chmod (struct inode *);
+ extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
+ #else  /* CONFIG_EXT3_FS_POSIX_ACL */
+ #include <linux/sched.h>
+-#define ext3_permission NULL
++#define ext3_check_acl NULL
+ static inline int
+ ext3_acl_chmod(struct inode *inode)
+--- a/fs/ext3/file.c
++++ b/fs/ext3/file.c
+@@ -23,8 +23,10 @@
+ #include <linux/jbd.h>
+ #include <linux/ext3_fs.h>
+ #include <linux/ext3_jbd.h>
++#include "namei.h"
+ #include "xattr.h"
+ #include "acl.h"
++#include "nfs4acl.h"
+ /*
+  * Called when an inode is released. Note that this is different
+@@ -134,5 +136,7 @@ const struct inode_operations ext3_file_
+       .removexattr    = generic_removexattr,
+ #endif
+       .permission     = ext3_permission,
++      .may_create     = ext3_may_create,
++      .may_delete     = ext3_may_delete,
+ };
+--- a/fs/ext3/ialloc.c
++++ b/fs/ext3/ialloc.c
+@@ -28,6 +28,7 @@
+ #include "xattr.h"
+ #include "acl.h"
++#include "nfs4acl.h"
+ /*
+  * ialloc.c contains the inodes allocation and deallocation routines
+@@ -595,7 +596,10 @@ got:
+               goto fail_drop;
+       }
+-      err = ext3_init_acl(handle, inode, dir);
++      if (test_opt(sb, NFS4ACL))
++              err = ext3_nfs4acl_init(handle, inode, dir);
++      else
++              err = ext3_init_acl(handle, inode, dir);
+       if (err)
+               goto fail_free_drop;
+--- a/fs/ext3/inode.c
++++ b/fs/ext3/inode.c
+@@ -38,6 +38,7 @@
+ #include <linux/bio.h>
+ #include "xattr.h"
+ #include "acl.h"
++#include "nfs4acl.h"
+ static int ext3_writepage_trans_blocks(struct inode *inode);
+@@ -2684,6 +2685,9 @@ struct inode *ext3_iget(struct super_blo
+       ei->i_acl = EXT3_ACL_NOT_CACHED;
+       ei->i_default_acl = EXT3_ACL_NOT_CACHED;
+ #endif
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++      ei->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
++#endif
+       ei->i_block_alloc_info = NULL;
+       ret = __ext3_get_inode_loc(inode, &iloc, 0);
+@@ -2983,6 +2987,65 @@ int ext3_write_inode(struct inode *inode
+       return ext3_force_commit(inode->i_sb);
+ }
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++static int ext3_inode_change_ok(struct inode *inode, struct iattr *attr)
++{
++      unsigned int ia_valid = attr->ia_valid;
++
++      if (!test_opt(inode->i_sb, NFS4ACL))
++              return inode_change_ok(inode, attr);
++
++      /* If force is set do it anyway. */
++      if (ia_valid & ATTR_FORCE)
++              return 0;
++
++      /* Make sure a caller can chown. */
++      if ((ia_valid & ATTR_UID) &&
++          (current->fsuid != inode->i_uid ||
++           attr->ia_uid != inode->i_uid) &&
++          (current->fsuid != attr->ia_uid ||
++           ext3_nfs4acl_permission(inode, ACE4_WRITE_OWNER)) &&
++          !capable(CAP_CHOWN))
++              goto error;
++
++      /* Make sure caller can chgrp. */
++      if ((ia_valid & ATTR_GID)) {
++              int in_group = in_group_p(attr->ia_gid);
++              if ((current->fsuid != inode->i_uid ||
++                  (!in_group && attr->ia_gid != inode->i_gid)) &&
++                  (!in_group ||
++                   ext3_nfs4acl_permission(inode, ACE4_WRITE_OWNER)) &&
++                  !capable(CAP_CHOWN))
++                      goto error;
++      }
++
++      /* Make sure a caller can chmod. */
++      if (ia_valid & ATTR_MODE) {
++              if (current->fsuid != inode->i_uid &&
++                  ext3_nfs4acl_permission(inode, ACE4_WRITE_ACL) &&
++                  !capable(CAP_FOWNER))
++                      goto error;
++              /* Also check the setgid bit! */
++              if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
++                              inode->i_gid) && !capable(CAP_FSETID))
++                      attr->ia_mode &= ~S_ISGID;
++      }
++
++      /* Check for setting the inode time. */
++      if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
++              if (current->fsuid != inode->i_uid &&
++                  ext3_nfs4acl_permission(inode, ACE4_WRITE_ATTRIBUTES) &&
++                  !capable(CAP_FOWNER))
++                      goto error;
++      }
++      return 0;
++error:
++      return -EPERM;
++}
++#else
++# define ext3_inode_change_ok inode_change_ok
++#endif
++
+ /*
+  * ext3_setattr()
+  *
+@@ -3006,7 +3069,7 @@ int ext3_setattr(struct dentry *dentry,
+       int error, rc = 0;
+       const unsigned int ia_valid = attr->ia_valid;
+-      error = inode_change_ok(inode, attr);
++      error = ext3_inode_change_ok(inode, attr);
+       if (error)
+               return error;
+@@ -3063,8 +3126,12 @@ int ext3_setattr(struct dentry *dentry,
+       if (inode->i_nlink)
+               ext3_orphan_del(NULL, inode);
+-      if (!rc && (ia_valid & ATTR_MODE))
+-              rc = ext3_acl_chmod(inode);
++      if (!rc && (ia_valid & ATTR_MODE)) {
++              if (test_opt(inode->i_sb, NFS4ACL))
++                      rc = ext3_nfs4acl_chmod(inode);
++              else
++                      rc = ext3_acl_chmod(inode);
++      }
+ err_out:
+       ext3_std_error(inode->i_sb, error);
+--- a/fs/ext3/namei.c
++++ b/fs/ext3/namei.c
+@@ -40,6 +40,7 @@
+ #include "namei.h"
+ #include "xattr.h"
+ #include "acl.h"
++#include "nfs4acl.h"
+ /*
+  * define how far ahead to read directories while searching them.
+@@ -2412,6 +2413,16 @@ end_rename:
+       return retval;
+ }
++int ext3_permission(struct inode *inode, int mask)
++{
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++      if (test_opt(inode->i_sb, NFS4ACL))
++              return ext3_nfs4acl_permission(inode, nfs4acl_want_to_mask(mask));
++      else
++#endif
++        return generic_permission(inode, mask, ext3_check_acl);
++}
++
+ /*
+  * directories can handle most operations...
+  */
+@@ -2433,6 +2444,8 @@ const struct inode_operations ext3_dir_i
+       .removexattr    = generic_removexattr,
+ #endif
+       .permission     = ext3_permission,
++      .may_create     = ext3_may_create,
++      .may_delete     = ext3_may_delete,
+ };
+ const struct inode_operations ext3_special_inode_operations = {
+@@ -2444,4 +2457,6 @@ const struct inode_operations ext3_speci
+       .removexattr    = generic_removexattr,
+ #endif
+       .permission     = ext3_permission,
++      .may_create     = ext3_may_create,
++      .may_delete     = ext3_may_delete,
+ };
+--- a/fs/ext3/namei.h
++++ b/fs/ext3/namei.h
+@@ -5,4 +5,5 @@
+  *
+ */
++extern int ext3_permission (struct inode *, int);
+ extern struct dentry *ext3_get_parent(struct dentry *child);
+--- /dev/null
++++ b/fs/ext3/nfs4acl.c
+@@ -0,0 +1,370 @@
++/*
++ * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2, or (at your option) any
++ * later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/ext3_jbd.h>
++#include <linux/ext3_fs.h>
++#include <linux/nfs4acl_xattr.h>
++#include "namei.h"
++#include "xattr.h"
++#include "nfs4acl.h"
++
++static inline struct nfs4acl *
++ext3_iget_nfs4acl(struct inode *inode)
++{
++      struct nfs4acl *acl = EXT3_NFS4ACL_NOT_CACHED;
++      struct ext3_inode_info *ei = EXT3_I(inode);
++
++      spin_lock(&inode->i_lock);
++      if (ei->i_nfs4acl != EXT3_NFS4ACL_NOT_CACHED)
++              acl = nfs4acl_get(ei->i_nfs4acl);
++      spin_unlock(&inode->i_lock);
++
++      return acl;
++}
++
++static inline void
++ext3_iset_nfs4acl(struct inode *inode, struct nfs4acl *acl)
++{
++      struct ext3_inode_info *ei = EXT3_I(inode);
++
++      spin_lock(&inode->i_lock);
++      if (ei->i_nfs4acl != EXT3_NFS4ACL_NOT_CACHED)
++              nfs4acl_put(ei->i_nfs4acl);
++      ei->i_nfs4acl = nfs4acl_get(acl);
++      spin_unlock(&inode->i_lock);
++}
++
++static struct nfs4acl *
++ext3_get_nfs4acl(struct inode *inode)
++{
++      const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
++      void *value = NULL;
++      struct nfs4acl *acl;
++      int retval;
++
++      if (!test_opt(inode->i_sb, NFS4ACL))
++              return NULL;
++
++      acl = ext3_iget_nfs4acl(inode);
++      if (acl != EXT3_NFS4ACL_NOT_CACHED)
++              return acl;
++      retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
++      if (retval > 0) {
++              value = kmalloc(retval, GFP_KERNEL);
++              if (!value)
++                      return ERR_PTR(-ENOMEM);
++              retval = ext3_xattr_get(inode, name_index, "", value, retval);
++      }
++      if (retval > 0) {
++              acl = nfs4acl_from_xattr(value, retval);
++              if (acl == ERR_PTR(-EINVAL))
++                      acl = ERR_PTR(-EIO);
++      } else if (retval == -ENODATA || retval == -ENOSYS)
++              acl = NULL;
++      else
++              acl = ERR_PTR(retval);
++      kfree(value);
++
++      if (!IS_ERR(acl))
++              ext3_iset_nfs4acl(inode, acl);
++
++      return acl;
++}
++
++static int
++ext3_set_nfs4acl(handle_t *handle, struct inode *inode, struct nfs4acl *acl)
++{
++      const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
++      size_t size = 0;
++      void *value = NULL;
++      int retval;
++
++      if (acl) {
++              size = nfs4acl_xattr_size(acl);
++              value = kmalloc(size, GFP_KERNEL);
++              if (!value)
++                      return -ENOMEM;
++              nfs4acl_to_xattr(acl, value);
++      }
++      if (handle)
++              retval = ext3_xattr_set_handle(handle, inode, name_index, "",
++                                             value, size, 0);
++      else
++              retval = ext3_xattr_set(inode, name_index, "", value, size, 0);
++      if (value)
++              kfree(value);
++      if (!retval)
++              ext3_iset_nfs4acl(inode, acl);
++
++      return retval;
++}
++
++int
++ext3_nfs4acl_permission(struct inode *inode, unsigned int mask)
++{
++      struct nfs4acl *acl;
++      int retval;
++
++      BUG_ON(!test_opt(inode->i_sb, NFS4ACL));
++
++      acl = ext3_get_nfs4acl(inode);
++      if (!acl)
++              retval = nfs4acl_generic_permission(inode, mask);
++      else if (IS_ERR(acl))
++              retval = PTR_ERR(acl);
++      else {
++              retval = nfs4acl_permission(inode, acl, mask);
++              nfs4acl_put(acl);
++      }
++
++      return retval;
++}
++
++int ext3_may_create(struct inode *dir, int isdir)
++{
++      int error;
++
++      if (test_opt(dir->i_sb, NFS4ACL)) {
++              unsigned int mask = (isdir ? ACE4_ADD_SUBDIRECTORY : ACE4_ADD_FILE) |
++                                  ACE4_EXECUTE;
++
++              error = ext3_nfs4acl_permission(dir, mask);
++      } else
++              error = ext3_permission(dir,  MAY_WRITE | MAY_EXEC);
++
++      return error;
++}
++
++static int check_sticky(struct inode *dir, struct inode *inode)
++{
++      if (!(dir->i_mode & S_ISVTX))
++              return 0;
++      if (inode->i_uid == current->fsuid)
++              return 0;
++      if (dir->i_uid == current->fsuid)
++              return 0;
++      return !capable(CAP_FOWNER);
++}
++
++int ext3_may_delete(struct inode *dir, struct inode *inode)
++{
++      int error;
++
++      if (test_opt(inode->i_sb, NFS4ACL)) {
++              error = ext3_nfs4acl_permission(dir, ACE4_DELETE_CHILD | ACE4_EXECUTE);
++              if (!error && check_sticky(dir, inode))
++                      error = -EPERM;
++              if (error && !ext3_nfs4acl_permission(inode, ACE4_DELETE))
++                      error = 0;
++      } else {
++              error = ext3_permission(dir, MAY_WRITE | MAY_EXEC);
++              if (!error && check_sticky(dir, inode))
++                      error = -EPERM;
++      }
++
++      return error;
++}
++
++int
++ext3_nfs4acl_init(handle_t *handle, struct inode *inode, struct inode *dir)
++{
++      struct nfs4acl *dir_acl = NULL, *acl;
++      int retval;
++
++      if (!S_ISLNK(inode->i_mode))
++              dir_acl = ext3_get_nfs4acl(dir);
++      if (!dir_acl || IS_ERR(dir_acl)) {
++              inode->i_mode &= ~current->fs->umask;
++              return PTR_ERR(dir_acl);
++      }
++      acl = nfs4acl_inherit(dir_acl, inode->i_mode);
++      nfs4acl_put(dir_acl);
++
++      retval = PTR_ERR(acl);
++      if (acl && !IS_ERR(acl)) {
++              retval = ext3_set_nfs4acl(handle, inode, acl);
++              inode->i_mode = (inode->i_mode & ~S_IRWXUGO) |
++                              nfs4acl_masks_to_mode(acl);
++              nfs4acl_put(acl);
++      }
++      return retval;
++}
++
++int
++ext3_nfs4acl_chmod(struct inode *inode)
++{
++      struct nfs4acl *acl;
++      int retval;
++
++      if (S_ISLNK(inode->i_mode))
++              return -EOPNOTSUPP;
++      acl = ext3_get_nfs4acl(inode);
++      if (!acl || IS_ERR(acl))
++              return PTR_ERR(acl);
++      acl = nfs4acl_chmod(acl, inode->i_mode);
++      if (IS_ERR(acl))
++              return PTR_ERR(acl);
++      retval = ext3_set_nfs4acl(NULL, inode, acl);
++      nfs4acl_put(acl);
++
++      return retval;
++}
++
++static size_t
++ext3_xattr_list_nfs4acl(struct inode *inode, char *list, size_t list_len,
++                      const char *name, size_t name_len)
++{
++      const size_t size = sizeof(NFS4ACL_XATTR);
++
++      if (!test_opt(inode->i_sb, NFS4ACL))
++              return 0;
++      if (list && size <= list_len)
++              memcpy(list, NFS4ACL_XATTR, size);
++      return size;
++}
++
++static int
++ext3_xattr_get_nfs4acl(struct inode *inode, const char *name, void *buffer,
++                     size_t buffer_size)
++{
++      struct nfs4acl *acl;
++      size_t size;
++
++      if (!test_opt(inode->i_sb, NFS4ACL))
++              return -EOPNOTSUPP;
++      if (strcmp(name, "") != 0)
++              return -EINVAL;
++
++      acl = ext3_get_nfs4acl(inode);
++      if (IS_ERR(acl))
++              return PTR_ERR(acl);
++      if (acl == NULL)
++              return -ENODATA;
++      size = nfs4acl_xattr_size(acl);
++      if (buffer) {
++              if (size > buffer_size)
++                      return -ERANGE;
++              nfs4acl_to_xattr(acl, buffer);
++      }
++      nfs4acl_put(acl);
++
++      return size;
++}
++
++#ifdef NFS4ACL_DEBUG
++static size_t
++ext3_xattr_list_masked_nfs4acl(struct inode *inode, char *list, size_t list_len,
++                             const char *name, size_t name_len)
++{
++      return 0;
++}
++
++static int
++ext3_xattr_get_masked_nfs4acl(struct inode *inode, const char *name,
++                            void *buffer, size_t buffer_size)
++{
++      const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
++      struct nfs4acl *acl;
++      void *xattr;
++      size_t size;
++      int retval;
++
++      if (!test_opt(inode->i_sb, NFS4ACL))
++              return -EOPNOTSUPP;
++      if (strcmp(name, "") != 0)
++              return -EINVAL;
++      retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
++      if (retval <= 0)
++              return retval;
++      xattr = kmalloc(retval, GFP_KERNEL);
++      if (!xattr)
++              return -ENOMEM;
++      retval = ext3_xattr_get(inode, name_index, "", xattr, retval);
++      if (retval <= 0)
++              return retval;
++      acl = nfs4acl_from_xattr(xattr, retval);
++      kfree(xattr);
++      if (IS_ERR(acl))
++              return PTR_ERR(acl);
++      retval = nfs4acl_apply_masks(&acl);
++      if (retval) {
++              nfs4acl_put(acl);
++              return retval;
++      }
++      size = nfs4acl_xattr_size(acl);
++      if (buffer) {
++              if (size > buffer_size)
++                      return -ERANGE;
++              nfs4acl_to_xattr(acl, buffer);
++      }
++      nfs4acl_put(acl);
++      return size;
++}
++#endif
++
++static int
++ext3_xattr_set_nfs4acl(struct inode *inode, const char *name,
++                     const void *value, size_t size, int flags)
++{
++      handle_t *handle;
++      struct nfs4acl *acl = NULL;
++      int retval, retries = 0;
++
++      if (S_ISLNK(inode->i_mode) || !test_opt(inode->i_sb, NFS4ACL))
++              return -EOPNOTSUPP;
++      if (strcmp(name, "") != 0)
++              return -EINVAL;
++      if (current->fsuid != inode->i_uid &&
++          ext3_nfs4acl_permission(inode, ACE4_WRITE_ACL) &&
++          !capable(CAP_FOWNER))
++              return -EPERM;
++      if (value) {
++              acl = nfs4acl_from_xattr(value, size);
++              if (IS_ERR(acl))
++                      return PTR_ERR(acl);
++
++              inode->i_mode &= ~S_IRWXUGO;
++              inode->i_mode |= nfs4acl_masks_to_mode(acl);
++      }
++
++retry:
++      handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
++      if (IS_ERR(handle))
++              return PTR_ERR(handle);
++      ext3_mark_inode_dirty(handle, inode);
++      retval = ext3_set_nfs4acl(handle, inode, acl);
++      ext3_journal_stop(handle);
++      if (retval == ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
++              goto retry;
++      nfs4acl_put(acl);
++      return retval;
++}
++
++struct xattr_handler ext3_nfs4acl_xattr_handler = {
++      .prefix = NFS4ACL_XATTR,
++      .list   = ext3_xattr_list_nfs4acl,
++      .get    = ext3_xattr_get_nfs4acl,
++      .set    = ext3_xattr_set_nfs4acl,
++};
++
++#ifdef NFS4ACL_DEBUG
++struct xattr_handler ext3_masked_nfs4acl_xattr_handler = {
++      .prefix = "system.masked-nfs4acl",
++      .list   = ext3_xattr_list_masked_nfs4acl,
++      .get    = ext3_xattr_get_masked_nfs4acl,
++      .set    = ext3_xattr_set_nfs4acl,
++};
++#endif
+--- /dev/null
++++ b/fs/ext3/nfs4acl.h
+@@ -0,0 +1,36 @@
++#ifndef __FS_EXT3_NFS4ACL_H
++#define __FS_EXT3_NFS4ACL_H
++
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++
++#include <linux/nfs4acl.h>
++
++/* Value for i_nfs4acl if NFS4ACL has not been cached */
++#define EXT3_NFS4ACL_NOT_CACHED ((void *)-1)
++
++extern int ext3_nfs4acl_permission(struct inode *, unsigned int);
++extern int ext3_may_create(struct inode *, int);
++extern int ext3_may_delete(struct inode *, struct inode *);
++extern int ext3_nfs4acl_init(handle_t *, struct inode *, struct inode *);
++extern int ext3_nfs4acl_chmod(struct inode *);
++
++#else  /* CONFIG_FS_EXT3_NFS4ACL */
++
++#define ext3_may_create NULL
++#define ext3_may_delete NULL
++
++static inline int
++ext3_nfs4acl_init(handle_t *handle, struct inode *inode, struct inode *dir)
++{
++      return 0;
++}
++
++static inline int
++ext3_nfs4acl_chmod(struct inode *inode)
++{
++      return 0;
++}
++
++#endif  /* CONFIG_FS_EXT3_NFS4ACL */
++
++#endif  /* __FS_EXT3_NFS4ACL_H */
+--- a/fs/ext3/super.c
++++ b/fs/ext3/super.c
+@@ -36,12 +36,14 @@
+ #include <linux/namei.h>
+ #include <linux/quotaops.h>
+ #include <linux/seq_file.h>
++#include <linux/nfs4acl.h>
+ #include <linux/log2.h>
+ #include <asm/uaccess.h>
+ #include "xattr.h"
+ #include "acl.h"
++#include "nfs4acl.h"
+ #include "namei.h"
+ static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
+@@ -454,6 +456,9 @@ static struct inode *ext3_alloc_inode(st
+       ei->i_acl = EXT3_ACL_NOT_CACHED;
+       ei->i_default_acl = EXT3_ACL_NOT_CACHED;
+ #endif
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++      ei->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
++#endif
+       ei->i_block_alloc_info = NULL;
+       ei->vfs_inode.i_version = 1;
+       return &ei->vfs_inode;
+@@ -516,6 +521,13 @@ static void ext3_clear_inode(struct inod
+               EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
+       }
+ #endif
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++      if (EXT3_I(inode)->i_nfs4acl &&
++                      EXT3_I(inode)->i_nfs4acl != EXT3_NFS4ACL_NOT_CACHED) {
++              nfs4acl_put(EXT3_I(inode)->i_nfs4acl);
++              EXT3_I(inode)->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
++      }
++#endif
+       ext3_discard_reservation(inode);
+       EXT3_I(inode)->i_block_alloc_info = NULL;
+       if (unlikely(rsv))
+@@ -750,7 +762,7 @@ enum {
+       Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
+       Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
+       Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
+-      Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
++      Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_acl_flavor, Opt_noacl,
+       Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
+       Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
+       Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+@@ -782,6 +794,7 @@ static match_table_t tokens = {
+       {Opt_user_xattr, "user_xattr"},
+       {Opt_nouser_xattr, "nouser_xattr"},
+       {Opt_acl, "acl"},
++      {Opt_acl_flavor, "acl=%s"},
+       {Opt_noacl, "noacl"},
+       {Opt_reservation, "reservation"},
+       {Opt_noreservation, "noreservation"},
+@@ -925,19 +938,33 @@ static int parse_options (char *options,
+                       printk("EXT3 (no)user_xattr options not supported\n");
+                       break;
+ #endif
+-#ifdef CONFIG_EXT3_FS_POSIX_ACL
+               case Opt_acl:
+-                      set_opt(sbi->s_mount_opt, POSIX_ACL);
++                      args[0].to = args[0].from;
++                      /* fall through */
++              case Opt_acl_flavor:
++#ifdef CONFIG_EXT3_FS_POSIX_ACL
++                      if (match_string(&args[0], "") ||
++                          match_string(&args[0], "posix")) {
++                              set_opt(sbi->s_mount_opt, POSIX_ACL);
++                              clear_opt(sbi->s_mount_opt, NFS4ACL);
++                      } else
++#endif
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++                      if (match_string(&args[0], "nfs4")) {
++                              clear_opt(sbi->s_mount_opt, POSIX_ACL);
++                              set_opt(sbi->s_mount_opt, NFS4ACL);
++                      } else
++#endif
++                      {
++                              printk(KERN_ERR "EXT3-fs: unsupported acl "
++                                     "flavor\n");
++                              return 0;
++                      }
+                       break;
+               case Opt_noacl:
+                       clear_opt(sbi->s_mount_opt, POSIX_ACL);
++                      clear_opt(sbi->s_mount_opt, NFS4ACL);
+                       break;
+-#else
+-              case Opt_acl:
+-              case Opt_noacl:
+-                      printk("EXT3 (no)acl options not supported\n");
+-                      break;
+-#endif
+               case Opt_reservation:
+                       set_opt(sbi->s_mount_opt, RESERVATION);
+                       break;
+@@ -1607,8 +1634,11 @@ static int ext3_fill_super (struct super
+                           NULL, 0))
+               goto failed_mount;
+-      sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+-              ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
++      sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
++      if (sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL)
++              sb->s_flags |= MS_POSIXACL;
++      if (sbi->s_mount_opt & EXT3_MOUNT_NFS4ACL)
++              sb->s_flags |= MS_POSIXACL | MS_WITHAPPEND;
+       if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV &&
+           (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
+@@ -2451,8 +2481,12 @@ static int ext3_remount (struct super_bl
+       if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
+               ext3_abort(sb, __func__, "Abort forced by user");
+-      sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+-              ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
++      sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
++      if (sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL)
++              sb->s_flags |= MS_POSIXACL;
++      if (sbi->s_mount_opt & EXT3_MOUNT_NFS4ACL)
++              sb->s_flags |= MS_POSIXACL;
++
+       es = sbi->s_es;
+--- a/fs/ext3/xattr.c
++++ b/fs/ext3/xattr.c
+@@ -114,6 +114,9 @@ static struct xattr_handler *ext3_xattr_
+ #ifdef CONFIG_EXT3_FS_SECURITY
+       [EXT3_XATTR_INDEX_SECURITY]          = &ext3_xattr_security_handler,
+ #endif
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++      [EXT3_XATTR_INDEX_NFS4ACL]           = &ext3_nfs4acl_xattr_handler,
++#endif
+ };
+ struct xattr_handler *ext3_xattr_handlers[] = {
+@@ -126,6 +129,12 @@ struct xattr_handler *ext3_xattr_handler
+ #ifdef CONFIG_EXT3_FS_SECURITY
+       &ext3_xattr_security_handler,
+ #endif
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++      &ext3_nfs4acl_xattr_handler,
++#ifdef NFS4ACL_DEBUG
++      &ext3_masked_nfs4acl_xattr_handler,
++#endif
++#endif
+       NULL
+ };
+--- a/fs/ext3/xattr.h
++++ b/fs/ext3/xattr.h
+@@ -21,6 +21,7 @@
+ #define EXT3_XATTR_INDEX_TRUSTED              4
+ #define       EXT3_XATTR_INDEX_LUSTRE                 5
+ #define EXT3_XATTR_INDEX_SECURITY             6
++#define EXT3_XATTR_INDEX_NFS4ACL              7
+ struct ext3_xattr_header {
+       __le32  h_magic;        /* magic number for identification */
+@@ -63,6 +64,10 @@ extern struct xattr_handler ext3_xattr_t
+ extern struct xattr_handler ext3_xattr_acl_access_handler;
+ extern struct xattr_handler ext3_xattr_acl_default_handler;
+ extern struct xattr_handler ext3_xattr_security_handler;
++extern struct xattr_handler ext3_nfs4acl_xattr_handler;
++#ifdef NFS4ACL_DEBUG
++extern struct xattr_handler ext3_masked_nfs4acl_xattr_handler;
++#endif
+ extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
+--- a/include/linux/ext3_fs.h
++++ b/include/linux/ext3_fs.h
+@@ -380,6 +380,7 @@ struct ext3_inode {
+ #define EXT3_MOUNT_QUOTA              0x80000 /* Some quota option set */
+ #define EXT3_MOUNT_USRQUOTA           0x100000 /* "old" user quota */
+ #define EXT3_MOUNT_GRPQUOTA           0x200000 /* "old" group quota */
++#define EXT3_MOUNT_NFS4ACL            0x400000 /* NFS version 4 ACLs */
+ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
+ #ifndef _LINUX_EXT2_FS_H
+--- a/include/linux/ext3_fs_i.h
++++ b/include/linux/ext3_fs_i.h
+@@ -107,6 +107,9 @@ struct ext3_inode_info {
+       struct posix_acl        *i_acl;
+       struct posix_acl        *i_default_acl;
+ #endif
++#ifdef CONFIG_EXT3_FS_NFS4ACL
++      struct nfs4acl          *i_nfs4acl;
++#endif
+       struct list_head i_orphan;      /* unlinked but open inodes */