Skip to contentSkip to conversation

Add extended attributes to ext2/3

PATCH In review [email protected] 2 participants 3 messages Oct 15, 2002

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

PATCH 4/4 Add extended attributes to ext2/3

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.

- Ted

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

# fs/Config.help             |    7 
# fs/Config.in               |    1 
# fs/ext2/Makefile           |    6 
# 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            |   18 
# fs/ext2/symlink.c          |   13 
# fs/ext2/xattr.c            | 1208 ++++++++++++++++++++++++++++++++++++++++
# fs/ext2/xattr_user.c       |  100 +++
# include/linux/ext2_fs.h    |   28 -
# include/linux/ext2_xattr.h |  135 +++++

# 14 files changed, 1531 insertions(+), 44 deletions(-) #
# The following is the BitKeeper ChangeSet Log # --------------------------------------------
# 02/10/14 [email protected] 1.786
# Port of (bugfixed) 0.8.50 xattr-ext2 to 2.5 #
# -------------------------------------------- #

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
@@ -93,6 +93,7 @@
 tristate 'ROM file system support' CONFIG_ROMFS_FS
 
 tristate 'Second extended fs support' CONFIG_EXT2_FS
+dep_bool '  Ext2 extended attributes' CONFIG_EXT2_FS_XATTR $CONFIG_EXT3_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 +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
@@ -55,4 +55,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);
@@ -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;
 
@@ -1024,9 +1035,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;
@@ -1035,15 +1044,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;
@@ -1075,11 +1086,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 +17 -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
+		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
+	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,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);
@@ -893,6 +907,7 @@
 out:
 	destroy_inodecache();
 out1:
+	exit_ext2_xattr();
 	return err;
 }
 
@@ -900,6 +915,7 @@
 {
 	unregister_filesystem(&ext2_fs_type);
 	destroy_inodecache();
+	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 +1208 -0

1,208 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 +135 -0

135 lines not on this page · raw message

#1 lore raw
Quoted 4 lines · [email protected] writes:

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.in line 96

Quoted 8 lines

diff -Nru a/fs/Config.in b/fs/Config.in

fs/Config.in +1 -0
@@ -93,6 +93,7 @@
 tristate 'ROM file system support' CONFIG_ROMFS_FS
 
 tristate 'Second extended fs support' CONFIG_EXT2_FS
+dep_bool '  Ext2 extended attributes' CONFIG_EXT2_FS_XATTR $CONFIG_EXT3_FS
                                                                        ^^^

Is this intentional?

Regards, Olaf.

#2 lore raw
Quoted 10 lines · Olaf Dietsche

fs/Config.in line 96

Quoted 8 lines

diff -Nru a/fs/Config.in b/fs/Config.in

fs/Config.in +1 -0
@@ -93,6 +93,7 @@
 tristate 'ROM file system support' CONFIG_ROMFS_FS
 
 tristate 'Second extended fs support' CONFIG_EXT2_FS
+dep_bool '  Ext2 extended attributes' CONFIG_EXT2_FS_XATTR $CONFIG_EXT3_FS
                                                                        ^^^

Is this intentional?

Nope, that's a typo. Thanks for catching it.

- Ted