File 0013-LU-14651-ldiskfs-add-5.11-kernel-support.patch of Package lustre_2_15

From 68448bded619dbb3ea96c7ce4a7151dd4cd7dcbf Mon Sep 17 00:00:00 2001
From: James Simmons <jsimmons@infradead.org>
Date: Wed, 6 Jul 2022 11:38:17 -0600
Subject: [PATCH 13/30] LU-14651 ldiskfs: add 5.11 kernel support

The Ubuntu 20.04.3 LTS moved to the 5.11 kernel. Support for this
kernel is a small step from the 5.10 kernel support. This patch
adds these small changes to support ldiskfs.

Test-Parameters: trivial
Change-Id: I3055736658b628fe79a6a9fc20ac01e7e1597630
Signed-off-by: James Simmons <jsimmons@infradead.org>
Reviewed-on: https://review.whamcloud.com/47900
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Jian Yu <yujian@whamcloud.com>
Reviewed-by: Shaun Tancheff <shaun.tancheff@hpe.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
---
 config/lustre-build-ldiskfs.m4                |   7 +-
 .../patches/ubuntu20.04.3/ext4-misc.patch     | 196 ++++++++++
 .../ext4-simple-blockalloc.patch              | 340 ++++++++++++++++++
 .../series/ldiskfs-5.11.0-40-ubuntu20.series  |  32 ++
 7 files changed, 576 insertions(+), 2 deletions(-)
 create mode 100644 ldiskfs/kernel_patches/patches/ubuntu20.04.3/ext4-misc.patch
 create mode 100644 ldiskfs/kernel_patches/patches/ubuntu20.04.3/ext4-simple-blockalloc.patch
 create mode 100644 ldiskfs/kernel_patches/series/ldiskfs-5.11.0-40-ubuntu20.series

diff --git a/config/lustre-build-ldiskfs.m4 b/config/lustre-build-ldiskfs.m4
index e3d43d84c67f..fe7c57667a99 100644
--- a/config/lustre-build-ldiskfs.m4
+++ b/config/lustre-build-ldiskfs.m4
@@ -69,6 +69,7 @@ AS_IF([test x$RHEL_KERNEL = xyes], [
 		esac
 	    ])
 ], [test x$UBUNTU_KERNEL = xyes], [
+	AS_VERSION_COMPARE([$LINUXRELEASE],[5.11.0],[
 	AS_VERSION_COMPARE([$LINUXRELEASE],[5.8.0],[
 	AS_VERSION_COMPARE([$LINUXRELEASE],[5.4.0],[
 	AS_VERSION_COMPARE([$LINUXRELEASE],[5.0.0],[
@@ -119,8 +120,10 @@ AS_IF([test x$RHEL_KERNEL = xyes], [
 	],
 	[LDISKFS_SERIES="5.4.0-ml.series"])],
 	[LDISKFS_SERIES="5.8.0-53-ubuntu20.series"],
-	[LDISKFS_SERIES="5.8.0-63-ubuntu20.series"],
-	[LDISKFS_SERIES="5.8.0-ml.series"])
+	[LDISKFS_SERIES="5.8.0-63-ubuntu20.series"])],
+	[LDISKFS_SERIES="5.11.0-40-ubuntu20.series"],
+	[LDISKFS_SERIES="5.11.0-40-ubuntu20.series"],
+	[LDISKFS_SERIES="5.11.0-40-ubuntu20.series"])
 ])
 ])
 # Not RHEL/SLES or Ubuntu .. probably mainline
