Skip to contentSkip to conversation

Add extended attributes to ext2/3

PATCH In review [email protected] 1 participant 1 message Oct 15, 2002 VFS

lore
Share & tools
lore
#0 lore raw

PATCH 3/4 Add extended attributes to ext2/3

This patch adds extended attribute support to the ext3 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/ext3/Makefile           |    6 
# fs/ext3/file.c             |    5 
# fs/ext3/ialloc.c           |    2 
# fs/ext3/inode.c            |   35 -
# fs/ext3/namei.c            |   22 
# fs/ext3/super.c            |   23 
# fs/ext3/symlink.c          |   16 
# fs/ext3/xattr.c            | 1191 ++++++++++++++++++++++++++++++++++++++++
# fs/ext3/xattr_user.c       |   99 +++
# include/linux/ext3_fs.h    |   31 -
# include/linux/ext3_jbd.h   |    8 
# include/linux/ext3_xattr.h |  137 +++++

# 14 files changed, 1535 insertions(+), 48 deletions(-) #
# The following is the BitKeeper ChangeSet Log # --------------------------------------------
# 02/10/14 [email protected] 1.785
# Port of (bugfixed) 0.8.50 xattr-ext3 to 2.5. #
# -------------------------------------------- #

fs/Config.help +7 -0
diff -Nru a/fs/Config.help b/fs/Config.help
@@ -154,6 +154,13 @@
   of your root partition (the one containing the directory /) cannot
   be compiled as a module, and so this may be dangerous.
 
+CONFIG_EXT3_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_JBD
   This is a generic journaling layer for block devices.  It is
   currently used by the ext3 file system, but it could also be used to
fs/Config.in +1 -0
diff -Nru a/fs/Config.in b/fs/Config.in
@@ -27,6 +27,7 @@
 dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL
 
 tristate 'Ext3 journalling file system support' CONFIG_EXT3_FS
+dep_bool '  Ext3 extended attributes' CONFIG_EXT3_FS_XATTR $CONFIG_EXT3_FS
 # 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 +6 -0
diff -Nru a/fs/ext3/Makefile b/fs/ext3/Makefile
@@ -7,4 +7,10 @@
 ext3-objs    := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
 		ioctl.o namei.o super.o symlink.o hash.o
 
+export-objs += xattr.o
+
+ifeq ($(CONFIG_EXT3_FS_XATTR),y)
+ext3-objs += xattr.o xattr_user.o
+endif
+
 include $(TOPDIR)/Rules.make
fs/ext3/file.c +5 -0
diff -Nru a/fs/ext3/file.c b/fs/ext3/file.c
@@ -22,6 +22,7 @@
 #include <linux/fs.h>
 #include <linux/jbd.h>
 #include <linux/ext3_fs.h>
+#include <linux/ext3_xattr.h>
 #include <linux/ext3_jbd.h>
 #include <linux/smp_lock.h>
 
@@ -98,5 +99,9 @@
 struct inode_operations ext3_file_inode_operations = {
 	.truncate	= ext3_truncate,
 	.setattr	= ext3_setattr,
+	.setxattr	= ext3_setxattr,
+	.getxattr	= ext3_getxattr,
+	.listxattr	= ext3_listxattr,
+	.removexattr	= ext3_removexattr,
 };
 
fs/ext3/ialloc.c +2 -0
diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
@@ -17,6 +17,7 @@
 #include <linux/jbd.h>
 #include <linux/ext3_fs.h>
 #include <linux/ext3_jbd.h>
+#include <linux/ext3_xattr.h>
 #include <linux/stat.h>
 #include <linux/string.h>
 #include <linux/quotaops.h>
@@ -118,6 +119,7 @@
 	 * as writing the quota to disk may need the lock as well.
 	 */
 	DQUOT_INIT(inode);
+	ext3_xattr_delete_inode(handle, inode);
 	DQUOT_FREE_INODE(inode);
 	DQUOT_DROP(inode);
 
fs/ext3/inode.c +22 -13
diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c
@@ -42,6 +42,18 @@
  */
 #undef SEARCH_FROM_ZERO
 
