@@ -1015,6 +1015,7 @@ static void ext4_put_super(struct super_block *sb)
10151015 struct ext4_sb_info * sbi = EXT4_SB (sb );
10161016 struct ext4_super_block * es = sbi -> s_es ;
10171017 struct buffer_head * * group_desc ;
1018+ struct flex_groups * * flex_groups ;
10181019 int aborted = 0 ;
10191020 int i , err ;
10201021
@@ -1052,8 +1053,13 @@ static void ext4_put_super(struct super_block *sb)
10521053 for (i = 0 ; i < sbi -> s_gdb_count ; i ++ )
10531054 brelse (group_desc [i ]);
10541055 kvfree (group_desc );
1056+ flex_groups = rcu_dereference (sbi -> s_flex_groups );
1057+ if (flex_groups ) {
1058+ for (i = 0 ; i < sbi -> s_flex_groups_allocated ; i ++ )
1059+ kvfree (flex_groups [i ]);
1060+ kvfree (flex_groups );
1061+ }
10551062 rcu_read_unlock ();
1056- kvfree (sbi -> s_flex_groups );
10571063 percpu_counter_destroy (& sbi -> s_freeclusters_counter );
10581064 percpu_counter_destroy (& sbi -> s_freeinodes_counter );
10591065 percpu_counter_destroy (& sbi -> s_dirs_counter );
@@ -2384,8 +2390,8 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
23842390int ext4_alloc_flex_bg_array (struct super_block * sb , ext4_group_t ngroup )
23852391{
23862392 struct ext4_sb_info * sbi = EXT4_SB (sb );
2387- struct flex_groups * new_groups ;
2388- int size ;
2393+ struct flex_groups * * old_groups , * * new_groups ;
2394+ int size , i ;
23892395
23902396 if (!sbi -> s_log_groups_per_flex )
23912397 return 0 ;
@@ -2394,29 +2400,45 @@ int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
23942400 if (size <= sbi -> s_flex_groups_allocated )
23952401 return 0 ;
23962402
2397- size = roundup_pow_of_two (size * sizeof ( struct flex_groups ));
2398- new_groups = kvzalloc ( size , GFP_KERNEL );
2403+ new_groups = kvzalloc ( roundup_pow_of_two (size *
2404+ sizeof ( * sbi -> s_flex_groups )) , GFP_KERNEL );
23992405 if (!new_groups ) {
2400- ext4_msg (sb , KERN_ERR , "not enough memory for %d flex groups" ,
2401- size / ( int ) sizeof ( struct flex_groups ) );
2406+ ext4_msg (sb , KERN_ERR ,
2407+ "not enough memory for %d flex group pointers" , size );
24022408 return - ENOMEM ;
24032409 }
2404-
2405- if (sbi -> s_flex_groups ) {
2406- memcpy (new_groups , sbi -> s_flex_groups ,
2407- (sbi -> s_flex_groups_allocated *
2408- sizeof (struct flex_groups )));
2409- kvfree (sbi -> s_flex_groups );
2410+ for (i = sbi -> s_flex_groups_allocated ; i < size ; i ++ ) {
2411+ new_groups [i ] = kvzalloc (roundup_pow_of_two (
2412+ sizeof (struct flex_groups )),
2413+ GFP_KERNEL );
2414+ if (!new_groups [i ]) {
2415+ for (i -- ; i >= sbi -> s_flex_groups_allocated ; i -- )
2416+ kvfree (new_groups [i ]);
2417+ kvfree (new_groups );
2418+ ext4_msg (sb , KERN_ERR ,
2419+ "not enough memory for %d flex groups" , size );
2420+ return - ENOMEM ;
2421+ }
24102422 }
2411- sbi -> s_flex_groups = new_groups ;
2412- sbi -> s_flex_groups_allocated = size / sizeof (struct flex_groups );
2423+ rcu_read_lock ();
2424+ old_groups = rcu_dereference (sbi -> s_flex_groups );
2425+ if (old_groups )
2426+ memcpy (new_groups , old_groups ,
2427+ (sbi -> s_flex_groups_allocated *
2428+ sizeof (struct flex_groups * )));
2429+ rcu_read_unlock ();
2430+ rcu_assign_pointer (sbi -> s_flex_groups , new_groups );
2431+ sbi -> s_flex_groups_allocated = size ;
2432+ if (old_groups )
2433+ ext4_kvfree_array_rcu (old_groups );
24132434 return 0 ;
24142435}
24152436
24162437static int ext4_fill_flex_info (struct super_block * sb )
24172438{
24182439 struct ext4_sb_info * sbi = EXT4_SB (sb );
24192440 struct ext4_group_desc * gdp = NULL ;
2441+ struct flex_groups * fg ;
24202442 ext4_group_t flex_group ;
24212443 int i , err ;
24222444
@@ -2434,12 +2456,11 @@ static int ext4_fill_flex_info(struct super_block *sb)
24342456 gdp = ext4_get_group_desc (sb , i , NULL );
24352457
24362458 flex_group = ext4_flex_group (sbi , i );
2437- atomic_add ( ext4_free_inodes_count ( sb , gdp ),
2438- & sbi -> s_flex_groups [ flex_group ]. free_inodes );
2459+ fg = sbi_array_rcu_deref ( sbi , s_flex_groups , flex_group );
2460+ atomic_add ( ext4_free_inodes_count ( sb , gdp ), & fg -> free_inodes );
24392461 atomic64_add (ext4_free_group_clusters (sb , gdp ),
2440- & sbi -> s_flex_groups [flex_group ].free_clusters );
2441- atomic_add (ext4_used_dirs_count (sb , gdp ),
2442- & sbi -> s_flex_groups [flex_group ].used_dirs );
2462+ & fg -> free_clusters );
2463+ atomic_add (ext4_used_dirs_count (sb , gdp ), & fg -> used_dirs );
24432464 }
24442465
24452466 return 1 ;
@@ -3641,6 +3662,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
36413662 struct buffer_head * bh , * * group_desc ;
36423663 struct ext4_super_block * es = NULL ;
36433664 struct ext4_sb_info * sbi = kzalloc (sizeof (* sbi ), GFP_KERNEL );
3665+ struct flex_groups * * flex_groups ;
36443666 ext4_fsblk_t block ;
36453667 ext4_fsblk_t sb_block = get_sb_block (& data );
36463668 ext4_fsblk_t logical_sb_block ;
@@ -4692,8 +4714,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
46924714 ext4_unregister_li_request (sb );
46934715failed_mount6 :
46944716 ext4_mb_release (sb );
4695- if (sbi -> s_flex_groups )
4696- kvfree (sbi -> s_flex_groups );
4717+ rcu_read_lock ();
4718+ flex_groups = rcu_dereference (sbi -> s_flex_groups );
4719+ if (flex_groups ) {
4720+ for (i = 0 ; i < sbi -> s_flex_groups_allocated ; i ++ )
4721+ kvfree (flex_groups [i ]);
4722+ kvfree (flex_groups );
4723+ }
4724+ rcu_read_unlock ();
46974725 percpu_counter_destroy (& sbi -> s_freeclusters_counter );
46984726 percpu_counter_destroy (& sbi -> s_freeinodes_counter );
46994727 percpu_counter_destroy (& sbi -> s_dirs_counter );
0 commit comments