Skip to contentSkip to conversation

support for large EAs

PATCH In review Kalpak Shah 1 participant 1 message Nov 17, 2008

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 support for large EAs

Hi,

This patch adds large EA support for e2fsprogs.

- add EXT4_FEATURE_INCOMPAT_EA_INODE feature
- inode_ea_map bitmap is added for tracking non-orphan EA inodes. Orphan EA inodes get linked to lost+found.
- xattr handling is needed for deleting corrupt EA entries

Ted, this patch is actually based on top of the e2fsprogs-expand-extra-isize.patch I had sent about a month back. If you are satisfied with the approach, I can send a patch series which applies to the tip of the e2fsprogs tree.

 e2fsck/e2fsck.h            |    1 
 e2fsck/pass1.c             |  199 ++++++++++++++++++++++++++++++++++++---------
 e2fsck/pass4.c             |   17 +++
 e2fsck/problem.c           |   24 +++++
 e2fsck/problem.h           |   13 ++
 lib/blkid/probe.h          |    1 
 lib/e2p/feature.c          |    2 
 lib/ext2fs/ext2_ext_attr.h |    5 -
 lib/ext2fs/ext2_fs.h       |    5 -
 lib/ext2fs/ext2fs.h        |    6 -
 lib/ext2fs/ext_attr.c      |   27 ++++--
 lib/ext2fs/swapfs.c        |    2 
 misc/mke2fs.c              |    3 
 misc/tune2fs.c             |    6 +
 14 files changed, 259 insertions(+), 52 deletions(-)

Thanks,
Kalpak

lib/blkid/probe.h +1 -0
Index: e2fsprogs-1.41.1/lib/blkid/probe.h
===================================================================
@@ -119,6 +119,7 @@ struct ext2_super_block {
 #define EXT4_FEATURE_INCOMPAT_64BIT		0x0080
 #define EXT4_FEATURE_INCOMPAT_MMP		0x0100
 #define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
+#define EXT4_FEATURE_INCOMPAT_EA_INODE		0x0400
 
 #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
lib/e2p/feature.c +2 -0
Index: e2fsprogs-1.41.1/lib/e2p/feature.c
===================================================================
@@ -75,6 +75,8 @@ static struct feature feature_list[] = {
 			"flex_bg"},
 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP,
 			"mmp" },
+	{	E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_EA_INODE,
+			"large_xattr" },
 	{	0, 0, 0 },
 };
 
lib/ext2fs/ext2_fs.h +4 -1
Index: e2fsprogs-1.41.1/lib/ext2fs/ext2_fs.h
===================================================================
@@ -273,6 +273,7 @@ struct ext2_dx_countlimit {
 #define EXT2_TOPDIR_FL			0x00020000 /* Top of directory hierarchies*/
 #define EXT4_HUGE_FILE_FL               0x00040000 /* Set to each huge file */
 #define EXT4_EXTENTS_FL 		0x00080000 /* Inode uses extents */
+#define EXT4_EA_INODE_FL		0x00200000 /* Inode used for large EA */
 #define EXT2_RESERVED_FL		0x80000000 /* reserved for ext2 lib */
 
 #define EXT2_FL_USER_VISIBLE		0x000BDFFF /* User visible flags */
@@ -649,11 +650,13 @@ struct ext2_super_block {
 #define EXT4_FEATURE_INCOMPAT_64BIT		0x0080
 #define EXT4_FEATURE_INCOMPAT_MMP		0x0100
 #define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
+#define EXT4_FEATURE_INCOMPAT_EA_INODE		0x0400
 
 
 #define EXT2_FEATURE_COMPAT_SUPP	0
 #define EXT2_FEATURE_INCOMPAT_SUPP    (EXT2_FEATURE_INCOMPAT_FILETYPE| \
-				       EXT4_FEATURE_INCOMPAT_MMP)
+				       EXT4_FEATURE_INCOMPAT_MMP| \
+				       EXT4_FEATURE_INCOMPAT_EA_INODE)
 #define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
 					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