+/*
+ * Test whether an inode is a fast symlink.
+ */
+static inline int ext3_inode_is_fast_symlink(struct inode *inode)
+{
+	int ea_blocks = EXT3_I(inode)->i_file_acl ?
+		(inode->i_sb->s_blocksize >> 9) : 0;
+
+	return (S_ISLNK(inode->i_mode) &&
+		inode->i_blocks - ea_blocks == 0);
+}
+
 /* The ext3 forget function must perform a revoke if we are freeing data
  * which has been journaled.  Metadata (eg. indirect blocks) must be
  * revoked in all cases. 
@@ -51,7 +63,7 @@
  * still needs to be revoked.
  */
 
-static int ext3_forget(handle_t *handle, int is_metadata,
+int ext3_forget(handle_t *handle, int is_metadata,
 		       struct inode *inode, struct buffer_head *bh,
 		       int blocknr)
 {
@@ -167,9 +179,7 @@
 {
 	handle_t *handle;
 	
-	if (is_bad_inode(inode) ||
-	    inode->i_ino == EXT3_ACL_IDX_INO ||
-	    inode->i_ino == EXT3_ACL_DATA_INO)
+	if (is_bad_inode(inode))
 		goto no_delete;
 
 	lock_kernel();
@@ -1979,6 +1989,8 @@
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	    S_ISLNK(inode->i_mode)))
 		return;
+	if (ext3_inode_is_fast_symlink(inode))
+		return;
 	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
 		return;
 
@@ -2130,8 +2142,6 @@
 	struct ext3_group_desc * gdp;
 		
 	if ((inode->i_ino != EXT3_ROOT_INO &&
-		inode->i_ino != EXT3_ACL_IDX_INO &&
-		inode->i_ino != EXT3_ACL_DATA_INO &&
 		inode->i_ino != EXT3_JOURNAL_INO &&
 		inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) ||
 		inode->i_ino > le32_to_cpu(
@@ -2263,10 +2273,7 @@
 
 	brelse (iloc.bh);
 
-	if (inode->i_ino == EXT3_ACL_IDX_INO ||
-	    inode->i_ino == EXT3_ACL_DATA_INO)
-		/* Nothing to do */ ;
-	else if (S_ISREG(inode->i_mode)) {
+	if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &ext3_file_inode_operations;
 		inode->i_fop = &ext3_file_operations;
 		if (ext3_should_writeback_data(inode))
@@ -2277,18 +2284,20 @@
 		inode->i_op = &ext3_dir_inode_operations;
 		inode->i_fop = &ext3_dir_operations;
 	} else if (S_ISLNK(inode->i_mode)) {
-		if (!inode->i_blocks)
+		if (ext3_inode_is_fast_symlink(inode))
 			inode->i_op = &ext3_fast_symlink_inode_operations;
 		else {
-			inode->i_op = &page_symlink_inode_operations;
+			inode->i_op = &ext3_symlink_inode_operations;
 			if (ext3_should_writeback_data(inode))
 				inode->i_mapping->a_ops = &ext3_writeback_aops;
 			else
 				inode->i_mapping->a_ops = &ext3_aops;
 		}
-	} else 
+	} else {
+		inode->i_op = &ext3_special_inode_operations;
 		init_special_inode(inode, inode->i_mode,
 				   le32_to_cpu(iloc.raw_inode->i_block[0]));
+	}
 	if (ei->i_flags & EXT3_SYNC_FL)
 		inode->i_flags |= S_SYNC;
 	if (ei->i_flags & EXT3_APPEND_FL)
fs/ext3/namei.c +16 -6
diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c
@@ -30,6 +30,7 @@
 #include <linux/time.h>
 #include <linux/ext3_fs.h>
 #include <linux/ext3_jbd.h>
+#include <linux/ext3_xattr.h>
 #include <linux/fcntl.h>
 #include <linux/stat.h>
 #include <linux/string.h>
@@ -1654,7 +1655,7 @@
 	if (IS_DIRSYNC(dir))
 		handle->h_sync = 1;
 
-	inode = ext3_new_inode (handle, dir, S_IFDIR);
+	inode = ext3_new_inode (handle, dir, S_IFDIR | mode);
 	err = PTR_ERR(inode);
 	if (IS_ERR(inode))
 		goto out_stop;
@@ -1662,7 +1663,6 @@
 	inode->i_op = &ext3_dir_inode_operations;
 	inode->i_fop = &ext3_dir_operations;
 	inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
-	inode->i_blocks = 0;	
 	dir_block = ext3_bread (handle, inode, 0, 1, &err);
 	if (!dir_block) {
 		inode->i_nlink--; /* is this nlink == 0? */
@@ -1689,9 +1689,6 @@
 	BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata");
 	ext3_journal_dirty_metadata(handle, dir_block);
 	brelse (dir_block);
-	inode->i_mode = S_IFDIR | mode;
-	if (dir->i_mode & S_ISGID)
-		inode->i_mode |= S_ISGID;
 	ext3_mark_inode_dirty(handle, inode);
 	err = ext3_add_entry (handle, dentry, inode);
 	if (err) {
@@ -2068,7 +2065,7 @@
 		goto out_stop;
 
 	if (l > sizeof (EXT3_I(inode)->i_data)) {
-		inode->i_op = &page_symlink_inode_operations;
+		inode->i_op = &ext3_symlink_inode_operations;
 		if (ext3_should_writeback_data(inode))
 			inode->i_mapping->a_ops = &ext3_writeback_aops;
 		else
@@ -2284,4 +2281,17 @@
 	.rmdir		= ext3_rmdir,
 	.mknod		= ext3_mknod,
 	.rename		= ext3_rename,
+	.setxattr	= ext3_setxattr,	
+	.getxattr	= ext3_getxattr,	
+	.listxattr	= ext3_listxattr,	
+	.removexattr	= ext3_removexattr,
 };
+
+struct inode_operations ext3_special_inode_operations = {
+	.setxattr	= ext3_setxattr,
+	.getxattr	= ext3_getxattr,
+	.listxattr	= ext3_listxattr,
+	.removexattr	= ext3_removexattr,
+};
+
+ 
fs/ext3/super.c +22 -1
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
@@ -24,6 +24,7 @@
 #include <linux/jbd.h>
 #include <linux/ext3_fs.h>
 #include <linux/ext3_jbd.h>
+#include <linux/ext3_xattr.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
@@ -405,6 +406,7 @@
 	struct ext3_super_block *es = sbi->s_es;
 	int i;
 
+	ext3_xattr_put_super(sb);
 	journal_destroy(sbi->s_journal);
 	if (!(sb->s_flags & MS_RDONLY)) {
 		EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
@@ -554,6 +556,7 @@
 			  int is_remount)
 {
 	unsigned long *mount_options = &sbi->s_mount_opt;
+	
 	uid_t *resuid = &sbi->s_resuid;
 	gid_t *resgid = &sbi->s_resgid;
 	char * this_char;
@@ -566,6 +569,13 @@
 			continue;
 		if ((value = strchr (this_char, '=')) != NULL)
 			*value++ = 0;
+#ifdef CONFIG_EXT3_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")) {
@@ -982,6 +992,12 @@
 	sbi->s_mount_opt = 0;
 	sbi->s_resuid = EXT3_DEF_RESUID;
 	sbi->s_resgid = EXT3_DEF_RESGID;
+
+	/* Default extended attribute flags */
+#ifdef CONFIG_EXT3_FS_XATTR
+	set_opt(sbi->s_mount_opt, XATTR_USER);
+#endif
+
 	if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0))
 		goto out_fail;
 
@@ -1820,7 +1836,10 @@
 
 static int __init init_ext3_fs(void)
 {
-	int err = init_inodecache();
+	int err = init_ext3_xattr();
+	if (err)
+		return err;
+	err = init_inodecache();
 	if (err)
 		goto out1;
         err = register_filesystem(&ext3_fs_type);
@@ -1830,6 +1849,7 @@
 out:
 	destroy_inodecache();
 out1:
+ 	exit_ext3_xattr();
 	return err;
 }
 
@@ -1837,6 +1857,7 @@
 {
 	unregister_filesystem(&ext3_fs_type);
 	destroy_inodecache();
+	exit_ext3_xattr();
 }
 
 MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
fs/ext3/symlink.c +15 -1
diff -Nru a/fs/ext3/symlink.c b/fs/ext3/symlink.c
@@ -20,6 +20,7 @@
 #include <linux/fs.h>
 #include <linux/jbd.h>
 #include <linux/ext3_fs.h>
+#include <linux/ext3_xattr.h>
 
 static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
@@ -33,7 +34,20 @@
 	return vfs_follow_link(nd, (char*)ei->i_data);
 }
 
+struct inode_operations ext3_symlink_inode_operations = {
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link,
+	.setxattr	= ext3_setxattr,
+	.getxattr	= ext3_getxattr,
+	.listxattr	= ext3_listxattr,
+	.removexattr	= ext3_removexattr,
+};
+
 struct inode_operations ext3_fast_symlink_inode_operations = {
-	.readlink	= ext3_readlink,		/* BKL not held.  Don't need */
+	.readlink	= ext3_readlink,	/* BKL not held.  Don't need */
 	.follow_link	= ext3_follow_link,	/* BKL not held.  Don't need */
+	.setxattr	= ext3_setxattr,
+	.getxattr	= ext3_getxattr,
+	.listxattr	= ext3_listxattr,
+	.removexattr	= ext3_removexattr,
 };
fs/ext3/xattr.c new file +1191 -0

1,191 lines not on this page · raw message

fs/ext3/xattr_user.c new file +99 -0

99 lines not on this page · raw message

include/linux/ext3_fs.h +5 -26
diff -Nru a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
@@ -64,8 +64,6 @@
  */
 #define	EXT3_BAD_INO		 1	/* Bad blocks inode */
 #define EXT3_ROOT_INO		 2	/* Root inode */
-#define EXT3_ACL_IDX_INO	 3	/* ACL inode */
-#define EXT3_ACL_DATA_INO	 4	/* ACL inode */
 #define EXT3_BOOT_LOADER_INO	 5	/* Boot loader inode */
 #define EXT3_UNDEL_DIR_INO	 6	/* Undelete directory inode */
 #define EXT3_RESIZE_INO		 7	/* Reserved group descriptors inode */
@@ -95,7 +93,6 @@
 #else
 # define EXT3_BLOCK_SIZE(s)		(EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size)
 #endif
-#define EXT3_ACLE_PER_BLOCK(s)		(EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_acl_entry))
 #define	EXT3_ADDR_PER_BLOCK(s)		(EXT3_BLOCK_SIZE(s) / sizeof (__u32))
 #ifdef __KERNEL__
 # define EXT3_BLOCK_SIZE_BITS(s)	((s)->s_blocksize_bits)
@@ -130,28 +127,6 @@
 #endif
 
 /*
- * ACL structures
- */
-struct ext3_acl_header	/* Header of Access Control Lists */
-{
-	__u32	aclh_size;
-	__u32	aclh_file_count;
-	__u32	aclh_acle_count;
-	__u32	aclh_first_acle;
-};
-
-struct ext3_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 ext3_group_desc
@@ -347,6 +322,7 @@
   #define EXT3_MOUNT_WRITEBACK_DATA	0x0C00	/* No data ordering */
 #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 */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
@@ -529,7 +505,7 @@
 #define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004 /* Needs recovery */
 #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008 /* Journal device */
 
-#define EXT3_FEATURE_COMPAT_SUPP	0
+#define EXT3_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR
 #define EXT3_FEATURE_INCOMPAT_SUPP	(EXT3_FEATURE_INCOMPAT_FILETYPE| \
 					 EXT3_FEATURE_INCOMPAT_RECOVER)
 #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
@@ -713,6 +689,7 @@
 
 
 /* inode.c */
+extern int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
 extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
 extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
 
@@ -781,8 +758,10 @@
 
 /* namei.c */
 extern struct inode_operations ext3_dir_inode_operations;
+extern struct inode_operations ext3_special_inode_operations;
 
 /* symlink.c */
+extern struct inode_operations ext3_symlink_inode_operations;
 extern struct inode_operations ext3_fast_symlink_inode_operations;
 
 
include/linux/ext3_jbd.h +7 -1
diff -Nru a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
@@ -30,13 +30,19 @@
 
 #define EXT3_SINGLEDATA_TRANS_BLOCKS	8
 
+/* Extended attributes may touch two data buffers, two bitmap buffers,
+ * and two group and summaries. */
+
+#define EXT3_XATTR_TRANS_BLOCKS		8
+
 /* Define the minimum size for a transaction which modifies data.  This
  * needs to take into account the fact that we may end up modifying two
  * quota files too (one for the group, one for the user quota).  The
  * superblock only gets updated once, of course, so don't bother
  * counting that again for the quota updates. */
 
-#define EXT3_DATA_TRANS_BLOCKS		(3 * EXT3_SINGLEDATA_TRANS_BLOCKS - 2)
+#define EXT3_DATA_TRANS_BLOCKS		(3 * EXT3_SINGLEDATA_TRANS_BLOCKS + \
+					 EXT3_XATTR_TRANS_BLOCKS - 2)
 
 extern int ext3_writepage_trans_blocks(struct inode *inode);
 
include/linux/ext3_xattr.h new file +137 -0

137 lines not on this page · raw message