Skip to contentSkip to conversation

6/11 Ext2/3 Updates: Extended attributes, ACL, etc.

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

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 6/11 Ext2/3 Updates: Extended attributes, ACL, etc.

Port of (bugfixed) 0.8.50 xattr-ext2 to 2.5 (w/ hch cleanups. mbcache API)

This patch adds extended attribute support to the ext2 filesystem. This uses the generic extended attribute patch which was developed by Andreas Gruenbacher and the XFS team. As a result, the user space utilities which work for XFS will also work with these patches.

fs/Config.help          |    7 
fs/Config.in            |    1 
fs/ext2/Makefile        |    6 
fs/ext2/ext2.h          |    2 
fs/ext2/file.c          |    7 
fs/ext2/ialloc.c        |    4 
fs/ext2/inode.c         |   39 -
fs/ext2/namei.c         |   16 
fs/ext2/super.c         |   20 
fs/ext2/symlink.c       |   14 
fs/ext2/xattr.c         | 1118 ++++++++++++++++++++++++++++++++++++++++++++++++
fs/ext2/xattr.h         |  135 +++++
fs/ext2/xattr_user.c    |  102 ++++
include/linux/ext2_fs.h |   28 -
14 files changed, 1450 insertions(+), 49 deletions(-)
fs/Config.help +7 -0
diff -Nru a/fs/Config.help b/fs/Config.help
@@ -123,6 +123,13 @@
   be compiled as a module, and so this could be dangerous.  Most
   everyone wants to say Y here.
 
+CONFIG_EXT2_FS_XATTR
+  Extended attributes are name:value pairs associated with inodes by
+  the kernel or by users (see the attr(5) manual page, or visit
+  <http://acl.bestbits.at/> for details).
+
+  If unsure, say N.
+
 CONFIG_EXT3_FS
   This is the journaling version of the Second extended file system
   (often called ext3), the de facto standard Linux file system
fs/Config.in +1 -0
diff -Nru a/fs/Config.in b/fs/Config.in
@@ -96,6 +96,7 @@
 tristate 'ROM file system support' CONFIG_ROMFS_FS
 
 tristate 'Second extended fs support' CONFIG_EXT2_FS
+dep_mbool '  Ext2 extended attributes' CONFIG_EXT2_FS_XATTR $CONFIG_EXT2_FS
 
 tristate 'System V/Xenix/V7/Coherent file system support' CONFIG_SYSV_FS
 
fs/ext2/Makefile +6 -0
diff -Nru a/fs/ext2/Makefile b/fs/ext2/Makefile
@@ -7,4 +7,10 @@
 ext2-objs := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
 	     ioctl.o namei.o super.o symlink.o
 
+export-objs += xattr.o
+
+ifeq ($(CONFIG_EXT2_FS_XATTR),y)
+ext2-objs += xattr.o xattr_user.o
+endif
+
 include $(TOPDIR)/Rules.make
fs/ext2/ext2.h +2 -0
diff -Nru a/fs/ext2/ext2.h b/fs/ext2/ext2.h
@@ -117,6 +117,8 @@
 
 /* namei.c */
 extern struct inode_operations ext2_dir_inode_operations;
+extern struct inode_operations ext2_special_inode_operations;
 
 /* symlink.c */
 extern struct inode_operations ext2_fast_symlink_inode_operations;
+extern struct inode_operations ext2_symlink_inode_operations;
fs/ext2/file.c +6 -1
diff -Nru a/fs/ext2/file.c b/fs/ext2/file.c
@@ -18,8 +18,9 @@
  * 	([email protected])
  */
 
-#include "ext2.h"
 #include <linux/time.h>
+#include "ext2.h"
+#include "xattr.h"
 
 /*
  * Called when an inode is released. Note that this is different
@@ -55,4 +56,8 @@
 
 struct inode_operations ext2_file_inode_operations = {
 	.truncate	= ext2_truncate,
+	.setxattr	= ext2_setxattr,
+	.getxattr	= ext2_getxattr,
+	.listxattr	= ext2_listxattr,
+	.removexattr	= ext2_removexattr,
 };
fs/ext2/ialloc.c +3 -1
diff -Nru a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
@@ -13,11 +13,12 @@
  */
 
 #include <linux/config.h>
-#include "ext2.h"
 #include <linux/quotaops.h>
 #include <linux/sched.h>
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>
+#include "ext2.h"
+#include "xattr.h"
 
 /*
  * ialloc.c contains the inodes allocation and deallocation routines
@@ -97,6 +98,7 @@
 	 */
 	if (!is_bad_inode(inode)) {
 		/* Quota is already initialized in iput() */
+		ext2_xattr_delete_inode(inode);
 	    	DQUOT_FREE_INODE(inode);
 		DQUOT_DROP(inode);
 	}
fs/ext2/inode.c +22 -17
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
@@ -39,6 +39,18 @@
 static int ext2_update_inode(struct inode * inode, int do_sync);
 
 /*
+ * Test whether an inode is a fast symlink.
+ */
+static inline int ext2_inode_is_fast_symlink(struct inode *inode)
+{
+	int ea_blocks = EXT2_I(inode)->i_file_acl ?
+		(inode->i_sb->s_blocksize >> 9) : 0;
+
+	return (S_ISLNK(inode->i_mode) &&
+		inode->i_blocks - ea_blocks == 0);
+}
+
+/*
  * Called at each iput()
  */
 void ext2_put_inode (struct inode * inode)
@@ -51,9 +63,7 @@
  */
 void ext2_delete_inode (struct inode * inode)
 {
-	if (is_bad_inode(inode) ||
-	    inode->i_ino == EXT2_ACL_IDX_INO ||
-	    inode->i_ino == EXT2_ACL_DATA_INO)
+	if (is_bad_inode(inode))
 		goto no_delete;
 	EXT2_I(inode)->i_dtime	= CURRENT_TIME;
 	mark_inode_dirty(inode);
@@ -843,6 +853,8 @@
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	    S_ISLNK(inode->i_mode)))
 		return;
