Skip to content

Commit

Permalink
xfs: increase number of ACL entries for V5 superblocks
Browse files Browse the repository at this point in the history
The limit of 25 ACL entries is arbitrary, but baked into the on-disk
format.  For version 5 superblocks, increase it to the maximum nuber
of ACLs that can fit into a single xattr.

Signed-off-by: Dave Chinner <[email protected]>
Reviewed-by: Brian Foster <[email protected]>
Reviewed-by: Mark Tinguely <[email protected]>
Signed-off-by: Ben Myers <[email protected]>
  • Loading branch information
Dave Chinner authored and Ben Myers committed Jun 5, 2013
1 parent d3eaace commit 5c87d4b
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 20 deletions.
31 changes: 18 additions & 13 deletions fs/xfs/xfs_acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#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>
Expand All @@ -34,15 +36,17 @@
*/

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;
struct xfs_acl_entry *ace;
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);
Expand Down Expand Up @@ -108,9 +112,9 @@ xfs_get_acl(struct inode *inode, int type)
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)
Expand All @@ -133,8 +137,8 @@ xfs_get_acl(struct inode *inode, int type)
* 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);

Expand All @@ -153,7 +157,7 @@ xfs_get_acl(struct inode *inode, int type)
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;

Expand Down Expand Up @@ -189,16 +193,17 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)

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);
Expand Down Expand Up @@ -243,7 +248,7 @@ xfs_set_mode(struct inode *inode, umode_t mode)
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);
Expand Down Expand Up @@ -379,7 +384,7 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
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) {
Expand Down
31 changes: 24 additions & 7 deletions fs/xfs/xfs_acl.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,36 @@ struct inode;
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"
Expand Down

0 comments on commit 5c87d4b

Please sign in to comment.