From deb6fcdd4d34dc141dc365d12653de4e18c1a750 Mon Sep 17 00:00:00 2001 From: Bobi Jam Date: Tue, 28 Jul 2015 11:36:34 +0800 Subject: [PATCH] LU-6911 ldiskfs: mds crash kernel at fs/inode.c:1358 A glitch exists in LU-4648 patch (commit ed69a331b1e502643fe074c121f9a8b9d041fc49) which does not put ea inodes to orphan list if no external ea is used. Signed-off-by: Bobi Jam Change-Id: I1c28b989d73d06317e4064b739d69fa9453c5deb Reviewed-on: http://review.whamcloud.com/15768 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Yang Sheng Reviewed-by: Fan Yong Reviewed-by: Oleg Drokin --- .../patches/rhel6.3/ext4-large-eas.patch | 116 ++++++----- .../patches/rhel7/ext4-large-eas.patch | 216 ++++++++++++--------- .../patches/sles11sp2/ext4-large-eas.patch | 122 +++++++----- .../patches/sles12/ext4-large-eas.patch | 168 ++++++++++------ 4 files changed, 372 insertions(+), 250 deletions(-) diff --git a/ldiskfs/kernel_patches/patches/rhel6.3/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/rhel6.3/ext4-large-eas.patch index 9f41d82..5981307 100644 --- a/ldiskfs/kernel_patches/patches/rhel6.3/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/rhel6.3/ext4-large-eas.patch @@ -2,7 +2,7 @@ Index: linux-stage/fs/ext4/ext4.h =================================================================== --- linux-stage.orig/fs/ext4/ext4.h +++ linux-stage/fs/ext4/ext4.h -@@ -1333,6 +1333,7 @@ EXT4_INODE_BIT_FNS(state, state_flags) +@@ -1329,6 +1329,7 @@ EXT4_INODE_BIT_FNS(state, state_flags) #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 #define EXT4_FEATURE_INCOMPAT_MMP 0x0100 #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 @@ -10,7 +10,7 @@ Index: linux-stage/fs/ext4/ext4.h #define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 #define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR -@@ -1342,6 +1343,7 @@ EXT4_INODE_BIT_FNS(state, state_flags) +@@ -1338,6 +1339,7 @@ EXT4_INODE_BIT_FNS(state, state_flags) EXT4_FEATURE_INCOMPAT_EXTENTS| \ EXT4_FEATURE_INCOMPAT_64BIT| \ EXT4_FEATURE_INCOMPAT_FLEX_BG| \ @@ -18,8 +18,8 @@ Index: linux-stage/fs/ext4/ext4.h EXT4_FEATURE_INCOMPAT_MMP| \ EXT4_FEATURE_INCOMPAT_DIRDATA) -@@ -1706,6 +1708,12 @@ struct mmpd_data { - #endif +@@ -1695,6 +1697,12 @@ struct mmpd_data { + #define EXT4_MMP_MAX_CHECK_INTERVAL 300UL /* + * Maximum size of xattr attributes for FEATURE_INCOMPAT_EA_INODE 1Mb @@ -31,7 +31,7 @@ Index: linux-stage/fs/ext4/ext4.h * Function prototypes */ -@@ -1717,6 +1725,10 @@ struct mmpd_data { +@@ -1706,6 +1714,10 @@ struct mmpd_data { # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, @@ -589,7 +589,7 @@ Index: linux-stage/fs/ext4/xattr.c if (error) goto cleanup; if (!is.s.not_found) { -@@ -1088,10 +1384,25 @@ ext4_xattr_set(struct inode *inode, int +@@ -1087,10 +1383,25 @@ ext4_xattr_set(struct inode *inode, int const void *value, size_t value_len, int flags) { handle_t *handle; @@ -616,7 +616,7 @@ Index: linux-stage/fs/ext4/xattr.c if (IS_ERR(handle)) { error = PTR_ERR(handle); } else { -@@ -1101,7 +1412,7 @@ retry: +@@ -1100,7 +1411,7 @@ retry: value, value_len, flags); error2 = ext4_journal_stop(handle); if (error == -ENOSPC && @@ -625,7 +625,7 @@ Index: linux-stage/fs/ext4/xattr.c goto retry; if (error == 0) error = error2; -@@ -1123,7 +1434,7 @@ static void ext4_xattr_shift_entries(str +@@ -1122,7 +1433,7 @@ static void ext4_xattr_shift_entries(str /* Adjust the value offsets of the entries */ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { @@ -634,11 +634,10 @@ Index: linux-stage/fs/ext4/xattr.c new_offs = le16_to_cpu(last->e_value_offs) + value_offs_shift; BUG_ON(new_offs + le32_to_cpu(last->e_value_size) -@@ -1356,20 +1667,92 @@ cleanup: +@@ -1355,22 +1666,135 @@ cleanup: return error; } -- +#define EIA_INCR 16 /* must be 2^n */ +#define EIA_MASK (EIA_INCR - 1) +/* Add the large xattr @ino into @lea_ino_array for later deletion. @@ -682,6 +681,43 @@ Index: linux-stage/fs/ext4/xattr.c + return 0; +} ++/** ++ * Add xattr inode to orphan list ++ */ ++static int ++ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, ++ int credits, struct ext4_xattr_ino_array *lea_ino_array) ++{ ++ struct inode *ea_inode = NULL; ++ int idx = 0, error = 0; ++ ++ if (lea_ino_array == NULL) ++ return 0; ++ ++ for (; idx < lea_ino_array->xia_count; ++idx) { ++ if (!ext4_handle_has_enough_credits(handle, credits)) { ++ error = ext4_journal_extend(handle, credits); ++ if (error > 0) ++ error = ext4_journal_restart(handle, credits); ++ ++ if (error != 0) { ++ ext4_warning(inode->i_sb, ++ "couldn't extend journal " ++ "(err %d)", error); ++ return error; ++ } ++ } ++ ea_inode = ext4_xattr_inode_iget(inode, ++ lea_ino_array->xia_inodes[idx], &error); ++ if (error) ++ continue; ++ ext4_orphan_add(handle, ea_inode); ++ /* the inode's i_count will be released by caller */ ++ } ++ ++ return 0; ++} + /* * ext4_xattr_delete_inode() * @@ -706,7 +742,8 @@ Index: linux-stage/fs/ext4/xattr.c + struct ext4_iloc iloc; + struct ext4_xattr_entry *entry; + int credits = 3, error = 0; -+ + +- if (!EXT4_I(inode)->i_file_acl) + if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) + goto delete_external_ea; + @@ -727,12 +764,18 @@ Index: linux-stage/fs/ext4/xattr.c + entry->e_value_inum = 0; + } + brelse(iloc.bh); - ++ +delete_external_ea: - if (!EXT4_I(inode)->i_file_acl) ++ if (!EXT4_I(inode)->i_file_acl) { ++ /* add xattr inode to orphan list */ ++ ext4_xattr_inode_orphan_add(handle, inode, credits, ++ *lea_ino_array); goto cleanup; ++ } bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); -@@ -1384,11 +1764,88 @@ ext4_xattr_delete_inode(handle_t *handle + if (!bh) { + ext4_error(inode->i_sb, "inode %lu: block %llu read error", +@@ -1383,11 +1807,71 @@ ext4_xattr_delete_inode(handle_t *handle inode->i_ino, EXT4_I(inode)->i_file_acl); goto cleanup; } @@ -748,30 +791,10 @@ Index: linux-stage/fs/ext4/xattr.c + } + + /* add xattr inode to orphan list */ -+ if (*lea_ino_array != NULL) { -+ struct inode *ea_inode = NULL; -+ int idx = 0; -+ -+ for (; idx < (*lea_ino_array)->xia_count; ++idx) { -+ if (!ext4_handle_has_enough_credits(handle, credits)) { -+ error = ext4_journal_extend(handle, credits); -+ if (error > 0) -+ error = ext4_journal_restart(handle, credits); -+ if (error != 0) { -+ ext4_warning(inode->i_sb, -+ "couldn't extend journal " -+ "(err %d)", error); -+ goto cleanup; -+ } -+ } -+ ea_inode = ext4_xattr_inode_iget(inode, -+ (*lea_ino_array)->xia_inodes[idx], &error); -+ if (error) -+ continue; -+ ext4_orphan_add(handle, ea_inode); -+ /* the inode's i_count will be released by caller */ -+ } -+ } ++ error = ext4_xattr_inode_orphan_add(handle, inode, credits, ++ *lea_ino_array); ++ if (error != 0) ++ goto cleanup; + + if (!IS_NOQUOTA(inode)) + credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); @@ -812,16 +835,19 @@ Index: linux-stage/fs/ext4/xattr.c + lea_ino_array->xia_inodes[idx], &err); + if (err) + continue; -+ ea_inode->i_nlink = 0; -+ iput(ea_inode); ++ + /* for inode's i_count get from ext4_xattr_delete_inode */ ++ if (!list_empty(&EXT4_I(ea_inode)->i_orphan)) ++ iput(ea_inode); ++ ++ ea_inode->i_nlink = 0; + iput(ea_inode); + } + kfree(lea_ino_array); } /* -@@ -1458,10 +1915,9 @@ ext4_xattr_cmp(struct ext4_xattr_header +@@ -1457,10 +1941,9 @@ ext4_xattr_cmp(struct ext4_xattr_header entry1->e_name_index != entry2->e_name_index || entry1->e_name_len != entry2->e_name_len || entry1->e_value_size != entry2->e_value_size || @@ -833,7 +859,7 @@ Index: linux-stage/fs/ext4/xattr.c if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), (char *)header2 + le16_to_cpu(entry2->e_value_offs), le32_to_cpu(entry1->e_value_size))) -@@ -1546,7 +2002,7 @@ static inline void ext4_xattr_hash_entry +@@ -1545,7 +2028,7 @@ static inline void ext4_xattr_hash_entry *name++; } @@ -913,7 +939,7 @@ Index: linux-stage/fs/ext4/inode.c if (ext4_should_order_data(inode)) ext4_begin_ordered_truncate(inode, 0); -@@ -238,7 +239,8 @@ void ext4_delete_inode(struct inode *ino +@@ -235,7 +237,8 @@ void ext4_delete_inode(struct inode *ino * protection against it */ sb_start_intwrite(inode->i_sb); @@ -923,7 +949,7 @@ Index: linux-stage/fs/ext4/inode.c if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); /* -@@ -251,9 +252,36 @@ void ext4_delete_inode(struct inode *ino +@@ -247,9 +250,36 @@ void ext4_delete_inode(struct inode *ino sb_end_intwrite(inode->i_sb); goto no_delete; } @@ -961,7 +987,7 @@ Index: linux-stage/fs/ext4/inode.c inode->i_size = 0; err = ext4_mark_inode_dirty(handle, inode); if (err) { -@@ -307,8 +335,12 @@ void ext4_delete_inode(struct inode *ino +@@ -303,8 +333,12 @@ void ext4_delete_inode(struct inode *ino clear_inode(inode); else ext4_free_inode(handle, inode); diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-large-eas.patch index 0a18c55..902e512 100644 --- a/ldiskfs/kernel_patches/patches/rhel7/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/rhel7/ext4-large-eas.patch @@ -4,11 +4,11 @@ not be saved in the external EA block, instead it would be saved in an external EA inode. So, the patch also helps support a larger number of EAs. -Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h +Index: linux-stage/fs/ext4/ext4.h =================================================================== ---- linux-3.10.0-123.13.2.el7.x86_64.orig/fs/ext4/ext4.h -+++ linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h -@@ -1534,6 +1534,7 @@ static inline void ext4_clear_state_flag +--- linux-stage.orig/fs/ext4/ext4.h ++++ linux-stage/fs/ext4/ext4.h +@@ -1579,6 +1579,7 @@ static inline void ext4_clear_state_flag EXT4_FEATURE_INCOMPAT_EXTENTS| \ EXT4_FEATURE_INCOMPAT_64BIT| \ EXT4_FEATURE_INCOMPAT_FLEX_BG| \ @@ -16,7 +16,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h EXT4_FEATURE_INCOMPAT_MMP | \ EXT4_FEATURE_INCOMPAT_DIRDATA| \ EXT4_FEATURE_INCOMPAT_INLINE_DATA) -@@ -1934,6 +1935,12 @@ struct mmpd_data { +@@ -1979,6 +1980,12 @@ struct mmpd_data { #define EXT4_MMP_MAX_CHECK_INTERVAL 300UL /* @@ -29,7 +29,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h * Function prototypes */ -@@ -1945,6 +1952,10 @@ struct mmpd_data { +@@ -1990,6 +1997,10 @@ struct mmpd_data { # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, @@ -40,19 +40,19 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h /* bitmap.c */ extern unsigned int ext4_count_free(char *bitmap, unsigned numchars); void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, -@@ -2157,6 +2168,7 @@ extern void ext4_set_inode_flags(struct +@@ -2194,6 +2205,7 @@ extern void ext4_set_inode_flags(struct extern void ext4_get_inode_flags(struct ext4_inode_info *); extern int ext4_alloc_da_blocks(struct inode *inode); extern void ext4_set_aops(struct inode *inode); +extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int chunk); extern int ext4_writepage_trans_blocks(struct inode *); extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); - extern int ext4_discard_partial_page_buffers(handle_t *handle, -Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inode.c + extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode, +Index: linux-stage/fs/ext4/inode.c =================================================================== ---- linux-3.10.0-123.13.2.el7.x86_64.orig/fs/ext4/inode.c -+++ linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inode.c -@@ -133,8 +183,6 @@ void ext4_evict_inode(struct inode *inod +--- linux-stage.orig/fs/ext4/inode.c ++++ linux-stage/fs/ext4/inode.c +@@ -134,8 +134,6 @@ static void ext4_invalidatepage(struct p unsigned int length); static int __ext4_journalled_writepage(struct page *page, unsigned int len); static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh); @@ -61,7 +61,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inode.c /* * Test whether an inode is a fast symlink. -@@ -183,6 +183,8 @@ void ext4_evict_inode(struct inode *inod +@@ -184,6 +182,8 @@ void ext4_evict_inode(struct inode *inod { handle_t *handle; int err; @@ -70,7 +70,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inode.c trace_ext4_evict_inode(inode); -@@ -235,8 +237,8 @@ void ext4_evict_inode(struct inode *inod +@@ -236,8 +236,8 @@ void ext4_evict_inode(struct inode *inod * protection against it */ sb_start_intwrite(inode->i_sb); @@ -81,7 +81,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inode.c if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); /* -@@ -248,9 +250,36 @@ void ext4_evict_inode(struct inode *inod +@@ -249,9 +249,36 @@ void ext4_evict_inode(struct inode *inod sb_end_intwrite(inode->i_sb); goto no_delete; } @@ -119,7 +119,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inode.c inode->i_size = 0; err = ext4_mark_inode_dirty(handle, inode); if (err) { -@@ -305,8 +334,12 @@ void ext4_evict_inode(struct inode *inod +@@ -306,8 +333,12 @@ void ext4_evict_inode(struct inode *inod ext4_clear_inode(inode); else ext4_free_inode(handle, inode); @@ -132,7 +132,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inode.c return; no_delete: ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ -@@ -4841,7 +4874,7 @@ static int ext4_index_trans_blocks(struc +@@ -4681,7 +4712,7 @@ static int ext4_index_trans_blocks(struc * * Also account for superblock, inode, quota and xattr blocks */ @@ -141,12 +141,11 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inode.c int pextents) { ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb); - int gdpblocks; -Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c +Index: linux-stage/fs/ext4/xattr.c =================================================================== ---- linux-3.10.0-123.13.2.el7.x86_64.orig/fs/ext4/xattr.c -+++ linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c -@@ -220,19 +220,26 @@ ext4_xattr_check_block(struct inode *ino +--- linux-stage.orig/fs/ext4/xattr.c ++++ linux-stage/fs/ext4/xattr.c +@@ -233,19 +233,26 @@ ext4_xattr_check_block(struct inode *ino } static inline int @@ -177,7 +176,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c { struct ext4_xattr_entry *entry; size_t name_len; -@@ -252,11 +259,103 @@ ext4_xattr_find_entry(struct ext4_xattr_ +@@ -265,11 +272,103 @@ ext4_xattr_find_entry(struct ext4_xattr_ break; } *pentry = entry; @@ -282,7 +281,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c static int ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, void *buffer, size_t buffer_size) -@@ -288,7 +387,8 @@ bad_block: +@@ -301,7 +400,8 @@ bad_block: } ext4_xattr_cache_insert(bh); entry = BFIRST(bh); @@ -292,7 +291,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (error == -EIO) goto bad_block; if (error) -@@ -298,8 +398,16 @@ bad_block: +@@ -311,8 +411,16 @@ bad_block: error = -ERANGE; if (size > buffer_size) goto cleanup; @@ -311,7 +310,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c } error = size; -@@ -333,7 +441,7 @@ ext4_xattr_ibody_get(struct inode *inode +@@ -346,7 +454,7 @@ ext4_xattr_ibody_get(struct inode *inode if (error) goto cleanup; error = ext4_xattr_find_entry(&entry, name_index, name, @@ -320,7 +319,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); -@@ -341,8 +449,16 @@ ext4_xattr_ibody_get(struct inode *inode +@@ -354,8 +462,16 @@ ext4_xattr_ibody_get(struct inode *inode error = -ERANGE; if (size > buffer_size) goto cleanup; @@ -339,8 +338,8 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c } error = size; -@@ -568,7 +684,7 @@ static size_t ext4_xattr_free_space(stru - *total += EXT4_XATTR_LEN(last->e_name_len); +@@ -600,7 +716,7 @@ static size_t ext4_xattr_free_space(stru + size_t *min_offs, void *base, int *total) { for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { - if (!last->e_value_block && last->e_value_size) { @@ -348,14 +347,15 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c size_t offs = le16_to_cpu(last->e_value_offs); if (offs < *min_offs) *min_offs = offs; -@@ -577,16 +693,172 @@ static size_t ext4_xattr_free_space(stru +@@ -611,16 +727,172 @@ static size_t ext4_xattr_free_space(stru return (*min_offs - ((void *)last - base) - sizeof(__u32)); } +/* + * Write the value of the EA in an inode. + */ -+static int + static int +-ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) +ext4_xattr_inode_write(handle_t *handle, struct inode *ea_inode, + const void *buf, int bufsize) +{ @@ -477,8 +477,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c +/* + * Add value of the EA in an inode. + */ - static int --ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) ++static int +ext4_xattr_inode_set(handle_t *handle, struct inode *inode, int *ea_ino, + const void *value, size_t value_len) +{ @@ -523,7 +522,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c size_t offs = le16_to_cpu(last->e_value_offs); if (offs < min_offs) min_offs = offs; -@@ -594,16 +865,21 @@ ext4_xattr_set_entry(struct ext4_xattr_i +@@ -628,16 +900,21 @@ ext4_xattr_set_entry(struct ext4_xattr_i } free = min_offs - ((void *)last - s->base) - sizeof(__u32); if (!s->not_found) { @@ -549,7 +548,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c return -ENOSPC; } -@@ -617,7 +893,8 @@ ext4_xattr_set_entry(struct ext4_xattr_i +@@ -651,7 +928,8 @@ ext4_xattr_set_entry(struct ext4_xattr_i s->here->e_name_len = name_len; memcpy(s->here->e_name, i->name, name_len); } else { @@ -559,7 +558,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c void *first_val = s->base + min_offs; size_t offs = le16_to_cpu(s->here->e_value_offs); void *val = s->base + offs; -@@ -651,13 +928,17 @@ ext4_xattr_set_entry(struct ext4_xattr_i +@@ -685,13 +963,17 @@ ext4_xattr_set_entry(struct ext4_xattr_i last = s->first; while (!IS_LAST_ENTRY(last)) { size_t o = le16_to_cpu(last->e_value_offs); @@ -579,7 +578,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (!i->value) { /* Remove the old name. */ size_t size = EXT4_XATTR_LEN(name_len); -@@ -671,10 +952,17 @@ ext4_xattr_set_entry(struct ext4_xattr_i +@@ -705,10 +987,17 @@ ext4_xattr_set_entry(struct ext4_xattr_i if (i->value) { /* Insert the new value. */ s->here->e_value_size = cpu_to_le32(i->value_len); @@ -598,7 +597,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (i->value == EXT4_ZERO_XATTR_VALUE) { memset(val, 0, size); } else { -@@ -724,7 +1012,7 @@ ext4_xattr_block_find(struct inode *inod +@@ -758,7 +1047,7 @@ ext4_xattr_block_find(struct inode *inod bs->s.end = bs->bh->b_data + bs->bh->b_size; bs->s.here = bs->s.first; error = ext4_xattr_find_entry(&bs->s.here, i->name_index, @@ -607,7 +606,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (error && error != -ENODATA) goto cleanup; bs->s.not_found = error; -@@ -748,8 +1036,6 @@ ext4_xattr_block_set(handle_t *handle, s +@@ -782,8 +1071,6 @@ ext4_xattr_block_set(handle_t *handle, s #define header(x) ((struct ext4_xattr_header *)(x)) @@ -616,7 +615,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (s->base) { ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev, bs->bh->b_blocknr); -@@ -764,7 +1050,7 @@ ext4_xattr_block_set(handle_t *handle, s +@@ -799,7 +1086,7 @@ ext4_xattr_block_set(handle_t *handle, s ce = NULL; } ea_bdebug(bs->bh, "modifying in-place"); @@ -625,7 +624,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (!error) { if (!IS_LAST_ENTRY(s->first)) ext4_xattr_rehash(header(s->base), -@@ -815,7 +1101,7 @@ ext4_xattr_block_set(handle_t *handle, s +@@ -850,7 +1137,7 @@ ext4_xattr_block_set(handle_t *handle, s s->end = s->base + sb->s_blocksize; } @@ -634,7 +633,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (error == -EIO) goto bad_block; if (error) -@@ -963,7 +1249,7 @@ int ext4_xattr_ibody_find(struct inode * +@@ -1000,7 +1287,7 @@ int ext4_xattr_ibody_find(struct inode * /* Find the named attribute. */ error = ext4_xattr_find_entry(&is->s.here, i->name_index, i->name, is->s.end - @@ -643,7 +642,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (error && error != -ENODATA) return error; is->s.not_found = error; -@@ -981,7 +1267,7 @@ int ext4_xattr_ibody_inline_set(handle_t +@@ -1018,7 +1305,7 @@ int ext4_xattr_ibody_inline_set(handle_t if (EXT4_I(inode)->i_extra_isize == 0) return -ENOSPC; @@ -652,7 +651,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (error) { if (error == -ENOSPC && ext4_has_inline_data(inode)) { -@@ -993,7 +1279,7 @@ int ext4_xattr_ibody_inline_set(handle_t +@@ -1030,7 +1317,7 @@ int ext4_xattr_ibody_inline_set(handle_t error = ext4_xattr_ibody_find(inode, i, is); if (error) return error; @@ -661,7 +660,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c } if (error) return error; -@@ -1019,7 +1305,7 @@ static int ext4_xattr_ibody_set(handle_t +@@ -1056,7 +1343,7 @@ static int ext4_xattr_ibody_set(handle_t if (EXT4_I(inode)->i_extra_isize == 0) return -ENOSPC; @@ -670,7 +669,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (error) return error; header = IHDR(inode, ext4_raw_inode(&is->iloc)); -@@ -1055,7 +1341,7 @@ ext4_xattr_set_handle(handle_t *handle, +@@ -1092,7 +1379,7 @@ ext4_xattr_set_handle(handle_t *handle, .name = name, .value = value, .value_len = value_len, @@ -679,7 +678,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c }; struct ext4_xattr_ibody_find is = { .s = { .not_found = -ENODATA, }, -@@ -1120,6 +1406,15 @@ ext4_xattr_set_handle(handle_t *handle, +@@ -1157,6 +1444,15 @@ ext4_xattr_set_handle(handle_t *handle, goto cleanup; } error = ext4_xattr_block_set(handle, inode, &i, &bs); @@ -695,7 +694,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (error) goto cleanup; if (!is.s.not_found) { -@@ -1166,9 +1461,22 @@ ext4_xattr_set(struct inode *inode, int +@@ -1203,9 +1499,22 @@ ext4_xattr_set(struct inode *inode, int const void *value, size_t value_len, int flags) { handle_t *handle; @@ -718,7 +717,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c retry: handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); if (IS_ERR(handle)) { -@@ -1180,7 +1488,7 @@ retry: +@@ -1217,7 +1526,7 @@ retry: value, value_len, flags); error2 = ext4_journal_stop(handle); if (error == -ENOSPC && @@ -727,7 +726,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c goto retry; if (error == 0) error = error2; -@@ -1202,7 +1510,7 @@ static void ext4_xattr_shift_entries(str +@@ -1239,7 +1548,7 @@ static void ext4_xattr_shift_entries(str /* Adjust the value offsets of the entries */ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { @@ -736,11 +735,10 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c new_offs = le16_to_cpu(last->e_value_offs) + value_offs_shift; BUG_ON(new_offs + le32_to_cpu(last->e_value_size) -@@ -1441,19 +1749,91 @@ cleanup: +@@ -1477,21 +1786,135 @@ cleanup: } -- +#define EIA_INCR 16 /* must be 2^n */ +#define EIA_MASK (EIA_INCR - 1) +/* Add the large xattr @ino into @lea_ino_array for later deletion. @@ -783,6 +781,44 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c + (*lea_ino_array)->xia_inodes[(*lea_ino_array)->xia_count++] = ino; + return 0; +} ++ ++/** ++ * Add xattr inode to orphan list ++ */ ++static int ++ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, ++ int credits, struct ext4_xattr_ino_array *lea_ino_array) ++{ ++ struct inode *ea_inode = NULL; ++ int idx = 0, error = 0; ++ ++ if (lea_ino_array == NULL) ++ return 0; ++ ++ for (; idx < lea_ino_array->xia_count; ++idx) { ++ if (!ext4_handle_has_enough_credits(handle, credits)) { ++ error = ext4_journal_extend(handle, credits); ++ if (error > 0) ++ error = ext4_journal_restart(handle, credits); ++ ++ if (error != 0) { ++ ext4_warning(inode->i_sb, ++ "couldn't extend journal " ++ "(err %d)", error); ++ return error; ++ } ++ } ++ ea_inode = ext4_xattr_inode_iget(inode, ++ lea_ino_array->xia_inodes[idx], &error); ++ if (error) ++ continue; ++ ext4_orphan_add(handle, ea_inode); ++ /* the inode's i_count will be released by caller */ ++ } ++ ++ return 0; ++} + /* * ext4_xattr_delete_inode() * @@ -807,13 +843,14 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c + struct ext4_iloc iloc; + struct ext4_xattr_entry *entry; + int credits = 3, error = 0; -+ + +- if (!EXT4_I(inode)->i_file_acl) + if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) + goto delete_external_ea; + + error = ext4_get_inode_loc(inode, &iloc); + if (error) -+ goto cleanup; + goto cleanup; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); + entry = IFIRST(header); @@ -828,12 +865,18 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c + entry->e_value_inum = 0; + } + brelse(iloc.bh); - ++ +delete_external_ea: - if (!EXT4_I(inode)->i_file_acl) - goto cleanup; ++ if (!EXT4_I(inode)->i_file_acl) { ++ /* add xattr inode to orphan list */ ++ ext4_xattr_inode_orphan_add(handle, inode, credits, ++ *lea_ino_array); ++ goto cleanup; ++ } bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); -@@ -1468,11 +1848,88 @@ ext4_xattr_delete_inode(handle_t *handle + if (!bh) { + EXT4_ERROR_INODE(inode, "block %llu read error", +@@ -1504,11 +1927,69 @@ ext4_xattr_delete_inode(handle_t *handle EXT4_I(inode)->i_file_acl); goto cleanup; } @@ -849,30 +892,10 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c + } + + /* add xattr inode to orphan list */ -+ if (*lea_ino_array != NULL) { -+ struct inode *ea_inode = NULL; -+ int idx = 0; -+ -+ for (; idx < (*lea_ino_array)->xia_count; ++idx) { -+ if (!ext4_handle_has_enough_credits(handle, 3)) { -+ error = ext4_journal_extend(handle, 3); -+ if (error > 0) -+ error = ext4_journal_restart(handle, 3); -+ if (error != 0) { -+ ext4_warning(inode->i_sb, -+ "couldn't extend journal " -+ "(err %d)", error); -+ goto cleanup; -+ } -+ } -+ ea_inode = ext4_xattr_inode_iget(inode, -+ (*lea_ino_array)->xia_inodes[idx], &error); -+ if (error) -+ continue; -+ ext4_orphan_add(handle, ea_inode); -+ /* the inode's i_count will be released by caller */ -+ } -+ } ++ error = ext4_xattr_inode_orphan_add(handle, inode, credits, ++ *lea_ino_array); ++ if (error != 0) ++ goto cleanup; + + if (!IS_NOQUOTA(inode)) + credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); @@ -913,16 +936,17 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c + lea_ino_array->xia_inodes[idx], &err); + if (err) + continue; -+ clear_nlink(ea_inode); -+ iput(ea_inode); + /* for inode's i_count get from ext4_xattr_delete_inode */ ++ if (!list_empty(&EXT4_I(ea_inode)->i_orphan)) ++ iput(ea_inode); ++ clear_nlink(ea_inode); + iput(ea_inode); + } + kfree(lea_ino_array); } /* -@@ -1542,10 +1999,9 @@ ext4_xattr_cmp(struct ext4_xattr_header +@@ -1578,10 +2059,9 @@ ext4_xattr_cmp(struct ext4_xattr_header entry1->e_name_index != entry2->e_name_index || entry1->e_name_len != entry2->e_name_len || entry1->e_value_size != entry2->e_value_size || @@ -934,7 +958,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), (char *)header2 + le16_to_cpu(entry2->e_value_offs), le32_to_cpu(entry1->e_value_size))) -@@ -1629,7 +2085,7 @@ static inline void ext4_xattr_hash_entry +@@ -1665,7 +2145,7 @@ static inline void ext4_xattr_hash_entry *name++; } @@ -943,10 +967,10 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.c __le32 *value = (__le32 *)((char *)header + le16_to_cpu(entry->e_value_offs)); for (n = (le32_to_cpu(entry->e_value_size) + -Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.h +Index: linux-stage/fs/ext4/xattr.h =================================================================== ---- linux-3.10.0-123.13.2.el7.x86_64.orig/fs/ext4/xattr.h -+++ linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.h +--- linux-stage.orig/fs/ext4/xattr.h ++++ linux-stage/fs/ext4/xattr.h @@ -42,7 +42,7 @@ struct ext4_xattr_entry { __u8 e_name_len; /* length of name */ __u8 e_name_index; /* attribute name index */ @@ -1000,11 +1024,11 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/xattr.h extern void ext4_xattr_put_super(struct super_block *); extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, -Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ialloc.c +Index: linux-stage/fs/ext4/ialloc.c =================================================================== ---- linux-3.10.0-123.13.2.el7.x86_64.orig/fs/ext4/ialloc.c -+++ linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ialloc.c -@@ -250,7 +250,6 @@ void ext4_free_inode(handle_t *handle, s +--- linux-stage.orig/fs/ext4/ialloc.c ++++ linux-stage/fs/ext4/ialloc.c +@@ -269,7 +269,6 @@ void ext4_free_inode(handle_t *handle, s * as writing the quota to disk may need the lock as well. */ dquot_initialize(inode); @@ -1012,10 +1036,10 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ialloc.c dquot_free_inode(inode); dquot_drop(inode); -Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inline.c +Index: linux-stage/fs/ext4/inline.c =================================================================== ---- linux-3.10.0-123.13.2.el7.x86_64.orig/fs/ext4/inline.c -+++ linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/inline.c +--- linux-stage.orig/fs/ext4/inline.c ++++ linux-stage/fs/ext4/inline.c @@ -59,7 +59,7 @@ static int get_max_inline_xattr_value_si /* Compute min_offs. */ diff --git a/ldiskfs/kernel_patches/patches/sles11sp2/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/sles11sp2/ext4-large-eas.patch index 133006f..57e5f90 100644 --- a/ldiskfs/kernel_patches/patches/sles11sp2/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/sles11sp2/ext4-large-eas.patch @@ -1,8 +1,14 @@ +This patch implements the large EA support in ext4. If the size of +an EA value is larger than the blocksize, then the EA value would +not be saved in the external EA block, instead it would be saved +in an external EA inode. So, the patch also helps support a larger +number of EAs. + Index: linux-stage/fs/ext4/ext4.h =================================================================== --- linux-stage.orig/fs/ext4/ext4.h +++ linux-stage/fs/ext4/ext4.h -@@ -1412,6 +1412,7 @@ static inline void ext4_clear_state_flag +@@ -1408,6 +1408,7 @@ static inline void ext4_clear_state_flag EXT4_FEATURE_INCOMPAT_EXTENTS| \ EXT4_FEATURE_INCOMPAT_64BIT| \ EXT4_FEATURE_INCOMPAT_FLEX_BG| \ @@ -10,8 +16,8 @@ Index: linux-stage/fs/ext4/ext4.h EXT4_FEATURE_INCOMPAT_MMP| \ EXT4_FEATURE_INCOMPAT_DIRDATA) -@@ -1775,6 +1776,12 @@ struct mmpd_data { - #endif +@@ -1764,6 +1765,12 @@ struct mmpd_data { + #define EXT4_MMP_MAX_CHECK_INTERVAL 300UL /* + * Maximum size of xattr attributes for FEATURE_INCOMPAT_EA_INODE 1Mb @@ -23,7 +29,7 @@ Index: linux-stage/fs/ext4/ext4.h * Function prototypes */ -@@ -1786,6 +1793,10 @@ struct mmpd_data { +@@ -1775,6 +1782,10 @@ struct mmpd_data { # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, @@ -34,7 +40,7 @@ Index: linux-stage/fs/ext4/ext4.h /* bitmap.c */ extern unsigned int ext4_count_free(char *bitmap, unsigned numchars); -@@ -1905,6 +1916,7 @@ extern void ext4_set_inode_flags(struct +@@ -1893,6 +1904,7 @@ extern void ext4_set_inode_flags(struct extern void ext4_get_inode_flags(struct ext4_inode_info *); extern int ext4_alloc_da_blocks(struct inode *inode); extern void ext4_set_aops(struct inode *inode); @@ -128,7 +134,7 @@ Index: linux-stage/fs/ext4/inode.c return; no_delete: ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ -@@ -5551,7 +5584,7 @@ static int ext4_index_trans_blocks(struc +@@ -5552,7 +5585,7 @@ static int ext4_index_trans_blocks(struc * * Also account for superblock, inode, quota and xattr blocks */ @@ -687,7 +693,7 @@ Index: linux-stage/fs/ext4/xattr.c if (error) goto cleanup; if (!is.s.not_found) { -@@ -1089,10 +1388,25 @@ ext4_xattr_set(struct inode *inode, int +@@ -1088,10 +1387,25 @@ ext4_xattr_set(struct inode *inode, int const void *value, size_t value_len, int flags) { handle_t *handle; @@ -714,7 +720,7 @@ Index: linux-stage/fs/ext4/xattr.c if (IS_ERR(handle)) { error = PTR_ERR(handle); } else { -@@ -1102,7 +1416,7 @@ retry: +@@ -1101,7 +1415,7 @@ retry: value, value_len, flags); error2 = ext4_journal_stop(handle); if (error == -ENOSPC && @@ -723,7 +729,7 @@ Index: linux-stage/fs/ext4/xattr.c goto retry; if (error == 0) error = error2; -@@ -1124,7 +1438,7 @@ static void ext4_xattr_shift_entries(str +@@ -1123,7 +1437,7 @@ static void ext4_xattr_shift_entries(str /* Adjust the value offsets of the entries */ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { @@ -732,11 +738,10 @@ Index: linux-stage/fs/ext4/xattr.c new_offs = le16_to_cpu(last->e_value_offs) + value_offs_shift; BUG_ON(new_offs + le32_to_cpu(last->e_value_size) -@@ -1359,20 +1673,92 @@ cleanup: +@@ -1358,22 +1672,135 @@ cleanup: return error; } -- +#define EIA_INCR 16 /* must be 2^n */ +#define EIA_MASK (EIA_INCR - 1) +/* Add the large xattr @ino into @lea_ino_array for later deletion. @@ -779,6 +784,43 @@ Index: linux-stage/fs/ext4/xattr.c + (*lea_ino_array)->xia_inodes[(*lea_ino_array)->xia_count++] = ino; + return 0; +} ++ ++/** ++ * Add xattr inode to orphan list ++ */ ++static int ++ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, ++ int credits, struct ext4_xattr_ino_array *lea_ino_array) ++{ ++ struct inode *ea_inode = NULL; ++ int idx = 0, error = 0; ++ ++ if (lea_ino_array == NULL) ++ return 0; + ++ for (; idx < lea_ino_array->xia_count; ++idx) { ++ if (!ext4_handle_has_enough_credits(handle, credits)) { ++ error = ext4_journal_extend(handle, credits); ++ if (error > 0) ++ error = ext4_journal_restart(handle, credits); ++ ++ if (error != 0) { ++ ext4_warning(inode->i_sb, ++ "couldn't extend journal " ++ "(err %d)", error); ++ return error; ++ } ++ } ++ ea_inode = ext4_xattr_inode_iget(inode, ++ lea_ino_array->xia_inodes[idx], &error); ++ if (error) ++ continue; ++ ext4_orphan_add(handle, ea_inode); ++ /* the inode's i_count will be released by caller */ ++ } ++ ++ return 0; ++} /* * ext4_xattr_delete_inode() @@ -804,13 +846,14 @@ Index: linux-stage/fs/ext4/xattr.c + struct ext4_iloc iloc; + struct ext4_xattr_entry *entry; + int credits = 3, error = 0; -+ + +- if (!EXT4_I(inode)->i_file_acl) + if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) + goto delete_external_ea; + + error = ext4_get_inode_loc(inode, &iloc); + if (error) -+ goto cleanup; + goto cleanup; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); + entry = IFIRST(header); @@ -825,12 +868,18 @@ Index: linux-stage/fs/ext4/xattr.c + entry->e_value_inum = 0; + } + brelse(iloc.bh); - ++ +delete_external_ea: - if (!EXT4_I(inode)->i_file_acl) - goto cleanup; ++ if (!EXT4_I(inode)->i_file_acl) { ++ /* add xattr inode to orphan list */ ++ ext4_xattr_inode_orphan_add(handle, inode, credits, ++ *lea_ino_array); ++ goto cleanup; ++ } bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); -@@ -1387,11 +1770,88 @@ ext4_xattr_delete_inode(handle_t *handle + if (!bh) { + EXT4_ERROR_INODE(inode, "block %llu read error", +@@ -1386,11 +1813,69 @@ ext4_xattr_delete_inode(handle_t *handle EXT4_I(inode)->i_file_acl); goto cleanup; } @@ -846,30 +895,10 @@ Index: linux-stage/fs/ext4/xattr.c + } + + /* adding xattr inode to orphan list */ -+ if (*lea_ino_array != NULL) { -+ struct inode *ea_inode = NULL; -+ int idx = (*lea_ino_array)->xia_count; -+ -+ for (idx = 0; idx < (*lea_ino_array)->xia_count; ++idx) { -+ if (!ext4_handle_has_enough_credits(handle, credits)) { -+ error = ext4_journal_extend(handle, credits); -+ if (error > 0) -+ error = ext4_journal_restart(handle, credits); -+ if (error != 0) { -+ ext4_warning(inode->i_sb, -+ "couldn't extend journal " -+ "(err %d)", error); -+ goto cleanup; -+ } -+ } -+ ea_inode = ext4_xattr_inode_iget(inode, -+ (*lea_ino_array)->xia_inodes[idx], &error); -+ if (error) -+ continue; -+ ext4_orphan_add(handle, ea_inode); -+ /* the inode's i_count will be released by caller */ -+ } -+ } ++ error = ext4_xattr_inode_orphan_add(handle, inode, credits, ++ *lea_ino_array); ++ if (error != 0) ++ goto cleanup; + + if (!IS_NOQUOTA(inode)) + credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); @@ -910,16 +939,17 @@ Index: linux-stage/fs/ext4/xattr.c + lea_ino_array->xia_inodes[idx], &err); + if (err) + continue; -+ ea_inode->i_nlink = 0; -+ iput(ea_inode); + /* for inode's i_count get from ext4_xattr_delete_inode */ ++ if (!list_empty(&EXT4_I(ea_inode)->i_orphan)) ++ iput(ea_inode); ++ ea_inode->i_nlink = 0; + iput(ea_inode); + } + kfree(lea_ino_array); } /* -@@ -1461,10 +1921,9 @@ ext4_xattr_cmp(struct ext4_xattr_header +@@ -1460,10 +1945,9 @@ ext4_xattr_cmp(struct ext4_xattr_header entry1->e_name_index != entry2->e_name_index || entry1->e_name_len != entry2->e_name_len || entry1->e_value_size != entry2->e_value_size || @@ -931,7 +961,7 @@ Index: linux-stage/fs/ext4/xattr.c if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), (char *)header2 + le16_to_cpu(entry2->e_value_offs), le32_to_cpu(entry1->e_value_size))) -@@ -1548,7 +2007,7 @@ static inline void ext4_xattr_hash_entry +@@ -1547,7 +2031,7 @@ static inline void ext4_xattr_hash_entry *name++; } @@ -1002,7 +1032,7 @@ Index: linux-stage/fs/ext4/ialloc.c =================================================================== --- linux-stage.orig/fs/ext4/ialloc.c +++ linux-stage/fs/ext4/ialloc.c -@@ -222,7 +222,6 @@ void ext4_free_inode(handle_t *handle, s +@@ -221,7 +221,6 @@ void ext4_free_inode(handle_t *handle, s * as writing the quota to disk may need the lock as well. */ dquot_initialize(inode); diff --git a/ldiskfs/kernel_patches/patches/sles12/ext4-large-eas.patch b/ldiskfs/kernel_patches/patches/sles12/ext4-large-eas.patch index 8f972ac..d596093 100644 --- a/ldiskfs/kernel_patches/patches/sles12/ext4-large-eas.patch +++ b/ldiskfs/kernel_patches/patches/sles12/ext4-large-eas.patch @@ -4,11 +4,11 @@ not be saved in the external EA block, instead it would be saved in an external EA inode. So, the patch also helps support a larger number of EAs. -Index: linux-3.12.39-47.1/fs/ext4/ext4.h +Index: linux-stage/fs/ext4/ext4.h =================================================================== ---- linux-3.12.39-47.1.orig/fs/ext4/ext4.h -+++ linux-3.12.39-47.1/fs/ext4/ext4.h -@@ -1538,6 +1538,7 @@ static inline void ext4_clear_state_flag +--- linux-stage.orig/fs/ext4/ext4.h ++++ linux-stage/fs/ext4/ext4.h +@@ -1545,6 +1545,7 @@ static inline void ext4_clear_state_flag EXT4_FEATURE_INCOMPAT_EXTENTS| \ EXT4_FEATURE_INCOMPAT_64BIT| \ EXT4_FEATURE_INCOMPAT_FLEX_BG| \ @@ -16,7 +16,7 @@ Index: linux-3.12.39-47.1/fs/ext4/ext4.h EXT4_FEATURE_INCOMPAT_MMP | \ EXT4_FEATURE_INCOMPAT_DIRDATA| \ EXT4_FEATURE_INCOMPAT_INLINE_DATA) -@@ -1938,6 +1939,12 @@ struct mmpd_data { +@@ -1945,6 +1946,12 @@ struct mmpd_data { #define EXT4_MMP_MAX_CHECK_INTERVAL 300UL /* @@ -29,7 +29,7 @@ Index: linux-3.12.39-47.1/fs/ext4/ext4.h * Function prototypes */ -@@ -1949,6 +1956,10 @@ struct mmpd_data { +@@ -1956,6 +1963,10 @@ struct mmpd_data { # define ATTRIB_NORET __attribute__((noreturn)) # define NORET_AND noreturn, @@ -40,7 +40,7 @@ Index: linux-3.12.39-47.1/fs/ext4/ext4.h /* bitmap.c */ extern unsigned int ext4_count_free(char *bitmap, unsigned numchars); void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, -@@ -2162,6 +2173,7 @@ extern void ext4_set_inode_flags(struct +@@ -2169,6 +2180,7 @@ extern void ext4_set_inode_flags(struct extern void ext4_get_inode_flags(struct ext4_inode_info *); extern int ext4_alloc_da_blocks(struct inode *inode); extern void ext4_set_aops(struct inode *inode); @@ -48,10 +48,10 @@ Index: linux-3.12.39-47.1/fs/ext4/ext4.h extern int ext4_writepage_trans_blocks(struct inode *); extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); extern int ext4_block_truncate_page(handle_t *handle, -Index: linux-3.12.39-47.1/fs/ext4/inode.c +Index: linux-stage/fs/ext4/inode.c =================================================================== ---- linux-3.12.39-47.1.orig/fs/ext4/inode.c -+++ linux-3.12.39-47.1/fs/ext4/inode.c +--- linux-stage.orig/fs/ext4/inode.c ++++ linux-stage/fs/ext4/inode.c @@ -135,8 +135,6 @@ static void ext4_invalidatepage(struct p unsigned int length); static int __ext4_journalled_writepage(struct page *page, unsigned int len); @@ -81,7 +81,7 @@ Index: linux-3.12.39-47.1/fs/ext4/inode.c if (IS_ERR(handle)) { ext4_std_error(inode->i_sb, PTR_ERR(handle)); /* -@@ -248,9 +248,33 @@ void ext4_evict_inode(struct inode *inod +@@ -248,9 +248,36 @@ void ext4_evict_inode(struct inode *inod sb_end_intwrite(inode->i_sb); goto no_delete; } @@ -99,6 +99,9 @@ Index: linux-3.12.39-47.1/fs/ext4/inode.c + goto stop_handle; + } + ++ if (!IS_NOQUOTA(inode)) ++ extra_credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); ++ + if (!ext4_handle_has_enough_credits(handle, + ext4_blocks_for_truncate(inode) + extra_credits)) { + err = ext4_journal_extend(handle, @@ -116,7 +119,7 @@ Index: linux-3.12.39-47.1/fs/ext4/inode.c inode->i_size = 0; err = ext4_mark_inode_dirty(handle, inode); if (err) { -@@ -305,8 +329,12 @@ void ext4_evict_inode(struct inode *inod +@@ -305,8 +332,12 @@ void ext4_evict_inode(struct inode *inod ext4_clear_inode(inode); else ext4_free_inode(handle, inode); @@ -129,7 +132,7 @@ Index: linux-3.12.39-47.1/fs/ext4/inode.c return; no_delete: ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ -@@ -4754,7 +4782,7 @@ static int ext4_index_trans_blocks(struc +@@ -4777,7 +4808,7 @@ static int ext4_index_trans_blocks(struc * * Also account for superblock, inode, quota and xattr blocks */ @@ -138,10 +141,10 @@ Index: linux-3.12.39-47.1/fs/ext4/inode.c int pextents) { ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb); -Index: linux-3.12.39-47.1/fs/ext4/xattr.c +Index: linux-stage/fs/ext4/xattr.c =================================================================== ---- linux-3.12.39-47.1.orig/fs/ext4/xattr.c -+++ linux-3.12.39-47.1/fs/ext4/xattr.c +--- linux-stage.orig/fs/ext4/xattr.c ++++ linux-stage/fs/ext4/xattr.c @@ -233,19 +233,26 @@ ext4_xattr_check_block(struct inode *ino } @@ -351,7 +354,8 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c +/* + * Write the value of the EA in an inode. + */ -+static int + static int +-ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) +ext4_xattr_inode_write(handle_t *handle, struct inode *ea_inode, + const void *buf, int bufsize) +{ @@ -473,8 +477,7 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c +/* + * Add value of the EA in an inode. + */ - static int --ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) ++static int +ext4_xattr_inode_set(handle_t *handle, struct inode *inode, int *ea_ino, + const void *value, size_t value_len) +{ @@ -732,11 +735,10 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c new_offs = le16_to_cpu(last->e_value_offs) + value_offs_shift; BUG_ON(new_offs + le32_to_cpu(last->e_value_size) -@@ -1472,19 +1781,91 @@ cleanup: +@@ -1472,21 +1781,135 @@ cleanup: } -- +#define EIA_INCR 16 /* must be 2^n */ +#define EIA_MASK (EIA_INCR - 1) +/* Add the large xattr @ino into @lea_ino_array for later deletion. @@ -779,6 +781,44 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c + (*lea_ino_array)->xia_inodes[(*lea_ino_array)->xia_count++] = ino; + return 0; +} ++ ++/** ++ * Add xattr inode to orphan list ++ */ ++static int ++ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, ++ int credits, struct ext4_xattr_ino_array *lea_ino_array) ++{ ++ struct inode *ea_inode = NULL; ++ int idx = 0, error = 0; ++ ++ if (lea_ino_array == NULL) ++ return 0; ++ ++ for (; idx < lea_ino_array->xia_count; ++idx) { ++ if (!ext4_handle_has_enough_credits(handle, credits)) { ++ error = ext4_journal_extend(handle, credits); ++ if (error > 0) ++ error = ext4_journal_restart(handle, credits); ++ ++ if (error != 0) { ++ ext4_warning(inode->i_sb, ++ "couldn't extend journal " ++ "(err %d)", error); ++ return error; ++ } ++ } ++ ea_inode = ext4_xattr_inode_iget(inode, ++ lea_ino_array->xia_inodes[idx], &error); ++ if (error) ++ continue; ++ ext4_orphan_add(handle, ea_inode); ++ /* the inode's i_count will be released by caller */ ++ } ++ ++ return 0; ++} + /* * ext4_xattr_delete_inode() * @@ -802,14 +842,15 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c + struct ext4_inode *raw_inode; + struct ext4_iloc iloc; + struct ext4_xattr_entry *entry; -+ int error = 0; -+ ++ int credits = 3, error = 0; + +- if (!EXT4_I(inode)->i_file_acl) + if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) + goto delete_external_ea; + + error = ext4_get_inode_loc(inode, &iloc); + if (error) -+ goto cleanup; + goto cleanup; + raw_inode = ext4_raw_inode(&iloc); + header = IHDR(inode, raw_inode); + entry = IFIRST(header); @@ -824,12 +865,18 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c + entry->e_value_inum = 0; + } + brelse(iloc.bh); - ++ +delete_external_ea: - if (!EXT4_I(inode)->i_file_acl) - goto cleanup; ++ if (!EXT4_I(inode)->i_file_acl) { ++ /* add xattr inode to orphan list */ ++ ext4_xattr_inode_orphan_add(handle, inode, credits, ++ *lea_ino_array); ++ goto cleanup; ++ } bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); -@@ -1499,11 +1880,74 @@ ext4_xattr_delete_inode(handle_t *handle + if (!bh) { + EXT4_ERROR_INODE(inode, "block %llu read error", +@@ -1499,11 +1922,69 @@ ext4_xattr_delete_inode(handle_t *handle EXT4_I(inode)->i_file_acl); goto cleanup; } @@ -845,28 +892,22 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c + } + + /* add xattr inode to orphan list */ -+ if (*lea_ino_array != NULL) { -+ struct inode *ea_inode = NULL; -+ int idx = 0; -+ -+ for (; idx < (*lea_ino_array)->xia_count; ++idx) { -+ if (!ext4_handle_has_enough_credits(handle, 3)) { -+ error = ext4_journal_extend(handle, 3); -+ if (error > 0) -+ error = ext4_journal_restart(handle, 3); -+ if (error != 0) { -+ ext4_warning(inode->i_sb, -+ "couldn't extend journal " -+ "(err %d)", error); -+ goto cleanup; -+ } -+ } -+ ea_inode = ext4_xattr_inode_iget(inode, -+ (*lea_ino_array)->xia_inodes[idx], &error); -+ if (error) -+ continue; -+ ext4_orphan_add(handle, ea_inode); -+ /* the inode's i_count will be released by caller */ ++ error = ext4_xattr_inode_orphan_add(handle, inode, credits, ++ *lea_ino_array); ++ if (error != 0) ++ goto cleanup; ++ ++ if (!IS_NOQUOTA(inode)) ++ credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); ++ ++ if (!ext4_handle_has_enough_credits(handle, credits)) { ++ error = ext4_journal_extend(handle, credits); ++ if (error > 0) ++ error = ext4_journal_restart(handle, credits); ++ if (error != 0) { ++ ext4_warning(inode->i_sb, ++ "couldn't extend journal (err %d)", error); ++ goto cleanup; + } + } + @@ -895,16 +936,17 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c + lea_ino_array->xia_inodes[idx], &err); + if (err) + continue; -+ clear_nlink(ea_inode); -+ iput(ea_inode); + /* for inode's i_count get from ext4_xattr_delete_inode */ ++ if (!list_empty(&EXT4_I(ea_inode)->i_orphan)) ++ iput(ea_inode); ++ clear_nlink(ea_inode); + iput(ea_inode); + } + kfree(lea_ino_array); } /* -@@ -1573,10 +2017,9 @@ ext4_xattr_cmp(struct ext4_xattr_header +@@ -1573,10 +2054,9 @@ ext4_xattr_cmp(struct ext4_xattr_header entry1->e_name_index != entry2->e_name_index || entry1->e_name_len != entry2->e_name_len || entry1->e_value_size != entry2->e_value_size || @@ -916,7 +958,7 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), (char *)header2 + le16_to_cpu(entry2->e_value_offs), le32_to_cpu(entry1->e_value_size))) -@@ -1660,7 +2103,7 @@ static inline void ext4_xattr_hash_entry +@@ -1660,7 +2140,7 @@ static inline void ext4_xattr_hash_entry *name++; } @@ -925,10 +967,10 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.c __le32 *value = (__le32 *)((char *)header + le16_to_cpu(entry->e_value_offs)); for (n = (le32_to_cpu(entry->e_value_size) + -Index: linux-3.12.39-47.1/fs/ext4/xattr.h +Index: linux-stage/fs/ext4/xattr.h =================================================================== ---- linux-3.12.39-47.1.orig/fs/ext4/xattr.h -+++ linux-3.12.39-47.1/fs/ext4/xattr.h +--- linux-stage.orig/fs/ext4/xattr.h ++++ linux-stage/fs/ext4/xattr.h @@ -42,7 +42,7 @@ struct ext4_xattr_entry { __u8 e_name_len; /* length of name */ __u8 e_name_index; /* attribute name index */ @@ -982,10 +1024,10 @@ Index: linux-3.12.39-47.1/fs/ext4/xattr.h extern void ext4_xattr_put_super(struct super_block *); extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, -Index: linux-3.12.39-47.1/fs/ext4/ialloc.c +Index: linux-stage/fs/ext4/ialloc.c =================================================================== ---- linux-3.12.39-47.1.orig/fs/ext4/ialloc.c -+++ linux-3.12.39-47.1/fs/ext4/ialloc.c +--- linux-stage.orig/fs/ext4/ialloc.c ++++ linux-stage/fs/ext4/ialloc.c @@ -252,7 +252,6 @@ void ext4_free_inode(handle_t *handle, s * as writing the quota to disk may need the lock as well. */ @@ -994,10 +1036,10 @@ Index: linux-3.12.39-47.1/fs/ext4/ialloc.c dquot_free_inode(inode); dquot_drop(inode); -Index: linux-3.12.39-47.1/fs/ext4/inline.c +Index: linux-stage/fs/ext4/inline.c =================================================================== ---- linux-3.12.39-47.1.orig/fs/ext4/inline.c -+++ linux-3.12.39-47.1/fs/ext4/inline.c +--- linux-stage.orig/fs/ext4/inline.c ++++ linux-stage/fs/ext4/inline.c @@ -59,7 +59,7 @@ static int get_max_inline_xattr_value_si /* Compute min_offs. */ -- 1.8.3.1