--- /dev/null
+diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
+index 2b76c79..07244bf 100644
+--- a/fs/ext4/balloc.c
++++ b/fs/ext4/balloc.c
+@@ -502,6 +502,7 @@ int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group,
+ block_group, (unsigned long long) bh->b_blocknr);
+ return 1;
+ }
++ EXT4_SB(sb)->block_bitmap_read_cnt++;
+ clear_buffer_new(bh);
+ /* Panic or remount fs read-only if block bitmap is invalid */
+ ext4_validate_block_bitmap(sb, desc, block_group, bh);
+@@ -655,6 +656,68 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
+ return ret;
+ }
+
++int ext4_load_block_bitmaps_bh(struct super_block *sb)
++{
++ struct ext4_super_block *es;
++ struct buffer_head *bitmap_bh = NULL;
++ struct ext4_group_desc *gdp;
++ ext4_group_t i;
++ ext4_group_t ngroups = ext4_get_groups_count(sb);
++ struct ext4_group_info *grp;
++
++ es = EXT4_SB(sb)->s_es;
++ gdp = NULL;
++
++ for (i = 0; i < ngroups; i++) {
++ gdp = ext4_get_group_desc(sb, i, NULL);
++ if (!gdp)
++ continue;
++ grp = NULL;
++ if (EXT4_SB(sb)->s_group_info)
++ grp = ext4_get_group_info(sb, i);
++ bitmap_bh = ext4_read_block_bitmap(sb, i);
++ if (bitmap_bh == NULL)
++ return -ENOMEM;
++ }
++ /* Reset block bitmap to zero now */
++ EXT4_SB(sb)->block_bitmap_read_cnt = 0;
++ ext4_msg(sb, KERN_INFO, "Preload %u block bitmaps finished", ngroups);
++
++ return 0;
++}
++
++void ext4_release_block_bitmaps_bh(struct super_block *sb)
++{
++ struct ext4_super_block *es;
++ struct buffer_head *bitmap_bh = NULL;
++ struct ext4_group_desc *gdp;
++ ext4_group_t i;
++ ext4_group_t ngroups = ext4_get_groups_count(sb);
++ struct ext4_group_info *grp;
++
++ es = EXT4_SB(sb)->s_es;
++ gdp = NULL;
++
++ ext4_msg(sb, KERN_INFO, "block bitmap read count: %lu", EXT4_SB(sb)->block_bitmap_read_cnt);
++
++ for (i = 0; i < ngroups; i++) {
++ gdp = ext4_get_group_desc(sb, i, NULL);
++ if (!gdp)
++ continue;
++ grp = NULL;
++ if (EXT4_SB(sb)->s_group_info)
++ grp = ext4_get_group_info(sb, i);
++ bitmap_bh = ext4_read_block_bitmap(sb, i);
++ if (bitmap_bh == NULL)
++ continue;
++ /* one for this read */
++ brelse(bitmap_bh);
++ /* one for memory reclaim purpose */
++ brelse(bitmap_bh);
++ }
++ ext4_msg(sb, KERN_INFO, "Release %u lock bitmaps finished", ngroups);
++}
++
+ /**
+ * ext4_count_free_clusters() -- count filesystem free clusters
+ * @sb: superblock
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index d4761df..338db31 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -1481,6 +1481,10 @@ struct ext4_sb_info {
+ struct ratelimit_state s_warning_ratelimit_state;
+ struct ratelimit_state s_msg_ratelimit_state;
+ struct dax_device *s_daxdev;
++
++ unsigned long block_bitmap_read_cnt;
++ unsigned long inode_bitmap_read_cnt;
++ unsigned s_loadbitmaps;
+ };
+
+ static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
+@@ -2201,6 +2205,8 @@ int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
+ struct buffer_head *bh);
+
+ /* balloc.c */
++int ext4_load_block_bitmaps_bh(struct super_block *sb);
++void ext4_release_block_bitmaps_bh(struct super_block *sb);
+ extern void ext4_get_group_no_and_offset(struct super_block *sb,
+ ext4_fsblk_t blocknr,
+ ext4_group_t *blockgrpp,
+diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
+index 8c5150d..1665eb6 100644
+--- a/fs/ext4/ialloc.c
++++ b/fs/ext4/ialloc.c
+@@ -162,6 +162,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
+ block_group, bitmap_blk);
+ return NULL;
+ }
++ EXT4_SB(sb)->inode_bitmap_read_cnt++;
+
+ verify:
+ ext4_lock_group(sb, block_group);
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index e29d142..ca8b50c 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -817,6 +817,11 @@ static void ext4_put_super(struct super_block *sb)
+ int aborted = 0;
+ int i, err;
+
++ if (sbi->s_loadbitmaps) {
++ ext4_release_block_bitmaps_bh(sb);
++ sbi->s_loadbitmaps = 0;
++ }
++
+ ext4_unregister_li_request(sb);
+ dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
+
+@@ -2676,6 +2681,13 @@ static ssize_t sbi_ui_store(struct ext4_attr *a,
+ return ret;
+ if (strcmp("max_dir_size", a->attr.name) == 0)
+ t >>= 10;
++ if (strcmp("loadbitmaps", a->attr.name) == 0) {
++ if (t == 0 && sbi->s_loadbitmaps) {
++ ext4_release_block_bitmaps_bh(sbi->s_sb);
++ } else if (t && sbi->s_loadbitmaps == 0) {
++ ret = ext4_load_block_bitmaps_bh(sbi->s_sb);
++ }
++ }
+ *ui = t;
+ return count;
+ }
+@@ -2802,6 +2814,7 @@ EXT4_RW_ATTR_SBI_UI(warning_ratelimit_interval_ms, s_warning_ratelimit_state.int
+ EXT4_RW_ATTR_SBI_UI(warning_ratelimit_burst, s_warning_ratelimit_state.burst);
+ EXT4_RW_ATTR_SBI_UI(msg_ratelimit_interval_ms, s_msg_ratelimit_state.interval);
+ EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst);
++EXT4_RW_ATTR_SBI_UI(loadbitmaps, s_loadbitmaps);
+ EXT4_RO_ATTR_ES_UI(errors_count, s_error_count);
+ EXT4_RO_ATTR_ES_UI(first_error_time, s_first_error_time);
+ EXT4_RO_ATTR_ES_UI(last_error_time, s_last_error_time);
+@@ -2835,6 +2848,7 @@ static struct attribute *ext4_attrs[] = {
+ ATTR_LIST(errors_count),
+ ATTR_LIST(first_error_time),
+ ATTR_LIST(last_error_time),
++ ATTR_LIST(loadbitmaps),
+ NULL,
+ };
+
}
run_test 417 "disable remote dir, striped dir and dir migration"
+test_450() {
+ remote_ost_nodsh && skip "remote OST with nodsh" && return
+ local mntdev
+ local canondev
+ local node
+ local cache_memory1
+ local cache_memory2
+
+ local LDPROC=/sys/fs/ldiskfs
+ local facets=$(get_facets OST)
+
+ for facet in ${facets//,/ }; do
+ canondev=$(ldiskfs_canon \
+ *.$(convert_facet2label $facet).mntdev $facet)
+ do_facet $facet "test -e $LDPROC/$canondev/loadbitmaps" ||
+ skip "loadbitmaps function not supported"
+ do_facet $facet "echo 3 > /proc/sys/vm/drop_caches"
+ cache_memory1=`do_facet $facet free -b | grep Mem: | awk '{print $6}'`
+ do_facet $facet "echo 1 >$LDPROC/$canondev/loadbitmaps"
+ cache_memory2=`do_facet $facet free -b | grep Mem: | awk '{print $6}'`
+ if [ $cache_memory1 -ge $cache_memory2 ];then
+ error "after loading should cost more memory"
+ fi
+
+ #test if release bitmaps works
+ do_facet $facet "echo 0 >$LDPROC/$canondev/loadbitmaps"
+ #bitmaps memory could be dropped now.
+ do_facet $facet "echo 3 > /proc/sys/vm/drop_caches"
+ cache_memory1=`do_facet $facet free -b | grep Mem: | awk '{print $6}'`
+ if [ $cache_memory1 -ge $cache_memory2 ];then
+ error "memory should be released"
+ fi
+
+ #release it again..
+ do_facet $facet "echo 0 >$LDPROC/$canondev/loadbitmaps"
+ #load serveral times but release once
+ do_facet $facet "echo 1 >$LDPROC/$canondev/loadbitmaps"
+ do_facet $facet "echo 1 >$LDPROC/$canondev/loadbitmaps"
+ do_facet $facet "echo 0 >$LDPROC/$canondev/loadbitmaps"
+ done
+}
+run_test 450 "Test loading bitmaps function"
+
# Checks that the outputs of df [-i] and lfs df [-i] match
#
# usage: check_lfs_df <blocks | inodes> <mountpoint>