Skip to contentSkip to conversation

Posix ACL support for ext 2/3 filesystems

PATCH New [email protected] 1 participant 1 message Oct 17, 2002 VFS

lore
Share & tools
lore
#0 lore raw

PATCH 4/5 Posix ACL support for ext 2/3 filesystems

This patch adds ACL support to the ext3 filesystem.

- Ted

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.800 -> 1.801
# include/linux/ext3_fs_i.h 1.3 -> 1.4

#	    fs/ext3/Makefile	1.5     -> 1.6    
#	fs/ext3/xattr_user.c	1.1     -> 1.2    
#	    fs/ext3/ialloc.c	1.18    -> 1.19   
#	     fs/ext3/xattr.c	1.1     -> 1.2    
#	     fs/ext3/namei.c	1.23    -> 1.24   
#	include/linux/ext3_fs.h	1.12    -> 1.13   
#	        fs/Config.in	1.43    -> 1.44   
#	     fs/ext3/inode.c	1.43    -> 1.44   
#	      fs/Config.help	1.23    -> 1.24   
#	     fs/ext3/super.c	1.34    -> 1.35   
#	      fs/ext3/file.c	1.10    -> 1.11   
#	               (new)	        -> 1.1     fs/ext3/acl.c  
#	               (new)	        -> 1.1     fs/ext3/acl.h  

#
# The following is the BitKeeper ChangeSet Log # --------------------------------------------
# 02/10/16 [email protected] 1.801
# Port of (bugfixed) 0.8.50 acl-ext3 to 2.5. #
# This patch adds ACL support to the ext3 filesystem. # -------------------------------------------- #

