From 4eb2183007d829f36fb228762ada2f603b458f8f Mon Sep 17 00:00:00 2001 From: Shaun Tancheff Date: Tue, 10 Sep 2024 15:58:56 +0700 Subject: [PATCH] LU-16350 ldiskfs: update for kernel 6.11 Update ext4-kill-dx-root.patch and ext4-lookup-dotdot.patch for kernel 6.11. These updates are also applicable to 6.10 stable, tested with 6.10.6 stable. HPE-bug-id: LUS-11376 Test-Parameters: trivial Signed-off-by: Shaun Tancheff Change-Id: I94f95eeff65b80f879a8b34aea05dc5fa289aa73 Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/56284 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin Reviewed-by: Andreas Dilger Reviewed-by: Li Dongyang Reviewed-by: Jian Yu --- config/lustre-build-ldiskfs.m4 | 6 +- .../patches/linux-6.11/ext4-kill-dx-root.patch | 328 +++++++++++++++++++++ .../patches/linux-6.11/ext4-lookup-dotdot.patch | 60 ++++ .../kernel_patches/series/ldiskfs-6.11-ml.series | 38 +++ 4 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 ldiskfs/kernel_patches/patches/linux-6.11/ext4-kill-dx-root.patch create mode 100644 ldiskfs/kernel_patches/patches/linux-6.11/ext4-lookup-dotdot.patch create mode 100644 ldiskfs/kernel_patches/series/ldiskfs-6.11-ml.series diff --git a/config/lustre-build-ldiskfs.m4 b/config/lustre-build-ldiskfs.m4 index 1ba84ec..440f4e0 100644 --- a/config/lustre-build-ldiskfs.m4 +++ b/config/lustre-build-ldiskfs.m4 @@ -192,7 +192,11 @@ AS_IF([test -z "$LDISKFS_SERIES"], AS_VERSION_COMPARE([$LINUXRELEASE],[6.10.0], [ LDISKFS_SERIES="6.7-ml.series"], [ LDISKFS_SERIES="6.10-ml.series"], [ - LDISKFS_SERIES="6.10-ml.series"] + AS_VERSION_COMPARE([$LINUXRELEASE],[6.10.5], [ + LDISKFS_SERIES="6.10-ml.series"], [ + LDISKFS_SERIES="6.11-ml.series"], [ + LDISKFS_SERIES="6.11-ml.series"] + )] # 6.11 )] # 6.10 )] # 6.7 )] # 6.6 diff --git a/ldiskfs/kernel_patches/patches/linux-6.11/ext4-kill-dx-root.patch b/ldiskfs/kernel_patches/patches/linux-6.11/ext4-kill-dx-root.patch new file mode 100644 index 0000000..0387ff9 --- /dev/null +++ b/ldiskfs/kernel_patches/patches/linux-6.11/ext4-kill-dx-root.patch @@ -0,0 +1,328 @@ +commit 2db3b2b33ee796f4ea61316773452d936303ad27 +Author: Pravin Shelar +AuthorDate: Sun Oct 4 18:13:14 2009 +0000 +Subject: [PATCH] LU-11922 ldiskfs: make dirdata work with metadata_csum + +Split monolithic definition of dx_root struct to separate dx_root_info +from fake struct ext4_dir_entry2 for improved code readability. +This allows "." and ".." dirents to have different sizes if necessary, +since we can't assume the rec_len 12 if dx_root dirents have dirdata. +Adds dx_get_dx_info() accessor instead of complex typecast at callers. +Does not change any functionality. + +Bugzilla-ID: 17670 +Signed-off-by: Pravin Shelar +Reviewed-by: Andreas Dilger +Reviewed-by: Girish Shilamkar +--- + fs/ext4/namei.c | 147 +++++++++++++++++++++++------------------------- + 1 file changed, 71 insertions(+), 76 deletions(-) + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 015c801a..0bb519ab 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -245,22 +245,13 @@ struct dx_entry + * hash version mod 4 should never be 0. Sincerely, the paranoia department. + */ + +-struct dx_root ++struct dx_root_info + { +- struct fake_dirent dot; +- char dot_name[4]; +- struct fake_dirent dotdot; +- char dotdot_name[4]; +- struct dx_root_info +- { +- __le32 reserved_zero; +- u8 hash_version; +- u8 info_length; /* 8 */ +- u8 indirect_levels; +- u8 unused_flags; +- } +- info; +- struct dx_entry entries[]; ++ __le32 reserved_zero; ++ u8 hash_version; ++ u8 info_length; /* 8 */ ++ u8 indirect_levels; ++ u8 unused_flags; + }; + + struct dx_node +@@ -566,6 +557,16 @@ ext4_next_entry(struct ext4_dir_entry_2 *p, unsigned long blocksize) + * Future: use high four bits of block for coalesce-on-delete flags + * Mask them off for now. + */ ++struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) ++{ ++ /* get dotdot first */ ++ de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(1)); ++ ++ /* dx root info is after dotdot entry */ ++ de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(2)); ++ ++ return (struct dx_root_info *)de; ++} + + static inline ext4_lblk_t dx_get_block(struct dx_entry *entry) + { +@@ -813,7 +814,7 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, + { + unsigned count, indirect, level, i; + struct dx_entry *at, *entries, *p, *q, *m; +- struct dx_root *root; ++ struct dx_root_info *info; + struct dx_frame *frame = frame_in; + struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR); + u32 hash; +@@ -825,24 +826,24 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, + if (IS_ERR(frame->bh)) + return (struct dx_frame *) frame->bh; + +- root = (struct dx_root *) frame->bh->b_data; +- if (root->info.hash_version != DX_HASH_TEA && +- root->info.hash_version != DX_HASH_HALF_MD4 && +- root->info.hash_version != DX_HASH_LEGACY && +- root->info.hash_version != DX_HASH_SIPHASH) { +- ext4_warning_inode(dir, +- "Unrecognised inode hash code %u for directory %lu", +- root->info.hash_version, dir->i_ino); ++ info = dx_get_dx_info((struct ext4_dir_entry_2 *)frame->bh->b_data); ++ if (info->hash_version != DX_HASH_TEA && ++ info->hash_version != DX_HASH_HALF_MD4 && ++ info->hash_version != DX_HASH_LEGACY && ++ info->hash_version != DX_HASH_SIPHASH) { ++ ext4_warning(dir->i_sb, ++ "Unrecognised inode hash code %d for directory #%lu", ++ info->hash_version, dir->i_ino); + goto fail; + } + if (ext4_hash_in_dirent(dir)) { +- if (root->info.hash_version != DX_HASH_SIPHASH) { ++ if (info->hash_version != DX_HASH_SIPHASH) { + ext4_warning_inode(dir, + "Hash in dirent, but hash is not SIPHASH"); + goto fail; + } + } else { +- if (root->info.hash_version == DX_HASH_SIPHASH) { ++ if (info->hash_version == DX_HASH_SIPHASH) { + ext4_warning_inode(dir, + "Hash code is SIPHASH, but hash not in dirent"); + goto fail; +@@ -850,7 +851,7 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, + } + if (fname) + hinfo = &fname->hinfo; +- hinfo->hash_version = root->info.hash_version; ++ hinfo->hash_version = info->hash_version; + if (hinfo->hash_version <= DX_HASH_TEA) + hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; + hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; +@@ -866,13 +867,13 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, + } + hash = hinfo->hash; + +- if (root->info.unused_flags & 1) { ++ if (info->unused_flags & 1) { + ext4_warning_inode(dir, "Unimplemented hash flags: %#06x", +- root->info.unused_flags); ++ info->unused_flags); + goto fail; + } + +- indirect = root->info.indirect_levels; ++ indirect = info->indirect_levels; + if (indirect >= ext4_dir_htree_level(dir->i_sb)) { + ext4_warning(dir->i_sb, + "Directory (ino: %lu) htree depth %#06x exceed" +@@ -885,14 +886,13 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, + goto fail; + } + +- entries = (struct dx_entry *)(((char *)&root->info) + +- root->info.info_length); ++ entries = (struct dx_entry *)(((char *)info) + info->info_length); + + if (dx_get_limit(entries) != dx_root_limit(dir, +- root->info.info_length)) { ++ info->info_length)) { + ext4_warning_inode(dir, "dx entry: limit %u != root limit %u", + dx_get_limit(entries), +- dx_root_limit(dir, root->info.info_length)); ++ dx_root_limit(dir, info->info_length)); + goto fail; + } + +@@ -978,7 +978,7 @@ static void dx_release(struct dx_frame *frames) + if (frames[0].bh == NULL) + return; + +- info = &((struct dx_root *)frames[0].bh->b_data)->info; ++ info = dx_get_dx_info((struct ext4_dir_entry_2 *)frames[0].bh->b_data); + /* save local copy, "info" may be freed after brelse() */ + indirect_levels = info->indirect_levels; + for (i = 0; i <= indirect_levels; i++) { +@@ -2246,44 +2246,39 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname, + return err ? err : err2; + } + +-static bool ext4_check_dx_root(struct inode *dir, struct dx_root *root) ++static bool ext4_check_dx_root(struct inode *dir, ++ struct ext4_dir_entry_2 *dot_de, ++ struct ext4_dir_entry_2 *dotdot_de, ++ struct ext4_dir_entry_2 **entry) + { +- struct fake_dirent *fde; + const char *error_msg; +- unsigned int rlen; + unsigned int blocksize = dir->i_sb->s_blocksize; +- char *blockend = (char *)root + dir->i_sb->s_blocksize; ++ struct ext4_dir_entry_2 *de = NULL; + +- fde = &root->dot; +- if (unlikely(fde->name_len != 1)) { ++ if (unlikely(dot_de->name_len != 1)) { + error_msg = "invalid name_len for '.'"; + goto corrupted; + } +- if (unlikely(strncmp(root->dot_name, ".", fde->name_len))) { ++ if (unlikely(strncmp(dot_de->name, ".", dot_de->name_len))) { + error_msg = "invalid name for '.'"; + goto corrupted; + } +- rlen = ext4_rec_len_from_disk(fde->rec_len, blocksize); +- if (unlikely((char *)fde + rlen >= blockend)) { +- error_msg = "invalid rec_len for '.'"; +- goto corrupted; +- } + +- fde = &root->dotdot; +- if (unlikely(fde->name_len != 2)) { ++ if (unlikely(dotdot_de->name_len != 2)) { + error_msg = "invalid name_len for '..'"; + goto corrupted; + } +- if (unlikely(strncmp(root->dotdot_name, "..", fde->name_len))) { ++ if (unlikely(strncmp(dotdot_de->name, "..", dotdot_de->name_len))) { + error_msg = "invalid name for '..'"; + goto corrupted; + } +- rlen = ext4_rec_len_from_disk(fde->rec_len, blocksize); +- if (unlikely((char *)fde + rlen >= blockend)) { ++ de = (struct ext4_dir_entry_2 *)((char *)dotdot_de + ++ ext4_rec_len_from_disk(dotdot_de->rec_len, blocksize)); ++ if ((char *)de >= (((char *)dot_de) + blocksize)) { + error_msg = "invalid rec_len for '..'"; + goto corrupted; + } +- ++ *entry = de; + return true; + + corrupted: +@@ -2301,16 +2296,15 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, + struct inode *inode, struct buffer_head *bh) + { + struct buffer_head *bh2; +- struct dx_root *root; + struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; + struct dx_entry *entries; +- struct ext4_dir_entry_2 *de, *de2; ++ struct ext4_dir_entry_2 *de, *de2, *dot_de, *dotdot_de; + char *data2, *top; + unsigned len; + int retval; + unsigned blocksize; + ext4_lblk_t block; +- struct fake_dirent *fde; ++ struct dx_root_info *dx_info; + int csum_size = 0; + + if (ext4_has_metadata_csum(inode->i_sb)) +@@ -2327,17 +2321,15 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, + return retval; + } + +- root = (struct dx_root *) bh->b_data; +- if (!ext4_check_dx_root(dir, root)) { ++ dot_de = (struct ext4_dir_entry_2 *)bh->b_data; ++ dotdot_de = ext4_next_entry(dot_de, blocksize); ++ if (!ext4_check_dx_root(dir, dot_de, dotdot_de, &de)) { + brelse(bh); + return -EFSCORRUPTED; + } + + /* The 0th block becomes the root, move the dirents out */ +- fde = &root->dotdot; +- de = (struct ext4_dir_entry_2 *)((char *)fde + +- ext4_rec_len_from_disk(fde->rec_len, blocksize)); +- len = ((char *) root) + (blocksize - csum_size) - (char *) de; ++ len = ((char *)dot_de) + (blocksize - csum_size) - (char *)de; + + /* Allocate new block for the 0th block's dirents */ + bh2 = ext4_append(handle, dir, &block); +@@ -2368,24 +2360,26 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, + ext4_initialize_dirent_tail(bh2, blocksize); + + /* Initialize the root; the dot dirents already exist */ +- de = (struct ext4_dir_entry_2 *) (&root->dotdot); +- de->rec_len = ext4_rec_len_to_disk( +- blocksize - ext4_dir_rec_len(2, NULL), blocksize); +- memset (&root->info, 0, sizeof(root->info)); +- root->info.info_length = sizeof(root->info); ++ dotdot_de->rec_len = ++ ext4_rec_len_to_disk(blocksize - le16_to_cpu(dot_de->rec_len), ++ blocksize); ++ ++ /* initialize hashing info */ ++ dx_info = dx_get_dx_info(dot_de); ++ memset(dx_info, 0, sizeof(*dx_info)); ++ dx_info->info_length = sizeof(*dx_info); + if (ext4_hash_in_dirent(dir)) +- root->info.hash_version = DX_HASH_SIPHASH; ++ dx_info->hash_version = DX_HASH_SIPHASH; + else +- root->info.hash_version = ++ dx_info->hash_version = + EXT4_SB(dir->i_sb)->s_def_hash_version; +- +- entries = root->entries; ++ entries = (void *)dx_info + sizeof(*dx_info); + dx_set_block(entries, 1); + dx_set_count(entries, 1); +- dx_set_limit(entries, dx_root_limit(dir, sizeof(root->info))); ++ dx_set_limit(entries, dx_root_limit(dir, sizeof(*dx_info))); + + /* Initialize as for dx_probe */ +- fname->hinfo.hash_version = root->info.hash_version; ++ fname->hinfo.hash_version = dx_info->hash_version; + if (fname->hinfo.hash_version <= DX_HASH_TEA) + fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; + fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; +@@ -2751,7 +2745,7 @@ again: + if (restart || err) + goto journal_error; + } else { +- struct dx_root *dxroot; ++ struct dx_root_info *info; + memcpy((char *) entries2, (char *) entries, + icount * sizeof(struct dx_entry)); + dx_set_limit(entries2, dx_node_limit(dir)); +@@ -2759,8 +2753,9 @@ again: + /* Set up root */ + dx_set_count(entries, 1); + dx_set_block(entries + 0, newblock); +- dxroot = (struct dx_root *)frames[0].bh->b_data; +- dxroot->info.indirect_levels += 1; ++ info = dx_get_dx_info((struct ext4_dir_entry_2 *) ++ frames[0].bh->b_data); ++ info->indirect_levels = 1; + dxtrace(printk(KERN_DEBUG + "Creating %d level index...\n", + dxroot->info.indirect_levels)); +-- +2.34.1 + diff --git a/ldiskfs/kernel_patches/patches/linux-6.11/ext4-lookup-dotdot.patch b/ldiskfs/kernel_patches/patches/linux-6.11/ext4-lookup-dotdot.patch new file mode 100644 index 0000000..2fb3c8b --- /dev/null +++ b/ldiskfs/kernel_patches/patches/linux-6.11/ext4-lookup-dotdot.patch @@ -0,0 +1,60 @@ +commit 113303973ec9f8484eb2355a1a6ef3c4c7fd6a56 +Author: Alex Zhuravlev +AuthorDate: Sat Feb 10 06:33:41 2007 +0000 +Subject: ext4: htree fix for '..' lookup + +Avoid looping in directory lookup when ext3_dx_find_entry() +can't find the '..' entry in a directory and then looks it +up in the directory. This results in the ".." (parent +directory) entry being added as the child of a directory +in the dcache. The '..' lookup can happen knfsd is looking +up the path of a disconnected dentry. + +Bugzilla-ID: b=10458 +Signed-off-by: Alex Zhuravlev +Reviewed-by: Kalpak Shah +Signed-off-by: Andreas Dilger +--- + fs/ext4/namei.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 6a95713f..56837d18 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -1825,6 +1825,32 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi + return ERR_PTR(-EPERM); + } + } ++ /* ".." shouldn't go into dcache to preserve dcache hierarchy ++ * otherwise we'll get parent being a child of actual child. ++ * see bug 10458 for details -bzzz */ ++ if (inode && (dentry->d_name.name[0] == '.' && ++ (dentry->d_name.len == 1 || (dentry->d_name.len == 2 && ++ dentry->d_name.name[1] == '.')))) { ++ struct dentry *goal = NULL; ++ ++ /* first, look for an existing dentry - any one is good */ ++ goal = d_find_any_alias(inode); ++ if (goal == NULL) { ++ spin_lock(&dentry->d_lock); ++ /* there is no alias, we need to make current dentry: ++ * a) inaccessible for __d_lookup() ++ * b) inaccessible for iopen */ ++ J_ASSERT(hlist_unhashed(&dentry->d_u.d_alias)); ++ dentry->d_flags |= DCACHE_NFSFS_RENAMED; ++ /* this is d_instantiate() ... */ ++ hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); ++ dentry->d_inode = inode; ++ spin_unlock(&dentry->d_lock); ++ } ++ if (goal) ++ iput(inode); ++ return goal; ++ } + + if (IS_ENABLED(CONFIG_UNICODE) && !inode && IS_CASEFOLDED(dir)) { + /* Eventually we want to call d_add_ci(dentry, NULL) +-- +2.34.1 + diff --git a/ldiskfs/kernel_patches/series/ldiskfs-6.11-ml.series b/ldiskfs/kernel_patches/series/ldiskfs-6.11-ml.series new file mode 100644 index 0000000..c49a97c --- /dev/null +++ b/ldiskfs/kernel_patches/series/ldiskfs-6.11-ml.series @@ -0,0 +1,38 @@ +linux-5.16/ext4-inode-version.patch +linux-6.11/ext4-lookup-dotdot.patch +linux-5.14/ext4-print-inum-in-htree-warning.patch +linux-6.10/ext4-prealloc.patch +linux-5.16/ext4-osd-iop-common.patch +linux-6.10/ext4-misc.patch +linux-6.10/ext4-mballoc-extra-checks.patch +sles15sp4/ext4-hash-indexed-dir-dotdot-update.patch +linux-6.11/ext4-kill-dx-root.patch +linux-6.5/ext4-mballoc-pa-free-mismatch.patch +linux-6.5/ext4-data-in-dirent.patch +linux-6.6/ext4-nocmtime.patch +base/ext4-htree-lock.patch +linux-6.5/ext4-pdirop.patch +linux-6.10/ext4-max-dir-size.patch +linux-6.10/ext4-corrupted-inode-block-bitmaps-handling-patches.patch +rhel9/ext4-give-warning-with-dir-htree-growing.patch +ubuntu18/ext4-jcb-optimization.patch +linux-6.2/ext4-attach-jinode-in-writepages.patch +linux-6.5/ext4-dont-check-before-replay.patch +rhel7.6/ext4-use-GFP_NOFS-in-ext4_inode_attach_jinode.patch +rhel7.6/ext4-export-orphan-add.patch +linux-5.18/ext4-export-mb-stream-allocator-variables.patch +ubuntu19/ext4-iget-with-flags.patch +linux-5.14/export-ext4fs-dirhash-helper.patch +linux-5.8/ext4-no-max-dir-size-limit-for-iam-objects.patch +rhel9/ext4-dquot-commit-speedup.patch +linux-6.7/ext4-ialloc-uid-gid-and-pass-owner-down.patch +linux-5.14/ext4-projid-xattrs.patch +linux-6.10/ext4-delayed-iput.patch +rhel8/ext4-ext-merge.patch +linux-5.14/ext4-xattr-disable-credits-check.patch +rhel9.2/ext4-fiemap-kernel-data.patch +rhel8/ext4-old_ea_inodes_handling_fix.patch +linux-6.10/ext4-filename-encode.patch +rhel9.1/ext4-enc-flag.patch +linux-6.6/ext4-encdata.patch +rhel9.4/ext4-add-IGET_NO_CHECKS-flag.patch -- 1.8.3.1