misc/mke2fs.c +2 -1
Index: e2fsprogs-1.41.1/misc/mke2fs.c
===================================================================
@@ -841,7 +841,8 @@ static __u32 ok_features[3] = {
 		EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
 		EXT2_FEATURE_INCOMPAT_META_BG|
 		EXT4_FEATURE_INCOMPAT_FLEX_BG|
-		EXT4_FEATURE_INCOMPAT_MMP,
+		EXT4_FEATURE_INCOMPAT_MMP|
+		EXT4_FEATURE_INCOMPAT_EA_INODE,
 	/* R/O compat */
 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
misc/tune2fs.c +5 -1
Index: e2fsprogs-1.41.1/misc/tune2fs.c
===================================================================
@@ -122,7 +122,8 @@ static __u32 ok_features[3] = {
 	EXT2_FEATURE_INCOMPAT_FILETYPE |
 		EXT3_FEATURE_INCOMPAT_EXTENTS |
 		EXT4_FEATURE_INCOMPAT_FLEX_BG |
-		EXT4_FEATURE_INCOMPAT_MMP,
+		EXT4_FEATURE_INCOMPAT_MMP |
+		EXT4_FEATURE_INCOMPAT_EA_INODE,
 	/* R/O compat */
 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -477,6 +478,9 @@ mmp_error:
 			ext2fs_free_mem(&buf);
 	}
 
+	if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_EA_INODE))
+		sb->s_feature_incompat |= EXT4_FEATURE_INCOMPAT_EA_INODE;
+
 	if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
 		/*
 		 * If adding a journal flag, let the create journal
e2fsck/pass1.c +161 -38

258 lines not on this page · raw message

e2fsck/problem.c +24 -0
Index: e2fsprogs-1.41.1/e2fsck/problem.c
===================================================================
@@ -928,6 +928,30 @@ static struct e2fsck_problem problem_tab
 	     "without deletion of an EA.\n"),
 	  PROMPT_FIX, 0 },
 
+	/* Inode has illegal EA value inode */
+	{ PR_1_ATTR_VALUE_EA_INODE,
+	  N_("@i %i has @I EA @i %N.\n"),
+	  PROMPT_FIX, PR_PREEN_OK },
+
+	/* Invalid back-pointer from EA-inode to parent inode */
+	{ PR_1_ATTR_INVAL_EA_INODE,
+	  N_("@I backpointer from EA @i %N to parent @i %i. "
+	     "Delete EA inode?\n"),
+	  PROMPT_FIX, PR_PREEN_OK },
+
+	/* Parent inode has invalid EA entry. EA inode does not have
+	 * EXT4_EA_INODE_FL flag */
+	{ PR_1_ATTR_NO_EA_INODE_FL,
+	  N_("Parent @i %i has @I EA entry. EA @i %N does not have "
+	     "EXT4_EA_INODE_FL flag. Delete EA entry?\n"),
+	  PROMPT_FIX, PR_PREEN_OK },
+
+	/* EA inode for parent inode does not have EXT4_EA_INODE_FL flag */
+	{ PR_1_ATTR_SET_EA_INODE_FL,
+	  N_("EA @i %N for parent @i %i does not have EXT4_EA_INODE_FL flag. "
+	     "Set the flag?\n"),
+	  PROMPT_FIX, PR_PREEN_OK },
+
 
 	/* Pass 1b errors */
 