diff --git a/ldiskfs/kernel_patches/patches/ubuntu20.04.3/ext4-misc.patch b/ldiskfs/kernel_patches/patches/ubuntu20.04.3/ext4-misc.patch
new file mode 100644
index 000000000000..35b12dadff30
--- /dev/null
+++ b/ldiskfs/kernel_patches/patches/ubuntu20.04.3/ext4-misc.patch
@@ -0,0 +1,196 @@
+diff -ur a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+--- a/fs/ext4/ext4.h	2022-03-24 16:23:11.725060881 -0600
++++ b/fs/ext4/ext4.h	2022-03-24 16:24:35.400642866 -0600
+@@ -1882,6 +1882,8 @@
+ 
+ #define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime
+ 
++#define JOURNAL_START_HAS_3ARGS	1
++
+ /*
+  * Codes for operating systems
+  */
+@@ -2121,7 +2123,21 @@
+ 
+ EXTN_FEATURE_FUNCS(2)
+ EXTN_FEATURE_FUNCS(3)
+-EXTN_FEATURE_FUNCS(4)
++static inline bool ext4_has_unknown_ext4_compat_features(struct super_block *sb)
++{
++	return ((EXT4_SB(sb)->s_es->s_feature_compat &
++		cpu_to_le32(~EXT4_FEATURE_COMPAT_SUPP)) != 0);
++}
++static inline bool ext4_has_unknown_ext4_ro_compat_features(struct super_block *sb)
++{
++	return ((EXT4_SB(sb)->s_es->s_feature_ro_compat &
++		cpu_to_le32(~EXT4_FEATURE_RO_COMPAT_SUPP)) != 0);
++}
++static inline bool ext4_has_unknown_ext4_incompat_features(struct super_block *sb)
++{
++	return ((EXT4_SB(sb)->s_es->s_feature_incompat &
++		cpu_to_le32(~EXT4_FEATURE_INCOMPAT_SUPP)) != 0);
++}
+ 
+ static inline bool ext4_has_compat_features(struct super_block *sb)
+ {
+@@ -3594,6 +3610,13 @@
+ #define EXT_MAX_BLOCKS	0xffffffff
+ 
+ extern void ext4_ext_tree_init(handle_t *handle, struct inode *inode);
++extern struct buffer_head *ext4_read_inode_bitmap(struct super_block *sb,
++						  ext4_group_t block_group);
++extern void ext4_inc_count(struct inode *inode);
++extern void ext4_dec_count(struct inode *inode);
++extern struct buffer_head *ext4_append(handle_t *handle,
++				       struct inode *inode,
++				       ext4_lblk_t *block);
+ extern int ext4_ext_index_trans_blocks(struct inode *inode, int extents);
+ extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
+ 			       struct ext4_map_blocks *map, int flags);
+diff -ur a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
+--- a/fs/ext4/ialloc.c	2022-03-24 16:23:11.713060939 -0600
++++ b/fs/ext4/ialloc.c	2022-03-24 16:24:35.404642846 -0600
+@@ -120,7 +120,7 @@
+  *
+  * Return buffer_head of bitmap on success, or an ERR_PTR on error.
+  */
+-static struct buffer_head *
++struct buffer_head *
+ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
+ {
+ 	struct ext4_group_desc *desc;
+@@ -215,6 +215,7 @@
+ 	put_bh(bh);
+ 	return ERR_PTR(err);
+ }
++EXPORT_SYMBOL(ext4_read_inode_bitmap);
+ 
+ /*
+  * NOTE! When we get the inode, we're the only people
+diff -ur a/fs/ext4/inode.c b/fs/ext4/inode.c
+--- a/fs/ext4/inode.c	2022-03-24 16:23:11.721060900 -0600
++++ b/fs/ext4/inode.c	2022-03-24 16:24:35.412642805 -0600
+@@ -6222,3 +6222,19 @@
+ 
+ 	return ret;
+ }
++EXPORT_SYMBOL(ext4_map_blocks);
++EXPORT_SYMBOL(ext4_truncate);
++EXPORT_SYMBOL(ext4_iget);
++EXPORT_SYMBOL(ext4_bread);
++EXPORT_SYMBOL(ext4_itable_unused_count);
++EXPORT_SYMBOL(ext4_force_commit);
++EXPORT_SYMBOL(__ext4_mark_inode_dirty);
++EXPORT_SYMBOL(ext4_get_group_desc);
++EXPORT_SYMBOL(__ext4_journal_get_write_access);
++EXPORT_SYMBOL(__ext4_journal_start_sb);
++EXPORT_SYMBOL(__ext4_journal_stop);
++EXPORT_SYMBOL(__ext4_handle_dirty_metadata);
++EXPORT_SYMBOL(__ext4_std_error);
++EXPORT_SYMBOL(ext4fs_dirhash);
++EXPORT_SYMBOL(ext4_get_inode_loc);
++EXPORT_SYMBOL(__ext4_journal_ensure_credits);
+diff -ur a/fs/ext4/namei.c b/fs/ext4/namei.c
+--- a/fs/ext4/namei.c	2022-03-24 16:23:11.725060881 -0600
++++ b/fs/ext4/namei.c	2022-03-24 16:24:35.420642764 -0600
+@@ -50,7 +50,7 @@
+ #define NAMEI_RA_BLOCKS  4
+ #define NAMEI_RA_SIZE	     (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+ 
+-static struct buffer_head *ext4_append(handle_t *handle,
++struct buffer_head *ext4_append(handle_t *handle,
+ 					struct inode *inode,
+ 					ext4_lblk_t *block)
+ {
+@@ -79,6 +79,8 @@
+ 	return bh;
+ }
+ 
++#define assert(test) J_ASSERT(test)
++
+ static int ext4_dx_csum_verify(struct inode *inode,
+ 			       struct ext4_dir_entry *dirent);
+ 
+@@ -181,6 +183,7 @@
+ 	}
+ 	return bh;
+ }
++EXPORT_SYMBOL(ext4_append);
+ 
+ #ifdef DX_DEBUG
+ #define dxtrace(command) command
+@@ -2568,23 +2571,25 @@
+  * for checking S_ISDIR(inode) (since the INODE_INDEX feature will not be set
+  * on regular files) and to avoid creating huge/slow non-HTREE directories.
+  */
+-static void ext4_inc_count(struct inode *inode)
++void ext4_inc_count(struct inode *inode)
+ {
+ 	inc_nlink(inode);
+ 	if (is_dx(inode) &&
+ 	    (inode->i_nlink > EXT4_LINK_MAX || inode->i_nlink == 2))
+ 		set_nlink(inode, 1);
+ }
++EXPORT_SYMBOL(ext4_inc_count);
+ 
+ /*
+  * If a directory had nlink == 1, then we should let it be 1. This indicates
+  * directory has >EXT4_LINK_MAX subdirs.
+  */
+-static void ext4_dec_count(struct inode *inode)
++void ext4_dec_count(struct inode *inode)
+ {
+ 	if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2)
+ 		drop_nlink(inode);
+ }
++EXPORT_SYMBOL(ext4_dec_count);
+ 
+ 
+ /*
+diff -ur a/fs/ext4/super.c b/fs/ext4/super.c
+--- a/fs/ext4/super.c	2022-03-24 16:23:11.601061482 -0600
++++ b/fs/ext4/super.c	2022-03-24 16:24:35.424642743 -0600
+@@ -5557,7 +5557,7 @@
+ 			__ext4_update_tstamp(&es->s_first_error_time,
+ 					     &es->s_first_error_time_hi,
+ 					     sbi->s_first_error_time);
+-			strncpy(es->s_first_error_func, sbi->s_first_error_func,
++			strlcpy(es->s_first_error_func, sbi->s_first_error_func,
+ 				sizeof(es->s_first_error_func));
+ 			es->s_first_error_line =
+ 				cpu_to_le32(sbi->s_first_error_line);
+@@ -5571,7 +5571,7 @@
+ 		__ext4_update_tstamp(&es->s_last_error_time,
+ 				     &es->s_last_error_time_hi,
+ 				     sbi->s_last_error_time);
+-		strncpy(es->s_last_error_func, sbi->s_last_error_func,
++		strlcpy(es->s_last_error_func, sbi->s_last_error_func,
+ 			sizeof(es->s_last_error_func));
+ 		es->s_last_error_line = cpu_to_le32(sbi->s_last_error_line);
+ 		es->s_last_error_ino = cpu_to_le32(sbi->s_last_error_ino);
+@@ -6760,16 +6760,12 @@
+ 	if (err)
+ 		goto out05;
+ 
+-	register_as_ext3();
+-	register_as_ext2();
+ 	err = register_filesystem(&ext4_fs_type);
+ 	if (err)
+ 		goto out;
+ 
+ 	return 0;
+ out:
+-	unregister_as_ext2();
+-	unregister_as_ext3();
+ out05:
+ 	destroy_inodecache();
+ out1:
+@@ -6793,8 +6789,6 @@
+ static void __exit ext4_exit_fs(void)
+ {
+ 	ext4_destroy_lazyinit_thread();
+-	unregister_as_ext2();
+-	unregister_as_ext3();
+ 	unregister_filesystem(&ext4_fs_type);
+ 	destroy_inodecache();
+ 	ext4_exit_mballoc();
diff --git a/ldiskfs/kernel_patches/patches/ubuntu20.04.3/ext4-simple-blockalloc.patch b/ldiskfs/kernel_patches/patches/ubuntu20.04.3/ext4-simple-blockalloc.patch
new file mode 100644
index 000000000000..66603b7a49e9
--- /dev/null
+++ b/ldiskfs/kernel_patches/patches/ubuntu20.04.3/ext4-simple-blockalloc.patch
@@ -0,0 +1,340 @@
+diff -ur a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+--- a/fs/ext4/ext4.h	2021-12-02 15:38:37.084207460 -0700
++++ b/fs/ext4/ext4.h	2021-12-02 15:41:51.939182417 -0700
+@@ -1554,6 +1554,9 @@
+ 	unsigned int s_mb_min_to_scan;
+ 	unsigned int s_mb_stats;
+ 	unsigned int s_mb_order2_reqs;
++	ext4_fsblk_t s_mb_c1_blocks;
++	ext4_fsblk_t s_mb_c2_blocks;
++	ext4_fsblk_t s_mb_c3_blocks;
+ 	unsigned long *s_mb_prealloc_table;
+ 	unsigned int s_mb_group_prealloc;
+ 	unsigned int s_mb_max_inode_prealloc;
+@@ -1573,6 +1576,9 @@
+ 	atomic_t s_bal_goals;	/* goal hits */
+ 	atomic_t s_bal_breaks;	/* too long searches */
+ 	atomic_t s_bal_2orders;	/* 2^order hits */
++	/* cX loop didn't find blocks */
++	atomic64_t s_bal_cX_failed[3];
++	atomic64_t s_bal_cX_skipped[3];
+ 	spinlock_t s_bal_lock;
+ 	unsigned long s_mb_buddies_generated;
+ 	unsigned long long s_mb_generation_time;
+@@ -2977,6 +2983,7 @@
+ /* mballoc.c */
+ extern const struct proc_ops ext4_seq_prealloc_table_fops;
+ extern const struct seq_operations ext4_mb_seq_groups_ops;
++extern const struct proc_ops ext4_mb_seq_alloc_fops;
+ extern const struct proc_ops ext4_seq_mb_last_group_fops;
+ extern int ext4_mb_seq_last_start_seq_show(struct seq_file *m, void *v);
+ extern long ext4_mb_stats;
+diff -ur a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
+--- a/fs/ext4/mballoc.c	2021-12-02 15:38:37.044207688 -0700
++++ b/fs/ext4/mballoc.c	2021-12-02 15:41:51.943182397 -0700
+@@ -2281,6 +2281,20 @@
+ 	}
+ }
+ 
++static u64 available_blocks_count(struct ext4_sb_info *sbi)
++{
++	ext4_fsblk_t resv_blocks;
++	u64 bfree;
++	struct ext4_super_block *es = sbi->s_es;
++
++	resv_blocks = EXT4_C2B(sbi, atomic64_read(&sbi->s_resv_clusters));
++	bfree = percpu_counter_sum_positive(&sbi->s_freeclusters_counter) -
++		 percpu_counter_sum_positive(&sbi->s_dirtyclusters_counter);
++
++	bfree = EXT4_C2B(sbi, max_t(s64, bfree, 0));
++	return bfree - (ext4_r_blocks_count(es) + resv_blocks);
++}
++
+ static noinline_for_stack int
+ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
+ {
+@@ -2291,6 +2305,7 @@
+ 	struct ext4_sb_info *sbi;
+ 	struct super_block *sb;
+ 	struct ext4_buddy e4b;
++	ext4_fsblk_t avail_blocks;
+ 	int lost;
+ 
+ 	sb = ac->ac_sb;
+@@ -2344,6 +2359,21 @@
+ 
+ 	/* Let's just scan groups to find more-less suitable blocks */
+ 	cr = ac->ac_2order ? 0 : 1;
++
++	/* Choose what loop to pass based on disk fullness */
++	avail_blocks = available_blocks_count(sbi) ;
++
++	if (avail_blocks < sbi->s_mb_c3_blocks) {
++		cr = 3;
++		atomic64_inc(&sbi->s_bal_cX_skipped[2]);
++	} else if(avail_blocks < sbi->s_mb_c2_blocks) {
++		cr = 2;
++		atomic64_inc(&sbi->s_bal_cX_skipped[1]);
++	} else if(avail_blocks < sbi->s_mb_c1_blocks) {
++		cr = 1;
++		atomic64_inc(&sbi->s_bal_cX_skipped[0]);
++	}
++
+ 	/*
+ 	 * cr == 0 try to get exact allocation,
+ 	 * cr == 3  try to get anything
+@@ -2431,6 +2461,9 @@
+ 			if (ac->ac_status != AC_STATUS_CONTINUE)
+ 				break;
+ 		}
++		/* Processed all groups and haven't found blocks */
++		if (i == ngroups)
++			atomic64_inc(&sbi->s_bal_cX_failed[cr]);
+ 	}
+ 
+ 	if (ac->ac_b_ex.fe_len > 0 && ac->ac_status != AC_STATUS_FOUND &&
+@@ -2719,6 +2752,92 @@
+ 	.proc_write	= ext4_mb_last_group_write,
+ };
+ 
++static int mb_seq_alloc_show(struct seq_file *seq, void *v)
++{
++	struct super_block *sb = seq->private;
++	struct ext4_sb_info *sbi = EXT4_SB(sb);
++
++	seq_printf(seq, "mballoc:\n");
++	seq_printf(seq, "\tblocks: %u\n", atomic_read(&sbi->s_bal_allocated));
++	seq_printf(seq, "\treqs: %u\n", atomic_read(&sbi->s_bal_reqs));
++	seq_printf(seq, "\tsuccess: %u\n", atomic_read(&sbi->s_bal_success));
++
++	seq_printf(seq, "\textents_scanned: %u\n",
++		   atomic_read(&sbi->s_bal_ex_scanned));
++	seq_printf(seq, "\t\tgoal_hits: %u\n", atomic_read(&sbi->s_bal_goals));
++	seq_printf(seq, "\t\t2^n_hits: %u\n", atomic_read(&sbi->s_bal_2orders));
++	seq_printf(seq, "\t\tbreaks: %u\n", atomic_read(&sbi->s_bal_breaks));
++	seq_printf(seq, "\t\tlost: %u\n", atomic_read(&sbi->s_mb_lost_chunks));
++
++	seq_printf(seq, "\tuseless_c1_loops: %llu\n",
++		   atomic64_read(&sbi->s_bal_cX_failed[0]));
++	seq_printf(seq, "\tuseless_c2_loops: %llu\n",
++		   atomic64_read(&sbi->s_bal_cX_failed[1]));
++	seq_printf(seq, "\tuseless_c3_loops: %llu\n",
++		   atomic64_read(&sbi->s_bal_cX_failed[2]));
++	seq_printf(seq, "\tskipped_c1_loops: %llu\n",
++		   atomic64_read(&sbi->s_bal_cX_skipped[0]));
++	seq_printf(seq, "\tskipped_c2_loops: %llu\n",
++		   atomic64_read(&sbi->s_bal_cX_skipped[1]));
++	seq_printf(seq, "\tskipped_c3_loops: %llu\n",
++		   atomic64_read(&sbi->s_bal_cX_skipped[2]));
++	seq_printf(seq, "\tbuddies_generated: %lu\n",
++		   sbi->s_mb_buddies_generated);
++	seq_printf(seq, "\tbuddies_time_used: %llu\n", sbi->s_mb_generation_time);
++	seq_printf(seq, "\tpreallocated: %u\n",
++		   atomic_read(&sbi->s_mb_preallocated));
++	seq_printf(seq, "\tdiscarded: %u\n",
++		   atomic_read(&sbi->s_mb_discarded));
++	return 0;
++}
++
++static ssize_t mb_seq_alloc_write(struct file *file,
++			      const char __user *buf,
++			      size_t cnt, loff_t *pos)
++{
++	struct ext4_sb_info *sbi = EXT4_SB(PDE_DATA(file_inode(file)));
++
++	atomic_set(&sbi->s_bal_allocated, 0),
++	atomic_set(&sbi->s_bal_reqs, 0),
++	atomic_set(&sbi->s_bal_success, 0);
++
++	atomic_set(&sbi->s_bal_ex_scanned, 0),
++	atomic_set(&sbi->s_bal_goals, 0),
++	atomic_set(&sbi->s_bal_2orders, 0),
++	atomic_set(&sbi->s_bal_breaks, 0),
++	atomic_set(&sbi->s_mb_lost_chunks, 0);
++
++	atomic64_set(&sbi->s_bal_cX_failed[0], 0),
++	atomic64_set(&sbi->s_bal_cX_failed[1], 0),
++	atomic64_set(&sbi->s_bal_cX_failed[2], 0);
++
++	atomic64_set(&sbi->s_bal_cX_skipped[0], 0),
++	atomic64_set(&sbi->s_bal_cX_skipped[1], 0),
++	atomic64_set(&sbi->s_bal_cX_skipped[2], 0);
++
++
++	sbi->s_mb_buddies_generated = 0;
++	sbi->s_mb_generation_time = 0;
++
++	atomic_set(&sbi->s_mb_preallocated, 0),
++	atomic_set(&sbi->s_mb_discarded, 0);
++
++	return cnt;
++}
++
++static int mb_seq_alloc_open(struct inode *inode, struct file *file)
++{
++	return single_open(file, mb_seq_alloc_show, PDE_DATA(inode));
++}
++
++const struct proc_ops ext4_mb_seq_alloc_fops = {
++	.proc_open	= mb_seq_alloc_open,
++	.proc_read	= seq_read,
++	.proc_lseek	= seq_lseek,
++	.proc_release	= single_release,
++	.proc_write	= mb_seq_alloc_write,
++};
++
+ int ext4_mb_seq_last_start_seq_show(struct seq_file *m, void *v)
+ {
+ 	struct ext4_sb_info *sbi = EXT4_SB(m->private);
+@@ -2973,6 +3092,7 @@
+ 	return 0;
+ }
+ 
++#define THRESHOLD_BLOCKS(ts) (ext4_blocks_count(sbi->s_es) / 100 * ts)
+ int ext4_mb_init(struct super_block *sb)
+ {
+ 	struct ext4_sb_info *sbi = EXT4_SB(sb);
+@@ -3027,6 +3147,9 @@
+ 	sbi->s_mb_stats = MB_DEFAULT_STATS;
+ 	sbi->s_mb_order2_reqs = MB_DEFAULT_ORDER2_REQS;
+ 	sbi->s_mb_max_inode_prealloc = MB_DEFAULT_MAX_INODE_PREALLOC;
++	sbi->s_mb_c1_blocks = THRESHOLD_BLOCKS(MB_DEFAULT_C1_THRESHOLD);
++	sbi->s_mb_c2_blocks = THRESHOLD_BLOCKS(MB_DEFAULT_C2_THRESHOLD);
++	sbi->s_mb_c3_blocks = THRESHOLD_BLOCKS(MB_DEFAULT_C3_THRESHOLD);
+ 	/*
+ 	 * The default group preallocation is 512, which for 4k block
+ 	 * sizes translates to 2 megabytes.  However for bigalloc file
+@@ -3166,6 +3289,16 @@
+ 				atomic_read(&sbi->s_bal_reqs),
+ 				atomic_read(&sbi->s_bal_success));
+ 		ext4_msg(sb, KERN_INFO,
++			"mballoc: (%llu, %llu, %llu) useless c(0,1,2) loops",
++				atomic64_read(&sbi->s_bal_cX_failed[0]),
++				atomic64_read(&sbi->s_bal_cX_failed[1]),
++				atomic64_read(&sbi->s_bal_cX_failed[2]));
++		ext4_msg(sb, KERN_INFO,
++			"mballoc: (%llu, %llu, %llu) skipped c(0,1,2) loops",
++				atomic64_read(&sbi->s_bal_cX_skipped[0]),
++				atomic64_read(&sbi->s_bal_cX_skipped[1]),
++				atomic64_read(&sbi->s_bal_cX_skipped[2]));
++		ext4_msg(sb, KERN_INFO,
+ 		      "mballoc: %u extents scanned, %u goal hits, "
+ 				"%u 2^N hits, %u breaks, %u lost",
+ 				atomic_read(&sbi->s_bal_ex_scanned),
+diff -ur a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h
+--- a/fs/ext4/mballoc.h	2021-12-02 15:38:36.772209242 -0700
++++ b/fs/ext4/mballoc.h	2021-12-02 15:41:51.943182397 -0700
+@@ -68,6 +68,9 @@
+  * for which requests use 2^N search using buddies
+  */
+ #define MB_DEFAULT_ORDER2_REQS		8
++#define MB_DEFAULT_C1_THRESHOLD		25
++#define MB_DEFAULT_C2_THRESHOLD		15
++#define MB_DEFAULT_C3_THRESHOLD		5
+ 
+ /*
+  * default group prealloc size 512 blocks
+diff -ur a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
+--- a/fs/ext4/sysfs.c	2021-12-02 15:38:37.044207688 -0700
++++ b/fs/ext4/sysfs.c	2021-12-02 15:43:17.050780832 -0700
+@@ -21,6 +21,9 @@
+ typedef enum {
+ 	attr_noop,
+ 	attr_delayed_allocation_blocks,
++	attr_mb_c1_threshold,
++	attr_mb_c2_threshold,
++	attr_mb_c3_threshold,
+ 	attr_session_write_kbytes,
+ 	attr_lifetime_write_kbytes,
+ 	attr_reserved_clusters,
+@@ -135,6 +138,32 @@
+ 			task_pid_vnr(sbi->s_journal->j_task));
+ }
+ 
++#define THRESHOLD_PERCENT(ts) (ts * 100 / ext4_blocks_count(sbi->s_es))
++
++static int save_threshold_percent(struct ext4_sb_info *sbi, const char *buf,
++				  ext4_fsblk_t *blocks)
++{
++	unsigned long long val;
++
++	int ret;
++
++	ret = kstrtoull(skip_spaces(buf), 0, &val);
++	if (ret || val > 100)
++		return -EINVAL;
++
++	*blocks = val * ext4_blocks_count(sbi->s_es) / 100;
++	return 0;
++}
++
++static ssize_t mb_threshold_store(struct ext4_sb_info *sbi,
++				  const char *buf, size_t count,
++				  ext4_fsblk_t *blocks)
++{
++	int ret = save_threshold_percent(sbi, buf, blocks);
++
++	return ret ?: count;
++}
++
+ #define EXT4_ATTR(_name,_mode,_id)					\
+ static struct ext4_attr ext4_attr_##_name = {				\
+ 	.attr = {.name = __stringify(_name), .mode = _mode },		\
+@@ -204,6 +233,9 @@
+ EXT4_ATTR_FUNC(lifetime_write_kbytes, 0444);
+ EXT4_ATTR_FUNC(reserved_clusters, 0644);
+ EXT4_ATTR_FUNC(sra_exceeded_retry_limit, 0444);
++EXT4_ATTR_FUNC(mb_c1_threshold, 0644);
++EXT4_ATTR_FUNC(mb_c2_threshold, 0644);
++EXT4_ATTR_FUNC(mb_c3_threshold, 0644);
+ 
+ EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, inode_readahead,
+ 		 ext4_sb_info, s_inode_readahead_blks);
+@@ -258,6 +290,9 @@
+ 	ATTR_LIST(lifetime_write_kbytes),
+ 	ATTR_LIST(reserved_clusters),
+ 	ATTR_LIST(sra_exceeded_retry_limit),
++	ATTR_LIST(mb_c1_threshold),
++	ATTR_LIST(mb_c2_threshold),
++	ATTR_LIST(mb_c3_threshold),
+ 	ATTR_LIST(inode_readahead_blks),
+ 	ATTR_LIST(inode_goal),
+ 	ATTR_LIST(max_dir_size),
+@@ -377,6 +412,15 @@
+ 		return snprintf(buf, PAGE_SIZE, "%llu\n",
+ 				(s64) EXT4_C2B(sbi,
+ 		       percpu_counter_sum(&sbi->s_dirtyclusters_counter)));
++	case attr_mb_c1_threshold:
++		return scnprintf(buf, PAGE_SIZE, "%llu\n",
++				 THRESHOLD_PERCENT(sbi->s_mb_c1_blocks));
++	case attr_mb_c2_threshold:
++		return scnprintf(buf, PAGE_SIZE, "%llu\n",
++				 THRESHOLD_PERCENT(sbi->s_mb_c2_blocks));
++	case attr_mb_c3_threshold:
++		return scnprintf(buf, PAGE_SIZE, "%llu\n",
++				 THRESHOLD_PERCENT(sbi->s_mb_c3_blocks));
+ 	case attr_session_write_kbytes:
+ 		return session_write_kbytes_show(sbi, buf);
+ 	case attr_lifetime_write_kbytes:
+@@ -482,6 +526,12 @@
+ 		return inode_readahead_blks_store(sbi, buf, len);
+ 	case attr_trigger_test_error:
+ 		return trigger_test_error(sbi, buf, len);
++	case attr_mb_c1_threshold:
++		return mb_threshold_store(sbi, buf, len, &sbi->s_mb_c1_blocks);
++	case attr_mb_c2_threshold:
++		return mb_threshold_store(sbi, buf, len, &sbi->s_mb_c2_blocks);
++	case attr_mb_c3_threshold:
++		return mb_threshold_store(sbi, buf, len, &sbi->s_mb_c3_blocks);
+ 	}
+ 	return 0;
+ }
+@@ -546,6 +596,8 @@
+ 				&ext4_seq_mb_last_group_fops, sb);
+ 		proc_create_single_data("mb_last_start", S_IRUGO, sbi->s_proc,
+ 				ext4_mb_seq_last_start_seq_show, sb);
++		proc_create_data("mb_alloc_stats", S_IFREG | S_IRUGO | S_IWUSR,
++				 sbi->s_proc, &ext4_mb_seq_alloc_fops, sb);
+ 	}
+ 	return 0;
+ }
diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.11.0-40-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.11.0-40-ubuntu20.series
new file mode 100644
index 000000000000..4790c812e66d
--- /dev/null
+++ b/ldiskfs/kernel_patches/series/ldiskfs-5.11.0-40-ubuntu20.series
@@ -0,0 +1,32 @@
+rhel8/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
+ubuntu20.04.3/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
+linux-5.10/ext4-data-in-dirent.patch
+rhel8/ext4-nocmtime.patch
+base/ext4-htree-lock.patch
+linux-5.10/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
+ubuntu2004/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
+base/ext4-delayed-iput.patch
diff --git a/lustre/tests/lutf/.gitignore b/lustre/tests/lutf/.gitignore
new file mode 100644
index 000000000000..70845e08eb0b
--- /dev/null
+++ b/lustre/tests/lutf/.gitignore
@@ -0,0 +1 @@
+Makefile.in
-- 
2.38.1

openSUSE Build Service is sponsored by