diff options
| author | Dave Chinner <dchinner@redhat.com> | 2013-06-05 12:09:10 +1000 | 
|---|---|---|
| committer | Ben Myers <bpm@sgi.com> | 2013-06-06 10:52:15 -0500 | 
| commit | 0a8aa1939777dd114479677f0044652c1fd72398 (patch) | |
| tree | 8ffde303c1bd382b421fc1d3a99b0be2f308caaf | |
| parent | f763fd440e094be37b38596ee14f1d64caa9bf9c (diff) | |
xfs: increase number of ACL entries for V5 superblocks
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 <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Mark Tinguely <tinuguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
(cherry picked from commit 5c87d4bc1a86bd6e6754ac3d6e111d776ddcfe57)
| -rw-r--r-- | fs/xfs/xfs_acl.c | 31 | ||||
| -rw-r--r-- | fs/xfs/xfs_acl.h | 31 | 
2 files changed, 42 insertions, 20 deletions
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 1d32f1d52763..306d883d89bc 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -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> @@ -34,7 +36,9 @@   */  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; @@ -42,7 +46,7 @@ xfs_acl_from_disk(struct xfs_acl *aclp)  	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); @@ -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) @@ -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); @@ -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; @@ -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); @@ -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); @@ -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) { diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 39632d941354..4016a567b83c 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h @@ -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"  | 
