Browse Source

xfs: fix memory allocation failures with ACLs

Ever since increasing the number of supported ACLs from 25 to as
many as can fit in an xattr, there have been reports of order 4
memory allocations failing in the ACL code. Fix it in the same way
we've fixed all the xattr read/write code that has the same problem.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Dave Chinner 12 năm trước cách đây
mục cha
commit
2dc164f296
1 tập tin đã thay đổi với 22 bổ sung10 xóa
  1. 22 10
      fs/xfs/xfs_acl.c

+ 22 - 10
fs/xfs/xfs_acl.c

@@ -152,9 +152,12 @@ xfs_get_acl(struct inode *inode, int type)
 	 * go out to the disk.
 	 * go out to the disk.
 	 */
 	 */
 	len = XFS_ACL_MAX_SIZE(ip->i_mount);
 	len = XFS_ACL_MAX_SIZE(ip->i_mount);
-	xfs_acl = kzalloc(len, GFP_KERNEL);
-	if (!xfs_acl)
-		return ERR_PTR(-ENOMEM);
+	xfs_acl = kmem_zalloc(len, KM_SLEEP | KM_MAYFAIL);
+	if (!xfs_acl) {
+		xfs_acl = kmem_zalloc_large(len);
+		if (!xfs_acl)
+			return ERR_PTR(-ENOMEM);
+	}
 
 
 	error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
 	error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
 							&len, ATTR_ROOT);
 							&len, ATTR_ROOT);
@@ -175,10 +178,13 @@ xfs_get_acl(struct inode *inode, int type)
 	if (IS_ERR(acl))
 	if (IS_ERR(acl))
 		goto out;
 		goto out;
 
 
- out_update_cache:
+out_update_cache:
 	set_cached_acl(inode, type, acl);
 	set_cached_acl(inode, type, acl);
- out:
-	kfree(xfs_acl);
+out:
+	if (is_vmalloc_addr(xfs_acl))
+		kmem_free_large(xfs_acl);
+	else
+		kfree(xfs_acl);
 	return acl;
 	return acl;
 }
 }
 
 
@@ -209,9 +215,12 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 		struct xfs_acl *xfs_acl;
 		struct xfs_acl *xfs_acl;
 		int len = XFS_ACL_MAX_SIZE(ip->i_mount);
 		int len = XFS_ACL_MAX_SIZE(ip->i_mount);
 
 
-		xfs_acl = kzalloc(len, GFP_KERNEL);
-		if (!xfs_acl)
-			return -ENOMEM;
+		xfs_acl = kmem_zalloc(len, KM_SLEEP | KM_MAYFAIL);
+		if (!xfs_acl) {
+			xfs_acl = kmem_zalloc_large(len);
+			if (!xfs_acl)
+				return -ENOMEM;
+		}
 
 
 		xfs_acl_to_disk(xfs_acl, acl);
 		xfs_acl_to_disk(xfs_acl, acl);
 
 
@@ -222,7 +231,10 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 		error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
 		error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
 				len, ATTR_ROOT);
 				len, ATTR_ROOT);
 
 
-		kfree(xfs_acl);
+		if (is_vmalloc_addr(xfs_acl))
+			kmem_free_large(xfs_acl);
+		else
+			kfree(xfs_acl);
 	} else {
 	} else {
 		/*
 		/*
 		 * A NULL ACL argument means we want to remove the ACL.
 		 * A NULL ACL argument means we want to remove the ACL.