[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

More ACL item support



Hi, 

Right now XFS can only support 21 ACLs.  I've changed some code to make it 
support more ACL items.  Basically I change all the "acl" structure in the
ACL handling function to dynamically allocated pointers. 

But it seems that if the maximum ACL number is increased to a large number, 
say 1000, very strange problems will happen. Kernel becomes unstable, oops with
ACL related function.  If the number is set to 25(default), everything is fine.
No problems.  I don't see obvious errors in the XFS ACL code.  Are there any 
ideas why this happens?   Thanks.

The attachment is a patch which is based on XFS 1.0.1 release.

-- 
Best Regards,
Harrison
--- 2.4-xfs/fs/xfs/linux/xfs_iops.c.acl	Mon Oct 15 20:03:22 2001
+++ 2.4-xfs/fs/xfs/linux/xfs_iops.c	Mon May 27 11:28:46 2002
@@ -74,10 +74,14 @@
 	struct inode	*ip;
 	vattr_t		va;
 #ifdef CONFIG_FS_POSIX_ACL
-	struct acl	pdacl; /* parent default ACL */
+	struct acl	*pdacl; /* parent default ACL */
 #endif
 	int		have_default_acl;
 
+	ACL_ALLOC(pdacl);
+	if(!pdacl)
+		return -ENOMEM;
+
 	dvp = LINVFS_GET_VN_ADDRESS(dir);
 	ASSERT(dvp);
 
@@ -87,7 +91,7 @@
 	bzero(&va, sizeof(va));
 	va.va_mask = AT_TYPE|AT_MODE;
 	va.va_type = tp;
-	have_default_acl = _ACL_GET_DEFAULT(dvp, &pdacl);
+	have_default_acl = _ACL_GET_DEFAULT(dvp, pdacl);
         if (!have_default_acl) {
 	    mode &= ~current->fs->umask;
 	}
@@ -107,6 +111,7 @@
 
 		va.va_type = IFTOVT(mode);
 		if (va.va_type == VNON) {
+			ACL_FREE(pdacl);
 			return -EINVAL;
 		}
 		VOP_CREATE(dvp, (char *)dentry->d_name.name, &va, 0, 0, &vp,
@@ -123,6 +128,7 @@
 		ip = LINVFS_GET_IP(vp);
 		if (!ip) {
 			VN_RELE(vp);
+			ACL_FREE(pdacl);
 			return -ENOMEM;
 		}
 		if (ISVDEV(tp))
@@ -135,10 +141,12 @@
 	}
 
         if (!error && have_default_acl) {
-	    error = _ACL_INHERIT(vp, &va, &pdacl);
+	    error = _ACL_INHERIT(vp, &va, pdacl);
 	    VMODIFY(vp);
         }
 
+	ACL_FREE(pdacl);
+
 	return -error;
 }
 
--- 2.4-xfs/fs/xfs/linux/acl.h.acl	Mon May 27 11:29:14 2002
+++ 2.4-xfs/fs/xfs/linux/acl.h	Mon May 27 15:30:03 2002
@@ -59,7 +59,7 @@
  * (USER_OBJ, GROUP_OBJ, MASK, & OTHER_OBJ)
  */
 #define NACLBASE	4
-#define ACL_MAX_ENTRIES 25	/* Arbitrarily chosen number */
+#define ACL_MAX_ENTRIES 105	/* Arbitrarily chosen number */
 
 /*
  * Data types required by POSIX P1003.1eD15
@@ -83,6 +83,42 @@
 	struct acl_entry	acl_entry[ACL_MAX_ENTRIES];
 };
 
+#ifdef XFS_ACL_DEBUG
+static long acl_kmem = 0;
+	#define ACL_ALLOC(ptr)					\
+	do {								\
+		ptr = (struct acl *)kmalloc((size_t)sizeof(struct acl), GFP_KERNEL);		\
+		if (ptr == 0) {						\
+			printk(KERN_ERR "kmalloc returns 0 at %s:%d\n",	\
+			       __FILE__, __LINE__);			\
+		} else {						\
+			acl_kmem += sizeof(struct acl);				\
+			printk(KERN_INFO "acl_alloc %d, kmem %ld\n", 	\
+				(size_t)sizeof(struct acl), acl_kmem);		\
+		}							\
+	} while (0)
+
+	#define ACL_FREE(ptr)						\
+	do {								\
+		kfree((ptr));						\
+		acl_kmem -= sizeof(struct acl);					\
+		printk(KERN_INFO "acl_free %d, kmem %ld\n", 		\
+			(size_t)sizeof(struct acl), acl_kmem);			\
+	} while (0)
+
+#else
+	#define ACL_ALLOC(ptr)					\
+	do {								\
+		ptr = (struct acl *)kmalloc((size_t) sizeof(struct acl), GFP_KERNEL);		\
+	} while (0)
+
+	#define ACL_FREE(ptr)						\
+	do {								\
+		kfree((ptr));						\
+	} while (0)
+
+#endif /* XFS_ACL_DEBUG */
+
 /*
  * Values for acl_get_entry
  */
