#include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
 #include "xfs_vnodeops.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
 #include "xfs_trace.h"
 #include <linux/slab.h>
 #include <linux/xattr.h>
  */
 
 STATIC struct posix_acl *
-xfs_acl_from_disk(struct xfs_acl *aclp)
+xfs_acl_from_disk(
+       struct xfs_acl  *aclp,
+       int             max_entries)
 {
        struct posix_acl_entry *acl_e;
        struct posix_acl *acl;
        unsigned int count, i;
 
        count = be32_to_cpu(aclp->acl_cnt);
-       if (count > XFS_ACL_MAX_ENTRIES)
+       if (count > max_entries)
                return ERR_PTR(-EFSCORRUPTED);
 
        acl = posix_acl_alloc(count, GFP_KERNEL);
        struct xfs_inode *ip = XFS_I(inode);
        struct posix_acl *acl;
        struct xfs_acl *xfs_acl;
-       int len = sizeof(struct xfs_acl);
        unsigned char *ea_name;
        int error;
+       int len;
 
        acl = get_cached_acl(inode, type);
        if (acl != ACL_NOT_CACHED)
         * If we have a cached ACLs value just return it, not need to
         * go out to the disk.
         */
-
-       xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
+       len = XFS_ACL_MAX_SIZE(ip->i_mount);
+       xfs_acl = kzalloc(len, GFP_KERNEL);
        if (!xfs_acl)
                return ERR_PTR(-ENOMEM);
 
                goto out;
        }
 
-       acl = xfs_acl_from_disk(xfs_acl);
+       acl = xfs_acl_from_disk(xfs_acl, XFS_ACL_MAX_ENTRIES(ip->i_mount));
        if (IS_ERR(acl))
                goto out;
 
 
        if (acl) {
                struct xfs_acl *xfs_acl;
-               int len;
+               int len = XFS_ACL_MAX_SIZE(ip->i_mount);
 
-               xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
+               xfs_acl = kzalloc(len, GFP_KERNEL);
                if (!xfs_acl)
                        return -ENOMEM;
 
                xfs_acl_to_disk(xfs_acl, acl);
-               len = sizeof(struct xfs_acl) -
-                       (sizeof(struct xfs_acl_entry) *
-                        (XFS_ACL_MAX_ENTRIES - acl->a_count));
+
+               /* subtract away the unused acl entries */
+               len -= sizeof(struct xfs_acl_entry) *
+                        (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
 
                error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
                                len, ATTR_ROOT);
 static int
 xfs_acl_exists(struct inode *inode, unsigned char *name)
 {
-       int len = sizeof(struct xfs_acl);
+       int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb));
 
        return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
                            ATTR_ROOT|ATTR_KERNOVAL) == 0);
                goto out_release;
 
        error = -EINVAL;
-       if (acl->a_count > XFS_ACL_MAX_ENTRIES)
+       if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb)))
                goto out_release;
 
        if (type == ACL_TYPE_ACCESS) {
 
 struct posix_acl;
 struct xfs_inode;
 
-#define XFS_ACL_MAX_ENTRIES 25
 #define XFS_ACL_NOT_PRESENT (-1)
 
 /* On-disk XFS access control list structure */
+struct xfs_acl_entry {
+       __be32  ae_tag;
+       __be32  ae_id;
+       __be16  ae_perm;
+       __be16  ae_pad;         /* fill the implicit hole in the structure */
+};
+
 struct xfs_acl {
-       __be32          acl_cnt;
-       struct xfs_acl_entry {
-               __be32  ae_tag;
-               __be32  ae_id;
-               __be16  ae_perm;
-       } acl_entry[XFS_ACL_MAX_ENTRIES];
+       __be32                  acl_cnt;
+       struct xfs_acl_entry    acl_entry[0];
 };
 
+/*
+ * The number of ACL entries allowed is defined by the on-disk format.
+ * For v4 superblocks, that is limited to 25 entries. For v5 superblocks, it is
+ * limited only by the maximum size of the xattr that stores the information.
+ */
+#define XFS_ACL_MAX_ENTRIES(mp)        \
+       (xfs_sb_version_hascrc(&mp->m_sb) \
+               ?  (XATTR_SIZE_MAX - sizeof(struct xfs_acl)) / \
+                                               sizeof(struct xfs_acl_entry) \
+               : 25)
+
+#define XFS_ACL_MAX_SIZE(mp) \
+       (sizeof(struct xfs_acl) + \
+               sizeof(struct xfs_acl_entry) * XFS_ACL_MAX_ENTRIES((mp)))
+
 /* On-disk XFS extended attribute names */
 #define SGI_ACL_FILE           (unsigned char *)"SGI_ACL_FILE"
 #define SGI_ACL_DEFAULT                (unsigned char *)"SGI_ACL_DEFAULT"