@@ -2356,7 +2356,7 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups)
23562356{
23572357 struct ext4_sb_info * sbi = EXT4_SB (sb );
23582358 unsigned size ;
2359- struct ext4_group_info * * * new_groupinfo ;
2359+ struct ext4_group_info * * * old_groupinfo , * * * new_groupinfo ;
23602360
23612361 size = (ngroups + EXT4_DESC_PER_BLOCK (sb ) - 1 ) >>
23622362 EXT4_DESC_PER_BLOCK_BITS (sb );
@@ -2369,13 +2369,16 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups)
23692369 ext4_msg (sb , KERN_ERR , "can't allocate buddy meta group" );
23702370 return - ENOMEM ;
23712371 }
2372- if (sbi -> s_group_info ) {
2373- memcpy (new_groupinfo , sbi -> s_group_info ,
2372+ rcu_read_lock ();
2373+ old_groupinfo = rcu_dereference (sbi -> s_group_info );
2374+ if (old_groupinfo )
2375+ memcpy (new_groupinfo , old_groupinfo ,
23742376 sbi -> s_group_info_size * sizeof (* sbi -> s_group_info ));
2375- kvfree (sbi -> s_group_info );
2376- }
2377- sbi -> s_group_info = new_groupinfo ;
2377+ rcu_read_unlock ();
2378+ rcu_assign_pointer (sbi -> s_group_info , new_groupinfo );
23782379 sbi -> s_group_info_size = size / sizeof (* sbi -> s_group_info );
2380+ if (old_groupinfo )
2381+ ext4_kvfree_array_rcu (old_groupinfo );
23792382 ext4_debug ("allocated s_groupinfo array for %d meta_bg's\n" ,
23802383 sbi -> s_group_info_size );
23812384 return 0 ;
@@ -2387,6 +2390,7 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
23872390{
23882391 int i ;
23892392 int metalen = 0 ;
2393+ int idx = group >> EXT4_DESC_PER_BLOCK_BITS (sb );
23902394 struct ext4_sb_info * sbi = EXT4_SB (sb );
23912395 struct ext4_group_info * * meta_group_info ;
23922396 struct kmem_cache * cachep = get_groupinfo_cache (sb -> s_blocksize_bits );
@@ -2405,12 +2409,12 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
24052409 "for a buddy group" );
24062410 goto exit_meta_group_info ;
24072411 }
2408- sbi -> s_group_info [group >> EXT4_DESC_PER_BLOCK_BITS (sb )] =
2409- meta_group_info ;
2412+ rcu_read_lock ();
2413+ rcu_dereference (sbi -> s_group_info )[idx ] = meta_group_info ;
2414+ rcu_read_unlock ();
24102415 }
24112416
2412- meta_group_info =
2413- sbi -> s_group_info [group >> EXT4_DESC_PER_BLOCK_BITS (sb )];
2417+ meta_group_info = sbi_array_rcu_deref (sbi , s_group_info , idx );
24142418 i = group & (EXT4_DESC_PER_BLOCK (sb ) - 1 );
24152419
24162420 meta_group_info [i ] = kmem_cache_zalloc (cachep , GFP_NOFS );
@@ -2458,8 +2462,13 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group,
24582462exit_group_info :
24592463 /* If a meta_group_info table has been allocated, release it now */
24602464 if (group % EXT4_DESC_PER_BLOCK (sb ) == 0 ) {
2461- kfree (sbi -> s_group_info [group >> EXT4_DESC_PER_BLOCK_BITS (sb )]);
2462- sbi -> s_group_info [group >> EXT4_DESC_PER_BLOCK_BITS (sb )] = NULL ;
2465+ struct ext4_group_info * * * group_info ;
2466+
2467+ rcu_read_lock ();
2468+ group_info = rcu_dereference (sbi -> s_group_info );
2469+ kfree (group_info [idx ]);
2470+ group_info [idx ] = NULL ;
2471+ rcu_read_unlock ();
24632472 }
24642473exit_meta_group_info :
24652474 return - ENOMEM ;
@@ -2472,6 +2481,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
24722481 struct ext4_sb_info * sbi = EXT4_SB (sb );
24732482 int err ;
24742483 struct ext4_group_desc * desc ;
2484+ struct ext4_group_info * * * group_info ;
24752485 struct kmem_cache * cachep ;
24762486
24772487 err = ext4_mb_alloc_groupinfo (sb , ngroups );
@@ -2507,11 +2517,16 @@ static int ext4_mb_init_backend(struct super_block *sb)
25072517 while (i -- > 0 )
25082518 kmem_cache_free (cachep , ext4_get_group_info (sb , i ));
25092519 i = sbi -> s_group_info_size ;
2520+ rcu_read_lock ();
2521+ group_info = rcu_dereference (sbi -> s_group_info );
25102522 while (i -- > 0 )
2511- kfree (sbi -> s_group_info [i ]);
2523+ kfree (group_info [i ]);
2524+ rcu_read_unlock ();
25122525 iput (sbi -> s_buddy_cache );
25132526err_freesgi :
2514- kvfree (sbi -> s_group_info );
2527+ rcu_read_lock ();
2528+ kvfree (rcu_dereference (sbi -> s_group_info ));
2529+ rcu_read_unlock ();
25152530 return - ENOMEM ;
25162531}
25172532
@@ -2700,7 +2715,7 @@ int ext4_mb_release(struct super_block *sb)
27002715 ext4_group_t ngroups = ext4_get_groups_count (sb );
27012716 ext4_group_t i ;
27022717 int num_meta_group_infos ;
2703- struct ext4_group_info * grinfo ;
2718+ struct ext4_group_info * grinfo , * * * group_info ;
27042719 struct ext4_sb_info * sbi = EXT4_SB (sb );
27052720 struct kmem_cache * cachep = get_groupinfo_cache (sb -> s_blocksize_bits );
27062721
@@ -2719,9 +2734,12 @@ int ext4_mb_release(struct super_block *sb)
27192734 num_meta_group_infos = (ngroups +
27202735 EXT4_DESC_PER_BLOCK (sb ) - 1 ) >>
27212736 EXT4_DESC_PER_BLOCK_BITS (sb );
2737+ rcu_read_lock ();
2738+ group_info = rcu_dereference (sbi -> s_group_info );
27222739 for (i = 0 ; i < num_meta_group_infos ; i ++ )
2723- kfree (sbi -> s_group_info [i ]);
2724- kvfree (sbi -> s_group_info );
2740+ kfree (group_info [i ]);
2741+ kvfree (group_info );
2742+ rcu_read_unlock ();
27252743 }
27262744 kfree (sbi -> s_mb_offsets );
27272745 kfree (sbi -> s_mb_maxs );
0 commit comments