e2fsck/problem.h +13 -0
Index: e2fsprogs-1.41.1/e2fsck/problem.h
===================================================================
@@ -548,6 +548,19 @@ struct problem_context {
  */
 #define PR_1_CLEAR_EXTRA_ISIZE		0x01006C
 
+/* Inode has illegal EA value inode */
+#define PR_1_ATTR_VALUE_EA_INODE	0x01006D
+
+/* Invalid back-pointer from EA-inode to parent inode */
+#define PR_1_ATTR_INVAL_EA_INODE	0x01006E
+
+/* Parent inode has invalid EA entry. EA inode does not have
+ * EXT4_EA_INODE_FL flag */
+#define PR_1_ATTR_NO_EA_INODE_FL	0x01006F
+
+/* EA inode for parent inode does not have EXT4_EA_INODE_FL flag */
+#define PR_1_ATTR_SET_EA_INODE_FL	0x010070
+
 /*
  * Pass 1b errors
  */
lib/ext2fs/ext2_ext_attr.h +4 -1
Index: e2fsprogs-1.41.1/lib/ext2fs/ext2_ext_attr.h
===================================================================
@@ -30,7 +30,7 @@ struct ext2_ext_attr_entry {
 	__u8	e_name_len;	/* length of name */
 	__u8	e_name_index;	/* attribute name index */
 	__u16	e_value_offs;	/* offset in disk block of value */
-	__u32	e_value_block;	/* disk block attribute is stored on (n/i) */
+	__u32	e_value_inum;	/* inode in which the value is stored */
 	__u32	e_value_size;	/* size of attribute value */
 	__u32	e_hash;		/* hash value of name and value */
 #if 1
@@ -38,6 +38,9 @@ struct ext2_ext_attr_entry {
 #endif
 };
 
+#define	EXT4_XATTR_MIN_LARGE_EA_SIZE(b) ((b) >> 1)
+#define	EXT4_XATTR_MAX_LARGE_EA_SIZE	(1024 * 1024)
+
 #define BHDR(block) ((struct ext2_ext_attr_header *) block)
 #define IHDR(inode)			   	\
 	((__u32 *) ((char *)inode +	     	\
lib/ext2fs/ext_attr.c +20 -7
Index: e2fsprogs-1.41.1/lib/ext2fs/ext_attr.c
===================================================================
@@ -45,7 +45,7 @@ __u32 ext2fs_ext_attr_hash_entry(struct 
 	}
 
 	/* The hash needs to be calculated on the data in little-endian. */
-	if (entry->e_value_block == 0 && entry->e_value_size != 0) {
+	if (entry->e_value_inum == 0 && entry->e_value_size != 0) {
 		__u32 *value = (__u32 *)data;
 		for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >>
 			 EXT2_EXT_ATTR_PAD_BITS; n; n--) {
@@ -190,6 +190,7 @@ struct ext2_attr_ibody_find {
 };
 
 struct ext2_attr_block_find {
+	ext2_ino_t ino;
 	struct ext2_attr_search s;
 	char *block;
 };
@@ -202,7 +203,7 @@ void ext2fs_attr_shift_entries(struct ex
 
 	/* Adjust the value offsets of the entries */
 	for (; !EXT2_EXT_IS_LAST_ENTRY(last); last = EXT2_EXT_ATTR_NEXT(last)) {
-		if (!last->e_value_block && last->e_value_size) {
+		if (last->e_value_inum == 0 && last->e_value_size) {
 			last->e_value_offs = last->e_value_offs +
 							value_offs_shift;
 		}
@@ -221,7 +222,7 @@ int ext2fs_attr_free_space(struct ext2_e
 {
 	for (; !EXT2_EXT_IS_LAST_ENTRY(last); last = EXT2_EXT_ATTR_NEXT(last)) {
 		*total += EXT2_EXT_ATTR_LEN(last->e_name_len);
-		if (!last->e_value_block && last->e_value_size) {
+		if (last->e_value_inum == 0 && last->e_value_size) {
 			int offs = last->e_value_offs;
 			if (offs < *min_offs)
 				*min_offs = offs;
@@ -360,7 +361,7 @@ static errcode_t ext2fs_attr_set_entry(e
 	/* Compute min_offs and last. */
 	for (last = s->first; !EXT2_EXT_IS_LAST_ENTRY(last);
 	     last = EXT2_EXT_ATTR_NEXT(last)) {
-		if (!last->e_value_block && last->e_value_size) {
+		if (last->e_value_inum == 0 && last->e_value_size) {
 			int offs = last->e_value_offs;
 
 			if (offs < min_offs)
@@ -370,7 +371,7 @@ static errcode_t ext2fs_attr_set_entry(e
 	free = min_offs - ((char *)last - s->base) - sizeof(__u32);
 
 	if (!s->not_found) {
-		if (!s->here->e_value_block && s->here->e_value_size) {
+		if (s->here->e_value_inum == 0 && s->here->e_value_size) {
 			int size = s->here->e_value_size;
 			free += EXT2_EXT_ATTR_SIZE(size);
 		}
@@ -393,7 +394,7 @@ static errcode_t ext2fs_attr_set_entry(e
 		s->here->e_name_len = name_len;
 		memcpy(s->here->e_name, i->name, name_len);
 	} else {
-		if (!s->here->e_value_block && s->here->e_value_size) {
+		if (s->here->e_value_inum == 0 && s->here->e_value_size) {
 			char *first_val = s->base + min_offs;
 			int offs = s->here->e_value_offs;
 			char *val = s->base + offs;
@@ -422,7 +423,7 @@ static errcode_t ext2fs_attr_set_entry(e
 			while (!EXT2_EXT_IS_LAST_ENTRY(last)) {
 				int o = last->e_value_offs;
 
-				if (!last->e_value_block &&
+				if (last->e_value_inum == 0 &&
 				    last->e_value_size && o < offs)
 					last->e_value_offs = o + size;
 				last = EXT2_EXT_ATTR_NEXT(last);
@@ -540,9 +541,20 @@ static errcode_t ext2fs_attr_block_set(e
 	/* Update the i_blocks if we added a new EA block */
 	if (!inode->i_file_acl && new_buf)
 		inode->i_blocks += fs->blocksize / 512;
+
+	/* Drop the previous xattr block. */
+	if (!new_buf) {
+		if (!fs->block_map)
+			ext2fs_read_block_bitmap(fs);
+		ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1);
+		inode->i_blocks -= fs->blocksize / 512;
+	}
+
 	/* Update the inode. */
 	inode->i_file_acl = new_buf ? blk : 0;
 
+	ext2fs_write_inode(fs, bs->ino, inode);
+
 cleanup:
 	if (clear_flag)
 		ext2fs_free_mem(&s->base);
@@ -829,6 +841,7 @@ errcode_t ext2fs_expand_extra_isize(ext2
 		.s = { .not_found = EXT2_ET_EA_NO_SPACE, },
 	};
 	struct ext2_attr_block_find bs = {
+		.ino = ino,
 		.s = { .not_found = EXT2_ET_EA_NO_SPACE, },
 	};
 	char *start, *end, *block_buf = NULL, *buffer =NULL, *b_entry_name=NULL;
lib/ext2fs/swapfs.c +1 -1
Index: e2fsprogs-1.41.1/lib/ext2fs/swapfs.c
===================================================================
@@ -110,7 +110,7 @@ void ext2fs_swap_ext_attr_entry(struct e
 				struct ext2_ext_attr_entry *from_entry)
 {
 	to_entry->e_value_offs  = ext2fs_swab16(from_entry->e_value_offs);
-	to_entry->e_value_block = ext2fs_swab32(from_entry->e_value_block);
+	to_entry->e_value_inum  = ext2fs_swab32(from_entry->e_value_inum);
 	to_entry->e_value_size  = ext2fs_swab32(from_entry->e_value_size);
 	to_entry->e_hash	= ext2fs_swab32(from_entry->e_hash);
 }
e2fsck/pass4.c +17 -0
Index: e2fsprogs-1.41.1/e2fsck/pass4.c
===================================================================
@@ -11,6 +11,7 @@
  * Pass 4 frees the following data structures:
  * 	- A bitmap of which inodes are in bad blocks.	(inode_bb_map)
  * 	- A bitmap of which inodes are imagic inodes.	(inode_imagic_map)
+ *	- A bitmap of EA inodes.			(inode_ea_map)
  */
 
 #include "e2fsck.h"
@@ -39,6 +40,20 @@ static int disconnect_inode(e2fsck_t ctx
 	} else {
 		e2fsck_read_inode(ctx, i, inode, "pass4: disconnect_inode");
 	}
+
+	if (inode->i_flags & EXT4_EA_INODE_FL) {
+		if (ext2fs_test_inode_bitmap(ctx->inode_ea_map, i)) {
+			ext2fs_icount_store(ctx->inode_count, i, 1);
+			return 0;
+		} else {
+			/* Zero the link count so that when inode is linked to
+			 * lost+found it has correct link count */
+			inode->i_links_count = 0;
+			e2fsck_write_inode(ctx, i, inode, "disconnect_inode");
+			ext2fs_icount_store(ctx->inode_link_info, i, 0);
+		}
+	}
+
 	clear_problem_context(&pctx);
 	pctx.ino = i;
 	pctx.inode = inode;
@@ -182,6 +197,8 @@ void e2fsck_pass4(e2fsck_t ctx)
 	ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0;
 	ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0;
 	ext2fs_free_icount(ctx->inode_badness); ctx->inode_badness = 0;
+	ext2fs_free_inode_bitmap(ctx->inode_ea_map);
+	ctx->inode_ea_map = 0;
 	ext2fs_free_inode_bitmap(ctx->inode_bb_map);
 	ctx->inode_bb_map = 0;
 	ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
lib/ext2fs/ext2fs.h +4 -2
Index: e2fsprogs-1.41.1/lib/ext2fs/ext2fs.h
===================================================================
@@ -550,7 +550,8 @@ typedef struct ext2_icount *ext2_icount_
 					 EXT3_FEATURE_INCOMPAT_RECOVER|\
 					 EXT3_FEATURE_INCOMPAT_EXTENTS|\
 					 EXT4_FEATURE_INCOMPAT_FLEX_BG|\
-					 EXT4_FEATURE_INCOMPAT_MMP)
+					 EXT4_FEATURE_INCOMPAT_MMP|\
+					 EXT4_FEATURE_INCOMPAT_EA_INODE)
 #else
 #define EXT2_LIB_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE|\
 					 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
@@ -558,7 +559,8 @@ typedef struct ext2_icount *ext2_icount_
 					 EXT3_FEATURE_INCOMPAT_RECOVER|\
 					 EXT3_FEATURE_INCOMPAT_EXTENTS|\
 					 EXT4_FEATURE_INCOMPAT_FLEX_BG|\
-					 EXT4_FEATURE_INCOMPAT_MMP)
+					 EXT4_FEATURE_INCOMPAT_MMP|\
+					 EXT4_FEATURE_INCOMPAT_EA_INODE)
 #endif
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
 					 EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
e2fsck/e2fsck.h +1 -0
Index: e2fsprogs-1.41.1/e2fsck/e2fsck.h
===================================================================
@@ -251,6 +251,7 @@ struct e2fsck_struct {
 	ext2fs_inode_bitmap inode_bb_map; /* Inodes which are in bad blocks */
 	ext2fs_inode_bitmap inode_imagic_map; /* AFS inodes */
 	ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
+	ext2fs_inode_bitmap inode_ea_map; /* EA inodes which are non-orphan */
 
 	ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
 	ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */