From 7b7e7e0b843e1c6d0b073b14a0cc87220079faf7 Mon Sep 17 00:00:00 2001 From: Xinliang Liu Date: Wed, 10 May 2023 10:08:38 +0000 Subject: [PATCH] LU-16824 ldiskfs: add support for openEuler 22.03 LTS SP1 Add openEuler 22.03 LTS SP1 config target file. Fix tiny conflicts for patch ext4-delayed-iput.patch and ext4-data-in-dirent.patch. Add missing patch ext4-encdata.patch. Add build required pkg kernel-debugsource for ldiskfs build. Change-Id: I68314c9df17ce991a5e46f2ed4746ce1703b1587 Test-Parameters: trivial Signed-off-by: Xinliang Liu Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/50978 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Jian Yu Reviewed-by: Oleg Drokin --- config/lustre-build-ldiskfs.m4 | 1 + contrib/lbuild/funcs.sh | 10 + contrib/lbuild/lbuild | 3 + contrib/lbuild/lbuild-oe2203 | 12 - contrib/lbuild/lbuild-oe2203sp1 | 40 ++ .../patches/oe2203/ext4-delayed-iput.patch | 187 +++++ .../patches/oe2203sp1/ext4-data-in-dirent.patch | 764 +++++++++++++++++++++ .../series/ldiskfs-5.10.0-oe2203.series | 3 +- .../series/ldiskfs-5.10.0-oe2203sp1.series | 35 + lustre.spec.in | 3 + lustre/ChangeLog | 3 +- lustre/autoconf/lustre-core.m4 | 1 + .../kernel_patches/targets/5.10-oe2203.target.in | 2 +- .../targets/5.10-oe2203sp1.target.in | 21 + 14 files changed, 1070 insertions(+), 15 deletions(-) create mode 100644 contrib/lbuild/lbuild-oe2203sp1 create mode 100644 ldiskfs/kernel_patches/patches/oe2203/ext4-delayed-iput.patch create mode 100644 ldiskfs/kernel_patches/patches/oe2203sp1/ext4-data-in-dirent.patch create mode 100644 ldiskfs/kernel_patches/series/ldiskfs-5.10.0-oe2203sp1.series create mode 100644 lustre/kernel_patches/targets/5.10-oe2203sp1.target.in diff --git a/config/lustre-build-ldiskfs.m4 b/config/lustre-build-ldiskfs.m4 index 3f7e578..df5799d 100644 --- a/config/lustre-build-ldiskfs.m4 +++ b/config/lustre-build-ldiskfs.m4 @@ -142,6 +142,7 @@ AS_IF([test x$RHEL_KERNEL = xyes], [ ], [test x$OPENEULER_KERNEL = xyes], [ case $OPENEULER_VERSION_NO in 2203.0) LDISKFS_SERIES="5.10.0-oe2203.series" ;; + 2203.1) LDISKFS_SERIES="5.10.0-oe2203sp1.series" ;; esac ]) ]) diff --git a/contrib/lbuild/funcs.sh b/contrib/lbuild/funcs.sh index 78e2af9..8db9532 100644 --- a/contrib/lbuild/funcs.sh +++ b/contrib/lbuild/funcs.sh @@ -156,8 +156,17 @@ autodetect_distro() { ;; "openEuler") name="oe" + # For LTS SP release the codename is 'LTS-SPx' e.g. 'LTS-SP1' + # otherwise the codename is 'n/a'. + lts_sp=$(lsb_release -s -c) # Change from YY.MM to YYMM, let DISTROMAJ contain MM part version=${version/./} + # Append LTS SP + if [[ "$lts_sp" != "n/a" ]]; then + lts_sp=${lts_sp##*-} + lts_sp=${lts_sp,,} + version="${version}${lts_sp}" + fi ;; *) fatal 1 "I don't know what distro name $name and version $version is.\nEither update autodetect_distro() or use the --distro argument." @@ -213,6 +222,7 @@ autodetect_target() { sles15.4) target="$(uname -r | cut -d . -f 1,2)-sles15sp4";; fc18) target="3.x-fc18";; oe2203) target="5.10-oe2203";; + oe2203sp1) target="5.10-oe2203sp1";; *) fatal 1 "I don't know what distro $distro is.\nEither update autodetect_target() or use the --target argument.";; esac diff --git a/contrib/lbuild/lbuild b/contrib/lbuild/lbuild index 0275a21..70ef15b 100755 --- a/contrib/lbuild/lbuild +++ b/contrib/lbuild/lbuild @@ -332,6 +332,9 @@ check_options() { 5.10-oe2203) CANONICAL_TARGET="oe2203" ;; + 5.10-oe2203sp1) + CANONICAL_TARGET="oe2203sp1" + ;; esac local timestampnodig=$(echo $TIMESTAMP | sed -e s/[0-9]*//g) diff --git a/contrib/lbuild/lbuild-oe2203 b/contrib/lbuild/lbuild-oe2203 index d49a1e6..1f4dc54 100644 --- a/contrib/lbuild/lbuild-oe2203 +++ b/contrib/lbuild/lbuild-oe2203 @@ -37,15 +37,3 @@ kernel_debuginfo_location() { echo "$base_os/update/$TARGET_ARCH/Packages/" } - -cleanup_rpmmacros() { - sed -i "/^%kernel_module_package/,/^)}$/d" $RMAC -} - -apply_kmod_requires_conflicts() { - if $PATCHLESS; then - # don't allow the patched kernel to be considered as - # a valid kernel for the patchless client - echo "Conflicts: kernel-lustre" >> rpm/kmp-lustre.preamble - fi -} diff --git a/contrib/lbuild/lbuild-oe2203sp1 b/contrib/lbuild/lbuild-oe2203sp1 new file mode 100644 index 0000000..b115a34 --- /dev/null +++ b/contrib/lbuild/lbuild-oe2203sp1 @@ -0,0 +1,40 @@ +source ${LBUILD_DIR}/lbuild-rhel + +# increment this if you have made a change that should force a new kernel +# to build built +BUILD_GEN+=".0" + +SPEC_NAME="kernel.spec" +DEVEL_PATH_ARCH_DELIMETER="." +USE_KABI=false +RPM_HELPERS_DIR="/usr/lib/rpm/openEuler" +# Pkg which contains ext4 source code +KERNEL_DEBUGINFO="kernel-debugsource-${lnxmaj}-${lnxrel}.${TARGET_ARCH}.rpm" +DISTRO_REPO_MIRROR=${DISTRO_REPO_MIRROR:-"https://repo.openeuler.org"} + +# force local definition of %dist into ~/.rpmmacros +# to avoid verbose extended strings like ".el9.centos" +# in kernel version and rpm names +# +RMAC=$HOME/.rpmmacros +grep '^%dist' $RMAC &> /dev/null || echo '%dist .oe2203sp1' >> $RMAC + +unpack_linux_devel_rpm-oe2203sp1() { + local callers_rpm="$1" + + unpack_linux_devel_rpm-rhel "$callers_rpm" +} + +find_linux_rpm-oe2203sp1() { + local prefix="$1" + local wanted_kernel="$2" + local pathtorpms=${3:-"$KERNELRPMSBASE/$lnxmaj/$DISTROMAJ/$TARGET_ARCH"} + + find_linux_rpm-rhel "$prefix" "$wanted_kernel" "$pathtorpms" +} + +kernel_debuginfo_location() { + local base_os="$DISTRO_REPO_MIRROR/openEuler-22.03-LTS-SP1" + + echo "$base_os/update/$TARGET_ARCH/Packages/" +} diff --git a/ldiskfs/kernel_patches/patches/oe2203/ext4-delayed-iput.patch b/ldiskfs/kernel_patches/patches/oe2203/ext4-delayed-iput.patch new file mode 100644 index 0000000..8dd44bd --- /dev/null +++ b/ldiskfs/kernel_patches/patches/oe2203/ext4-delayed-iput.patch @@ -0,0 +1,187 @@ +From 5230b17f70f7d30161db506d4f631131befb319d Mon Sep 17 00:00:00 2001 +From: Xinliang Liu +Date: Wed, 10 May 2023 09:46:14 +0000 +Subject: [PATCH] ext4 delayed iput + +When changing a large xattr value to a different large xattr value, +the old xattr inode is freed. Truncate during the final iput causes +current transaction restart. Eventually, parent inode bh is marked +dirty and kernel panic happens when jbd2 figures out that this bh +belongs to the committed transaction. + +A possible fix is to call this final iput in a separate thread. +This way, setxattr transactions will never be split into two. +Since the setxattr code adds xattr inodes with nlink=0 into the +orphan list, old xattr inodes will be properly cleaned up in +any case. + +Signed-off-by: Andrew Perepechko +HPE-bug-id: LUS-10534 + +Changes since v1: +- fixed a bug added during the porting +- fixed a workqueue related deadlock reported by Tetsuo Handa + +Signed-off-by: Xinliang Liu +--- + fs/ext4/ext4.h | 7 +++++-- + fs/ext4/page-io.c | 2 +- + fs/ext4/super.c | 15 ++++++++------- + fs/ext4/xattr.c | 39 +++++++++++++++++++++++++++++++++++++-- + 4 files changed, 51 insertions(+), 12 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 213a2b6..bbf50b6 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1599,8 +1599,11 @@ struct ext4_sb_info { + struct flex_groups * __rcu *s_flex_groups; + ext4_group_t s_flex_groups_allocated; + +- /* workqueue for reserved extent conversions (buffered io) */ +- struct workqueue_struct *rsv_conversion_wq; ++ /* ++ * workqueue for reserved extent conversions (buffered io) ++ * and large ea inodes reclaim ++ */ ++ struct workqueue_struct *s_misc_wq; + + /* timer for periodic error stats printing */ + struct timer_list s_err_report; +diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c +index b076fab..c027af5 100644 +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -233,7 +233,7 @@ static void ext4_add_complete_io(ext4_io_end_t *io_end) + WARN_ON(!(io_end->flag & EXT4_IO_END_UNWRITTEN)); + WARN_ON(!io_end->handle && sbi->s_journal); + spin_lock_irqsave(&ei->i_completed_io_lock, flags); +- wq = sbi->rsv_conversion_wq; ++ wq = sbi->s_misc_wq; + if (list_empty(&ei->i_rsv_conversion_list)) + queue_work(wq, &ei->i_rsv_conversion_work); + list_add_tail(&io_end->list, &ei->i_rsv_conversion_list); +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 8829e9d..b0fd2bc 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -1223,10 +1223,11 @@ static void ext4_put_super(struct super_block *sb) + ext4_unregister_sysfs(sb); + + ext4_unregister_li_request(sb); ++ flush_workqueue(sbi->s_misc_wq); + ext4_quota_off_umount(sb); + + flush_work(&sbi->s_error_work); +- destroy_workqueue(sbi->rsv_conversion_wq); ++ destroy_workqueue(sbi->s_misc_wq); + + if (sbi->s_journal) { + aborted = is_journal_aborted(sbi->s_journal); +@@ -5001,9 +5002,9 @@ no_journal: + * The maximum number of concurrent works can be high and + * concurrency isn't really necessary. Limit it to 1. + */ +- EXT4_SB(sb)->rsv_conversion_wq = +- alloc_workqueue("ext4-rsv-conversion", WQ_MEM_RECLAIM | WQ_UNBOUND, 1); +- if (!EXT4_SB(sb)->rsv_conversion_wq) { ++ EXT4_SB(sb)->s_misc_wq = ++ alloc_workqueue("ext4-misc", WQ_MEM_RECLAIM | WQ_UNBOUND, 1); ++ if (!EXT4_SB(sb)->s_misc_wq) { + printk(KERN_ERR "EXT4-fs: failed to create workqueue\n"); + ret = -ENOMEM; + goto failed_mount4; +@@ -5225,8 +5226,8 @@ failed_mount4a: + sb->s_root = NULL; + failed_mount4: + ext4_msg(sb, KERN_ERR, "mount failed"); +- if (EXT4_SB(sb)->rsv_conversion_wq) +- destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq); ++ if (EXT4_SB(sb)->s_misc_wq) ++ destroy_workqueue(EXT4_SB(sb)->s_misc_wq); + failed_mount_wq: + ext4_xattr_destroy_cache(sbi->s_ea_inode_cache); + sbi->s_ea_inode_cache = NULL; +@@ -5800,7 +5801,7 @@ static int ext4_sync_fs(struct super_block *sb, int wait) + return 0; + + trace_ext4_sync_fs(sb, wait); +- flush_workqueue(sbi->rsv_conversion_wq); ++ flush_workqueue(sbi->s_misc_wq); + /* + * Writeback quota in non-journalled quota case - journalled quota has + * no dirty dquots +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index 1cb753a..dd72157 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1597,6 +1597,36 @@ static int ext4_xattr_inode_lookup_create(handle_t *handle, struct inode *inode, + return 0; + } + ++struct delayed_iput_work { ++ struct work_struct work; ++ struct inode *inode; ++}; ++ ++static void delayed_iput_fn(struct work_struct *work) ++{ ++ struct delayed_iput_work *diwork; ++ ++ diwork = container_of(work, struct delayed_iput_work, work); ++ iput(diwork->inode); ++ kfree(diwork); ++} ++ ++static void delayed_iput(struct inode *inode, struct delayed_iput_work *work) ++{ ++ if (!inode) { ++ kfree(work); ++ return; ++ } ++ ++ if (!work) { ++ iput(inode); ++ } else { ++ INIT_WORK(&work->work, delayed_iput_fn); ++ work->inode = inode; ++ queue_work(EXT4_SB(inode->i_sb)->s_misc_wq, &work->work); ++ } ++} ++ + /* + * Reserve min(block_size/8, 1024) bytes for xattr entries/names if ea_inode + * feature is enabled. +@@ -1614,6 +1644,7 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i, + int in_inode = i->in_inode; + struct inode *old_ea_inode = NULL; + struct inode *new_ea_inode = NULL; ++ struct delayed_iput_work *diwork = NULL; + size_t old_size, new_size; + int ret; + +@@ -1690,7 +1721,11 @@ static int ext4_xattr_set_entry(struct ext4_xattr_info *i, + * Finish that work before doing any modifications to the xattr data. + */ + if (!s->not_found && here->e_value_inum) { +- ret = ext4_xattr_inode_iget(inode, ++ diwork = kmalloc(sizeof(*diwork), GFP_NOFS); ++ if (!diwork) ++ ret = -ENOMEM; ++ else ++ ret = ext4_xattr_inode_iget(inode, + le32_to_cpu(here->e_value_inum), + le32_to_cpu(here->e_hash), + &old_ea_inode); +@@ -1843,7 +1878,7 @@ update_hash: + + ret = 0; + out: +- iput(old_ea_inode); ++ delayed_iput(old_ea_inode, diwork); + iput(new_ea_inode); + return ret; + } +-- +2.33.0 + diff --git a/ldiskfs/kernel_patches/patches/oe2203sp1/ext4-data-in-dirent.patch b/ldiskfs/kernel_patches/patches/oe2203sp1/ext4-data-in-dirent.patch new file mode 100644 index 0000000..9512f94 --- /dev/null +++ b/ldiskfs/kernel_patches/patches/oe2203sp1/ext4-data-in-dirent.patch @@ -0,0 +1,764 @@ +From ef3b0235735794064352d9b053802b368ecdfcc9 Mon Sep 17 00:00:00 2001 +From: Xinliang Liu +Date: Thu, 11 May 2023 09:57:05 +0000 +Subject: [PATCH] ext4 data in dirent + +this patch implements feature which allows ext4 fs users (e.g. Lustre) +to store data in ext4 dirent. +data is stored in ext4 dirent after file-name, this space is accounted +in de->rec_len. flag EXT4_DIRENT_LUFID added to d_type if extra data +is present. + +make use of dentry->d_fsdata to pass fid to ext4. so no +changes in ext4_add_entry() interface required. + +Signed-off-by: Xinliang Liu +--- + fs/ext4/dir.c | 13 ++- + fs/ext4/ext4.h | 100 +++++++++++++++++++-- + fs/ext4/fast_commit.c | 2 +- + fs/ext4/inline.c | 8 +- + fs/ext4/namei.c | 201 +++++++++++++++++++++++++++++++++--------- + fs/ext4/super.c | 4 +- + 6 files changed, 270 insertions(+), 58 deletions(-) + +diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c +index 70a0f5e..ff7d8c3 100644 +--- a/fs/ext4/dir.c ++++ b/fs/ext4/dir.c +@@ -78,7 +78,7 @@ int __ext4_check_dir_entry(const char *function, unsigned int line, + error_msg = "rec_len is smaller than minimal"; + else if (unlikely(rlen % 4 != 0)) + error_msg = "rec_len % 4 != 0"; +- else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len))) ++ else if (unlikely(rlen < EXT4_DIR_ENTRY_LEN(de))) + error_msg = "rec_len is too small for name_len"; + else if (unlikely(next_offset > size)) + error_msg = "directory entry overrun"; +@@ -226,7 +226,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx) + * failure will be detected in the + * dirent test below. */ + if (ext4_rec_len_from_disk(de->rec_len, +- sb->s_blocksize) < EXT4_DIR_REC_LEN(1)) ++ sb->s_blocksize) < EXT4_DIR_REC_LEN(1)) + break; + i += ext4_rec_len_from_disk(de->rec_len, + sb->s_blocksize); +@@ -449,12 +449,17 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, + struct fname *fname, *new_fn; + struct dir_private_info *info; + int len; ++ int extra_data = 0; + + info = dir_file->private_data; + p = &info->root.rb_node; + + /* Create and allocate the fname structure */ +- len = sizeof(struct fname) + ent_name->len + 1; ++ if (dirent->file_type & EXT4_DIRENT_LUFID) ++ extra_data = ext4_get_dirent_data_len(dirent); ++ ++ len = sizeof(struct fname) + ent_name->len + extra_data + 1; ++ + new_fn = kzalloc(len, GFP_KERNEL); + if (!new_fn) + return -ENOMEM; +@@ -463,7 +468,7 @@ int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, + new_fn->inode = le32_to_cpu(dirent->inode); + new_fn->name_len = ent_name->len; + new_fn->file_type = dirent->file_type; +- memcpy(new_fn->name, ent_name->name, ent_name->len); ++ memcpy(new_fn->name, ent_name->name, ent_name->len + extra_data); + + while (*p) { + parent = *p; +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 143ce00..98786d8 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1167,6 +1167,7 @@ struct ext4_inode_info { + __u32 i_csum_seed; + + kprojid_t i_projid; ++ void *i_dirdata; + + /* Protect concurrent add cluster delayed block and remove block */ + struct mutex i_clu_lock; +@@ -1191,6 +1192,7 @@ struct ext4_inode_info { + * Mount flags set via mount options or defaults + */ + #define EXT4_MOUNT_NO_MBCACHE 0x00001 /* Do not use mbcache */ ++#define EXT4_MOUNT_DIRDATA 0x00002 /* Data in directory entries */ + #define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */ + #define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */ + #define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ +@@ -2086,6 +2088,7 @@ EXT4_FEATURE_INCOMPAT_FUNCS(casefold, CASEFOLD) + EXT4_FEATURE_INCOMPAT_FLEX_BG| \ + EXT4_FEATURE_INCOMPAT_EA_INODE| \ + EXT4_FEATURE_INCOMPAT_MMP | \ ++ EXT4_FEATURE_INCOMPAT_DIRDATA| \ + EXT4_FEATURE_INCOMPAT_INLINE_DATA | \ + EXT4_FEATURE_INCOMPAT_ENCRYPT | \ + EXT4_FEATURE_INCOMPAT_CASEFOLD | \ +@@ -2268,6 +2271,43 @@ struct ext4_dir_entry_tail { + #define EXT4_FT_SYMLINK 7 + + #define EXT4_FT_MAX 8 ++#define EXT4_FT_MASK 0xf ++ ++#if EXT4_FT_MAX > EXT4_FT_MASK ++#error "conflicting EXT4_FT_MAX and EXT4_FT_MASK" ++#endif ++ ++/* ++ * d_type has 4 unused bits, so it can hold four types data. these different ++ * type of data (e.g. lustre data, high 32 bits of 64-bit inode number) can be ++ * stored, in flag order, after file-name in ext4 dirent. ++*/ ++/* ++ * this flag is added to d_type if ext4 dirent has extra data after ++ * filename. this data length is variable and length is stored in first byte ++ * of data. data start after filename NUL byte. ++ * This is used by Lustre FS. ++ */ ++#define EXT4_DIRENT_LUFID 0x10 ++ ++#define EXT4_LUFID_MAGIC 0xAD200907UL ++struct ext4_dentry_param { ++ __u32 edp_magic; /* EXT4_LUFID_MAGIC */ ++ char edp_len; /* size of edp_data in bytes */ ++ char edp_data[0]; /* packed array of data */ ++} __packed; ++ ++static inline unsigned char *ext4_dentry_get_data(struct super_block *sb, ++ struct ext4_dentry_param *p) ++ ++{ ++ if (!ext4_has_feature_dirdata(sb)) ++ return NULL; ++ if (p && p->edp_magic == EXT4_LUFID_MAGIC) ++ return &p->edp_len; ++ else ++ return NULL; ++} + + #define EXT4_FT_DIR_CSUM 0xDE + +@@ -2278,8 +2318,16 @@ struct ext4_dir_entry_tail { + */ + #define EXT4_DIR_PAD 4 + #define EXT4_DIR_ROUND (EXT4_DIR_PAD - 1) +-#define EXT4_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) & \ ++#define EXT4_DIR_REC_LEN_(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) & \ + ~EXT4_DIR_ROUND) ++#define EXT4_DIR_ENTRY_LEN_(de) (EXT4_DIR_REC_LEN_((de)->name_len +\ ++ ext4_get_dirent_data_len(de))) ++/* ldiskfs */ ++#define EXT4_DIR_REC_LEN(name_len) EXT4_DIR_REC_LEN_((name_len)) ++#define EXT4_DIR_ENTRY_LEN(de) EXT4_DIR_ENTRY_LEN_((de)) ++/* lustre osd_handler compat */ ++#define __EXT4_DIR_REC_LEN(name_len) EXT4_DIR_REC_LEN_((name_len)) ++ + #define EXT4_MAX_REC_LEN ((1<<16)-1) + + /* +@@ -2746,11 +2794,11 @@ extern int ext4_find_dest_de(struct inode *dir, struct inode *inode, + struct buffer_head *bh, + void *buf, int buf_size, + struct ext4_filename *fname, +- struct ext4_dir_entry_2 **dest_de); ++ struct ext4_dir_entry_2 **dest_de, int *dlen); + void ext4_insert_dentry(struct inode *inode, + struct ext4_dir_entry_2 *de, + int buf_size, +- struct ext4_filename *fname); ++ struct ext4_filename *fname, void *data); + static inline void ext4_update_dx_flag(struct inode *inode) + { + if (!ext4_has_feature_dir_index(inode->i_sb) && +@@ -2766,10 +2814,17 @@ static const unsigned char ext4_filetype_table[] = { + + static inline unsigned char get_dtype(struct super_block *sb, int filetype) + { +- if (!ext4_has_feature_filetype(sb) || filetype >= EXT4_FT_MAX) ++ int fl_index = filetype & EXT4_FT_MASK; ++ ++ if (!ext4_has_feature_filetype(sb) || fl_index >= EXT4_FT_MAX) + return DT_UNKNOWN; + +- return ext4_filetype_table[filetype]; ++ if (!test_opt(sb, DIRDATA)) ++ return ext4_filetype_table[fl_index]; ++ ++ return (ext4_filetype_table[fl_index]) | ++ (filetype & EXT4_DIRENT_LUFID); ++ + } + extern int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, + void *buf, int buf_size); +@@ -2965,7 +3020,8 @@ extern int ext4_ind_migrate(struct inode *inode); + + /* namei.c */ + extern int ext4_init_new_dir(handle_t *handle, struct inode *dir, +- struct inode *inode); ++ struct inode *inode, ++ const void *data1, const void *data2); + extern int ext4_dirblock_csum_verify(struct inode *inode, + struct buffer_head *bh); + extern int ext4_orphan_add(handle_t *, struct inode *); +@@ -2976,6 +3032,8 @@ extern struct inode *ext4_create_inode(handle_t *handle, + extern int ext4_delete_entry(handle_t *handle, struct inode * dir, + struct ext4_dir_entry_2 *de_del, + struct buffer_head *bh); ++extern int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir, ++ struct inode *inode, const void *, const void *); + extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, + __u32 start_minor_hash, __u32 *next_hash); + extern int ext4_search_dir(struct buffer_head *bh, +@@ -3765,6 +3823,36 @@ static inline int ext4_buffer_uptodate(struct buffer_head *bh) + return buffer_uptodate(bh); + } + ++/* ++ * Compute the total directory entry data length. ++ * This includes the filename and an implicit NUL terminator (always present), ++ * and optional extensions. Each extension has a bit set in the high 4 bits of ++ * de->file_type, and the extension length is the first byte in each entry. ++ */ ++static inline int ext4_get_dirent_data_len(struct ext4_dir_entry_2 *de) ++{ ++ char *len = de->name + de->name_len + 1 /* NUL terminator */; ++ int dlen = 0; ++ __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; ++ struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de; ++ ++ if (!t->det_reserved_zero1 && ++ le16_to_cpu(t->det_rec_len) == ++ sizeof(struct ext4_dir_entry_tail) && ++ !t->det_reserved_zero2 && ++ t->det_reserved_ft == EXT4_FT_DIR_CSUM) ++ return 0; ++ ++ while (extra_data_flags) { ++ if (extra_data_flags & 1) { ++ dlen += *len + (dlen == 0); ++ len += *len; ++ } ++ extra_data_flags >>= 1; ++ } ++ return dlen; ++} ++ + #endif /* __KERNEL__ */ + + #define EFSBADCRC EBADMSG /* Bad CRC detected */ +diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c +index 41dcf21..1023ace 100644 +--- a/fs/ext4/fast_commit.c ++++ b/fs/ext4/fast_commit.c +@@ -1547,7 +1547,7 @@ static int ext4_fc_replay_create(struct super_block *sb, struct ext4_fc_tl *tl, + jbd_debug(1, "Dir %d not found.", darg.ino); + goto out; + } +- ret = ext4_init_new_dir(NULL, dir, inode); ++ ret = ext4_init_new_dir(NULL, dir, inode, NULL, NULL); + iput(dir); + if (ret) { + ret = 0; +diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c +index c2c688c..686d14a 100644 +--- a/fs/ext4/inline.c ++++ b/fs/ext4/inline.c +@@ -1033,7 +1033,7 @@ static int ext4_add_dirent_to_inline(handle_t *handle, + struct ext4_dir_entry_2 *de; + + err = ext4_find_dest_de(dir, inode, iloc->bh, inline_start, +- inline_size, fname, &de); ++ inline_size, fname, &de, NULL); + if (err) + return err; + +@@ -1041,7 +1041,7 @@ static int ext4_add_dirent_to_inline(handle_t *handle, + err = ext4_journal_get_write_access(handle, iloc->bh); + if (err) + return err; +- ext4_insert_dentry(inode, de, inline_size, fname); ++ ext4_insert_dentry(inode, de, inline_size, fname, NULL); + + ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size); + +@@ -1398,7 +1398,7 @@ int ext4_inlinedir_to_tree(struct file *dir_file, + fake.name_len = 1; + strcpy(fake.name, "."); + fake.rec_len = ext4_rec_len_to_disk( +- EXT4_DIR_REC_LEN(fake.name_len), ++ EXT4_DIR_ENTRY_LEN(&fake), + inline_size); + ext4_set_de_type(inode->i_sb, &fake, S_IFDIR); + de = &fake; +@@ -1408,7 +1408,7 @@ int ext4_inlinedir_to_tree(struct file *dir_file, + fake.name_len = 2; + strcpy(fake.name, ".."); + fake.rec_len = ext4_rec_len_to_disk( +- EXT4_DIR_REC_LEN(fake.name_len), ++ EXT4_DIR_ENTRY_LEN(&fake), + inline_size); + ext4_set_de_type(inode->i_sb, &fake, S_IFDIR); + de = &fake; +diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c +index 1537a76..24e1276 100644 +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -295,7 +295,8 @@ static unsigned dx_get_count(struct dx_entry *entries); + static unsigned dx_get_limit(struct dx_entry *entries); + static void dx_set_count(struct dx_entry *entries, unsigned value); + static void dx_set_limit(struct dx_entry *entries, unsigned value); +-static unsigned dx_root_limit(struct inode *dir, unsigned infosize); ++static inline unsigned dx_root_limit(struct inode *dir, ++ struct ext4_dir_entry_2 *dot_de, unsigned infosize); + static unsigned dx_node_limit(struct inode *dir); + static struct dx_frame *dx_probe(struct ext4_filename *fname, + struct inode *dir, +@@ -439,22 +440,23 @@ static struct dx_countlimit *get_dx_countlimit(struct inode *inode, + { + struct ext4_dir_entry *dp; + struct dx_root_info *root; +- int count_offset; ++ int count_offset, dot_rec_len, dotdot_rec_len; + + if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) + count_offset = 8; +- else if (le16_to_cpu(dirent->rec_len) == 12) { +- dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); ++ else { ++ dot_rec_len = le16_to_cpu(dirent->rec_len); ++ dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len); + if (le16_to_cpu(dp->rec_len) != +- EXT4_BLOCK_SIZE(inode->i_sb) - 12) ++ EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len) + return NULL; +- root = (struct dx_root_info *)(((void *)dp + 12)); ++ dotdot_rec_len = EXT4_DIR_ENTRY_LEN((struct ext4_dir_entry_2 *)dp); ++ root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len)); + if (root->reserved_zero || + root->info_length != sizeof(struct dx_root_info)) + return NULL; +- count_offset = 32; +- } else +- return NULL; ++ count_offset = 8 + dot_rec_len + dotdot_rec_len; ++ } + + if (offset) + *offset = count_offset; +@@ -559,11 +561,12 @@ ext4_next_entry(struct ext4_dir_entry_2 *p, unsigned long blocksize) + */ + struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) + { ++ BUG_ON(de->name_len != 1); + /* get dotdot first */ +- de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(1)); ++ de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_ENTRY_LEN(de)); + + /* dx root info is after dotdot entry */ +- de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_REC_LEN(2)); ++ de = (struct ext4_dir_entry_2 *)((char *)de + EXT4_DIR_ENTRY_LEN(de)); + + return (struct dx_root_info *)de; + } +@@ -608,10 +611,16 @@ static inline void dx_set_limit(struct dx_entry *entries, unsigned value) + ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value); + } + +-static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize) ++static inline unsigned dx_root_limit(struct inode *dir, ++ struct ext4_dir_entry_2 *dot_de, unsigned infosize) + { +- unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - +- EXT4_DIR_REC_LEN(2) - infosize; ++ struct ext4_dir_entry_2 *dotdot_de; ++ unsigned entry_space; ++ ++ BUG_ON(dot_de->name_len != 1); ++ dotdot_de = ext4_next_entry(dot_de, dir->i_sb->s_blocksize); ++ entry_space = dir->i_sb->s_blocksize - EXT4_DIR_ENTRY_LEN(dot_de) - ++ EXT4_DIR_ENTRY_LEN(dotdot_de) - infosize; + + if (ext4_has_metadata_csum(dir->i_sb)) + entry_space -= sizeof(struct dx_tail); +@@ -731,7 +740,7 @@ static struct stats dx_show_leaf(struct inode *dir, + (unsigned) ((char *) de - base)); + #endif + } +- space += EXT4_DIR_REC_LEN(de->name_len); ++ space += EXT4_DIR_ENTRY_LEN(de); + names++; + } + de = ext4_next_entry(de, size); +@@ -840,11 +849,14 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, + + entries = (struct dx_entry *)(((char *)info) + info->info_length); + +- if (dx_get_limit(entries) != dx_root_limit(dir, +- info->info_length)) { ++ if (dx_get_limit(entries) != ++ dx_root_limit(dir, (struct ext4_dir_entry_2 *)frame->bh->b_data, ++ info->info_length)) { + ext4_warning_inode(dir, "dx entry: limit %u != root limit %u", + dx_get_limit(entries), +- dx_root_limit(dir, info->info_length)); ++ dx_root_limit(dir, ++ (struct ext4_dir_entry_2 *)frame->bh->b_data, ++ info->info_length)); + goto fail; + } + +@@ -1851,7 +1863,7 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count, + while (count--) { + struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) + (from + (map->offs<<2)); +- rec_len = EXT4_DIR_REC_LEN(de->name_len); ++ rec_len = EXT4_DIR_ENTRY_LEN(de); + memcpy (to, de, rec_len); + ((struct ext4_dir_entry_2 *) to)->rec_len = + ext4_rec_len_to_disk(rec_len, blocksize); +@@ -1882,7 +1894,7 @@ static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize) + while ((char*)de < base + blocksize) { + next = ext4_next_entry(de, blocksize); + if (de->inode && de->name_len) { +- rec_len = EXT4_DIR_REC_LEN(de->name_len); ++ rec_len = EXT4_DIR_ENTRY_LEN(de); + if (de > to) + memmove(to, de, rec_len); + to->rec_len = ext4_rec_len_to_disk(rec_len, blocksize); +@@ -2023,14 +2035,16 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode, + struct buffer_head *bh, + void *buf, int buf_size, + struct ext4_filename *fname, +- struct ext4_dir_entry_2 **dest_de) ++ struct ext4_dir_entry_2 **dest_de, int *dlen) + { + struct ext4_dir_entry_2 *de; +- unsigned short reclen = EXT4_DIR_REC_LEN(fname_len(fname)); ++ unsigned short reclen = EXT4_DIR_REC_LEN(fname_len(fname)) + ++ (dlen ? *dlen : 0); + int nlen, rlen; + unsigned int offset = 0; + char *top; + ++ dlen ? *dlen = 0 : 0; /* default set to 0 */ + de = (struct ext4_dir_entry_2 *)buf; + top = buf + buf_size - reclen; + while ((char *) de <= top) { +@@ -2039,10 +2053,26 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode, + return -EFSCORRUPTED; + if (ext4_match(dir, fname, de)) + return -EEXIST; +- nlen = EXT4_DIR_REC_LEN(de->name_len); ++ nlen = EXT4_DIR_ENTRY_LEN(de); + rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); + if ((de->inode ? rlen - nlen : rlen) >= reclen) + break; ++ /* Then for dotdot entries, check for the smaller space ++ * required for just the entry, no FID */ ++ if (fname_len(fname) == 2 && memcmp(fname_name(fname), "..", 2) == 0) { ++ if ((de->inode ? rlen - nlen : rlen) >= ++ EXT4_DIR_REC_LEN(fname_len(fname))) { ++ /* set dlen=1 to indicate not ++ * enough space store fid */ ++ dlen ? *dlen = 1 : 0; ++ break; ++ } ++ /* The new ".." entry must be written over the ++ * previous ".." entry, which is the first ++ * entry traversed by this scan. If it doesn't ++ * fit, something is badly wrong, so -EIO. */ ++ return -EIO; ++ } + de = (struct ext4_dir_entry_2 *)((char *)de + rlen); + offset += rlen; + } +@@ -2056,12 +2086,12 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode, + void ext4_insert_dentry(struct inode *inode, + struct ext4_dir_entry_2 *de, + int buf_size, +- struct ext4_filename *fname) ++ struct ext4_filename *fname, void *data) + { + + int nlen, rlen; + +- nlen = EXT4_DIR_REC_LEN(de->name_len); ++ nlen = EXT4_DIR_ENTRY_LEN(de); + rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); + if (de->inode) { + struct ext4_dir_entry_2 *de1 = +@@ -2075,6 +2105,11 @@ void ext4_insert_dentry(struct inode *inode, + ext4_set_de_type(inode->i_sb, de, inode->i_mode); + de->name_len = fname_len(fname); + memcpy(de->name, fname_name(fname), fname_len(fname)); ++ if (data) { ++ de->name[fname_len(fname)] = 0; ++ memcpy(&de->name[fname_len(fname) + 1], data, *(char *)data); ++ de->file_type |= EXT4_DIRENT_LUFID; ++ } + } + + /* +@@ -2092,14 +2127,19 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname, + { + unsigned int blocksize = dir->i_sb->s_blocksize; + int csum_size = 0; +- int err, err2; ++ int err, err2, dlen = 0; ++ unsigned char *data; + ++ data = ext4_dentry_get_data(inode->i_sb, (struct ext4_dentry_param *) ++ EXT4_I(inode)->i_dirdata); + if (ext4_has_metadata_csum(inode->i_sb)) + csum_size = sizeof(struct ext4_dir_entry_tail); + + if (!de) { ++ if (data) ++ dlen = (*data) + 1; + err = ext4_find_dest_de(dir, inode, bh, bh->b_data, +- blocksize - csum_size, fname, &de); ++ blocksize - csum_size, fname, &de, &dlen); + if (err) + return err; + } +@@ -2111,7 +2151,10 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname, + } + + /* By now the buffer is marked for journaling */ +- ext4_insert_dentry(inode, de, blocksize, fname); ++ /* If writing the short form of "dotdot", don't add the data section */ ++ if (dlen == 1) ++ data = NULL; ++ ext4_insert_dentry(inode, de, blocksize, fname, data); + + /* + * XXX shouldn't update any times until successful +@@ -2217,7 +2260,8 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, + + dx_set_block(entries, 1); + dx_set_count(entries, 1); +- dx_set_limit(entries, dx_root_limit(dir, sizeof(*dx_info))); ++ dx_set_limit(entries, dx_root_limit(dir, ++ dot_de, sizeof(*dx_info))); + + /* Initialize as for dx_probe */ + fname->hinfo.hash_version = dx_info->hash_version; +@@ -2267,6 +2311,8 @@ static int ext4_update_dotdot(handle_t *handle, struct dentry *dentry, + struct buffer_head *dir_block; + struct ext4_dir_entry_2 *de; + int len, journal = 0, err = 0; ++ int dlen = 0; ++ char *data; + + if (IS_ERR(handle)) + return PTR_ERR(handle); +@@ -2292,11 +2338,16 @@ static int ext4_update_dotdot(handle_t *handle, struct dentry *dentry, + goto out_journal; + + journal = 1; +- de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(1)); ++ de->rec_len = cpu_to_le16(EXT4_DIR_ENTRY_LEN(de)); + } + +- len -= EXT4_DIR_REC_LEN(1); +- assert(len == 0 || len >= EXT4_DIR_REC_LEN(2)); ++ len -= EXT4_DIR_ENTRY_LEN(de); ++ data = ext4_dentry_get_data(dir->i_sb, ++ (struct ext4_dentry_param *)dentry->d_fsdata); ++ if (data) ++ dlen = *data + 1; ++ assert(len == 0 || len >= EXT4_DIR_REC_LEN(2 + dlen)); ++ + de = (struct ext4_dir_entry_2 *) + ((char *) de + le16_to_cpu(de->rec_len)); + if (!journal) { +@@ -2313,7 +2364,12 @@ static int ext4_update_dotdot(handle_t *handle, struct dentry *dentry, + assert(le16_to_cpu(de->rec_len) >= EXT4_DIR_REC_LEN(2)); + de->name_len = 2; + strcpy(de->name, ".."); +- ext4_set_de_type(dir->i_sb, de, S_IFDIR); ++ if (data != NULL && ext4_get_dirent_data_len(de) >= dlen) { ++ de->name[2] = 0; ++ memcpy(&de->name[2 + 1], data, *data); ++ ext4_set_de_type(dir->i_sb, de, S_IFDIR); ++ de->file_type |= EXT4_DIRENT_LUFID; ++ } + + out_journal: + if (journal) { +@@ -2351,6 +2407,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, + ext4_lblk_t block, blocks; + int csum_size = 0; + ++ EXT4_I(inode)->i_dirdata = dentry->d_fsdata; + if (ext4_has_metadata_csum(inode->i_sb)) + csum_size = sizeof(struct ext4_dir_entry_tail); + +@@ -2918,37 +2975,70 @@ err_unlock_inode: + return err; + } + ++struct tp_block { ++ struct inode *inode; ++ void *data1; ++ void *data2; ++}; ++ + struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode, + struct ext4_dir_entry_2 *de, + int blocksize, int csum_size, + unsigned int parent_ino, int dotdot_real_len) + { ++ void *data1 = NULL, *data2 = NULL; ++ int dot_reclen = 0; ++ ++ if (dotdot_real_len == 10) { ++ struct tp_block *tpb = (struct tp_block *)inode; ++ data1 = tpb->data1; ++ data2 = tpb->data2; ++ inode = tpb->inode; ++ dotdot_real_len = 0; ++ } + de->inode = cpu_to_le32(inode->i_ino); + de->name_len = 1; +- de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len), +- blocksize); + strcpy(de->name, "."); + ext4_set_de_type(inode->i_sb, de, S_IFDIR); + ++ /* get packed fid data*/ ++ data1 = ext4_dentry_get_data(inode->i_sb, ++ (struct ext4_dentry_param *) data1); ++ if (data1) { ++ de->name[1] = 0; ++ memcpy(&de->name[2], data1, *(char *) data1); ++ de->file_type |= EXT4_DIRENT_LUFID; ++ } ++ de->rec_len = cpu_to_le16(EXT4_DIR_ENTRY_LEN(de)); ++ dot_reclen = cpu_to_le16(de->rec_len); + de = ext4_next_entry(de, blocksize); + de->inode = cpu_to_le32(parent_ino); + de->name_len = 2; ++ strcpy(de->name, ".."); ++ ext4_set_de_type(inode->i_sb, de, S_IFDIR); ++ data2 = ext4_dentry_get_data(inode->i_sb, ++ (struct ext4_dentry_param *) data2); ++ if (data2) { ++ de->name[2] = 0; ++ memcpy(&de->name[3], data2, *(char *) data2); ++ de->file_type |= EXT4_DIRENT_LUFID; ++ } + if (!dotdot_real_len) + de->rec_len = ext4_rec_len_to_disk(blocksize - +- (csum_size + EXT4_DIR_REC_LEN(1)), ++ (csum_size + dot_reclen), + blocksize); + else + de->rec_len = ext4_rec_len_to_disk( +- EXT4_DIR_REC_LEN(de->name_len), blocksize); +- strcpy(de->name, ".."); +- ext4_set_de_type(inode->i_sb, de, S_IFDIR); ++ EXT4_DIR_ENTRY_LEN(de), blocksize); + + return ext4_next_entry(de, blocksize); + } + + int ext4_init_new_dir(handle_t *handle, struct inode *dir, +- struct inode *inode) ++ struct inode *inode, ++ const void *data1, const void *data2) + { ++ struct tp_block param; + struct buffer_head *dir_block = NULL; + struct ext4_dir_entry_2 *de; + ext4_lblk_t block = 0; +@@ -2972,7 +3062,11 @@ int ext4_init_new_dir(handle_t *handle, struct inode *dir, + if (IS_ERR(dir_block)) + return PTR_ERR(dir_block); + de = (struct ext4_dir_entry_2 *)dir_block->b_data; +- ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0); ++ param.inode = inode; ++ param.data1 = (void *)data1; ++ param.data2 = (void *)data2; ++ ext4_init_dot_dotdot((struct inode *)(¶m), de, blocksize, ++ csum_size, dir->i_ino, 10); + set_nlink(inode, 2); + if (csum_size) + ext4_initialize_dirent_tail(dir_block, blocksize); +@@ -2987,6 +3081,29 @@ out: + return err; + } + ++/* Initialize @inode as a subdirectory of @dir, and add the ++ * "." and ".." entries into the first directory block. */ ++int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir, ++ struct inode *inode, ++ const void *data1, const void *data2) ++{ ++ int rc; ++ ++ if (IS_ERR(handle)) ++ return PTR_ERR(handle); ++ ++ if (IS_DIRSYNC(dir)) ++ ext4_handle_sync(handle); ++ ++ inode->i_op = &ext4_dir_inode_operations; ++ inode->i_fop = &ext4_dir_operations; ++ rc = ext4_init_new_dir(handle, dir, inode, data1, data2); ++ if (!rc) ++ rc = ext4_mark_inode_dirty(handle, inode); ++ return rc; ++} ++EXPORT_SYMBOL(ext4_add_dot_dotdot); ++ + static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) + { + handle_t *handle; +@@ -3013,7 +3130,7 @@ retry: + + inode->i_op = &ext4_dir_inode_operations; + inode->i_fop = &ext4_dir_operations; +- err = ext4_init_new_dir(handle, dir, inode); ++ err = ext4_init_new_dir(handle, dir, inode, NULL, NULL); + if (err) + goto out_clear_inode; + err = ext4_mark_inode_dirty(handle, inode); +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 6c33a10..59b87b4 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -1719,7 +1719,7 @@ enum { + Opt_inlinecrypt, + Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, + Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, +- Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, ++ Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, Opt_dirdata, + Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version, + Opt_dax, Opt_dax_always, Opt_dax_inode, Opt_dax_never, + Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_warn_on_error, +@@ -1803,6 +1803,7 @@ static const match_table_t tokens = { + {Opt_nolazytime, "nolazytime"}, + {Opt_debug_want_extra_isize, "debug_want_extra_isize=%u"}, + {Opt_nodelalloc, "nodelalloc"}, ++ {Opt_dirdata, "dirdata"}, + {Opt_removed, "mblk_io_submit"}, + {Opt_removed, "nomblk_io_submit"}, + {Opt_block_validity, "block_validity"}, +@@ -2043,6 +2044,7 @@ static const struct mount_opts { + {Opt_usrjquota, 0, MOPT_Q | MOPT_STRING}, + {Opt_grpjquota, 0, MOPT_Q | MOPT_STRING}, + {Opt_offusrjquota, 0, MOPT_Q}, ++ {Opt_dirdata, EXT4_MOUNT_DIRDATA, MOPT_SET}, + {Opt_offgrpjquota, 0, MOPT_Q}, + {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT}, + {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT}, +-- +2.33.0 + diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.10.0-oe2203.series b/ldiskfs/kernel_patches/series/ldiskfs-5.10.0-oe2203.series index b667234..d5b0e8f 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.10.0-oe2203.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.10.0-oe2203.series @@ -29,6 +29,7 @@ linux-5.8/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch base/ext4-projid-xattrs.patch linux-5.8/ext4-enc-flag.patch -base/ext4-delayed-iput.patch +oe2203/ext4-delayed-iput.patch linux-5.10/ext4-fiemap-kernel-data.patch rhel8/ext4-old_ea_inodes_handling_fix.patch +rhel8/ext4-encdata.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.10.0-oe2203sp1.series b/ldiskfs/kernel_patches/series/ldiskfs-5.10.0-oe2203sp1.series new file mode 100644 index 0000000..ab90afa --- /dev/null +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.10.0-oe2203sp1.series @@ -0,0 +1,35 @@ +linux-5.16/ext4-inode-version.patch +linux-5.4/ext4-lookup-dotdot.patch +suse15/ext4-print-inum-in-htree-warning.patch +linux-5.8/ext4-prealloc.patch +ubuntu18/ext4-osd-iop-common.patch +oe2203/ext4-misc.patch +linux-5.8/ext4-mballoc-extra-checks.patch +linux-5.4/ext4-hash-indexed-dir-dotdot-update.patch +linux-5.8/ext4-kill-dx-root.patch +linux-5.8/ext4-mballoc-pa-free-mismatch.patch +oe2203sp1/ext4-data-in-dirent.patch +rhel8/ext4-nocmtime.patch +base/ext4-htree-lock.patch +oe2203/ext4-pdirop.patch +linux-5.8/ext4-max-dir-size.patch +linux-5.8/ext4-corrupted-inode-block-bitmaps-handling-patches.patch +linux-5.10/ext4-give-warning-with-dir-htree-growing.patch +ubuntu18/ext4-jcb-optimization.patch +linux-5.10/ext4-attach-jinode-in-writepages.patch +rhel8/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.8/ext4-export-mb-stream-allocator-variables.patch +ubuntu19/ext4-iget-with-flags.patch +linux-5.4/export-ext4fs-dirhash-helper.patch +ubuntu20.04.3/ext4-simple-blockalloc.patch +linux-5.14/ext4-xattr-disable-credits-check.patch +linux-5.8/ext4-no-max-dir-size-limit-for-iam-objects.patch +rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch +linux-5.8/ext4-enc-flag.patch +oe2203/ext4-delayed-iput.patch +linux-5.10/ext4-fiemap-kernel-data.patch +rhel8/ext4-old_ea_inodes_handling_fix.patch +rhel8/ext4-encdata.patch diff --git a/lustre.spec.in b/lustre.spec.in index 75cc484..a4d1121 100644 --- a/lustre.spec.in +++ b/lustre.spec.in @@ -229,6 +229,9 @@ Suggests: bash-completion %else %if "%{_vendor}" == "openEuler" BuildRequires: openEuler-rpm-config +%if %{with ldiskfs} +BuildRequires: kernel-debugsource +%endif %endif BuildRequires: pkg-config %endif diff --git a/lustre/ChangeLog b/lustre/ChangeLog index d54e18f..942cea7 100644 --- a/lustre/ChangeLog +++ b/lustre/ChangeLog @@ -28,7 +28,8 @@ TBD Whamcloud vanilla linux 5.4.0 (ZFS + ldiskfs) vanilla linux 5.4.21 (ZFS + ldiskfs) vanilla linux 5.4.136 (ZFS + ldiskfs) - 5.10.0-60.79.0.103.oe2203 (openEuler 22.03 LTS) + 5.10.0-60.94.0.118.oe2203 (openEuler 22.03 LTS) + 5.10.0-136.32.0.108.oe2203sp1 (openEuler 22.03 LTS SP1) * ldiskfs needs an ldiskfs patch series for that kernel, ZFS does not * Client primary kernels built and tested during release cycle: 5.14.0-284.18.1.el9 (RHEL9.2) diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index b546649..ab6e3b3 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -4744,6 +4744,7 @@ lustre/kernel_patches/targets/5.3-sles15sp3.target lustre/kernel_patches/targets/5.14-sles15sp4.target lustre/kernel_patches/targets/3.x-fc18.target lustre/kernel_patches/targets/5.10-oe2203.target +lustre/kernel_patches/targets/5.10-oe2203sp1.target lustre/ldlm/Makefile lustre/ldlm/autoMakefile lustre/ec/autoMakefile diff --git a/lustre/kernel_patches/targets/5.10-oe2203.target.in b/lustre/kernel_patches/targets/5.10-oe2203.target.in index c049ac2..69c7e33 100644 --- a/lustre/kernel_patches/targets/5.10-oe2203.target.in +++ b/lustre/kernel_patches/targets/5.10-oe2203.target.in @@ -1,5 +1,5 @@ lnxmaj="5.10.0" -lnxrel="60.79.0.103.oe2203" +lnxrel="60.94.0.118.oe2203" KERNEL_SRPM=kernel-${lnxmaj}-${lnxrel}.src.rpm SERIES="" diff --git a/lustre/kernel_patches/targets/5.10-oe2203sp1.target.in b/lustre/kernel_patches/targets/5.10-oe2203sp1.target.in new file mode 100644 index 0000000..81112d1 --- /dev/null +++ b/lustre/kernel_patches/targets/5.10-oe2203sp1.target.in @@ -0,0 +1,21 @@ +lnxmaj="5.10.0" +lnxrel="136.32.0.108.oe2203sp1" + +KERNEL_SRPM=kernel-${lnxmaj}-${lnxrel}.src.rpm +SERIES="" +EXTRA_VERSION=${lnxrel}_lustre.@VERSION@ +LUSTRE_VERSION=@VERSION@ + +DEVEL_PATH_ARCH_DELIMETER="." +OFED_VERSION=inkernel + +#SMP_ARCHS="i686 x86_64 ia64 ppc64" +# openEuler doesn't use smp specific kernels +SMP_ARCHS="" + +for cc in gcc ; do + if which $cc >/dev/null 2>/dev/null ; then + export CC=$cc + break + fi +done -- 1.8.3.1