fs/Config.help +11 -0
diff -Nru a/fs/Config.help b/fs/Config.help
@@ -166,7 +166,18 @@
   the kernel or by users (see the attr(5) manual page, or visit
   <http://acl.bestbits.at/> for details).
 
+  You need this for POSIX ACL support on ext3.
+
   If unsure, say N.
+
+CONFIG_EXT3_FS_POSIX_ACL
+  Posix Access Control Lists (ACLs) support permissions for users and
+  groups beyond the owner/group/world scheme.
+
+  To learn more about Access Control Lists, visit the Posix ACLs for
+  Linux website <http://acl.bestbits.at/>.
+
+  If you don't know what Access Control Lists are, say N.
 
 CONFIG_JBD
   This is a generic journaling layer for block devices.  It is
fs/Config.in +1 -0
diff -Nru a/fs/Config.in b/fs/Config.in
@@ -28,6 +28,7 @@
 
 tristate 'Ext3 journalling file system support' CONFIG_EXT3_FS
 dep_mbool '  Ext3 extended attributes' CONFIG_EXT3_FS_XATTR $CONFIG_EXT3_FS
+dep_mbool '  Ext3 POSIX Access Control Lists' CONFIG_EXT3_FS_POSIX_ACL $CONFIG_EXT3_FS_XATTR $CONFIG_FS_POSIX_ACL
 # CONFIG_JBD could be its own option (even modular), but until there are
 # other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS
 # dep_tristate '  Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS
fs/ext3/Makefile +4 -0
diff -Nru a/fs/ext3/Makefile b/fs/ext3/Makefile
@@ -13,4 +13,8 @@
 ext3-objs += xattr.o xattr_user.o
 endif
 
+ifeq ($(CONFIG_EXT3_FS_POSIX_ACL),y)
+ext3-objs += acl.o
+endif
+
 include $(TOPDIR)/Rules.make
fs/ext3/acl.c new file +584 -0

584 lines not on this page · raw message

fs/ext3/acl.h new file +91 -0

91 lines not on this page · raw message

fs/ext3/file.c +2 -0
diff -Nru a/fs/ext3/file.c b/fs/ext3/file.c
@@ -24,6 +24,7 @@
 #include <linux/ext3_fs.h>
 #include <linux/ext3_jbd.h>
 #include "xattr.h"
+#include "acl.h"
 
 /*
  * Called when an inode is released. Note that this is different
@@ -102,5 +103,6 @@
 	.getxattr	= ext3_getxattr,
 	.listxattr	= ext3_listxattr,
 	.removexattr	= ext3_removexattr,
+	.permission	= ext3_permission,
 };
 
fs/ext3/ialloc.c +23 -9
diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
@@ -26,6 +26,7 @@
 #include <asm/byteorder.h>
 
 #include "xattr.h"
+#include "acl.h"
 
 /*
  * ialloc.c contains the inodes allocation and deallocation routines
@@ -423,20 +424,27 @@
 	inode->i_generation = EXT3_SB(sb)->s_next_generation++;
 
 	ei->i_state = EXT3_STATE_NEW;
-	err = ext3_mark_inode_dirty(handle, inode);
-	if (err) goto fail;
-	
+
 	unlock_super(sb);
 	ret = inode;
 	if(DQUOT_ALLOC_INODE(inode)) {
 		DQUOT_DROP(inode);
-		inode->i_flags |= S_NOQUOTA;
-		inode->i_nlink = 0;
-		iput(inode);
-		ret = ERR_PTR(-EDQUOT);
-	} else {
-		ext3_debug("allocating inode %lu\n", inode->i_ino);
+		err = -EDQUOT;
+		goto fail2;
 	}
+	err = ext3_init_acl(handle, inode, dir);
+	if (err) {
+		DQUOT_FREE_INODE(inode);
+		goto fail2;
+  	}
+	err = ext3_mark_inode_dirty(handle, inode);
+	if (err) {
+		ext3_std_error(sb, err);
+		DQUOT_FREE_INODE(inode);
+		goto fail2;
+	}
+
+	ext3_debug("allocating inode %lu\n", inode->i_ino);
 	goto really_out;
 fail:
 	ext3_std_error(sb, err);
@@ -447,6 +455,12 @@
 really_out:
 	brelse(bitmap_bh);
 	return ret;
+
+fail2:
+	inode->i_flags |= S_NOQUOTA;
+	inode->i_nlink = 0;
+	iput(inode);
+	return ERR_PTR(err);
 }
 
 /* Verify that we are loading a valid orphan from disk */
fs/ext3/inode.c +24 -8
diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c
@@ -34,6 +34,8 @@
 #include <linux/string.h>
 #include <linux/buffer_head.h>
 #include <linux/mpage.h>
+#include "xattr.h"
+#include "acl.h"
 
 /*
  * SEARCH_FROM_ZERO forces each block allocation to search from the start
@@ -2199,7 +2201,11 @@
 	struct buffer_head *bh;
 	int block;
 	
-	if(ext3_get_inode_loc(inode, &iloc))
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+	ei->i_acl = EXT3_ACL_NOT_CACHED;
+	ei->i_default_acl = EXT3_ACL_NOT_CACHED;
+#endif
+	if (ext3_get_inode_loc(inode, &iloc))
 		goto bad_inode;
 	bh = iloc.bh;
 	raw_inode = iloc.raw_inode;
@@ -2495,13 +2501,8 @@
  * be freed, so we have a strong guarantee that no future commit will
  * leave these blocks visible to the user.)  
  *
- * This is only needed for regular files.  rmdir() has its own path, and
- * we can never truncate a direcory except on final unlink (at which
- * point i_nlink is zero so recovery is easy.)
- *
- * Called with the BKL.  
+ * Called with inode->sem down.
  */
-
 int ext3_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = dentry->d_inode;
@@ -2521,7 +2522,8 @@
 
 	lock_kernel();
 
-	if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
+	if (S_ISREG(inode->i_mode) &&
+	    attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
 		handle_t *handle;
 
 		handle = ext3_journal_start(inode, 3);
@@ -2545,6 +2547,20 @@
 	 * orphan list manually. */
 	if (inode->i_nlink)
 		ext3_orphan_del(NULL, inode);
+
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+	if (!rc && test_opt(inode->i_sb, POSIX_ACL) && (ia_valid & ATTR_MODE)) {
+		handle_t *handle;
+
+		handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
+		if (IS_ERR(handle)) {
+			error = PTR_ERR(handle);
+			goto err_out;
+		}
+		rc = ext3_acl_chmod(handle, inode);
+		error = ext3_journal_stop(handle, inode);
+	}
+#endif
 
 err_out:
 	ext3_std_error(inode->i_sb, error);
fs/ext3/namei.c +9 -2
diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c
@@ -37,7 +37,7 @@
 #include <linux/buffer_head.h>
 #include <linux/smp_lock.h>
 #include "xattr.h"
-
+#include "acl.h"
 
 /*
  * define how far ahead to read directories while searching them.
@@ -1624,7 +1624,10 @@
 	inode = ext3_new_inode (handle, dir, mode);
 	err = PTR_ERR(inode);
 	if (!IS_ERR(inode)) {
-		init_special_inode(inode, mode, rdev);
+		init_special_inode(inode, inode->i_mode, rdev);
+#ifdef CONFIG_EXT3_FS_XATTR
+		inode->i_op = &ext3_special_inode_operations;
+#endif
 		err = ext3_add_nondir(handle, dentry, inode);
 		ext3_mark_inode_dirty(handle, inode);
 	}
@@ -2281,17 +2284,21 @@
 	.rmdir		= ext3_rmdir,
 	.mknod		= ext3_mknod,
 	.rename		= ext3_rename,
+	.setattr	= ext3_setattr,
 	.setxattr	= ext3_setxattr,	
 	.getxattr	= ext3_getxattr,	
 	.listxattr	= ext3_listxattr,	
 	.removexattr	= ext3_removexattr,
+	.permission	= ext3_permission,
 };
 
 struct inode_operations ext3_special_inode_operations = {
+	.setattr	= ext3_setattr,
 	.setxattr	= ext3_setxattr,
 	.getxattr	= ext3_getxattr,
 	.listxattr	= ext3_listxattr,
 	.removexattr	= ext3_removexattr,
+	.permission	= ext3_permission,
 };
 
  
fs/ext3/super.c +39 -0
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
@@ -31,6 +31,7 @@
 #include <linux/buffer_head.h>
 #include <asm/uaccess.h>
 #include "xattr.h"
+#include "acl.h"
 
 #ifdef CONFIG_JBD_DEBUG
 static int ext3_ro_after; /* Make fs read-only after this many jiffies */
@@ -458,6 +459,10 @@
 	ei = kmem_cache_alloc(ext3_inode_cachep, SLAB_NOFS);
 	if (!ei)
 		return NULL;
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+	ei->i_acl = EXT3_ACL_NOT_CACHED;
+	ei->i_default_acl = EXT3_ACL_NOT_CACHED;
+#endif
 	return &ei->vfs_inode;
 }
 
@@ -495,6 +500,26 @@
 		printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n");
 }
 
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+
+static void ext3_clear_inode(struct inode *inode)
+{
+       if (EXT3_I(inode)->i_acl &&
+           EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
+               posix_acl_release(EXT3_I(inode)->i_acl);
+               EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED;
+       }
+       if (EXT3_I(inode)->i_default_acl &&
+           EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) {
+               posix_acl_release(EXT3_I(inode)->i_default_acl);
+               EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
+       }
+}
+
+#else
+# define ext3_clear_inode NULL
+#endif
+
 static struct super_operations ext3_sops = {
 	.alloc_inode	= ext3_alloc_inode,
 	.destroy_inode	= ext3_destroy_inode,
@@ -509,6 +534,7 @@
 	.unlockfs	= ext3_unlockfs,		/* BKL not held.  We take it */
 	.statfs		= ext3_statfs,		/* BKL not held. */
 	.remount_fs	= ext3_remount,		/* BKL held */
+	.clear_inode	= ext3_clear_inode,	/* BKL not needed. */
 };
 
 struct dentry *ext3_get_parent(struct dentry *child);