--- 2.4-xfs/fs/xfs/xfs_acl.c.acl	Mon Jul  9 14:16:12 2001
+++ 2.4-xfs/fs/xfs/xfs_acl.c	Mon May 27 11:28:46 2002
@@ -45,27 +45,40 @@
 int
 xfs_acl_iaccess( xfs_inode_t *ip, mode_t mode, cred_t *cr )
 {
-	struct acl acl;
+	struct acl *pacl;
+	int rc = 0;
+
+	ACL_ALLOC(pacl);
+	if(!pacl)
+		return ENOMEM;	/* XFS return positive errors */
 
 	/*
 	 * If the file has no ACL return -1.
 	 */
-	if (xfs_attr_fetch(ip, SGI_ACL_FILE, (char *)&acl, sizeof(struct acl)))
-		return -1;
-	xfs_acl_get_endian(&acl);
+	if (xfs_attr_fetch(ip, SGI_ACL_FILE, (char *)pacl, sizeof(struct acl))) {
+		rc = -1;
+		goto exit;
+	}
+	xfs_acl_get_endian(pacl);
 
 	/*
 	 * If the file has an empty ACL return -1.
 	 */
-	if (acl.acl_cnt == ACL_NOT_PRESENT)
-		return -1;
+	if (pacl->acl_cnt == ACL_NOT_PRESENT) {
+		rc = -1;
+		goto exit;
+	}
 
 	/*
 	 * Synchronize ACL with mode bits
 	 */
-	xfs_acl_sync_mode(ip->i_d.di_mode, &acl);
+	xfs_acl_sync_mode(ip->i_d.di_mode, pacl);
 
-	return xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, &acl, mode, cr);
+	rc = xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, pacl, mode, cr);
+
+exit:
+	ACL_FREE(pacl);
+	return rc;
 }
 
 /*
@@ -315,23 +328,31 @@
 xfs_acl_set_attr(vnode_t *vp, struct acl *aclp, int kind, int *error)
 {
     struct acl_entry *ace, *newace, *end;
-    struct acl newacl;
+    struct acl *pnewacl;
     int len = sizeof(struct acl);
 
+    ACL_ALLOC(pnewacl);
+    if(!pnewacl) {
+	    printk("Not enough memory!\n");
+	    return;
+    }
+
     /* do the endian conversion */ 
     /* loop thru ACEs of ACL */
     end = &aclp->acl_entry[0]+aclp->acl_cnt;
-    for (ace=&aclp->acl_entry[0],newace=&newacl.acl_entry[0]; ace < end; 
+    for (ace=&aclp->acl_entry[0],newace=&(pnewacl->acl_entry[0]); ace < end; 
          ace++,newace++) {
 	INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag);
 	INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id);
 	INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm);
     }
 
-    INT_SET(newacl.acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
+    INT_SET(pnewacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
 
     VOP_ATTR_SET(vp, kind==ACL_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT, 
-                 (char *)&newacl, len, ATTR_ROOT, sys_cred, *error);
+                 (char *)pnewacl, len, ATTR_ROOT, sys_cred, *error);
+
+    ACL_FREE(pnewacl);
 }
 
 STATIC int
