aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2009-05-01 08:50:38 -0400
committerTheodore Ts'o <tytso@mit.edu>2009-05-01 08:50:38 -0400
commit8df9675f8b498d0bfa1f0b5b06f56bf1ff366dd5 (patch)
tree38fd56a82049f50b4d774af47b9d39f116071755
parent9ca92389c5312a51e819c15c762f0abdc7f3129b (diff)
ext4: Avoid races caused by on-line resizing and SMP memory reordering
Ext4's on-line resizing adds a new block group and then, only at the last step adjusts s_groups_count. However, it's possible on SMP systems that another CPU could see the updated the s_group_count and not see the newly initialized data structures for the just-added block group. For this reason, it's important to insert a SMP read barrier after reading s_groups_count and before reading any (for example) the new block group descriptors allowed by the increased value of s_groups_count. Unfortunately, we rather blatently violate this locking protocol documented in fs/ext4/resize.c. Fortunately, (1) on-line resizes happen relatively rarely, and (2) it seems rare that the filesystem code will immediately try to use just-added block group before any memory ordering issues resolve themselves. So apparently problems here are relatively hard to hit, since ext3 has been vulnerable to the same issue for years with no one apparently complaining. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/balloc.c15
-rw-r--r--fs/ext4/ext4.h12
-rw-r--r--fs/ext4/ialloc.c40
-rw-r--r--fs/ext4/inode.c7
-rw-r--r--fs/ext4/mballoc.c45
-rw-r--r--fs/ext4/super.c3
6 files changed, 67 insertions, 55 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 53c72ad85877..a5ba039850c5 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -88,6 +88,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
88 ext4_group_t block_group, struct ext4_group_desc *gdp) 88 ext4_group_t block_group, struct ext4_group_desc *gdp)
89{ 89{
90 int bit, bit_max; 90 int bit, bit_max;
91 ext4_group_t ngroups = ext4_get_groups_count(sb);
91 unsigned free_blocks, group_blocks; 92 unsigned free_blocks, group_blocks;
92 struct ext4_sb_info *sbi = EXT4_SB(sb); 93 struct ext4_sb_info *sbi = EXT4_SB(sb);
93 94
@@ -123,7 +124,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
123 bit_max += ext4_bg_num_gdb(sb, block_group); 124 bit_max += ext4_bg_num_gdb(sb, block_group);
124 } 125 }
125 126
126 if (block_group == sbi->s_groups_count - 1) { 127 if (block_group == ngroups - 1) {
127 /* 128 /*
128 * Even though mke2fs always initialize first and last group 129 * Even though mke2fs always initialize first and last group
129 * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need 130 * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
@@ -131,7 +132,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
131 */ 132 */
132 group_blocks = ext4_blocks_count(sbi->s_es) - 133 group_blocks = ext4_blocks_count(sbi->s_es) -
133 le32_to_cpu(sbi->s_es->s_first_data_block) - 134 le32_to_cpu(sbi->s_es->s_first_data_block) -
134 (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1)); 135 (EXT4_BLOCKS_PER_GROUP(sb) * (ngroups - 1));
135 } else { 136 } else {
136 group_blocks = EXT4_BLOCKS_PER_GROUP(sb); 137 group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
137 } 138 }
@@ -205,18 +206,18 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
205{ 206{
206 unsigned int group_desc; 207 unsigned int group_desc;
207 unsigned int offset; 208 unsigned int offset;
209 ext4_group_t ngroups = ext4_get_groups_count(sb);
208 struct ext4_group_desc *desc; 210 struct ext4_group_desc *desc;
209 struct ext4_sb_info *sbi = EXT4_SB(sb); 211 struct ext4_sb_info *sbi = EXT4_SB(sb);
210 212
211 if (block_group >= sbi->s_groups_count) { 213 if (block_group >= ngroups) {
212 ext4_error(sb, "ext4_get_group_desc", 214 ext4_error(sb, "ext4_get_group_desc",
213 "block_group >= groups_count - " 215 "block_group >= groups_count - "
214 "block_group = %u, groups_count = %u", 216 "block_group = %u, groups_count = %u",
215 block_group, sbi->s_groups_count); 217 block_group, ngroups);
216 218
217 return NULL; 219 return NULL;
218 } 220 }
219 smp_rmb();
220 221
221 group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); 222 group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
222 offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); 223 offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
@@ -665,7 +666,7 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
665 ext4_fsblk_t desc_count; 666 ext4_fsblk_t desc_count;
666 struct ext4_group_desc *gdp; 667 struct ext4_group_desc *gdp;
667 ext4_group_t i; 668 ext4_group_t i;
668 ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; 669 ext4_group_t ngroups = ext4_get_groups_count(sb);
669#ifdef EXT4FS_DEBUG 670#ifdef EXT4FS_DEBUG
670 struct ext4_super_block *es; 671 struct ext4_super_block *es;
671 ext4_fsblk_t bitmap_count; 672 ext4_fsblk_t bitmap_count;
@@ -677,7 +678,6 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
677 bitmap_count = 0; 678 bitmap_count = 0;
678 gdp = NULL; 679 gdp = NULL;
679 680
680 smp_rmb();
681 for (i = 0; i < ngroups; i++) { 681 for (i = 0; i < ngroups; i++) {
682 gdp = ext4_get_group_desc(sb, i, NULL); 682 gdp = ext4_get_group_desc(sb, i, NULL);
683 if (!gdp) 683 if (!gdp)
@@ -700,7 +700,6 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
700 return bitmap_count; 700 return bitmap_count;
701#else 701#else
702 desc_count = 0; 702 desc_count = 0;
703 smp_rmb();
704 for (i = 0; i < ngroups; i++) { 703 for (i = 0; i < ngroups; i++) {
705 gdp = ext4_get_group_desc(sb, i, NULL); 704 gdp = ext4_get_group_desc(sb, i, NULL);
706 if (!gdp) 705 if (!gdp)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index d0f15ef56de1..02ec44bf38e6 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1228,6 +1228,18 @@ struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
1228 return grp_info[indexv][indexh]; 1228 return grp_info[indexv][indexh];
1229} 1229}
1230 1230
1231/*
1232 * Reading s_groups_count requires using smp_rmb() afterwards. See
1233 * the locking protocol documented in the comments of ext4_group_add()
1234 * in resize.c
1235 */
1236static inline ext4_group_t ext4_get_groups_count(struct super_block *sb)
1237{
1238 ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
1239
1240 smp_rmb();
1241 return ngroups;
1242}
1231 1243
1232static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi, 1244static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi,
1233 ext4_group_t block_group) 1245 ext4_group_t block_group)
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index f18e0a08a6b5..55ba419ca00b 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -316,7 +316,7 @@ error_return:
316static int find_group_dir(struct super_block *sb, struct inode *parent, 316static int find_group_dir(struct super_block *sb, struct inode *parent,
317 ext4_group_t *best_group) 317 ext4_group_t *best_group)
318{ 318{
319 ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; 319 ext4_group_t ngroups = ext4_get_groups_count(sb);
320 unsigned int freei, avefreei; 320 unsigned int freei, avefreei;
321 struct ext4_group_desc *desc, *best_desc = NULL; 321 struct ext4_group_desc *desc, *best_desc = NULL;
322 ext4_group_t group; 322 ext4_group_t group;
@@ -353,7 +353,7 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
353 struct flex_groups *flex_group = sbi->s_flex_groups; 353 struct flex_groups *flex_group = sbi->s_flex_groups;
354 ext4_group_t parent_group = EXT4_I(parent)->i_block_group; 354 ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
355 ext4_group_t parent_fbg_group = ext4_flex_group(sbi, parent_group); 355 ext4_group_t parent_fbg_group = ext4_flex_group(sbi, parent_group);
356 ext4_group_t ngroups = sbi->s_groups_count; 356 ext4_group_t ngroups = ext4_get_groups_count(sb);
357 int flex_size = ext4_flex_bg_size(sbi); 357 int flex_size = ext4_flex_bg_size(sbi);
358 ext4_group_t best_flex = parent_fbg_group; 358 ext4_group_t best_flex = parent_fbg_group;
359 int blocks_per_flex = sbi->s_blocks_per_group * flex_size; 359 int blocks_per_flex = sbi->s_blocks_per_group * flex_size;
@@ -362,7 +362,7 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
362 ext4_group_t n_fbg_groups; 362 ext4_group_t n_fbg_groups;
363 ext4_group_t i; 363 ext4_group_t i;
364 364
365 n_fbg_groups = (sbi->s_groups_count + flex_size - 1) >> 365 n_fbg_groups = (ngroups + flex_size - 1) >>
366 sbi->s_log_groups_per_flex; 366 sbi->s_log_groups_per_flex;
367 367
368find_close_to_parent: 368find_close_to_parent:
@@ -478,20 +478,21 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
478{ 478{
479 ext4_group_t parent_group = EXT4_I(parent)->i_block_group; 479 ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
480 struct ext4_sb_info *sbi = EXT4_SB(sb); 480 struct ext4_sb_info *sbi = EXT4_SB(sb);
481 ext4_group_t ngroups = sbi->s_groups_count; 481 ext4_group_t real_ngroups = ext4_get_groups_count(sb);
482 int inodes_per_group = EXT4_INODES_PER_GROUP(sb); 482 int inodes_per_group = EXT4_INODES_PER_GROUP(sb);
483 unsigned int freei, avefreei; 483 unsigned int freei, avefreei;
484 ext4_fsblk_t freeb, avefreeb; 484 ext4_fsblk_t freeb, avefreeb;
485 unsigned int ndirs; 485 unsigned int ndirs;
486 int max_dirs, min_inodes; 486 int max_dirs, min_inodes;
487 ext4_grpblk_t min_blocks; 487 ext4_grpblk_t min_blocks;
488 ext4_group_t i, grp, g; 488 ext4_group_t i, grp, g, ngroups;
489 struct ext4_group_desc *desc; 489 struct ext4_group_desc *desc;
490 struct orlov_stats stats; 490 struct orlov_stats stats;
491 int flex_size = ext4_flex_bg_size(sbi); 491 int flex_size = ext4_flex_bg_size(sbi);
492 492
493 ngroups = real_ngroups;
493 if (flex_size > 1) { 494 if (flex_size > 1) {
494 ngroups = (ngroups + flex_size - 1) >> 495 ngroups = (real_ngroups + flex_size - 1) >>
495 sbi->s_log_groups_per_flex; 496 sbi->s_log_groups_per_flex;
496 parent_group >>= sbi->s_log_groups_per_flex; 497 parent_group >>= sbi->s_log_groups_per_flex;
497 } 498 }
@@ -543,7 +544,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
543 */ 544 */
544 grp *= flex_size; 545 grp *= flex_size;
545 for (i = 0; i < flex_size; i++) { 546 for (i = 0; i < flex_size; i++) {
546 if (grp+i >= sbi->s_groups_count) 547 if (grp+i >= real_ngroups)
547 break; 548 break;
548 desc = ext4_get_group_desc(sb, grp+i, NULL); 549 desc = ext4_get_group_desc(sb, grp+i, NULL);
549 if (desc && ext4_free_inodes_count(sb, desc)) { 550 if (desc && ext4_free_inodes_count(sb, desc)) {
@@ -583,7 +584,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
583 } 584 }
584 585
585fallback: 586fallback:
586 ngroups = sbi->s_groups_count; 587 ngroups = real_ngroups;
587 avefreei = freei / ngroups; 588 avefreei = freei / ngroups;
588fallback_retry: 589fallback_retry:
589 parent_group = EXT4_I(parent)->i_block_group; 590 parent_group = EXT4_I(parent)->i_block_group;
@@ -613,9 +614,8 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
613 ext4_group_t *group, int mode) 614 ext4_group_t *group, int mode)
614{ 615{
615 ext4_group_t parent_group = EXT4_I(parent)->i_block_group; 616 ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
616 ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; 617 ext4_group_t i, last, ngroups = ext4_get_groups_count(sb);
617 struct ext4_group_desc *desc; 618 struct ext4_group_desc *desc;
618 ext4_group_t i, last;
619 int flex_size = ext4_flex_bg_size(EXT4_SB(sb)); 619 int flex_size = ext4_flex_bg_size(EXT4_SB(sb));
620 620
621 /* 621 /*
@@ -799,11 +799,10 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
799 struct super_block *sb; 799 struct super_block *sb;
800 struct buffer_head *inode_bitmap_bh = NULL; 800 struct buffer_head *inode_bitmap_bh = NULL;
801 struct buffer_head *group_desc_bh; 801 struct buffer_head *group_desc_bh;
802 ext4_group_t group = 0; 802 ext4_group_t ngroups, group = 0;
803 unsigned long ino = 0; 803 unsigned long ino = 0;
804 struct inode *inode; 804 struct inode *inode;
805 struct ext4_group_desc *gdp = NULL; 805 struct ext4_group_desc *gdp = NULL;
806 struct ext4_super_block *es;
807 struct ext4_inode_info *ei; 806 struct ext4_inode_info *ei;
808 struct ext4_sb_info *sbi; 807 struct ext4_sb_info *sbi;
809 int ret2, err = 0; 808 int ret2, err = 0;
@@ -818,15 +817,14 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
818 return ERR_PTR(-EPERM); 817 return ERR_PTR(-EPERM);
819 818
820 sb = dir->i_sb; 819 sb = dir->i_sb;
820 ngroups = ext4_get_groups_count(sb);
821 trace_mark(ext4_request_inode, "dev %s dir %lu mode %d", sb->s_id, 821 trace_mark(ext4_request_inode, "dev %s dir %lu mode %d", sb->s_id,
822 dir->i_ino, mode); 822 dir->i_ino, mode);
823 inode = new_inode(sb); 823 inode = new_inode(sb);
824 if (!inode) 824 if (!inode)
825 return ERR_PTR(-ENOMEM); 825 return ERR_PTR(-ENOMEM);
826 ei = EXT4_I(inode); 826 ei = EXT4_I(inode);
827
828 sbi = EXT4_SB(sb); 827 sbi = EXT4_SB(sb);
829 es = sbi->s_es;
830 828
831 if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) { 829 if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) {
832 ret2 = find_group_flex(sb, dir, &group); 830 ret2 = find_group_flex(sb, dir, &group);
@@ -856,7 +854,7 @@ got_group:
856 if (ret2 == -1) 854 if (ret2 == -1)
857 goto out; 855 goto out;
858 856
859 for (i = 0; i < sbi->s_groups_count; i++) { 857 for (i = 0; i < ngroups; i++) {
860 err = -EIO; 858 err = -EIO;
861 859
862 gdp = ext4_get_group_desc(sb, group, &group_desc_bh); 860 gdp = ext4_get_group_desc(sb, group, &group_desc_bh);
@@ -917,7 +915,7 @@ repeat_in_this_group:
917 * group descriptor metadata has not yet been updated. 915 * group descriptor metadata has not yet been updated.
918 * So we just go onto the next blockgroup. 916 * So we just go onto the next blockgroup.
919 */ 917 */
920 if (++group == sbi->s_groups_count) 918 if (++group == ngroups)
921 group = 0; 919 group = 0;
922 } 920 }
923 err = -ENOSPC; 921 err = -ENOSPC;
@@ -1158,7 +1156,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
1158{ 1156{
1159 unsigned long desc_count; 1157 unsigned long desc_count;
1160 struct ext4_group_desc *gdp; 1158 struct ext4_group_desc *gdp;
1161 ext4_group_t i; 1159 ext4_group_t i, ngroups = ext4_get_groups_count(sb);
1162#ifdef EXT4FS_DEBUG 1160#ifdef EXT4FS_DEBUG
1163 struct ext4_super_block *es; 1161 struct ext4_super_block *es;
1164 unsigned long bitmap_count, x; 1162 unsigned long bitmap_count, x;
@@ -1168,7 +1166,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
1168 desc_count = 0; 1166 desc_count = 0;
1169 bitmap_count = 0; 1167 bitmap_count = 0;
1170 gdp = NULL; 1168 gdp = NULL;
1171 for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { 1169 for (i = 0; i < ngroups; i++) {
1172 gdp = ext4_get_group_desc(sb, i, NULL); 1170 gdp = ext4_get_group_desc(sb, i, NULL);
1173 if (!gdp) 1171 if (!gdp)
1174 continue; 1172 continue;
@@ -1190,7 +1188,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
1190 return desc_count; 1188 return desc_count;
1191#else 1189#else
1192 desc_count = 0; 1190 desc_count = 0;
1193 for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { 1191 for (i = 0; i < ngroups; i++) {
1194 gdp = ext4_get_group_desc(sb, i, NULL); 1192 gdp = ext4_get_group_desc(sb, i, NULL);
1195 if (!gdp) 1193 if (!gdp)
1196 continue; 1194 continue;
@@ -1205,9 +1203,9 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
1205unsigned long ext4_count_dirs(struct super_block * sb) 1203unsigned long ext4_count_dirs(struct super_block * sb)
1206{ 1204{
1207 unsigned long count = 0; 1205 unsigned long count = 0;
1208 ext4_group_t i; 1206 ext4_group_t i, ngroups = ext4_get_groups_count(sb);
1209 1207
1210 for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { 1208 for (i = 0; i < ngroups; i++) {
1211 struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL); 1209 struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
1212 if (!gdp) 1210 if (!gdp)
1213 continue; 1211 continue;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 96f3366f59f6..4e7f363e3030 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4965,7 +4965,8 @@ static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk)
4965 */ 4965 */
4966int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk) 4966int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk)
4967{ 4967{
4968 int groups, gdpblocks; 4968 ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb);
4969 int gdpblocks;
4969 int idxblocks; 4970 int idxblocks;
4970 int ret = 0; 4971 int ret = 0;
4971 4972
@@ -4992,8 +4993,8 @@ int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk)
4992 groups += nrblocks; 4993 groups += nrblocks;
4993 4994
4994 gdpblocks = groups; 4995 gdpblocks = groups;
4995 if (groups > EXT4_SB(inode->i_sb)->s_groups_count) 4996 if (groups > ngroups)
4996 groups = EXT4_SB(inode->i_sb)->s_groups_count; 4997 groups = ngroups;
4997 if (groups > EXT4_SB(inode->i_sb)->s_gdb_count) 4998 if (groups > EXT4_SB(inode->i_sb)->s_gdb_count)
4998 gdpblocks = EXT4_SB(inode->i_sb)->s_gdb_count; 4999 gdpblocks = EXT4_SB(inode->i_sb)->s_gdb_count;
4999 5000
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index f871677a7984..c3af9e6b6668 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -739,6 +739,7 @@ static void ext4_mb_generate_buddy(struct super_block *sb,
739 739
740static int ext4_mb_init_cache(struct page *page, char *incore) 740static int ext4_mb_init_cache(struct page *page, char *incore)
741{ 741{
742 ext4_group_t ngroups;
742 int blocksize; 743 int blocksize;
743 int blocks_per_page; 744 int blocks_per_page;
744 int groups_per_page; 745 int groups_per_page;
@@ -757,6 +758,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
757 758
758 inode = page->mapping->host; 759 inode = page->mapping->host;
759 sb = inode->i_sb; 760 sb = inode->i_sb;
761 ngroups = ext4_get_groups_count(sb);
760 blocksize = 1 << inode->i_blkbits; 762 blocksize = 1 << inode->i_blkbits;
761 blocks_per_page = PAGE_CACHE_SIZE / blocksize; 763 blocks_per_page = PAGE_CACHE_SIZE / blocksize;
762 764
@@ -780,7 +782,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
780 for (i = 0; i < groups_per_page; i++) { 782 for (i = 0; i < groups_per_page; i++) {
781 struct ext4_group_desc *desc; 783 struct ext4_group_desc *desc;
782 784
783 if (first_group + i >= EXT4_SB(sb)->s_groups_count) 785 if (first_group + i >= ngroups)
784 break; 786 break;
785 787
786 err = -EIO; 788 err = -EIO;
@@ -852,7 +854,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
852 struct ext4_group_info *grinfo; 854 struct ext4_group_info *grinfo;
853 855
854 group = (first_block + i) >> 1; 856 group = (first_block + i) >> 1;
855 if (group >= EXT4_SB(sb)->s_groups_count) 857 if (group >= ngroups)
856 break; 858 break;
857 859
858 /* 860 /*
@@ -1788,6 +1790,7 @@ int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group)
1788 int block, pnum; 1790 int block, pnum;
1789 int blocks_per_page; 1791 int blocks_per_page;
1790 int groups_per_page; 1792 int groups_per_page;
1793 ext4_group_t ngroups = ext4_get_groups_count(sb);
1791 ext4_group_t first_group; 1794 ext4_group_t first_group;
1792 struct ext4_group_info *grp; 1795 struct ext4_group_info *grp;
1793 1796
@@ -1807,7 +1810,7 @@ int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group)
1807 /* read all groups the page covers into the cache */ 1810 /* read all groups the page covers into the cache */
1808 for (i = 0; i < groups_per_page; i++) { 1811 for (i = 0; i < groups_per_page; i++) {
1809 1812
1810 if ((first_group + i) >= EXT4_SB(sb)->s_groups_count) 1813 if ((first_group + i) >= ngroups)
1811 break; 1814 break;
1812 grp = ext4_get_group_info(sb, first_group + i); 1815 grp = ext4_get_group_info(sb, first_group + i);
1813 /* take all groups write allocation 1816 /* take all groups write allocation
@@ -1945,8 +1948,7 @@ err:
1945static noinline_for_stack int 1948static noinline_for_stack int
1946ext4_mb_regular_allocator(struct ext4_allocation_context *ac) 1949ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
1947{ 1950{
1948 ext4_group_t group; 1951 ext4_group_t ngroups, group, i;
1949 ext4_group_t i;
1950 int cr; 1952 int cr;
1951 int err = 0; 1953 int err = 0;
1952 int bsbits; 1954 int bsbits;
@@ -1957,6 +1959,7 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
1957 1959
1958 sb = ac->ac_sb; 1960 sb = ac->ac_sb;
1959 sbi = EXT4_SB(sb); 1961 sbi = EXT4_SB(sb);
1962 ngroups = ext4_get_groups_count(sb);
1960 BUG_ON(ac->ac_status == AC_STATUS_FOUND); 1963 BUG_ON(ac->ac_status == AC_STATUS_FOUND);
1961 1964
1962 /* first, try the goal */ 1965 /* first, try the goal */
@@ -2017,11 +2020,11 @@ repeat:
2017 */ 2020 */
2018 group = ac->ac_g_ex.fe_group; 2021 group = ac->ac_g_ex.fe_group;
2019 2022
2020 for (i = 0; i < EXT4_SB(sb)->s_groups_count; group++, i++) { 2023 for (i = 0; i < ngroups; group++, i++) {
2021 struct ext4_group_info *grp; 2024 struct ext4_group_info *grp;
2022 struct ext4_group_desc *desc; 2025 struct ext4_group_desc *desc;
2023 2026
2024 if (group == EXT4_SB(sb)->s_groups_count) 2027 if (group == ngroups)
2025 group = 0; 2028 group = 0;
2026 2029
2027 /* quick check to skip empty groups */ 2030 /* quick check to skip empty groups */
@@ -2315,12 +2318,10 @@ static struct file_operations ext4_mb_seq_history_fops = {
2315static void *ext4_mb_seq_groups_start(struct seq_file *seq, loff_t *pos) 2318static void *ext4_mb_seq_groups_start(struct seq_file *seq, loff_t *pos)
2316{ 2319{
2317 struct super_block *sb = seq->private; 2320 struct super_block *sb = seq->private;
2318 struct ext4_sb_info *sbi = EXT4_SB(sb);
2319 ext4_group_t group; 2321 ext4_group_t group;
2320 2322
2321 if (*pos < 0 || *pos >= sbi->s_groups_count) 2323 if (*pos < 0 || *pos >= ext4_get_groups_count(sb))
2322 return NULL; 2324 return NULL;
2323
2324 group = *pos + 1; 2325 group = *pos + 1;
2325 return (void *) ((unsigned long) group); 2326 return (void *) ((unsigned long) group);
2326} 2327}
@@ -2328,11 +2329,10 @@ static void *ext4_mb_seq_groups_start(struct seq_file *seq, loff_t *pos)
2328static void *ext4_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos) 2329static void *ext4_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos)
2329{ 2330{
2330 struct super_block *sb = seq->private; 2331 struct super_block *sb = seq->private;
2331 struct ext4_sb_info *sbi = EXT4_SB(sb);
2332 ext4_group_t group; 2332 ext4_group_t group;
2333 2333
2334 ++*pos; 2334 ++*pos;
2335 if (*pos < 0 || *pos >= sbi->s_groups_count) 2335 if (*pos < 0 || *pos >= ext4_get_groups_count(sb))
2336 return NULL; 2336 return NULL;
2337 group = *pos + 1; 2337 group = *pos + 1;
2338 return (void *) ((unsigned long) group); 2338 return (void *) ((unsigned long) group);
@@ -2587,6 +2587,7 @@ void ext4_mb_update_group_info(struct ext4_group_info *grp, ext4_grpblk_t add)
2587 2587
2588static int ext4_mb_init_backend(struct super_block *sb) 2588static int ext4_mb_init_backend(struct super_block *sb)
2589{ 2589{
2590 ext4_group_t ngroups = ext4_get_groups_count(sb);
2590 ext4_group_t i; 2591 ext4_group_t i;
2591 int metalen; 2592 int metalen;
2592 struct ext4_sb_info *sbi = EXT4_SB(sb); 2593 struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -2598,7 +2599,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
2598 struct ext4_group_desc *desc; 2599 struct ext4_group_desc *desc;
2599 2600
2600 /* This is the number of blocks used by GDT */ 2601 /* This is the number of blocks used by GDT */
2601 num_meta_group_infos = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 2602 num_meta_group_infos = (ngroups + EXT4_DESC_PER_BLOCK(sb) -
2602 1) >> EXT4_DESC_PER_BLOCK_BITS(sb); 2603 1) >> EXT4_DESC_PER_BLOCK_BITS(sb);
2603 2604
2604 /* 2605 /*
@@ -2644,7 +2645,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
2644 for (i = 0; i < num_meta_group_infos; i++) { 2645 for (i = 0; i < num_meta_group_infos; i++) {
2645 if ((i + 1) == num_meta_group_infos) 2646 if ((i + 1) == num_meta_group_infos)
2646 metalen = sizeof(*meta_group_info) * 2647 metalen = sizeof(*meta_group_info) *
2647 (sbi->s_groups_count - 2648 (ngroups -
2648 (i << EXT4_DESC_PER_BLOCK_BITS(sb))); 2649 (i << EXT4_DESC_PER_BLOCK_BITS(sb)));
2649 meta_group_info = kmalloc(metalen, GFP_KERNEL); 2650 meta_group_info = kmalloc(metalen, GFP_KERNEL);
2650 if (meta_group_info == NULL) { 2651 if (meta_group_info == NULL) {
@@ -2655,7 +2656,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
2655 sbi->s_group_info[i] = meta_group_info; 2656 sbi->s_group_info[i] = meta_group_info;
2656 } 2657 }
2657 2658
2658 for (i = 0; i < sbi->s_groups_count; i++) { 2659 for (i = 0; i < ngroups; i++) {
2659 desc = ext4_get_group_desc(sb, i, NULL); 2660 desc = ext4_get_group_desc(sb, i, NULL);
2660 if (desc == NULL) { 2661 if (desc == NULL) {
2661 printk(KERN_ERR 2662 printk(KERN_ERR
@@ -2781,13 +2782,14 @@ static void ext4_mb_cleanup_pa(struct ext4_group_info *grp)
2781 2782
2782int ext4_mb_release(struct super_block *sb) 2783int ext4_mb_release(struct super_block *sb)
2783{ 2784{
2785 ext4_group_t ngroups = ext4_get_groups_count(sb);
2784 ext4_group_t i; 2786 ext4_group_t i;
2785 int num_meta_group_infos; 2787 int num_meta_group_infos;
2786 struct ext4_group_info *grinfo; 2788 struct ext4_group_info *grinfo;
2787 struct ext4_sb_info *sbi = EXT4_SB(sb); 2789 struct ext4_sb_info *sbi = EXT4_SB(sb);
2788 2790
2789 if (sbi->s_group_info) { 2791 if (sbi->s_group_info) {
2790 for (i = 0; i < sbi->s_groups_count; i++) { 2792 for (i = 0; i < ngroups; i++) {
2791 grinfo = ext4_get_group_info(sb, i); 2793 grinfo = ext4_get_group_info(sb, i);
2792#ifdef DOUBLE_CHECK 2794#ifdef DOUBLE_CHECK
2793 kfree(grinfo->bb_bitmap); 2795 kfree(grinfo->bb_bitmap);
@@ -2797,7 +2799,7 @@ int ext4_mb_release(struct super_block *sb)
2797 ext4_unlock_group(sb, i); 2799 ext4_unlock_group(sb, i);
2798 kfree(grinfo); 2800 kfree(grinfo);
2799 } 2801 }
2800 num_meta_group_infos = (sbi->s_groups_count + 2802 num_meta_group_infos = (ngroups +
2801 EXT4_DESC_PER_BLOCK(sb) - 1) >> 2803 EXT4_DESC_PER_BLOCK(sb) - 1) >>
2802 EXT4_DESC_PER_BLOCK_BITS(sb); 2804 EXT4_DESC_PER_BLOCK_BITS(sb);
2803 for (i = 0; i < num_meta_group_infos; i++) 2805 for (i = 0; i < num_meta_group_infos; i++)
@@ -4121,7 +4123,7 @@ static void ext4_mb_return_to_preallocation(struct inode *inode,
4121static void ext4_mb_show_ac(struct ext4_allocation_context *ac) 4123static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
4122{ 4124{
4123 struct super_block *sb = ac->ac_sb; 4125 struct super_block *sb = ac->ac_sb;
4124 ext4_group_t i; 4126 ext4_group_t ngroups, i;
4125 4127
4126 printk(KERN_ERR "EXT4-fs: Can't allocate:" 4128 printk(KERN_ERR "EXT4-fs: Can't allocate:"
4127 " Allocation context details:\n"); 4129 " Allocation context details:\n");
@@ -4145,7 +4147,8 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
4145 printk(KERN_ERR "EXT4-fs: %lu scanned, %d found\n", ac->ac_ex_scanned, 4147 printk(KERN_ERR "EXT4-fs: %lu scanned, %d found\n", ac->ac_ex_scanned,
4146 ac->ac_found); 4148 ac->ac_found);
4147 printk(KERN_ERR "EXT4-fs: groups: \n"); 4149 printk(KERN_ERR "EXT4-fs: groups: \n");
4148 for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) { 4150 ngroups = ext4_get_groups_count(sb);
4151 for (i = 0; i < ngroups; i++) {
4149 struct ext4_group_info *grp = ext4_get_group_info(sb, i); 4152 struct ext4_group_info *grp = ext4_get_group_info(sb, i);
4150 struct ext4_prealloc_space *pa; 4153 struct ext4_prealloc_space *pa;
4151 ext4_grpblk_t start; 4154 ext4_grpblk_t start;
@@ -4469,13 +4472,13 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
4469 4472
4470static int ext4_mb_discard_preallocations(struct super_block *sb, int needed) 4473static int ext4_mb_discard_preallocations(struct super_block *sb, int needed)
4471{ 4474{
4472 ext4_group_t i; 4475 ext4_group_t i, ngroups = ext4_get_groups_count(sb);
4473 int ret; 4476 int ret;
4474 int freed = 0; 4477 int freed = 0;
4475 4478
4476 trace_mark(ext4_mb_discard_preallocations, "dev %s needed %d", 4479 trace_mark(ext4_mb_discard_preallocations, "dev %s needed %d",
4477 sb->s_id, needed); 4480 sb->s_id, needed);
4478 for (i = 0; i < EXT4_SB(sb)->s_groups_count && needed > 0; i++) { 4481 for (i = 0; i < ngroups && needed > 0; i++) {
4479 ret = ext4_mb_discard_group_preallocations(sb, i, needed); 4482 ret = ext4_mb_discard_group_preallocations(sb, i, needed);
4480 freed += ret; 4483 freed += ret;
4481 needed -= ret; 4484 needed -= ret;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 68c3a44c4a97..fcd7b24c6df3 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3557,9 +3557,8 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
3557 if (test_opt(sb, MINIX_DF)) { 3557 if (test_opt(sb, MINIX_DF)) {
3558 sbi->s_overhead_last = 0; 3558 sbi->s_overhead_last = 0;
3559 } else if (sbi->s_blocks_last != ext4_blocks_count(es)) { 3559 } else if (sbi->s_blocks_last != ext4_blocks_count(es)) {
3560 ext4_group_t ngroups = sbi->s_groups_count, i; 3560 ext4_group_t i, ngroups = ext4_get_groups_count(sb);
3561 ext4_fsblk_t overhead = 0; 3561 ext4_fsblk_t overhead = 0;
3562 smp_rmb();
3563 3562
3564 /* 3563 /*
3565 * Compute the overhead (FS structures). This is constant 3564 * Compute the overhead (FS structures). This is constant