support for large EAs
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.
Signed-off-by Andreas Dilger <[email protected]>
Signed-off-by Kalpak Shah <[email protected]>
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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(ewhile (!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
@@ -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
@@ -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
@@ -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
@@ -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 */