All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kalpak Shah <Kalpak.Shah@Sun.COM>
To: linux-ext4 <linux-ext4@vger.kernel.org>
Cc: TheodoreTso <tytso@mit.edu>, Andreas Dilger <adilger@Sun.COM>
Subject: [PATCH 1/2 e2fsprogs] support for large EAs
Date: Tue, 18 Nov 2008 02:06:19 +0530	[thread overview]
Message-ID: <1226954180.3972.72.camel@localhost> (raw)

[-- Attachment #1: Type: text/plain, Size: 1234 bytes --]

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.

Signed-off-by: Andreas Dilger <adilger@sun.com>
Signed-off-by: Kalpak Shah <kalpak.shah@sun.com>

 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

[-- Attachment #2: e2fsprogs-large-xattrs.patch --]
[-- Type: text/x-patch, Size: 22355 bytes --]

Index: e2fsprogs-1.41.1/lib/blkid/probe.h
===================================================================
--- e2fsprogs-1.41.1.orig/lib/blkid/probe.h
+++ 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| \
Index: e2fsprogs-1.41.1/lib/e2p/feature.c
===================================================================
--- e2fsprogs-1.41.1.orig/lib/e2p/feature.c
+++ 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 },
 };
 
Index: e2fsprogs-1.41.1/lib/ext2fs/ext2_fs.h
===================================================================
--- e2fsprogs-1.41.1.orig/lib/ext2fs/ext2_fs.h
+++ 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| \
Index: e2fsprogs-1.41.1/misc/mke2fs.c
===================================================================
--- e2fsprogs-1.41.1.orig/misc/mke2fs.c
+++ 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|
Index: e2fsprogs-1.41.1/misc/tune2fs.c
===================================================================
--- e2fsprogs-1.41.1.orig/misc/tune2fs.c
+++ 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
Index: e2fsprogs-1.41.1/e2fsck/pass1.c
===================================================================
--- e2fsprogs-1.41.1.orig/e2fsck/pass1.c
+++ e2fsprogs-1.41.1/e2fsck/pass1.c
@@ -28,6 +28,7 @@
  * 	- A bitmap of which blocks are in use.		(block_found_map)
  * 	- A bitmap of which blocks are in use by two inodes	(block_dup_map)
  * 	- The data blocks of the directory inodes.	(dir_map)
+ *	- A bitmap of EA inodes.			(inode_ea_map)
  *
  * Pass 1 is designed to stash away enough information so that the
  * other passes should not need to read in the inode information
@@ -269,6 +270,125 @@ static void check_size(e2fsck_t ctx, str
 	e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
 }
 
+extern char *ext2_attr_index_prefix[];
+
+static void e2fsck_block_alloc_stats(ext2_filsys fs, blk64_t blk, int inuse)
+{
+	e2fsck_t ctx = (e2fsck_t) fs->priv_data;
+
+	if (ctx->block_found_map) {
+		if (inuse > 0)
+			ext2fs_mark_block_bitmap(ctx->block_found_map,
+						 (blk_t) blk);
+		else
+			ext2fs_unmark_block_bitmap(ctx->block_found_map,
+						   (blk_t) blk);
+	}
+}
+
+static void mark_inode_ea_map(e2fsck_t ctx, struct problem_context *pctx,
+			      ext2_ino_t ino)
+{
+	if (!ctx->inode_ea_map) {
+		pctx->errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
+					 _("EA inode map"),
+					 &ctx->inode_ea_map);
+		if (pctx->errcode) {
+			fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR,
+				    pctx);
+			exit(1);
+		}
+	}
+
+	ext2fs_mark_inode_bitmap(ctx->inode_ea_map, ino);
+}
+
+/*
+ * Delete an EA entry. If this is the last entry to be deleted, then i_file_acl
+ * must have been freed, so we must update e2fsck block statistics and set
+ * i_file_acl_deleted.
+ * When we delete the entry successfully, this function returns 0, else
+ * non-zero value.
+ */
+static int e2fsck_ea_entry_delete(e2fsck_t ctx, struct ext2_ext_attr_entry *entry,
+				  struct problem_context *pctx,
+				  int *i_file_acl_deleted, problem_t prob)
+{
+	blk_t i_file_acl = pctx->inode->i_file_acl;
+	int err = 1;
+
+	pctx->num = entry->e_value_inum;
+
+	if (fix_problem(ctx, prob, pctx)) {
+		/* Delete corrupt EA entry */
+		err = ext2fs_attr_set(ctx->fs, pctx->ino, pctx->inode,
+				      entry->e_name_index, entry->e_name,
+				      0, 0, 0);
+		if (err == 0) {
+			if (i_file_acl && pctx->inode->i_file_acl == 0) {
+				e2fsck_block_alloc_stats(ctx->fs, i_file_acl, -1);
+				*i_file_acl_deleted = 1;
+			}
+			return 0;
+		}
+	}
+
+	return err;
+}
+
+/*
+ * Check validity of EA inode. Return 0 if EA inode is valid, nonzero otherwise.
+ */
+static int check_large_ea_inode(e2fsck_t ctx, struct ext2_ext_attr_entry *entry,
+				struct problem_context *pctx,
+				int *i_file_acl_deleted)
+{
+	struct ext2_inode inode;
+	int ret;
+
+	/* Check if inode is within valid range */
+	if ((entry->e_value_inum < EXT2_FIRST_INODE(ctx->fs->super)) ||
+	    (entry->e_value_inum > ctx->fs->super->s_inodes_count)) {
+		ret = e2fsck_ea_entry_delete(ctx, entry, pctx,
+					     i_file_acl_deleted,
+					     PR_1_ATTR_VALUE_EA_INODE);
+		/* If user refuses to delete this entry, caller may try to set
+		 * the bit for this out-of-bound inode in inode_ea_map, so
+		 * always return failure */
+		return 1;
+	}
+
+	e2fsck_read_inode(ctx, entry->e_value_inum, &inode, "pass1");
+	if (!(inode.i_flags & EXT4_EA_INODE_FL)) {
+		/* If EXT4_EA_INODE_FL flag is not present but back-pointer
+		 * matches then we should set this flag */
+		if (inode.i_mtime == pctx->ino &&
+		    inode.i_generation == pctx->inode->i_generation &&
+		    fix_problem(ctx, PR_1_ATTR_SET_EA_INODE_FL, pctx)) {
+			inode.i_flags |= EXT4_EA_INODE_FL;
+			ext2fs_write_inode(ctx->fs, entry->e_value_inum, &inode);
+
+			return 0;
+		}
+
+		ret = e2fsck_ea_entry_delete(ctx, entry, pctx,
+					     i_file_acl_deleted,
+					     PR_1_ATTR_NO_EA_INODE_FL);
+		return ret;
+	}
+
+	/* Validate the inode back-pointer */
+	if (inode.i_mtime != pctx->ino ||
+	    inode.i_generation != pctx->inode->i_generation) {
+		ret = e2fsck_ea_entry_delete(ctx, entry, pctx,
+					     i_file_acl_deleted,
+					     PR_1_ATTR_INVAL_EA_INODE);
+		return ret;
+	}
+
+	return 0;
+}
+
 static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
 {
 	struct ext2_super_block *sb = ctx->fs->super;
@@ -307,18 +427,25 @@ static void check_ea_in_inode(e2fsck_t c
 		/* attribute len eats this space */
 		remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
 
-		/* check value size */
-		if (entry->e_value_size == 0 || entry->e_value_size > remain) {
+		if (entry->e_value_size == 0) {
 			pctx->num = entry->e_value_size;
 			problem = PR_1_ATTR_VALUE_SIZE;
 			goto fix;
 		}
 
-		/* e_value_block must be 0 in inode's ea */
-		if (entry->e_value_block != 0) {
-			pctx->num = entry->e_value_block;
-			problem = PR_1_ATTR_VALUE_BLOCK;
-			goto fix;
+		if (entry->e_value_inum == 0) {
+			/* check value size */
+			if (entry->e_value_size > remain) {
+				pctx->num = entry->e_value_size;
+				problem = PR_1_ATTR_VALUE_SIZE;
+				goto fix;
+			}
+		} else {
+			int ret, tmp;
+
+			ret = check_large_ea_inode(ctx, entry, pctx, &tmp);
+			if (ret == 0)
+				mark_inode_ea_map(ctx, pctx, entry->e_value_inum);
 		}
 
 		hash = ext2fs_ext_attr_hash_entry(entry,
@@ -331,7 +458,10 @@ static void check_ea_in_inode(e2fsck_t c
 			goto fix;
 		}
 
-		remain -= entry->e_value_size;
+		/* If EA value is stored in external inode then it does not
+		 * consume space here */
+		if (entry->e_value_inum == 0)
+			remain -= entry->e_value_size;
 
 		entry = EXT2_EXT_ATTR_NEXT(entry);
 	}
@@ -510,8 +640,6 @@ extern void e2fsck_setup_tdb_icount(e2fs
 		*ret = 0;
 }
 
-extern char *ext2_attr_index_prefix[];
-
 int e2fsck_pass1_delete_attr(e2fsck_t ctx, struct ext2_inode_large *inode,
 			     struct problem_context *pctx, int needed_size)
 {
@@ -568,7 +696,7 @@ int e2fsck_pass1_delete_attr(e2fsck_t ct
 		if (EXT2_EXT_IS_LAST_ENTRY(entry)) {
 			if (in_inode) {
 				entry = entry_blk;
-			        len = sizeof(entry->e_name);
+				len = sizeof(entry->e_name);
 				entry_size = ext2fs_attr_get_next_attr(entry,
 							index, name, len, 1);
 				in_inode = 0;
@@ -1609,6 +1737,7 @@ static int check_ext_attr(e2fsck_t ctx, 
 	struct ext2_ext_attr_entry *entry;
 	int		count;
 	region_t	region = 0;
+	int ret;
 
 	blk = inode->i_file_acl;
 	if (blk == 0)
@@ -1730,19 +1859,27 @@ static int check_ext_attr(e2fsck_t ctx, 
 				goto clear_extattr;
 			break;
 		}
-		if (entry->e_value_block != 0) {
-			if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
-				goto clear_extattr;
-		}
-		if (entry->e_value_offs + entry->e_value_size > fs->blocksize) {
-			if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
-				goto clear_extattr;
-			break;
-		}
-		if (entry->e_value_size &&
-		    region_allocate(region, entry->e_value_offs,
-				    EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
-			if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
+		if (entry->e_value_inum == 0) {
+			if (entry->e_value_offs + entry->e_value_size > fs->blocksize) {
+				if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
+					goto clear_extattr;
+				break;
+			}
+			if (entry->e_value_size &&
+			    region_allocate(region, entry->e_value_offs,
+					    EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
+				if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
+					goto clear_extattr;
+			}
+		} else {
+			int i_file_acl_deleted = 0;
+
+			ret = check_large_ea_inode(ctx, entry, pctx,
+						   &i_file_acl_deleted);
+			if (ret == 0)
+				mark_inode_ea_map(ctx, pctx, entry->e_value_inum);
+
+			if (i_file_acl_deleted)
 				goto clear_extattr;
 		}
 
@@ -2883,20 +3020,6 @@ static errcode_t e2fsck_get_alloc_block(
 	return (0);
 }
 
-static void e2fsck_block_alloc_stats(ext2_filsys fs, blk64_t blk, int inuse)
-{
-	e2fsck_t ctx = (e2fsck_t) fs->priv_data;
-
-	if (ctx->block_found_map) {
-		if (inuse > 0)
-			ext2fs_mark_block_bitmap(ctx->block_found_map,
-						 (blk_t) blk);
-		else
-			ext2fs_unmark_block_bitmap(ctx->block_found_map,
-						   (blk_t) blk);
-	}
-}
-
 void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int bool)
 {
 	ext2_filsys fs = ctx->fs;
Index: e2fsprogs-1.41.1/e2fsck/problem.c
===================================================================
--- e2fsprogs-1.41.1.orig/e2fsck/problem.c
+++ 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 */
 
Index: e2fsprogs-1.41.1/e2fsck/problem.h
===================================================================
--- e2fsprogs-1.41.1.orig/e2fsck/problem.h
+++ 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
  */
Index: e2fsprogs-1.41.1/lib/ext2fs/ext2_ext_attr.h
===================================================================
--- e2fsprogs-1.41.1.orig/lib/ext2fs/ext2_ext_attr.h
+++ 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 +	     	\
Index: e2fsprogs-1.41.1/lib/ext2fs/ext_attr.c
===================================================================
--- e2fsprogs-1.41.1.orig/lib/ext2fs/ext_attr.c
+++ 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;
Index: e2fsprogs-1.41.1/lib/ext2fs/swapfs.c
===================================================================
--- e2fsprogs-1.41.1.orig/lib/ext2fs/swapfs.c
+++ 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);
 }
Index: e2fsprogs-1.41.1/e2fsck/pass4.c
===================================================================
--- e2fsprogs-1.41.1.orig/e2fsck/pass4.c
+++ 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);
Index: e2fsprogs-1.41.1/lib/ext2fs/ext2fs.h
===================================================================
--- e2fsprogs-1.41.1.orig/lib/ext2fs/ext2fs.h
+++ 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|\
Index: e2fsprogs-1.41.1/e2fsck/e2fsck.h
===================================================================
--- e2fsprogs-1.41.1.orig/e2fsck/e2fsck.h
+++ 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 */

                 reply	other threads:[~2008-11-17 20:46 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1226954180.3972.72.camel@localhost \
    --to=kalpak.shah@sun.com \
    --cc=adilger@Sun.COM \
    --cc=linux-ext4@vger.kernel.org \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.