+	if (ext2_inode_is_fast_symlink(inode))
+		return;
 	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
 		return;
 
@@ -929,8 +941,7 @@
 	struct ext2_group_desc * gdp;
 
 	*p = NULL;
-	if ((ino != EXT2_ROOT_INO && ino != EXT2_ACL_IDX_INO &&
-	     ino != EXT2_ACL_DATA_INO && ino < EXT2_FIRST_INO(sb)) ||
+	if ((ino != EXT2_ROOT_INO && ino < EXT2_FIRST_INO(sb)) ||
 	    ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count))
 		goto Einval;
 
@@ -1026,9 +1037,7 @@
 	for (n = 0; n < EXT2_N_BLOCKS; n++)
 		ei->i_data[n] = raw_inode->i_block[n];
 
-	if (ino == EXT2_ACL_IDX_INO || ino == EXT2_ACL_DATA_INO)
-		/* Nothing to do */ ;
-	else if (S_ISREG(inode->i_mode)) {
+	if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &ext2_file_inode_operations;
 		inode->i_fop = &ext2_file_operations;
 		inode->i_mapping->a_ops = &ext2_aops;
@@ -1037,15 +1046,17 @@
 		inode->i_fop = &ext2_dir_operations;
 		inode->i_mapping->a_ops = &ext2_aops;
 	} else if (S_ISLNK(inode->i_mode)) {
-		if (!inode->i_blocks)
+		if (ext2_inode_is_fast_symlink(inode))
 			inode->i_op = &ext2_fast_symlink_inode_operations;
 		else {
-			inode->i_op = &page_symlink_inode_operations;
+			inode->i_op = &ext2_symlink_inode_operations;
 			inode->i_mapping->a_ops = &ext2_aops;
 		}
-	} else 
+	} else {
+		inode->i_op = &ext2_special_inode_operations;
 		init_special_inode(inode, inode->i_mode,
 				   le32_to_cpu(raw_inode->i_block[0]));
+	}
 	brelse (bh);
 	if (ei->i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
@@ -1082,12 +1093,6 @@
 	if (ei->i_state & EXT2_STATE_NEW)
 		memset(raw_inode, 0, EXT2_SB(sb)->s_inode_size);
 
-	if (ino == EXT2_ACL_IDX_INO || ino == EXT2_ACL_DATA_INO) {
-		ext2_error (sb, "ext2_write_inode", "bad inode number: %lu",
-			    (unsigned long) ino);
-		brelse(bh);
-		return -EIO;
-	}
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
 	if (!(test_opt(sb, NO_UID32))) {
 		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
fs/ext2/namei.c +14 -2
diff -Nru a/fs/ext2/namei.c b/fs/ext2/namei.c
@@ -29,8 +29,9 @@
  *        David S. Miller ([email protected]), 1995
  */
 
-#include "ext2.h"
 #include <linux/pagemap.h>
+#include "ext2.h"
+#include "xattr.h"
 
 /*
  * Couple of helper functions - make the code slightly cleaner.
@@ -162,7 +163,7 @@
 
 	if (l > sizeof (EXT2_I(inode)->i_data)) {
 		/* slow symlink */
-		inode->i_op = &page_symlink_inode_operations;
+		inode->i_op = &ext2_symlink_inode_operations;
 		inode->i_mapping->a_ops = &ext2_aops;
 		err = page_symlink(inode, symname, l);
 		if (err)
@@ -368,4 +369,15 @@
 	.rmdir		= ext2_rmdir,
 	.mknod		= ext2_mknod,
 	.rename		= ext2_rename,
+	.setxattr	= ext2_setxattr,
+	.getxattr	= ext2_getxattr,
+	.listxattr	= ext2_listxattr,
+	.removexattr	= ext2_removexattr,
+};
+
+struct inode_operations ext2_special_inode_operations = {
+	.setxattr	= ext2_setxattr,
+	.getxattr	= ext2_getxattr,
+	.listxattr	= ext2_listxattr,
+	.removexattr	= ext2_removexattr,
 };
fs/ext2/super.c +18 -2
diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c
@@ -19,7 +19,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
-#include "ext2.h"
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
@@ -27,6 +26,8 @@
 #include <linux/buffer_head.h>
 #include <linux/smp_lock.h>
 #include <asm/uaccess.h>
+#include "ext2.h"
+#include "xattr.h"
 
 
 static void ext2_sync_super(struct super_block *sb,
@@ -127,6 +128,7 @@
 	int i;
 	struct ext2_sb_info *sbi = EXT2_SB(sb);
 
+	ext2_xattr_put_super(sb);
 	if (!(sb->s_flags & MS_RDONLY)) {
 		struct ext2_super_block *es = sbi->s_es;
 
@@ -278,6 +280,13 @@
 			continue;
 		if ((value = strchr (this_char, '=')) != NULL)
 			*value++ = 0;
+#ifdef CONFIG_EXT2_FS_XATTR
+		if (!strcmp (this_char, "user_xattr"))
+			set_opt (sbi->s_mount_opt, XATTR_USER);
+		else if (!strcmp (this_char, "nouser_xattr"))
+			clear_opt (sbi->s_mount_opt, XATTR_USER);
+		else
+#endif
 		if (!strcmp (this_char, "bsddf"))
 			clear_opt (sbi->s_mount_opt, MINIX_DF);
 		else if (!strcmp (this_char, "nouid32")) {
@@ -560,6 +569,8 @@
 		set_opt(sbi->s_mount_opt, GRPID);
 	if (def_mount_opts & EXT2_DEFM_UID16)
 		set_opt(sbi->s_mount_opt, NO_UID32);
+	if (def_mount_opts & EXT2_DEFM_XATTR_USER)
+		set_opt(sbi->s_mount_opt, XATTR_USER);
 	
 	if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC)
 		set_opt(sbi->s_mount_opt, ERRORS_PANIC);
@@ -917,7 +928,10 @@
 
 static int __init init_ext2_fs(void)
 {
-	int err = init_inodecache();
+	int err = init_ext2_xattr();
+	if (err)
+		return err;
+	err = init_inodecache();
 	if (err)
 		goto out1;
         err = register_filesystem(&ext2_fs_type);
@@ -927,6 +941,7 @@
 out:
 	destroy_inodecache();
 out1:
+	exit_ext2_xattr();
 	return err;
 }
 
@@ -934,6 +949,7 @@
 {
 	unregister_filesystem(&ext2_fs_type);
 	destroy_inodecache();
+	exit_ext2_xattr();
 }
 
 module_init(init_ext2_fs)
fs/ext2/symlink.c +14 -0
diff -Nru a/fs/ext2/symlink.c b/fs/ext2/symlink.c
@@ -18,6 +18,7 @@
  */
 
 #include "ext2.h"
+#include "xattr.h"
 
 static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
@@ -31,7 +32,20 @@
 	return vfs_follow_link(nd, (char *)ei->i_data);
 }
 
+struct inode_operations ext2_symlink_inode_operations = {
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link,
+	.setxattr	= ext2_setxattr,
+	.getxattr	= ext2_getxattr,
+	.listxattr	= ext2_listxattr,
+	.removexattr	= ext2_removexattr,
+};
+ 
 struct inode_operations ext2_fast_symlink_inode_operations = {
 	.readlink	= ext2_readlink,
 	.follow_link	= ext2_follow_link,
+	.setxattr	= ext2_setxattr,
+	.getxattr	= ext2_getxattr,
+	.listxattr	= ext2_listxattr,
+	.removexattr	= ext2_removexattr,
 };
fs/ext2/xattr.c new file +1118 -0

1,118 lines not on this page · raw message

fs/ext2/xattr.h new file +135 -0

135 lines not on this page · raw message

fs/ext2/xattr_user.c new file +102 -0

102 lines not on this page · raw message

include/linux/ext2_fs.h +2 -26
diff -Nru a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
@@ -58,8 +58,6 @@
  */
 #define	EXT2_BAD_INO		 1	/* Bad blocks inode */
 #define EXT2_ROOT_INO		 2	/* Root inode */
-#define EXT2_ACL_IDX_INO	 3	/* ACL inode */
-#define EXT2_ACL_DATA_INO	 4	/* ACL inode */
 #define EXT2_BOOT_LOADER_INO	 5	/* Boot loader inode */
 #define EXT2_UNDEL_DIR_INO	 6	/* Undelete directory inode */
 
@@ -99,7 +97,6 @@
 #else
 # define EXT2_BLOCK_SIZE(s)		(EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
 #endif
-#define EXT2_ACLE_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
 #define	EXT2_ADDR_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (__u32))
 #ifdef __KERNEL__
 # define EXT2_BLOCK_SIZE_BITS(s)	((s)->s_blocksize_bits)
@@ -134,28 +131,6 @@
 #endif
 
 /*
- * ACL structures
- */
-struct ext2_acl_header	/* Header of Access Control Lists */
-{
-	__u32	aclh_size;
-	__u32	aclh_file_count;
-	__u32	aclh_acle_count;
-	__u32	aclh_first_acle;
-};
-
-struct ext2_acl_entry	/* Access Control List Entry */
-{
-	__u32	acle_size;
-	__u16	acle_perms;	/* Access permissions */
-	__u16	acle_type;	/* Type of entry */
-	__u16	acle_tag;	/* User or group identity */
-	__u16	acle_pad1;
-	__u32	acle_next;	/* Pointer on next entry for the */
-					/* same inode or on next free entry */
-};
-
-/*
  * Structure of a blocks group descriptor
  */
 struct ext2_group_desc
@@ -332,6 +307,7 @@
 #define EXT2_MOUNT_ERRORS_PANIC		0x0040	/* Panic on errors */
 #define EXT2_MOUNT_MINIX_DF		0x0080	/* Mimics the Minix statfs */
 #define EXT2_MOUNT_NO_UID32		0x0200  /* Disable 32-bit UIDs */
+#define EXT2_MOUNT_XATTR_USER		0x4000	/* Extended user attributes */
 
 #define clear_opt(o, opt)		o &= ~EXT2_MOUNT_##opt
 #define set_opt(o, opt)			o |= EXT2_MOUNT_##opt
@@ -489,7 +465,7 @@
 #define EXT2_FEATURE_INCOMPAT_META_BG		0x0010
 #define EXT2_FEATURE_INCOMPAT_ANY		0xffffffff
 
-#define EXT2_FEATURE_COMPAT_SUPP	0
+#define EXT2_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR
 #define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE| \
 					 EXT2_FEATURE_INCOMPAT_META_BG)
 #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \