Skip to contentSkip to conversation

Add extended attributes to ext2/3

RFC PATCH In review [email protected] 1 participant 1 message Oct 8, 2002

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

RFC PATCH 4/4 Add extended attributes to ext2/3

This is the fourth of four patches which add extended attribute support to the ext2 and ext3 filesystems. Please comment and bleed.

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.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
#

# fs/Config.help             |   24 
# fs/Config.in               |    5 
# fs/ext2/Makefile           |    4 
# fs/ext2/ext2.h             |    3 
# fs/ext2/file.c             |    4 
# fs/ext2/ialloc.c           |    1 
# fs/ext2/inode.c            |   38 -
# fs/ext2/namei.c            |   13 
# fs/ext2/super.c            |   24 
# fs/ext2/symlink.c          |   13 
# fs/ext2/xattr.c            | 1228 +++++++++++++++++++++++++++++++++++++++++++++
# fs/ext2/xattr_user.c       |  100 +++
# include/linux/ext2_fs.h    |   28 -
# include/linux/ext2_xattr.h |  157 +++++

#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/10/05 [email protected] 1.668
# Port of 0.8.50 xattr-ext2 to 2.5.
#
# Enable EA's by default.
# --------------------------------------------
#

fs/Config.help +24 -0
diff -Nru a/fs/Config.help b/fs/Config.help
@@ -123,6 +123,30 @@
   be compiled as a module, and so this could be dangerous.  Most
   everyone wants to say Y here.
 
+Ext2 extended attributes
+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.
+
+Ext2 extended attribute block sharing
+CONFIG_EXT2_FS_XATTR_SHARING
+  This options enables code for sharing identical extended attribute
+  blocks among multiple inodes.
+
+  Usually, say Y.
+
+Ext2 extended user attributes
+CONFIG_EXT2_FS_XATTR_USER
+  This option enables extended user attributes on ext2. Processes can
+  associate extended user attributes with inodes to store additional
+  information such as the character encoding of files, etc. (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 +5 -0
diff -Nru a/fs/Config.in b/fs/Config.in
@@ -97,6 +97,11 @@
 tristate 'ROM file system support' CONFIG_ROMFS_FS
 
 tristate 'Second extended fs support' CONFIG_EXT2_FS
+if [ "$CONFIG_EXT2_FS" != "n" ] ; then
+  define_tristate CONFIG_EXT2_FS_XATTR $CONFIG_EXT2_FS
+  define_bool CONFIG_EXT2_FS_XATTR_SHARING y
+  define_bool CONFIG_EXT2_FS_XATTR_USER y
+fi
 
 tristate 'System V/Xenix/V7/Coherent file system support' CONFIG_SYSV_FS
 
fs/ext2/Makefile +4 -0
diff -Nru a/fs/ext2/Makefile b/fs/ext2/Makefile
@@ -7,4 +7,8 @@
 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
+obj-$(CONFIG_EXT2_FS_XATTR) += xattr.o
+obj-$(CONFIG_EXT2_FS_XATTR_USER) += xattr_user.o
+
 include $(TOPDIR)/Rules.make
fs/ext2/ext2.h +3 -0
diff -Nru a/fs/ext2/ext2.h b/fs/ext2/ext2.h
@@ -1,5 +1,6 @@
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
+#include <linux/ext2_xattr.h>
 
 /*
  * second extended file system inode data in memory
@@ -110,6 +111,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 +4 -0
diff -Nru a/fs/ext2/file.c b/fs/ext2/file.c
@@ -53,4 +53,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 +1 -0
diff -Nru a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
@@ -97,6 +97,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 -16
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);
@@ -848,6 +858,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;
 
@@ -934,8 +946,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;
 
@@ -1029,9 +1040,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;
@@ -1040,15 +1049,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;
@@ -1080,11 +1091,6 @@
 	if (IS_ERR(raw_inode))
  		return -EIO;
 
-	if (ino == EXT2_ACL_IDX_INO || ino == EXT2_ACL_DATA_INO) {
-		ext2_error (sb, "ext2_write_inode", "bad inode number: %lu", 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 +12 -1
diff -Nru a/fs/ext2/namei.c b/fs/ext2/namei.c
@@ -162,7 +162,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 +368,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 +23 -1
diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c
@@ -131,6 +131,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;
 
@@ -233,6 +234,13 @@
 			continue;
 		if ((value = strchr (this_char, '=')) != NULL)
 			*value++ = 0;
+#ifdef CONFIG_EXT2_FS_XATTR_USER
+		if (!strcmp (this_char, "user_xattr"))
+			set_opt (*mount_options, XATTR_USER);
+		else if (!strcmp (this_char, "nouser_xattr"))
+			clear_opt (*mount_options, XATTR_USER);
+		else
+#endif
 		if (!strcmp (this_char, "bsddf"))
 			clear_opt (*mount_options, MINIX_DF);
 		else if (!strcmp (this_char, "nouid32")) {
@@ -487,6 +495,9 @@
 	 */
 
 	sbi->s_mount_opt = 0;
+#ifdef CONFIG_EXT2_FS_XATTR_USER
+	set_opt (EXT2_SB(sb)->s_mount_opt, XATTR_USER);
+#endif
 	if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
 	    &sbi->s_mount_opt))
 		goto failed_sbi;
@@ -883,7 +894,13 @@
 
 static int __init init_ext2_fs(void)
 {
-	int err = init_inodecache();
+	int err = init_ext2_xattr();
+	if (err)
+		return err;
+	err = init_ext2_xattr_user();
+	if (err)
+		goto out2;
+	err = init_inodecache();
 	if (err)
 		goto out1;
         err = register_filesystem(&ext2_fs_type);
@@ -893,6 +910,9 @@
 out:
 	destroy_inodecache();
 out1:
+	exit_ext2_xattr_user();
+out2:
+	exit_ext2_xattr();
 	return err;
 }
 
@@ -900,6 +920,8 @@
 {
 	unregister_filesystem(&ext2_fs_type);
 	destroy_inodecache();
+	exit_ext2_xattr_user();
+	exit_ext2_xattr();
 }
 
 module_init(init_ext2_fs)
fs/ext2/symlink.c +13 -0
diff -Nru a/fs/ext2/symlink.c b/fs/ext2/symlink.c
@@ -31,7 +31,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 +1228 -0

1,228 lines not on this page · raw message

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

100 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
@@ -475,7 +451,7 @@
 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008
 #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
 #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
include/linux/ext2_xattr.h new file +157 -0

157 lines not on this page · raw message