@@ -576,6 +602,13 @@
 			clear_opt (*mount_options, XATTR_USER);
 		else
 #endif
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+		if (!strcmp(this_char, "acl"))
+			set_opt (*mount_options, POSIX_ACL);
+		else if (!strcmp(this_char, "noacl"))
+			clear_opt (*mount_options, POSIX_ACL);
+		else
+#endif
 		if (!strcmp (this_char, "bsddf"))
 			clear_opt (*mount_options, MINIX_DF);
 		else if (!strcmp (this_char, "nouid32")) {
@@ -1001,6 +1034,9 @@
 	if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0))
 		goto out_fail;
 
+	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+		((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+
 	blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE);
 
 	/*
@@ -1719,6 +1755,9 @@
 
 	if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
 		ext3_abort(sb, __FUNCTION__, "Abort forced by user");
+
+	sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+		((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
 
 	es = sbi->s_es;
 
fs/ext3/xattr.c +19 -4
diff -Nru a/fs/ext3/xattr.c b/fs/ext3/xattr.c
@@ -61,6 +61,7 @@
 #include <linux/quotaops.h>
 #include <asm/semaphore.h>
 #include "xattr.h"
+#include "acl.h"
 
 #define EXT3_EA_USER "user."
 
@@ -1105,15 +1106,27 @@
 	err = ext3_xattr_register(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler);
 	if (err)
 		return err;
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+	err = init_ext3_acl();
+	if (err)
+		goto out;
+#endif
 	ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL,
 		sizeof(struct mb_cache_entry) +
 		sizeof(struct mb_cache_entry_index), 1, 6);
 	if (!ext3_xattr_cache) {
-		ext3_xattr_unregister(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler);
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto out1;
 	}
-
 	return 0;
+out1:
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+	exit_ext3_acl();
+out:
+#endif
+	ext3_xattr_unregister(EXT3_XATTR_INDEX_USER,
+			      &ext3_xattr_user_handler);
+	return err;
 }
 
 void
@@ -1122,6 +1135,8 @@
 	if (ext3_xattr_cache)
 		mb_cache_destroy(ext3_xattr_cache);
 	ext3_xattr_cache = NULL;
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+	exit_ext3_acl();
+#endif
 	ext3_xattr_unregister(EXT3_XATTR_INDEX_USER, &ext3_xattr_user_handler);
 }
-
fs/ext3/xattr_user.c +1 -4
diff -Nru a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c
@@ -12,10 +12,7 @@
 #include <linux/ext3_jbd.h>
 #include <linux/ext3_fs.h>
 #include "xattr.h"
-
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-# include <linux/ext3_acl.h>
-#endif
+#include "acl.h"
 
 #define XATTR_USER_PREFIX "user."
 
include/linux/ext3_fs.h +1 -0
diff -Nru a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
@@ -323,6 +323,7 @@
 #define EXT3_MOUNT_UPDATE_JOURNAL	0x1000	/* Update the journal format */
 #define EXT3_MOUNT_NO_UID32		0x2000  /* Disable 32-bit UIDs */
 #define EXT3_MOUNT_XATTR_USER		0x4000	/* Extended user attributes */
+#define EXT3_MOUNT_POSIX_ACL		0x8000	/* POSIX Access Control Lists */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
include/linux/ext3_fs_i.h +4 -0
diff -Nru a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
@@ -41,6 +41,10 @@
 	__u32	i_prealloc_count;
 #endif
 	__u32	i_dir_start_lookup;
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
+	struct posix_acl	*i_acl;
+	struct posix_acl	*i_default_acl;
+#endif
 	
 	struct list_head i_orphan;	/* unlinked but open inodes */