@@ -383,7 +404,7 @@
 int
 xfs_acl_inherit(vnode_t *vp, vattr_t *vap, struct acl *pdaclp)
 {
-	struct acl cacl;
+	struct acl *pcacl;
 	int error = 0;
 
 	/*
@@ -395,6 +416,11 @@
 	if (pdaclp == NULL || xfs_acl_invalid(pdaclp))
 		return (0);
 
+	ACL_ALLOC(pcacl);
+	if(!pcacl) {
+		return ENOMEM;
+	}
+
 	/*
 	 * Copy the default ACL of the containing directory to
 	 * the access ACL of the new file and use the mode that
@@ -402,11 +428,11 @@
 	 * the u::,g::[m::], and o:: entries.  This is what makes
 	 * umask() "work" with ACL's.
 	 */
-        memcpy(&cacl, pdaclp, sizeof(cacl));
-	xfs_acl_filter_mode(vap->va_mode, &cacl);
+        memcpy(pcacl, pdaclp, sizeof(struct acl));
+	xfs_acl_filter_mode(vap->va_mode, pcacl);
 
 	/* set the mode to the acl */ 
-	xfs_acl_setmode(vp, &cacl);
+	xfs_acl_setmode(vp, pcacl);
 
 	/*
 	 * Set the default and access acl on the file.  The mode is already
@@ -420,9 +446,11 @@
 		xfs_acl_set_attr(vp, pdaclp, ACL_DEFAULT, &error);
 	}
 	if (!error) {
-		xfs_acl_set_attr(vp, &cacl, ACL_ACCESS, &error);
+		xfs_acl_set_attr(vp, pcacl, ACL_ACCESS, &error);
 	}
 
+	ACL_FREE(pcacl);
+	
 	return (error);
 }
 
@@ -430,11 +458,16 @@
 STATIC int
 xfs_acl_vget(vnode_t *vp, int kind, struct acl *acl)
 {
-	struct acl kacl;
-	int size = sizeof(kacl);
+	struct acl *pkacl;
+	int size = sizeof(struct acl);
 	int error = 0;
 	vattr_t	va;
 
+	ACL_ALLOC(pkacl);
+	if(!pkacl) {
+		return ENOMEM;
+	}
+
 #ifdef	SERIOUS_DEBUG
 	cmn_err(CE_NOTE, "xfs_acl_vget 0x%x %s 0x%x", vp, (kind == ACL_ACCESS) ? "ACCESS_ACL" : "DEFAULT_ACL", acl);
 #endif	/* SERIOUS_DEBUG */
@@ -442,10 +475,10 @@
 	/*
 	 * Get the ACL if there is one...
 	 */
-	memset(&kacl, 0, size);	/* Make sure we don't copyout random stack */
-	xfs_acl_get_attr(vp, &kacl, kind, &error);
+	memset(pkacl, 0, size);	/* Make sure we don't copyout random stack */
+	xfs_acl_get_attr(vp, pkacl, kind, &error);
 
-	if (!error && xfs_acl_invalid(&kacl)) {
+	if (!error && xfs_acl_invalid(pkacl)) {
 #ifdef	SERIOUS_DEBUG
 		cmn_err(CE_WARN, "Invalid acl fetched");
 #endif	/* SERIOUS_DEBUG */
@@ -466,13 +499,13 @@
 	 * ACL, then the ACL is deemed NOT PRESENT.
 	 */
 	if (error) {
-		kacl.acl_cnt = ACL_NOT_PRESENT;
+		pkacl->acl_cnt = ACL_NOT_PRESENT;
 	} else if (kind == ACL_ACCESS) {
 		/*
 		 * Synchronize an Access ACL with the mode before
 		 * copying it out.
 		 */
-		xfs_acl_sync_mode(va.va_mode, &kacl);
+		xfs_acl_sync_mode(va.va_mode, pkacl);
 	}
 
 
@@ -485,10 +518,13 @@
 	if (error == ENOATTR)
 		error = 0;
 
-	if (!error && copyout((caddr_t)&kacl, (caddr_t)acl,
+	if (!error && copyout((caddr_t)pkacl, (caddr_t)acl,
 			      sizeof(struct acl))) {
 		error = EFAULT;
 	}
+
+	ACL_FREE(pkacl);
+
 	return (error);
 }
 
@@ -593,19 +629,33 @@
 int
 xfs_acl_set(vnode_t *vp, struct acl *acl, struct acl *dacl)
 {
-	struct acl kacl;
-	struct acl kdacl;
+	struct acl *pkacl;
+	struct acl *pkdacl;
 	vattr_t va;
 	int error;
 
 	if (!acl && !dacl)
 		return (EINVAL);
-	if (acl && copy_from_user((caddr_t)&kacl, (caddr_t)acl, 
-	    sizeof (struct acl)))
-		return (EFAULT);
-	if (dacl && copy_from_user((caddr_t)&kdacl, (caddr_t)dacl, 
-	    sizeof (struct acl)))
-		return (EFAULT);
+	ACL_ALLOC(pkacl);
+	if(!pkacl) {
+		return ENOMEM;
+	}
+	ACL_ALLOC(pkdacl);
+	if(!pkdacl) {
+		ACL_FREE(pkacl);
+		return ENOMEM;
+	}
+	
+	if (acl && copy_from_user((caddr_t)pkacl, (caddr_t)acl, 
+	    sizeof (struct acl))) {
+		error = (EFAULT);
+		goto exit;
+	}
+	if (dacl && copy_from_user((caddr_t)pkdacl, (caddr_t)dacl, 
+	    sizeof (struct acl))) {
+		error = (EFAULT);
+		goto exit;
+	}
 
 	VN_HOLD(vp);
 
@@ -630,15 +680,20 @@
 			/*
 			 * Set the access ACL.
 			 */
-			error = xfs_acl_vset(vp, &kacl);
+			error = xfs_acl_vset(vp, pkacl);
 		if (!error && dacl)
 			/*
 			 * Set the default ACL.
 			 */
-			error = xfs_dacl_vset(vp, &kdacl);
+			error = xfs_dacl_vset(vp, pkdacl);
 	}
 
 	VN_RELE(vp);
+
+exit:
+	ACL_FREE(pkacl);
+	ACL_FREE(pkdacl);
+
 	return (error);
 }