]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.suse/nfs4acl-common.diff
Imported linux-2.6.27.39 suse/xen patches.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.suse / nfs4acl-common.diff
diff --git a/src/patches/suse-2.6.27.31/patches.suse/nfs4acl-common.diff b/src/patches/suse-2.6.27.31/patches.suse/nfs4acl-common.diff
deleted file mode 100644 (file)
index bccf826..0000000
+++ /dev/null
@@ -1,1770 +0,0 @@
-From: Andreas Gruenbacher <agruen@suse.de>
-Subject: NFSv4 ACL in-memory representation and manipulation
-    
-* In-memory representation (struct nfs4acl).
-* Functionality a filesystem needs such as permission checking,
-  apply mode to acl, compute mode from acl, inheritance upon file
-  create.
-* Compute a mask-less acl from struct nfs4acl that grants the same
-  permissions. Protocols which don't understand the masks need
-  this.
-* Convert to/from xattrs.
-
-Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
-
----
- fs/Kconfig                    |    4 
- fs/Makefile                   |    4 
- fs/nfs4acl_base.c             |  565 +++++++++++++++++++++++++++++++
- fs/nfs4acl_compat.c           |  757 ++++++++++++++++++++++++++++++++++++++++++
- fs/nfs4acl_xattr.c            |  146 ++++++++
- include/linux/nfs4acl.h       |  205 +++++++++++
- include/linux/nfs4acl_xattr.h |   32 +
- 7 files changed, 1713 insertions(+)
-
---- a/fs/Kconfig
-+++ b/fs/Kconfig
-@@ -419,6 +419,10 @@ config FS_POSIX_ACL
-       bool
-       default n
-+config FS_NFS4ACL
-+      bool
-+      default n
-+
- source "fs/xfs/Kconfig"
- source "fs/gfs2/Kconfig"
---- a/fs/Makefile
-+++ b/fs/Makefile
-@@ -50,6 +50,10 @@ obj-$(CONFIG_FS_POSIX_ACL)  += posix_acl.
- obj-$(CONFIG_NFS_COMMON)      += nfs_common/
- obj-$(CONFIG_GENERIC_ACL)     += generic_acl.o
-+obj-$(CONFIG_FS_NFS4ACL)      += nfs4acl.o
-+nfs4acl-y                     := nfs4acl_base.o nfs4acl_xattr.o \
-+                                 nfs4acl_compat.o
-+
- obj-$(CONFIG_QUOTA)           += dquot.o
- obj-$(CONFIG_QFMT_V1)         += quota_v1.o
- obj-$(CONFIG_QFMT_V2)         += quota_v2.o
---- /dev/null
-+++ b/fs/nfs4acl_base.c
-@@ -0,0 +1,565 @@
-+/*
-+ * 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/sched.h>
-+#include <linux/module.h>
-+#include <linux/fs.h>
-+#include <linux/nfs4acl.h>
-+
-+MODULE_LICENSE("GPL");
-+
-+/*
-+ * ACL entries that have ACE4_SPECIAL_WHO set in ace->e_flags use the
-+ * pointer values of these constants in ace->u.e_who to avoid massive
-+ * amounts of string comparisons.
-+ */
-+
-+const char nfs4ace_owner_who[]          = "OWNER@";
-+const char nfs4ace_group_who[]          = "GROUP@";
-+const char nfs4ace_everyone_who[] = "EVERYONE@";
-+
-+EXPORT_SYMBOL(nfs4ace_owner_who);
-+EXPORT_SYMBOL(nfs4ace_group_who);
-+EXPORT_SYMBOL(nfs4ace_everyone_who);
-+
-+/**
-+ * nfs4acl_alloc  -  allocate an acl
-+ * @count:    number of entries
-+ */
-+struct nfs4acl *
-+nfs4acl_alloc(int count)
-+{
-+      size_t size = sizeof(struct nfs4acl) + count * sizeof(struct nfs4ace);
-+      struct nfs4acl *acl = kmalloc(size, GFP_KERNEL);
-+
-+      if (acl) {
-+              memset(acl, 0, size);
-+              atomic_set(&acl->a_refcount, 1);
-+              acl->a_count = count;
-+      }
-+      return acl;
-+}
-+EXPORT_SYMBOL(nfs4acl_alloc);
-+
-+/**
-+ * nfs4acl_clone  -  create a copy of an acl
-+ */
-+struct nfs4acl *
-+nfs4acl_clone(const struct nfs4acl *acl)
-+{
-+      int count = acl->a_count;
-+      size_t size = sizeof(struct nfs4acl) + count * sizeof(struct nfs4ace);
-+      struct nfs4acl *dup = kmalloc(size, GFP_KERNEL);
-+
-+      if (dup) {
-+              memcpy(dup, acl, size);
-+              atomic_set(&dup->a_refcount, 1);
-+      }
-+      return dup;
-+}
-+
-+/*
-+ * The POSIX permissions are supersets of the below mask flags.
-+ *
-+ * The ACE4_READ_ATTRIBUTES and ACE4_READ_ACL flags are always granted
-+ * in POSIX. The ACE4_SYNCHRONIZE flag has no meaning under POSIX. We
-+ * make sure that we do not mask them if they are set, so that users who
-+ * rely on these flags won't get confused.
-+ */
-+#define ACE4_POSIX_MODE_READ ( \
-+      ACE4_READ_DATA | ACE4_LIST_DIRECTORY )
-+#define ACE4_POSIX_MODE_WRITE ( \
-+      ACE4_WRITE_DATA | ACE4_ADD_FILE | \
-+      ACE4_APPEND_DATA | ACE4_ADD_SUBDIRECTORY | \
-+      ACE4_DELETE_CHILD )
-+#define ACE4_POSIX_MODE_EXEC ( \
-+      ACE4_EXECUTE)
-+
-+static int
-+nfs4acl_mask_to_mode(unsigned int mask)
-+{
-+      int mode = 0;
-+
-+      if (mask & ACE4_POSIX_MODE_READ)
-+              mode |= MAY_READ;
-+      if (mask & ACE4_POSIX_MODE_WRITE)
-+              mode |= MAY_WRITE;
-+      if (mask & ACE4_POSIX_MODE_EXEC)
-+              mode |= MAY_EXEC;
-+
-+      return mode;
-+}
-+
-+/**
-+ * nfs4acl_masks_to_mode  -  compute file mode permission bits from file masks
-+ *
-+ * Compute the file mode permission bits from the file masks in the acl.
-+ */
-+int
-+nfs4acl_masks_to_mode(const struct nfs4acl *acl)
-+{
-+      return nfs4acl_mask_to_mode(acl->a_owner_mask) << 6 |
-+             nfs4acl_mask_to_mode(acl->a_group_mask) << 3 |
-+             nfs4acl_mask_to_mode(acl->a_other_mask);
-+}
-+EXPORT_SYMBOL(nfs4acl_masks_to_mode);
-+
-+static unsigned int
-+nfs4acl_mode_to_mask(mode_t mode)
-+{
-+      unsigned int mask = ACE4_POSIX_ALWAYS_ALLOWED;
-+
-+      if (mode & MAY_READ)
-+              mask |= ACE4_POSIX_MODE_READ;
-+      if (mode & MAY_WRITE)
-+              mask |= ACE4_POSIX_MODE_WRITE;
-+      if (mode & MAY_EXEC)
-+              mask |= ACE4_POSIX_MODE_EXEC;
-+
-+      return mask;
-+}
-+
-+/**
-+ * nfs4acl_chmod  -  update the file masks to reflect the new mode
-+ * @mode:     file mode permission bits to apply to the @acl
-+ *
-+ * Converts the mask flags corresponding to the owner, group, and other file
-+ * permissions and computes the file masks. Returns @acl if it already has the
-+ * appropriate file masks, or updates the flags in a copy of @acl. Takes over
-+ * @acl.
-+ */
-+struct nfs4acl *
-+nfs4acl_chmod(struct nfs4acl *acl, mode_t mode)
-+{
-+      unsigned int owner_mask, group_mask, other_mask;
-+      struct nfs4acl *clone;
-+
-+      owner_mask = nfs4acl_mode_to_mask(mode >> 6);
-+      group_mask = nfs4acl_mode_to_mask(mode >> 3);
-+      other_mask = nfs4acl_mode_to_mask(mode);
-+
-+      if (acl->a_owner_mask == owner_mask &&
-+          acl->a_group_mask == group_mask &&
-+          acl->a_other_mask == other_mask)
-+              return acl;
-+
-+      clone = nfs4acl_clone(acl);
-+      nfs4acl_put(acl);
-+      if (!clone)
-+              return ERR_PTR(-ENOMEM);
-+
-+      clone->a_owner_mask = owner_mask;
-+      clone->a_group_mask = group_mask;
-+      clone->a_other_mask = other_mask;
-+
-+      if (nfs4acl_write_through(&clone)) {
-+              nfs4acl_put(clone);
-+              clone = ERR_PTR(-ENOMEM);
-+      }
-+      return clone;
-+}
-+EXPORT_SYMBOL(nfs4acl_chmod);
-+
-+/**
-+ * nfs4acl_want_to_mask  - convert permission want argument to a mask
-+ * @want:     @want argument of the permission inode operation
-+ *
-+ * When checking for append, @want is (MAY_WRITE | MAY_APPEND).
-+ */
-+unsigned int
-+nfs4acl_want_to_mask(int want)
-+{
-+      unsigned int mask = 0;
-+
-+      if (want & MAY_READ)
-+              mask |= ACE4_READ_DATA;
-+      if (want & MAY_APPEND)
-+              mask |= ACE4_APPEND_DATA;
-+      else if (want & MAY_WRITE)
-+              mask |= ACE4_WRITE_DATA;
-+      if (want & MAY_EXEC)
-+              mask |= ACE4_EXECUTE;
-+
-+      return mask;
-+}
-+EXPORT_SYMBOL(nfs4acl_want_to_mask);
-+
-+/**
-+ * nfs4acl_capability_check  -  check for capabilities overriding read/write access
-+ * @inode:    inode to check
-+ * @mask:     requested access (ACE4_* bitmask)
-+ *
-+ * Capabilities other than CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH must be checked
-+ * separately.
-+ */
-+static inline int nfs4acl_capability_check(struct inode *inode, unsigned int mask)
-+{
-+      /*
-+       * Read/write DACs are always overridable.
-+       * Executable DACs are overridable if at least one exec bit is set.
-+       */
-+      if (!(mask & (ACE4_WRITE_ACL | ACE4_WRITE_OWNER)) &&
-+          (!(mask & ACE4_EXECUTE) ||
-+          (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode)))
-+              if (capable(CAP_DAC_OVERRIDE))
-+                      return 0;
-+
-+      /*
-+       * Searching includes executable on directories, else just read.
-+       */
-+      if (!(mask & ~(ACE4_READ_DATA | ACE4_EXECUTE)) &&
-+          (S_ISDIR(inode->i_mode) || !(mask & ACE4_EXECUTE)))
-+              if (capable(CAP_DAC_READ_SEARCH))
-+                      return 0;
-+
-+      return -EACCES;
-+}
-+
-+/**
-+ * nfs4acl_permission  -  permission check algorithm with masking
-+ * @inode:    inode to check
-+ * @acl:      nfs4 acl of the inode
-+ * @mask:     requested access (ACE4_* bitmask)
-+ *
-+ * Checks if the current process is granted @mask flags in @acl. With
-+ * write-through, the OWNER@ is always granted the owner file mask, the
-+ * GROUP@ is always granted the group file mask, and EVERYONE@ is always
-+ * granted the other file mask. Otherwise, processes are only granted
-+ * @mask flags which they are granted in the @acl as well as in their
-+ * file mask.
-+ */
-+int nfs4acl_permission(struct inode *inode, const struct nfs4acl *acl,
-+                     unsigned int mask)
-+{
-+      const struct nfs4ace *ace;
-+      unsigned int file_mask, requested = mask, denied = 0;
-+      int in_owning_group = in_group_p(inode->i_gid);
-+      int owner_or_group_class = in_owning_group;
-+
-+      /*
-+       * A process is in the
-+       *   - owner file class if it owns the file, in the
-+       *   - group file class if it is in the file's owning group or
-+       *     it matches any of the user or group entries, and in the
-+       *   - other file class otherwise.
-+       */
-+
-+      nfs4acl_for_each_entry(ace, acl) {
-+              unsigned int ace_mask = ace->e_mask;
-+
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+              if (nfs4ace_is_owner(ace)) {
-+                      if (current->fsuid != inode->i_uid)
-+                              continue;
-+                      goto is_owner;
-+              } else if (nfs4ace_is_group(ace)) {
-+                      if (!in_owning_group)
-+                              continue;
-+              } else if (nfs4ace_is_unix_id(ace)) {
-+                      if (ace->e_flags & ACE4_IDENTIFIER_GROUP) {
-+                              if (!in_group_p(ace->u.e_id))
-+                                      continue;
-+                      } else {
-+                              if (current->fsuid != ace->u.e_id)
-+                                      continue;
-+                      }
-+              } else
-+                      goto is_everyone;
-+
-+              /*
-+               * Apply the group file mask to entries other than OWNER@ and
-+               * EVERYONE@. This is not required for correct access checking
-+               * but ensures that we grant the same permissions as the acl
-+               * computed by nfs4acl_apply_masks().
-+               *
-+               * For example, without this restriction, 'group@:rw::allow'
-+               * with mode 0600 would grant rw access to owner processes
-+               * which are also in the owning group. This cannot be expressed
-+               * in an acl.
-+               */
-+              if (nfs4ace_is_allow(ace))
-+                      ace_mask &= acl->a_group_mask;
-+
-+          is_owner:
-+              /* The process is in the owner or group file class. */
-+              owner_or_group_class = 1;
-+
-+          is_everyone:
-+              /* Check which mask flags the ACE allows or denies. */
-+              if (nfs4ace_is_deny(ace))
-+                      denied |= ace_mask & mask;
-+              mask &= ~ace_mask;
-+
-+              /* Keep going until we know which file class the process is in. */
-+              if (!mask && owner_or_group_class)
-+                      break;
-+      }
-+      denied |= mask;
-+
-+      /*
-+       * Figure out which file mask applies.
-+       * Clear write-through if the process is in the file group class but
-+       * not in the owning group, and so the denied permissions apply.
-+       */
-+      if (current->fsuid == inode->i_uid)
-+              file_mask = acl->a_owner_mask;
-+      else if (in_owning_group || owner_or_group_class)
-+              file_mask = acl->a_group_mask;
-+      else
-+              file_mask = acl->a_other_mask;
-+
-+      denied |= requested & ~file_mask;
-+      if (!denied)
-+              return 0;
-+      return nfs4acl_capability_check(inode, requested);
-+}
-+EXPORT_SYMBOL(nfs4acl_permission);
-+
-+/**
-+ * nfs4acl_generic_permission  -  permission check algorithm without explicit acl
-+ * @inode:    inode to check permissions for
-+ * @mask:     requested access (ACE4_* bitmask)
-+ *
-+ * The file mode of a file without ACL corresponds to an ACL with a single
-+ * "EVERYONE:~0::ALLOW" entry, with file masks that correspond to the file mode
-+ * permissions. Instead of constructing a temporary ACL and applying
-+ * nfs4acl_permission() to it, compute the identical result directly from the file
-+ * mode.
-+ */
-+int nfs4acl_generic_permission(struct inode *inode, unsigned int mask)
-+{
-+      int mode = inode->i_mode;
-+
-+      if (current->fsuid == inode->i_uid)
-+              mode >>= 6;
-+      else if (in_group_p(inode->i_gid))
-+              mode >>= 3;
-+      if (!(mask & ~nfs4acl_mode_to_mask(mode)))
-+              return 0;
-+      return nfs4acl_capability_check(inode, mask);
-+}
-+EXPORT_SYMBOL(nfs4acl_generic_permission);
-+
-+/*
-+ * nfs4ace_is_same_who  -  do both acl entries refer to the same identifier?
-+ */
-+int
-+nfs4ace_is_same_who(const struct nfs4ace *a, const struct nfs4ace *b)
-+{
-+#define WHO_FLAGS (ACE4_SPECIAL_WHO | ACE4_IDENTIFIER_GROUP)
-+      if ((a->e_flags & WHO_FLAGS) != (b->e_flags & WHO_FLAGS))
-+              return 0;
-+      if (a->e_flags & ACE4_SPECIAL_WHO)
-+              return a->u.e_who == b->u.e_who;
-+      else
-+              return a->u.e_id == b->u.e_id;
-+#undef WHO_FLAGS
-+}
-+
-+/**
-+ * nfs4acl_set_who  -  set a special who value
-+ * @ace:      acl entry
-+ * @who:      who value to use
-+ */
-+int
-+nfs4ace_set_who(struct nfs4ace *ace, const char *who)
-+{
-+      if (!strcmp(who, nfs4ace_owner_who))
-+              who = nfs4ace_owner_who;
-+      else if (!strcmp(who, nfs4ace_group_who))
-+              who = nfs4ace_group_who;
-+      else if (!strcmp(who, nfs4ace_everyone_who))
-+              who = nfs4ace_everyone_who;
-+      else
-+              return -EINVAL;
-+
-+      ace->u.e_who = who;
-+      ace->e_flags |= ACE4_SPECIAL_WHO;
-+      ace->e_flags &= ~ACE4_IDENTIFIER_GROUP;
-+      return 0;
-+}
-+EXPORT_SYMBOL(nfs4ace_set_who);
-+
-+/**
-+ * nfs4acl_allowed_to_who  -  mask flags allowed to a specific who value
-+ *
-+ * Computes the mask values allowed to a specific who value, taking
-+ * EVERYONE@ entries into account.
-+ */
-+static unsigned int
-+nfs4acl_allowed_to_who(struct nfs4acl *acl, struct nfs4ace *who)
-+{
-+      struct nfs4ace *ace;
-+      unsigned int allowed = 0;
-+
-+      nfs4acl_for_each_entry_reverse(ace, acl) {
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+              if (nfs4ace_is_same_who(ace, who) ||
-+                  nfs4ace_is_everyone(ace)) {
-+                      if (nfs4ace_is_allow(ace))
-+                              allowed |= ace->e_mask;
-+                      else if (nfs4ace_is_deny(ace))
-+                              allowed &= ~ace->e_mask;
-+              }
-+      }
-+      return allowed;
-+}
-+
-+/**
-+ * nfs4acl_compute_max_masks  -  compute upper bound masks
-+ *
-+ * Computes upper bound owner, group, and other masks so that none of
-+ * the mask flags allowed by the acl are disabled (for any choice of the
-+ * file owner or group membership).
-+ */
-+static void
-+nfs4acl_compute_max_masks(struct nfs4acl *acl)
-+{
-+      struct nfs4ace *ace;
-+
-+      acl->a_owner_mask = 0;
-+      acl->a_group_mask = 0;
-+      acl->a_other_mask = 0;
-+
-+      nfs4acl_for_each_entry_reverse(ace, acl) {
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+
-+              if (nfs4ace_is_owner(ace)) {
-+                      if (nfs4ace_is_allow(ace))
-+                              acl->a_owner_mask |= ace->e_mask;
-+                      else if (nfs4ace_is_deny(ace))
-+                              acl->a_owner_mask &= ~ace->e_mask;
-+              } else if (nfs4ace_is_everyone(ace)) {
-+                      if (nfs4ace_is_allow(ace)) {
-+                              struct nfs4ace who = {
-+                                      .e_flags = ACE4_SPECIAL_WHO,
-+                                      .u.e_who = nfs4ace_group_who,
-+                              };
-+
-+                              acl->a_other_mask |= ace->e_mask;
-+                              acl->a_group_mask |=
-+                                      nfs4acl_allowed_to_who(acl, &who);
-+                              acl->a_owner_mask |= ace->e_mask;
-+                      } else if (nfs4ace_is_deny(ace)) {
-+                              acl->a_other_mask &= ~ace->e_mask;
-+                              acl->a_group_mask &= ~ace->e_mask;
-+                              acl->a_owner_mask &= ~ace->e_mask;
-+                      }
-+              } else {
-+                      if (nfs4ace_is_allow(ace)) {
-+                              unsigned int mask =
-+                                      nfs4acl_allowed_to_who(acl, ace);
-+
-+                              acl->a_group_mask |= mask;
-+                              acl->a_owner_mask |= mask;
-+                      }
-+              }
-+      }
-+}
-+
-+/**
-+ * nfs4acl_inherit  -  compute the acl a new file will inherit
-+ * @dir_acl:  acl of the containing direcory
-+ * @mode:     file type and create mode of the new file
-+ *
-+ * Given the containing directory's acl, this function will compute the
-+ * acl that new files in that directory will inherit, or %NULL if
-+ * @dir_acl does not contain acl entries inheritable by this file.
-+ *
-+ * Without write-through, the file masks in the returned acl are set to
-+ * the intersection of the create mode and the maximum permissions
-+ * allowed to each file class. With write-through, the file masks are
-+ * set to the create mode.
-+ */
-+struct nfs4acl *
-+nfs4acl_inherit(const struct nfs4acl *dir_acl, mode_t mode)
-+{
-+      const struct nfs4ace *dir_ace;
-+      struct nfs4acl *acl;
-+      struct nfs4ace *ace;
-+      int count = 0;
-+
-+      if (S_ISDIR(mode)) {
-+              nfs4acl_for_each_entry(dir_ace, dir_acl) {
-+                      if (!nfs4ace_is_inheritable(dir_ace))
-+                              continue;
-+                      count++;
-+              }
-+              if (!count)
-+                      return NULL;
-+              acl = nfs4acl_alloc(count);
-+              if (!acl)
-+                      return ERR_PTR(-ENOMEM);
-+              ace = acl->a_entries;
-+              nfs4acl_for_each_entry(dir_ace, dir_acl) {
-+                      if (!nfs4ace_is_inheritable(dir_ace))
-+                              continue;
-+                      memcpy(ace, dir_ace, sizeof(struct nfs4ace));
-+                      if (dir_ace->e_flags & ACE4_NO_PROPAGATE_INHERIT_ACE)
-+                              nfs4ace_clear_inheritance_flags(ace);
-+                      if ((dir_ace->e_flags & ACE4_FILE_INHERIT_ACE) &&
-+                          !(dir_ace->e_flags & ACE4_DIRECTORY_INHERIT_ACE))
-+                              ace->e_flags |= ACE4_INHERIT_ONLY_ACE;
-+                      ace++;
-+              }
-+      } else {
-+              nfs4acl_for_each_entry(dir_ace, dir_acl) {
-+                      if (!(dir_ace->e_flags & ACE4_FILE_INHERIT_ACE))
-+                              continue;
-+                      count++;
-+              }
-+              if (!count)
-+                      return NULL;
-+              acl = nfs4acl_alloc(count);
-+              if (!acl)
-+                      return ERR_PTR(-ENOMEM);
-+              ace = acl->a_entries;
-+              nfs4acl_for_each_entry(dir_ace, dir_acl) {
-+                      if (!(dir_ace->e_flags & ACE4_FILE_INHERIT_ACE))
-+                              continue;
-+                      memcpy(ace, dir_ace, sizeof(struct nfs4ace));
-+                      nfs4ace_clear_inheritance_flags(ace);
-+                      ace++;
-+              }
-+      }
-+
-+      /* The maximum max flags that the owner, group, and other classes
-+         are allowed. */
-+      if (dir_acl->a_flags & ACL4_WRITE_THROUGH) {
-+              acl->a_owner_mask = ACE4_VALID_MASK;
-+              acl->a_group_mask = ACE4_VALID_MASK;
-+              acl->a_other_mask = ACE4_VALID_MASK;
-+
-+              mode &= ~current->fs->umask;
-+      } else
-+              nfs4acl_compute_max_masks(acl);
-+
-+      /* Apply the create mode. */
-+      acl->a_owner_mask &= nfs4acl_mode_to_mask(mode >> 6);
-+      acl->a_group_mask &= nfs4acl_mode_to_mask(mode >> 3);
-+      acl->a_other_mask &= nfs4acl_mode_to_mask(mode);
-+
-+      if (nfs4acl_write_through(&acl)) {
-+              nfs4acl_put(acl);
-+              return ERR_PTR(-ENOMEM);
-+      }
-+
-+      acl->a_flags = (dir_acl->a_flags & ACL4_WRITE_THROUGH);
-+
-+      return acl;
-+}
-+EXPORT_SYMBOL(nfs4acl_inherit);
---- /dev/null
-+++ b/fs/nfs4acl_compat.c
-@@ -0,0 +1,757 @@
-+/*
-+ * 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/module.h>
-+#include <linux/fs.h>
-+#include <linux/nfs4acl.h>
-+
-+/**
-+ * struct nfs4acl_alloc  -  remember how many entries are actually allocated
-+ * @acl:      acl with a_count <= @count
-+ * @count:    the actual number of entries allocated in @acl
-+ *
-+ * We pass around this structure while modifying an acl, so that we do
-+ * not have to reallocate when we remove existing entries followed by
-+ * adding new entries.
-+ */
-+struct nfs4acl_alloc {
-+      struct nfs4acl *acl;
-+      unsigned int count;
-+};
-+
-+/**
-+ * nfs4acl_delete_entry  -  delete an entry in an acl
-+ * @x:                acl and number of allocated entries
-+ * @ace:      an entry in @x->acl
-+ *
-+ * Updates @ace so that it points to the entry before the deleted entry
-+ * on return. (When deleting the first entry, @ace will point to the
-+ * (non-existant) entry before the first entry). This behavior is the
-+ * expected behavior when deleting entries while forward iterating over
-+ * an acl.
-+ */
-+static void
-+nfs4acl_delete_entry(struct nfs4acl_alloc *x, struct nfs4ace **ace)
-+{
-+      void *end = x->acl->a_entries + x->acl->a_count;
-+
-+      memmove(*ace, *ace + 1, end - (void *)(*ace + 1));
-+      (*ace)--;
-+      x->acl->a_count--;
-+}
-+
-+/**
-+ * nfs4acl_insert_entry  -  insert an entry in an acl
-+ * @x:                acl and number of allocated entries
-+ * @ace:      entry before which the new entry shall be inserted
-+ *
-+ * Insert a new entry in @x->acl at position @ace, and zero-initialize
-+ * it.  This may require reallocating @x->acl.
-+ */
-+static int
-+nfs4acl_insert_entry(struct nfs4acl_alloc *x, struct nfs4ace **ace)
-+{
-+      if (x->count == x->acl->a_count) {
-+              int n = *ace - x->acl->a_entries;
-+              struct nfs4acl *acl2;
-+
-+              acl2 = nfs4acl_alloc(x->acl->a_count + 1);
-+              if (!acl2)
-+                      return -1;
-+              acl2->a_flags = x->acl->a_flags;
-+              acl2->a_owner_mask = x->acl->a_owner_mask;
-+              acl2->a_group_mask = x->acl->a_group_mask;
-+              acl2->a_other_mask = x->acl->a_other_mask;
-+              memcpy(acl2->a_entries, x->acl->a_entries,
-+                     n * sizeof(struct nfs4ace));
-+              memcpy(acl2->a_entries + n + 1, *ace,
-+                     (x->acl->a_count - n) * sizeof(struct nfs4ace));
-+              kfree(x->acl);
-+              x->acl = acl2;
-+              x->count = acl2->a_count;
-+              *ace = acl2->a_entries + n;
-+      } else {
-+              void *end = x->acl->a_entries + x->acl->a_count;
-+
-+              memmove(*ace + 1, *ace, end - (void *)*ace);
-+              x->acl->a_count++;
-+      }
-+      memset(*ace, 0, sizeof(struct nfs4ace));
-+      return 0;
-+}
-+
-+/**
-+ * nfs4ace_change_mask  -  change the mask in @ace to @mask
-+ * @x:                acl and number of allocated entries
-+ * @ace:      entry to modify
-+ * @mask:     new mask for @ace
-+ *
-+ * Set the effective mask of @ace to @mask. This will require splitting
-+ * off a separate acl entry if @ace is inheritable. In that case, the
-+ * effective- only acl entry is inserted after the inheritable acl
-+ * entry, end the inheritable acl entry is set to inheritable-only. If
-+ * @mode is 0, either set the original acl entry to inheritable-only if
-+ * it was inheritable, or remove it otherwise.  The returned @ace points
-+ * to the modified or inserted effective-only acl entry if that entry
-+ * exists, to the entry that has become inheritable-only, or else to the
-+ * previous entry in the acl. This is the expected behavior when
-+ * modifying masks while forward iterating over an acl.
-+ */
-+static int
-+nfs4ace_change_mask(struct nfs4acl_alloc *x, struct nfs4ace **ace,
-+                         unsigned int mask)
-+{
-+      if (mask && (*ace)->e_mask == mask)
-+              return 0;
-+      if (mask & ~ACE4_POSIX_ALWAYS_ALLOWED) {
-+              if (nfs4ace_is_inheritable(*ace)) {
-+                      if (nfs4acl_insert_entry(x, ace))
-+                              return -1;
-+                      memcpy(*ace, *ace + 1, sizeof(struct nfs4ace));
-+                      (*ace)->e_flags |= ACE4_INHERIT_ONLY_ACE;
-+                      (*ace)++;
-+                      nfs4ace_clear_inheritance_flags(*ace);
-+              }
-+              (*ace)->e_mask = mask;
-+      } else {
-+              if (nfs4ace_is_inheritable(*ace))
-+                      (*ace)->e_flags |= ACE4_INHERIT_ONLY_ACE;
-+              else
-+                      nfs4acl_delete_entry(x, ace);
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * nfs4acl_move_everyone_aces_down  -  move everyone@ acl entries to the end
-+ * @x:                acl and number of allocated entries
-+ *
-+ * Move all everyone acl entries to the bottom of the acl so that only a
-+ * single everyone@ allow acl entry remains at the end, and update the
-+ * mask fields of all acl entries on the way. If everyone@ is not
-+ * granted any permissions, no empty everyone@ acl entry is inserted.
-+ *
-+ * This transformation does not modify the permissions that the acl
-+ * grants, but we need it to simplify successive transformations.
-+ */
-+static int
-+nfs4acl_move_everyone_aces_down(struct nfs4acl_alloc *x)
-+{
-+      struct nfs4ace *ace;
-+      unsigned int allowed = 0, denied = 0;
-+
-+      nfs4acl_for_each_entry(ace, x->acl) {
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+              if (nfs4ace_is_everyone(ace)) {
-+                      if (nfs4ace_is_allow(ace))
-+                              allowed |= (ace->e_mask & ~denied);
-+                      else if (nfs4ace_is_deny(ace))
-+                              denied |= (ace->e_mask & ~allowed);
-+                      else
-+                              continue;
-+                      if (nfs4ace_change_mask(x, &ace, 0))
-+                              return -1;
-+              } else {
-+                      if (nfs4ace_is_allow(ace)) {
-+                              if (nfs4ace_change_mask(x, &ace, allowed |
-+                                              (ace->e_mask & ~denied)))
-+                                      return -1;
-+                      } else if (nfs4ace_is_deny(ace)) {
-+                              if (nfs4ace_change_mask(x, &ace, denied |
-+                                              (ace->e_mask & ~allowed)))
-+                                      return -1;
-+                      }
-+              }
-+      }
-+      if (allowed & ~ACE4_POSIX_ALWAYS_ALLOWED) {
-+              struct nfs4ace *last_ace = ace - 1;
-+
-+              if (nfs4ace_is_everyone(last_ace) &&
-+                  nfs4ace_is_allow(last_ace) &&
-+                  nfs4ace_is_inherit_only(last_ace) &&
-+                  last_ace->e_mask == allowed)
-+                      last_ace->e_flags &= ~ACE4_INHERIT_ONLY_ACE;
-+              else {
-+                      if (nfs4acl_insert_entry(x, &ace))
-+                              return -1;
-+                      ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
-+                      ace->e_flags = ACE4_SPECIAL_WHO;
-+                      ace->e_mask = allowed;
-+                      ace->u.e_who = nfs4ace_everyone_who;
-+              }
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * __nfs4acl_propagate_everyone  -  propagate everyone@ mask flags up for @who
-+ * @x:                acl and number of allocated entries
-+ * @who:      identifier to propagate mask flags for
-+ * @allow:    mask flags to propagate up
-+ *
-+ * Propagate mask flags from the trailing everyone@ allow acl entry up
-+ * for the specified @who.
-+ *
-+ * The idea here is to precede the trailing EVERYONE@ ALLOW entry by an
-+ * additional @who ALLOW entry, but with the following optimizations:
-+ * (1) we don't bother setting any flags in the new @who ALLOW entry
-+ * that has already been allowed or denied by a previous @who entry, (2)
-+ * we merge the new @who entry with a previous @who entry if there is
-+ * such a previous @who entry and there are no intervening DENY entries
-+ * with mask flags that overlap the flags we care about.
-+ */
-+static int
-+__nfs4acl_propagate_everyone(struct nfs4acl_alloc *x, struct nfs4ace *who,
-+                        unsigned int allow)
-+{
-+      struct nfs4ace *allow_last = NULL, *ace;
-+
-+      /* Remove the mask flags from allow that are already determined for
-+         this who value, and figure out if there is an ALLOW entry for
-+         this who value that is "reachable" from the trailing EVERYONE@
-+         ALLOW ACE. */
-+      nfs4acl_for_each_entry(ace, x->acl) {
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+              if (nfs4ace_is_allow(ace)) {
-+                      if (nfs4ace_is_same_who(ace, who)) {
-+                              allow &= ~ace->e_mask;
-+                              allow_last = ace;
-+                      }
-+              } else if (nfs4ace_is_deny(ace)) {
-+                      if (nfs4ace_is_same_who(ace, who))
-+                              allow &= ~ace->e_mask;
-+                      if (allow & ace->e_mask)
-+                              allow_last = NULL;
-+              }
-+      }
-+
-+      if (allow) {
-+              if (allow_last)
-+                      return nfs4ace_change_mask(x, &allow_last,
-+                                                 allow_last->e_mask | allow);
-+              else {
-+                      struct nfs4ace who_copy;
-+
-+                      ace = x->acl->a_entries + x->acl->a_count - 1;
-+                      memcpy(&who_copy, who, sizeof(struct nfs4ace));
-+                      if (nfs4acl_insert_entry(x, &ace))
-+                              return -1;
-+                      memcpy(ace, &who_copy, sizeof(struct nfs4ace));
-+                      ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
-+                      nfs4ace_clear_inheritance_flags(ace);
-+                      ace->e_mask = allow;
-+              }
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * nfs4acl_propagate_everyone  -  propagate everyone@ mask flags up the acl
-+ * @x:                acl and number of allocated entries
-+ *
-+ * Make sure for owner@, group@, and all other users, groups, and
-+ * special identifiers that they are allowed or denied all permissions
-+ * that are granted be the trailing everyone@ acl entry. If they are
-+ * not, try to add the missing permissions to existing allow acl entries
-+ * for those users, or introduce additional acl entries if that is not
-+ * possible.
-+ *
-+ * We do this so that no mask flags will get lost when finally applying
-+ * the file masks to the acl entries: otherwise, with an other file mask
-+ * that is more restrictive than the owner and/or group file mask, mask
-+ * flags that were allowed to processes in the owner and group classes
-+ * and that the other mask denies would be lost. For example, the
-+ * following two acls show the problem when mode 0664 is applied to
-+ * them:
-+ *
-+ *    masking without propagation (wrong)
-+ *    ===========================================================
-+ *    joe:r::allow            => joe:r::allow
-+ *    everyone@:rwx::allow    => everyone@:r::allow
-+ *    -----------------------------------------------------------
-+ *    joe:w::deny             => joe:w::deny
-+ *    everyone@:rwx::allow       everyone@:r::allow
-+ *
-+ * Note that the permissions of joe end up being more restrictive than
-+ * what the acl would allow when first computing the allowed flags and
-+ * then applying the respective mask. With propagation of permissions,
-+ * we get:
-+ *
-+ *    masking after propagation (correct)
-+ *    ===========================================================
-+ *    joe:r::allow            => joe:rw::allow
-+ *                               owner@:rw::allow
-+ *                               group@:rw::allow
-+ *    everyone@:rwx::allow       everyone@:r::allow
-+ *    -----------------------------------------------------------
-+ *    joe:w::deny             => owner@:x::deny
-+ *                               joe:w::deny
-+ *                               owner@:rw::allow
-+ *                               owner@:rw::allow
-+ *                               joe:r::allow
-+ *    everyone@:rwx::allow       everyone@:r::allow
-+ *
-+ * The examples show the acls that would result from propagation with no
-+ * masking performed. In fact, we do apply the respective mask to the
-+ * acl entries before computing the propagation because this will save
-+ * us from adding acl entries that would end up with empty mask fields
-+ * after applying the masks.
-+ *
-+ * It is ensured that no more than one entry will be inserted for each
-+ * who value, no matter how many entries each who value has already.
-+ */
-+static int
-+nfs4acl_propagate_everyone(struct nfs4acl_alloc *x)
-+{
-+      int write_through = (x->acl->a_flags & ACL4_WRITE_THROUGH);
-+      struct nfs4ace who = { .e_flags = ACE4_SPECIAL_WHO };
-+      struct nfs4ace *ace;
-+      unsigned int owner_allow, group_allow;
-+      int retval;
-+
-+      if (!((x->acl->a_owner_mask | x->acl->a_group_mask) &
-+            ~x->acl->a_other_mask))
-+              return 0;
-+      if (!x->acl->a_count)
-+              return 0;
-+      ace = x->acl->a_entries + x->acl->a_count - 1;
-+      if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_everyone(ace))
-+              return 0;
-+      if (!(ace->e_mask & ~x->acl->a_other_mask)) {
-+              /* None of the allowed permissions will get masked. */
-+              return 0;
-+      }
-+      owner_allow = ace->e_mask & x->acl->a_owner_mask;
-+      group_allow = ace->e_mask & x->acl->a_group_mask;
-+
-+      /* Propagate everyone@ permissions through to owner@. */
-+      if (owner_allow && !write_through &&
-+          (x->acl->a_owner_mask & ~x->acl->a_other_mask)) {
-+              who.u.e_who = nfs4ace_owner_who;
-+              retval = __nfs4acl_propagate_everyone(x, &who, owner_allow);
-+              if (retval)
-+                      return -1;
-+      }
-+
-+      if (group_allow && (x->acl->a_group_mask & ~x->acl->a_other_mask)) {
-+              int n;
-+
-+              if (!write_through) {
-+                      /* Propagate everyone@ permissions through to group@. */
-+                      who.u.e_who = nfs4ace_group_who;
-+                      retval = __nfs4acl_propagate_everyone(x, &who,
-+                                                            group_allow);
-+                      if (retval)
-+                              return -1;
-+              }
-+
-+              /* Start from the entry before the trailing EVERYONE@ ALLOW
-+                 entry. We will not hit EVERYONE@ entries in the loop. */
-+              for (n = x->acl->a_count - 2; n != -1; n--) {
-+                      ace = x->acl->a_entries + n;
-+
-+                      if (nfs4ace_is_inherit_only(ace) ||
-+                          nfs4ace_is_owner(ace) ||
-+                          nfs4ace_is_group(ace))
-+                              continue;
-+                      if (nfs4ace_is_allow(ace) || nfs4ace_is_deny(ace)) {
-+                              /* Any inserted entry will end up below the
-+                                 current entry. */
-+                              retval = __nfs4acl_propagate_everyone(x, ace,
-+                                                                 group_allow);
-+                              if (retval)
-+                                      return -1;
-+                      }
-+              }
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * __nfs4acl_apply_masks  -  apply the masks to the acl entries
-+ * @x:                acl and number of allocated entries
-+ *
-+ * Apply the owner file mask to owner@ entries, the intersection of the
-+ * group and other file masks to everyone@ entries, and the group file
-+ * mask to all other entries.
-+ */
-+static int
-+__nfs4acl_apply_masks(struct nfs4acl_alloc *x)
-+{
-+      struct nfs4ace *ace;
-+
-+      nfs4acl_for_each_entry(ace, x->acl) {
-+              unsigned int mask;
-+
-+              if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_allow(ace))
-+                      continue;
-+              if (nfs4ace_is_owner(ace))
-+                      mask = x->acl->a_owner_mask;
-+              else if (nfs4ace_is_everyone(ace))
-+                      mask = x->acl->a_other_mask;
-+              else
-+                      mask = x->acl->a_group_mask;
-+              if (nfs4ace_change_mask(x, &ace, ace->e_mask & mask))
-+                      return -1;
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * nfs4acl_max_allowed  -  maximum mask flags that anybody is allowed
-+ */
-+static unsigned int
-+nfs4acl_max_allowed(struct nfs4acl *acl)
-+{
-+      struct nfs4ace *ace;
-+      unsigned int allowed = 0;
-+
-+      nfs4acl_for_each_entry_reverse(ace, acl) {
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+              if (nfs4ace_is_allow(ace))
-+                      allowed |= ace->e_mask;
-+              else if (nfs4ace_is_deny(ace)) {
-+                      if (nfs4ace_is_everyone(ace))
-+                              allowed &= ~ace->e_mask;
-+              }
-+      }
-+      return allowed;
-+}
-+
-+/**
-+ * nfs4acl_isolate_owner_class  -  limit the owner class to the owner file mask
-+ * @x:                acl and number of allocated entries
-+ *
-+ * Make sure the owner class (owner@) is granted no more than the owner
-+ * mask by first checking which permissions anyone is granted, and then
-+ * denying owner@ all permissions beyond that.
-+ */
-+static int
-+nfs4acl_isolate_owner_class(struct nfs4acl_alloc *x)
-+{
-+      struct nfs4ace *ace;
-+      unsigned int allowed = 0;
-+
-+      allowed = nfs4acl_max_allowed(x->acl);
-+      if (allowed & ~x->acl->a_owner_mask) {
-+              /* Figure out if we can update an existig OWNER@ DENY entry. */
-+              nfs4acl_for_each_entry(ace, x->acl) {
-+                      if (nfs4ace_is_inherit_only(ace))
-+                              continue;
-+                      if (nfs4ace_is_deny(ace)) {
-+                              if (nfs4ace_is_owner(ace))
-+                                      break;
-+                      } else if (nfs4ace_is_allow(ace)) {
-+                              ace = x->acl->a_entries + x->acl->a_count;
-+                              break;
-+                      }
-+              }
-+              if (ace != x->acl->a_entries + x->acl->a_count) {
-+                      if (nfs4ace_change_mask(x, &ace, ace->e_mask |
-+                                      (allowed & ~x->acl->a_owner_mask)))
-+                              return -1;
-+              } else {
-+                      /* Insert an owner@ deny entry at the front. */
-+                      ace = x->acl->a_entries;
-+                      if (nfs4acl_insert_entry(x, &ace))
-+                              return -1;
-+                      ace->e_type = ACE4_ACCESS_DENIED_ACE_TYPE;
-+                      ace->e_flags = ACE4_SPECIAL_WHO;
-+                      ace->e_mask = allowed & ~x->acl->a_owner_mask;
-+                      ace->u.e_who = nfs4ace_owner_who;
-+              }
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * __nfs4acl_isolate_who  -  isolate entry from EVERYONE@ ALLOW entry
-+ * @x:                acl and number of allocated entries
-+ * @who:      identifier to isolate
-+ * @deny:     mask flags this identifier should not be allowed
-+ *
-+ * Make sure that @who is not allowed any mask flags in @deny by checking
-+ * which mask flags this identifier is allowed, and adding excess allowed
-+ * mask flags to an existing DENY entry before the trailing EVERYONE@ ALLOW
-+ * entry, or inserting such an entry.
-+ */
-+static int
-+__nfs4acl_isolate_who(struct nfs4acl_alloc *x, struct nfs4ace *who,
-+                    unsigned int deny)
-+{
-+      struct nfs4ace *ace;
-+      unsigned int allowed = 0, n;
-+
-+      /* Compute the mask flags granted to this who value. */
-+      nfs4acl_for_each_entry_reverse(ace, x->acl) {
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+              if (nfs4ace_is_same_who(ace, who)) {
-+                      if (nfs4ace_is_allow(ace))
-+                              allowed |= ace->e_mask;
-+                      else if (nfs4ace_is_deny(ace))
-+                              allowed &= ~ace->e_mask;
-+                      deny &= ~ace->e_mask;
-+              }
-+      }
-+      if (!deny)
-+              return 0;
-+
-+      /* Figure out if we can update an existig DENY entry.  Start
-+         from the entry before the trailing EVERYONE@ ALLOW entry. We
-+         will not hit EVERYONE@ entries in the loop. */
-+      for (n = x->acl->a_count - 2; n != -1; n--) {
-+              ace = x->acl->a_entries + n;
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+              if (nfs4ace_is_deny(ace)) {
-+                      if (nfs4ace_is_same_who(ace, who))
-+                              break;
-+              } else if (nfs4ace_is_allow(ace) &&
-+                         (ace->e_mask & deny)) {
-+                      n = -1;
-+                      break;
-+              }
-+      }
-+      if (n != -1) {
-+              if (nfs4ace_change_mask(x, &ace, ace->e_mask | deny))
-+                      return -1;
-+      } else {
-+              /* Insert a eny entry before the trailing EVERYONE@ DENY
-+                 entry. */
-+              struct nfs4ace who_copy;
-+
-+              ace = x->acl->a_entries + x->acl->a_count - 1;
-+              memcpy(&who_copy, who, sizeof(struct nfs4ace));
-+              if (nfs4acl_insert_entry(x, &ace))
-+                      return -1;
-+              memcpy(ace, &who_copy, sizeof(struct nfs4ace));
-+              ace->e_type = ACE4_ACCESS_DENIED_ACE_TYPE;
-+              nfs4ace_clear_inheritance_flags(ace);
-+              ace->e_mask = deny;
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * nfs4acl_isolate_group_class  -  limit the group class to the group file mask
-+ * @x:                acl and number of allocated entries
-+ *
-+ * Make sure the group class (all entries except owner@ and everyone@) is
-+ * granted no more than the group mask by inserting DENY entries for group
-+ * class entries where necessary.
-+ */
-+static int
-+nfs4acl_isolate_group_class(struct nfs4acl_alloc *x)
-+{
-+      struct nfs4ace who = {
-+              .e_flags = ACE4_SPECIAL_WHO,
-+              .u.e_who = nfs4ace_group_who,
-+      };
-+      struct nfs4ace *ace;
-+      unsigned int deny;
-+
-+      if (!x->acl->a_count)
-+              return 0;
-+      ace = x->acl->a_entries + x->acl->a_count - 1;
-+      if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_everyone(ace))
-+              return 0;
-+      deny = ace->e_mask & ~x->acl->a_group_mask;
-+
-+      if (deny) {
-+              unsigned int n;
-+
-+              if (__nfs4acl_isolate_who(x, &who, deny))
-+                      return -1;
-+
-+              /* Start from the entry before the trailing EVERYONE@ ALLOW
-+                 entry. We will not hit EVERYONE@ entries in the loop. */
-+              for (n = x->acl->a_count - 2; n != -1; n--) {
-+                      ace = x->acl->a_entries + n;
-+
-+                      if (nfs4ace_is_inherit_only(ace) ||
-+                          nfs4ace_is_owner(ace) ||
-+                          nfs4ace_is_group(ace))
-+                              continue;
-+                      if (__nfs4acl_isolate_who(x, ace, deny))
-+                              return -1;
-+              }
-+      }
-+      return 0;
-+}
-+
-+/**
-+ * __nfs4acl_write_through  -  grant the full masks to owner@, group@, everyone@
-+ *
-+ * Make sure that owner, group@, and everyone@ are allowed the full mask
-+ * permissions, and not only the permissions granted both by the acl and
-+ * the masks.
-+ */
-+static int
-+__nfs4acl_write_through(struct nfs4acl_alloc *x)
-+{
-+      struct nfs4ace *ace;
-+      unsigned int allowed;
-+
-+      /* Remove all owner@ and group@ ACEs: we re-insert them at the
-+         top. */
-+      nfs4acl_for_each_entry(ace, x->acl) {
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+              if ((nfs4ace_is_owner(ace) || nfs4ace_is_group(ace)) &&
-+                  nfs4ace_change_mask(x, &ace, 0))
-+                      return -1;
-+      }
-+
-+      /* Insert the everyone@ allow entry at the end, or update the
-+         existing entry. */
-+      allowed = x->acl->a_other_mask;
-+      if (allowed & ~ACE4_POSIX_ALWAYS_ALLOWED) {
-+              ace = x->acl->a_entries + x->acl->a_count - 1;
-+              if (x->acl->a_count && nfs4ace_is_everyone(ace) &&
-+                  !nfs4ace_is_inherit_only(ace)) {
-+                      if (nfs4ace_change_mask(x, &ace, allowed))
-+                              return -1;
-+              } else {
-+                      ace = x->acl->a_entries + x->acl->a_count;
-+                      if (nfs4acl_insert_entry(x, &ace))
-+                              return -1;
-+                      ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
-+                      ace->e_flags = ACE4_SPECIAL_WHO;
-+                      ace->e_mask = allowed;
-+                      ace->u.e_who = nfs4ace_everyone_who;
-+              }
-+      }
-+
-+      /* Compute the permissions that owner@ and group@ are already granted
-+         though the everyone@ allow entry at the end. Note that the acl
-+         contains no owner@ or group@ entries at this point. */
-+      allowed = 0;
-+      nfs4acl_for_each_entry_reverse(ace, x->acl) {
-+              if (nfs4ace_is_inherit_only(ace))
-+                      continue;
-+              if (nfs4ace_is_allow(ace)) {
-+                      if (nfs4ace_is_everyone(ace))
-+                              allowed |= ace->e_mask;
-+              } else if (nfs4ace_is_deny(ace))
-+                              allowed &= ~ace->e_mask;
-+      }
-+
-+      /* Insert the appropriate group@ allow entry at the front. */
-+      if (x->acl->a_group_mask & ~allowed) {
-+              ace = x->acl->a_entries;
-+              if (nfs4acl_insert_entry(x, &ace))
-+                      return -1;
-+              ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
-+              ace->e_flags = ACE4_SPECIAL_WHO;
-+              ace->e_mask = x->acl->a_group_mask /*& ~allowed*/;
-+              ace->u.e_who = nfs4ace_group_who;
-+      }
-+
-+      /* Insert the appropriate owner@ allow entry at the front. */
-+      if (x->acl->a_owner_mask & ~allowed) {
-+              ace = x->acl->a_entries;
-+              if (nfs4acl_insert_entry(x, &ace))
-+                      return -1;
-+              ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
-+              ace->e_flags = ACE4_SPECIAL_WHO;
-+              ace->e_mask = x->acl->a_owner_mask /*& ~allowed*/;
-+              ace->u.e_who = nfs4ace_owner_who;
-+      }
-+
-+      /* Insert the appropriate owner@ deny entry at the front. */
-+      allowed = nfs4acl_max_allowed(x->acl);
-+      if (allowed & ~x->acl->a_owner_mask) {
-+              nfs4acl_for_each_entry(ace, x->acl) {
-+                      if (nfs4ace_is_inherit_only(ace))
-+                              continue;
-+                      if (nfs4ace_is_allow(ace)) {
-+                              ace = x->acl->a_entries + x->acl->a_count;
-+                              break;
-+                      }
-+                      if (nfs4ace_is_deny(ace) && nfs4ace_is_owner(ace))
-+                              break;
-+              }
-+              if (ace != x->acl->a_entries + x->acl->a_count) {
-+                      if (nfs4ace_change_mask(x, &ace, ace->e_mask |
-+                                      (allowed & ~x->acl->a_owner_mask)))
-+                              return -1;
-+              } else {
-+                      ace = x->acl->a_entries;
-+                      if (nfs4acl_insert_entry(x, &ace))
-+                              return -1;
-+                      ace->e_type = ACE4_ACCESS_DENIED_ACE_TYPE;
-+                      ace->e_flags = ACE4_SPECIAL_WHO;
-+                      ace->e_mask = allowed & ~x->acl->a_owner_mask;
-+                      ace->u.e_who = nfs4ace_owner_who;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/**
-+ * nfs4acl_apply_masks  -  apply the masks to the acl
-+ *
-+ * Apply the masks so that the acl allows no more flags than the
-+ * intersection between the flags that the original acl allows and the
-+ * mask matching the process.
-+ *
-+ * Note: this algorithm may push the number of entries in the acl above
-+ * ACL4_XATTR_MAX_COUNT, so a read-modify-write cycle would fail.
-+ */
-+int
-+nfs4acl_apply_masks(struct nfs4acl **acl)
-+{
-+      struct nfs4acl_alloc x = {
-+              .acl = *acl,
-+              .count = (*acl)->a_count,
-+      };
-+      int retval = 0;
-+
-+      if (nfs4acl_move_everyone_aces_down(&x) ||
-+          nfs4acl_propagate_everyone(&x) ||
-+          __nfs4acl_apply_masks(&x) ||
-+          nfs4acl_isolate_owner_class(&x) ||
-+          nfs4acl_isolate_group_class(&x))
-+              retval = -ENOMEM;
-+
-+      *acl = x.acl;
-+      return retval;
-+}
-+EXPORT_SYMBOL(nfs4acl_apply_masks);
-+
-+int nfs4acl_write_through(struct nfs4acl **acl)
-+{
-+      struct nfs4acl_alloc x = {
-+              .acl = *acl,
-+              .count = (*acl)->a_count,
-+      };
-+      int retval = 0;
-+
-+      if (!((*acl)->a_flags & ACL4_WRITE_THROUGH))
-+              goto out;
-+
-+      if (nfs4acl_move_everyone_aces_down(&x) ||
-+          nfs4acl_propagate_everyone(&x) ||
-+          __nfs4acl_write_through(&x))
-+              retval = -ENOMEM;
-+
-+      *acl = x.acl;
-+out:
-+      return retval;
-+}
---- /dev/null
-+++ b/fs/nfs4acl_xattr.c
-@@ -0,0 +1,146 @@
-+/*
-+ * 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/slab.h>
-+#include <linux/module.h>
-+#include <linux/nfs4acl_xattr.h>
-+
-+MODULE_LICENSE("GPL");
-+
-+struct nfs4acl *
-+nfs4acl_from_xattr(const void *value, size_t size)
-+{
-+      const struct nfs4acl_xattr *xattr_acl = value;
-+      const struct nfs4ace_xattr *xattr_ace = (void *)(xattr_acl + 1);
-+      struct nfs4acl *acl;
-+      struct nfs4ace *ace;
-+      int count;
-+
-+      if (size < sizeof(struct nfs4acl_xattr) ||
-+          xattr_acl->a_version != ACL4_XATTR_VERSION ||
-+          (xattr_acl->a_flags & ~ACL4_VALID_FLAGS))
-+              return ERR_PTR(-EINVAL);
-+
-+      count = be16_to_cpu(xattr_acl->a_count);
-+      if (count > ACL4_XATTR_MAX_COUNT)
-+              return ERR_PTR(-EINVAL);
-+
-+      acl = nfs4acl_alloc(count);
-+      if (!acl)
-+              return ERR_PTR(-ENOMEM);
-+
-+      acl->a_flags = xattr_acl->a_flags;
-+      acl->a_owner_mask = be32_to_cpu(xattr_acl->a_owner_mask);
-+      if (acl->a_owner_mask & ~ACE4_VALID_MASK)
-+              goto fail_einval;
-+      acl->a_group_mask = be32_to_cpu(xattr_acl->a_group_mask);
-+      if (acl->a_group_mask & ~ACE4_VALID_MASK)
-+              goto fail_einval;
-+      acl->a_other_mask = be32_to_cpu(xattr_acl->a_other_mask);
-+      if (acl->a_other_mask & ~ACE4_VALID_MASK)
-+              goto fail_einval;
-+
-+      nfs4acl_for_each_entry(ace, acl) {
-+              const char *who = (void *)(xattr_ace + 1), *end;
-+              ssize_t used = (void *)who - value;
-+
-+              if (used > size)
-+                      goto fail_einval;
-+              end = memchr(who, 0, size - used);
-+              if (!end)
-+                      goto fail_einval;
-+
-+              ace->e_type = be16_to_cpu(xattr_ace->e_type);
-+              ace->e_flags = be16_to_cpu(xattr_ace->e_flags);
-+              ace->e_mask = be32_to_cpu(xattr_ace->e_mask);
-+              ace->u.e_id = be32_to_cpu(xattr_ace->e_id);
-+
-+              if (ace->e_flags & ~ACE4_VALID_FLAGS) {
-+                      memset(ace, 0, sizeof(struct nfs4ace));
-+                      goto fail_einval;
-+              }
-+              if (ace->e_type > ACE4_ACCESS_DENIED_ACE_TYPE ||
-+                  (ace->e_mask & ~ACE4_VALID_MASK))
-+                      goto fail_einval;
-+
-+              if (who == end) {
-+                      if (ace->u.e_id == -1)
-+                              goto fail_einval;  /* uid/gid needed */
-+              } else if (nfs4ace_set_who(ace, who))
-+                      goto fail_einval;
-+
-+              xattr_ace = (void *)who + ALIGN(end - who + 1, 4);
-+      }
-+
-+      return acl;
-+
-+fail_einval:
-+      nfs4acl_put(acl);
-+      return ERR_PTR(-EINVAL);
-+}
-+EXPORT_SYMBOL(nfs4acl_from_xattr);
-+
-+size_t
-+nfs4acl_xattr_size(const struct nfs4acl *acl)
-+{
-+      size_t size = sizeof(struct nfs4acl_xattr);
-+      const struct nfs4ace *ace;
-+
-+      nfs4acl_for_each_entry(ace, acl) {
-+              size += sizeof(struct nfs4ace_xattr) +
-+                      (nfs4ace_is_unix_id(ace) ? 4 :
-+                       ALIGN(strlen(ace->u.e_who) + 1, 4));
-+      }
-+      return size;
-+}
-+EXPORT_SYMBOL(nfs4acl_xattr_size);
-+
-+void
-+nfs4acl_to_xattr(const struct nfs4acl *acl, void *buffer)
-+{
-+      struct nfs4acl_xattr *xattr_acl = buffer;
-+      struct nfs4ace_xattr *xattr_ace;
-+      const struct nfs4ace *ace;
-+
-+      xattr_acl->a_version = ACL4_XATTR_VERSION;
-+      xattr_acl->a_flags = acl->a_flags;
-+      xattr_acl->a_count = cpu_to_be16(acl->a_count);
-+
-+      xattr_acl->a_owner_mask = cpu_to_be32(acl->a_owner_mask);
-+      xattr_acl->a_group_mask = cpu_to_be32(acl->a_group_mask);
-+      xattr_acl->a_other_mask = cpu_to_be32(acl->a_other_mask);
-+
-+      xattr_ace = (void *)(xattr_acl + 1);
-+      nfs4acl_for_each_entry(ace, acl) {
-+              xattr_ace->e_type = cpu_to_be16(ace->e_type);
-+              xattr_ace->e_flags = cpu_to_be16(ace->e_flags &
-+                      ACE4_VALID_FLAGS);
-+              xattr_ace->e_mask = cpu_to_be32(ace->e_mask);
-+              if (nfs4ace_is_unix_id(ace)) {
-+                      xattr_ace->e_id = cpu_to_be32(ace->u.e_id);
-+                      memset(xattr_ace->e_who, 0, 4);
-+                      xattr_ace = (void *)xattr_ace->e_who + 4;
-+              } else {
-+                      int sz = ALIGN(strlen(ace->u.e_who) + 1, 4);
-+
-+                      xattr_ace->e_id = cpu_to_be32(-1);
-+                      memset(xattr_ace->e_who + sz - 4, 0, 4);
-+                      strcpy(xattr_ace->e_who, ace->u.e_who);
-+                      xattr_ace = (void *)xattr_ace->e_who + sz;
-+              }
-+      }
-+}
-+EXPORT_SYMBOL(nfs4acl_to_xattr);
---- /dev/null
-+++ b/include/linux/nfs4acl.h
-@@ -0,0 +1,205 @@
-+#ifndef __NFS4ACL_H
-+#define __NFS4ACL_H
-+
-+struct nfs4ace {
-+      unsigned short  e_type;
-+      unsigned short  e_flags;
-+      unsigned int    e_mask;
-+      union {
-+              unsigned int    e_id;
-+              const char      *e_who;
-+      } u;
-+};
-+
-+struct nfs4acl {
-+      atomic_t        a_refcount;
-+      unsigned int    a_owner_mask;
-+      unsigned int    a_group_mask;
-+      unsigned int    a_other_mask;
-+      unsigned short  a_count;
-+      unsigned short  a_flags;
-+      struct nfs4ace  a_entries[0];
-+};
-+
-+#define nfs4acl_for_each_entry(_ace, _acl) \
-+      for (_ace = _acl->a_entries; \
-+           _ace != _acl->a_entries + _acl->a_count; \
-+           _ace++)
-+
-+#define nfs4acl_for_each_entry_reverse(_ace, _acl) \
-+      for (_ace = _acl->a_entries + _acl->a_count - 1; \
-+           _ace != _acl->a_entries - 1; \
-+           _ace--)
-+
-+/* a_flags values */
-+#define ACL4_WRITE_THROUGH            0x40
-+
-+#define ACL4_VALID_FLAGS \
-+      ACL4_WRITE_THROUGH
-+
-+/* e_type values */
-+#define ACE4_ACCESS_ALLOWED_ACE_TYPE  0x0000
-+#define ACE4_ACCESS_DENIED_ACE_TYPE   0x0001
-+/*#define ACE4_SYSTEM_AUDIT_ACE_TYPE  0x0002*/
-+/*#define ACE4_SYSTEM_ALARM_ACE_TYPE  0x0003*/
-+
-+/* e_flags bitflags */
-+#define ACE4_FILE_INHERIT_ACE         0x0001
-+#define ACE4_DIRECTORY_INHERIT_ACE    0x0002
-+#define ACE4_NO_PROPAGATE_INHERIT_ACE 0x0004
-+#define ACE4_INHERIT_ONLY_ACE         0x0008
-+/*#define ACE4_SUCCESSFUL_ACCESS_ACE_FLAG     0x0010*/
-+/*#define ACE4_FAILED_ACCESS_ACE_FLAG 0x0020*/
-+#define ACE4_IDENTIFIER_GROUP         0x0040
-+#define ACE4_SPECIAL_WHO              0x4000  /* in-memory representation only */
-+
-+#define ACE4_VALID_FLAGS ( \
-+      ACE4_FILE_INHERIT_ACE | \
-+      ACE4_DIRECTORY_INHERIT_ACE | \
-+      ACE4_NO_PROPAGATE_INHERIT_ACE | \
-+      ACE4_INHERIT_ONLY_ACE | \
-+      ACE4_IDENTIFIER_GROUP )
-+
-+/* e_mask bitflags */
-+#define ACE4_READ_DATA                        0x00000001
-+#define ACE4_LIST_DIRECTORY           0x00000001
-+#define ACE4_WRITE_DATA                       0x00000002
-+#define ACE4_ADD_FILE                 0x00000002
-+#define ACE4_APPEND_DATA              0x00000004
-+#define ACE4_ADD_SUBDIRECTORY         0x00000004
-+#define ACE4_READ_NAMED_ATTRS         0x00000008
-+#define ACE4_WRITE_NAMED_ATTRS                0x00000010
-+#define ACE4_EXECUTE                  0x00000020
-+#define ACE4_DELETE_CHILD             0x00000040
-+#define ACE4_READ_ATTRIBUTES          0x00000080
-+#define ACE4_WRITE_ATTRIBUTES         0x00000100
-+#define ACE4_DELETE                   0x00010000
-+#define ACE4_READ_ACL                 0x00020000
-+#define ACE4_WRITE_ACL                        0x00040000
-+#define ACE4_WRITE_OWNER              0x00080000
-+#define ACE4_SYNCHRONIZE              0x00100000
-+
-+#define ACE4_VALID_MASK ( \
-+      ACE4_READ_DATA | ACE4_LIST_DIRECTORY | \
-+      ACE4_WRITE_DATA | ACE4_ADD_FILE | \
-+      ACE4_APPEND_DATA | ACE4_ADD_SUBDIRECTORY | \
-+      ACE4_READ_NAMED_ATTRS | \
-+      ACE4_WRITE_NAMED_ATTRS | \
-+      ACE4_EXECUTE | \
-+      ACE4_DELETE_CHILD | \
-+      ACE4_READ_ATTRIBUTES | \
-+      ACE4_WRITE_ATTRIBUTES | \
-+      ACE4_DELETE | \
-+      ACE4_READ_ACL | \
-+      ACE4_WRITE_ACL | \
-+      ACE4_WRITE_OWNER | \
-+      ACE4_SYNCHRONIZE )
-+
-+#define ACE4_POSIX_ALWAYS_ALLOWED ( \
-+      ACE4_SYNCHRONIZE | \
-+      ACE4_READ_ATTRIBUTES | \
-+      ACE4_READ_ACL )
-+/*
-+ * Duplicate an NFS4ACL handle.
-+ */
-+static inline struct nfs4acl *
-+nfs4acl_get(struct nfs4acl *acl)
-+{
-+      if (acl)
-+              atomic_inc(&acl->a_refcount);
-+      return acl;
-+}
-+
-+/*
-+ * Free an NFS4ACL handle
-+ */
-+static inline void
-+nfs4acl_put(struct nfs4acl *acl)
-+{
-+      if (acl && atomic_dec_and_test(&acl->a_refcount))
-+              kfree(acl);
-+}
-+
-+/* Special e_who identifiers: we use these pointer values in comparisons
-+   instead of strcmp for efficiency. */
-+
-+extern const char nfs4ace_owner_who[];
-+extern const char nfs4ace_group_who[];
-+extern const char nfs4ace_everyone_who[];
-+
-+static inline int
-+nfs4ace_is_owner(const struct nfs4ace *ace)
-+{
-+      return (ace->e_flags & ACE4_SPECIAL_WHO) &&
-+             ace->u.e_who == nfs4ace_owner_who;
-+}
-+
-+static inline int
-+nfs4ace_is_group(const struct nfs4ace *ace)
-+{
-+      return (ace->e_flags & ACE4_SPECIAL_WHO) &&
-+             ace->u.e_who == nfs4ace_group_who;
-+}
-+
-+static inline int
-+nfs4ace_is_everyone(const struct nfs4ace *ace)
-+{
-+      return (ace->e_flags & ACE4_SPECIAL_WHO) &&
-+             ace->u.e_who == nfs4ace_everyone_who;
-+}
-+
-+static inline int
-+nfs4ace_is_unix_id(const struct nfs4ace *ace)
-+{
-+      return !(ace->e_flags & ACE4_SPECIAL_WHO);
-+}
-+
-+static inline int
-+nfs4ace_is_inherit_only(const struct nfs4ace *ace)
-+{
-+      return ace->e_flags & ACE4_INHERIT_ONLY_ACE;
-+}
-+
-+static inline int
-+nfs4ace_is_inheritable(const struct nfs4ace *ace)
-+{
-+      return ace->e_flags & (ACE4_FILE_INHERIT_ACE |
-+                             ACE4_DIRECTORY_INHERIT_ACE);
-+}
-+
-+static inline void
-+nfs4ace_clear_inheritance_flags(struct nfs4ace *ace)
-+{
-+      ace->e_flags &= ~(ACE4_FILE_INHERIT_ACE |
-+                        ACE4_DIRECTORY_INHERIT_ACE |
-+                        ACE4_NO_PROPAGATE_INHERIT_ACE |
-+                        ACE4_INHERIT_ONLY_ACE);
-+}
-+
-+static inline int
-+nfs4ace_is_allow(const struct nfs4ace *ace)
-+{
-+      return ace->e_type == ACE4_ACCESS_ALLOWED_ACE_TYPE;
-+}
-+
-+static inline int
-+nfs4ace_is_deny(const struct nfs4ace *ace)
-+{
-+      return ace->e_type == ACE4_ACCESS_DENIED_ACE_TYPE;
-+}
-+
-+extern struct nfs4acl *nfs4acl_alloc(int count);
-+extern struct nfs4acl *nfs4acl_clone(const struct nfs4acl *acl);
-+
-+extern unsigned int nfs4acl_want_to_mask(int want);
-+extern int nfs4acl_permission(struct inode *, const struct nfs4acl *, unsigned int);
-+extern int nfs4acl_generic_permission(struct inode *, unsigned int);
-+extern int nfs4ace_is_same_who(const struct nfs4ace *, const struct nfs4ace *);
-+extern int nfs4ace_set_who(struct nfs4ace *ace, const char *who);
-+extern struct nfs4acl *nfs4acl_inherit(const struct nfs4acl *, mode_t);
-+extern int nfs4acl_masks_to_mode(const struct nfs4acl *);
-+extern struct nfs4acl *nfs4acl_chmod(struct nfs4acl *, mode_t);
-+extern int nfs4acl_apply_masks(struct nfs4acl **acl);
-+extern int nfs4acl_write_through(struct nfs4acl **acl);
-+
-+#endif /* __NFS4ACL_H */
---- /dev/null
-+++ b/include/linux/nfs4acl_xattr.h
-@@ -0,0 +1,32 @@
-+#ifndef __NFS4ACL_XATTR_H
-+#define __NFS4ACL_XATTR_H
-+
-+#include <linux/nfs4acl.h>
-+
-+#define NFS4ACL_XATTR "system.nfs4acl"
-+
-+struct nfs4ace_xattr {
-+      __be16          e_type;
-+      __be16          e_flags;
-+      __be32          e_mask;
-+      __be32          e_id;
-+      char            e_who[0];
-+};
-+
-+struct nfs4acl_xattr {
-+      unsigned char   a_version;
-+      unsigned char   a_flags;
-+      __be16          a_count;
-+      __be32          a_owner_mask;
-+      __be32          a_group_mask;
-+      __be32          a_other_mask;
-+};
-+
-+#define ACL4_XATTR_VERSION    0
-+#define ACL4_XATTR_MAX_COUNT  1024
-+
-+extern struct nfs4acl *nfs4acl_from_xattr(const void *, size_t);
-+extern size_t nfs4acl_xattr_size(const struct nfs4acl *acl);
-+extern void nfs4acl_to_xattr(const struct nfs4acl *, void *);
-+
-+#endif /* __NFS4ACL_XATTR_H */