diff options
Diffstat (limited to 'fs/ext4/resize.c')
-rw-r--r-- | fs/ext4/resize.c | 432 |
1 files changed, 343 insertions, 89 deletions
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 41f6ef68e2e1..7a75e1086961 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -45,6 +45,28 @@ void ext4_resize_end(struct super_block *sb) | |||
45 | smp_mb__after_clear_bit(); | 45 | smp_mb__after_clear_bit(); |
46 | } | 46 | } |
47 | 47 | ||
48 | static ext4_group_t ext4_meta_bg_first_group(struct super_block *sb, | ||
49 | ext4_group_t group) { | ||
50 | return (group >> EXT4_DESC_PER_BLOCK_BITS(sb)) << | ||
51 | EXT4_DESC_PER_BLOCK_BITS(sb); | ||
52 | } | ||
53 | |||
54 | static ext4_fsblk_t ext4_meta_bg_first_block_no(struct super_block *sb, | ||
55 | ext4_group_t group) { | ||
56 | group = ext4_meta_bg_first_group(sb, group); | ||
57 | return ext4_group_first_block_no(sb, group); | ||
58 | } | ||
59 | |||
60 | static ext4_grpblk_t ext4_group_overhead_blocks(struct super_block *sb, | ||
61 | ext4_group_t group) { | ||
62 | ext4_grpblk_t overhead; | ||
63 | overhead = ext4_bg_num_gdb(sb, group); | ||
64 | if (ext4_bg_has_super(sb, group)) | ||
65 | overhead += 1 + | ||
66 | le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks); | ||
67 | return overhead; | ||
68 | } | ||
69 | |||
48 | #define outside(b, first, last) ((b) < (first) || (b) >= (last)) | 70 | #define outside(b, first, last) ((b) < (first) || (b) >= (last)) |
49 | #define inside(b, first, last) ((b) >= (first) && (b) < (last)) | 71 | #define inside(b, first, last) ((b) >= (first) && (b) < (last)) |
50 | 72 | ||
@@ -57,9 +79,7 @@ static int verify_group_input(struct super_block *sb, | |||
57 | ext4_fsblk_t end = start + input->blocks_count; | 79 | ext4_fsblk_t end = start + input->blocks_count; |
58 | ext4_group_t group = input->group; | 80 | ext4_group_t group = input->group; |
59 | ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; | 81 | ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; |
60 | unsigned overhead = ext4_bg_has_super(sb, group) ? | 82 | unsigned overhead = ext4_group_overhead_blocks(sb, group); |
61 | (1 + ext4_bg_num_gdb(sb, group) + | ||
62 | le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; | ||
63 | ext4_fsblk_t metaend = start + overhead; | 83 | ext4_fsblk_t metaend = start + overhead; |
64 | struct buffer_head *bh = NULL; | 84 | struct buffer_head *bh = NULL; |
65 | ext4_grpblk_t free_blocks_count, offset; | 85 | ext4_grpblk_t free_blocks_count, offset; |
@@ -200,13 +220,15 @@ static void free_flex_gd(struct ext4_new_flex_group_data *flex_gd) | |||
200 | * be a partial of a flex group. | 220 | * be a partial of a flex group. |
201 | * | 221 | * |
202 | * @sb: super block of fs to which the groups belongs | 222 | * @sb: super block of fs to which the groups belongs |
223 | * | ||
224 | * Returns 0 on a successful allocation of the metadata blocks in the | ||
225 | * block group. | ||
203 | */ | 226 | */ |
204 | static void ext4_alloc_group_tables(struct super_block *sb, | 227 | static int ext4_alloc_group_tables(struct super_block *sb, |
205 | struct ext4_new_flex_group_data *flex_gd, | 228 | struct ext4_new_flex_group_data *flex_gd, |
206 | int flexbg_size) | 229 | int flexbg_size) |
207 | { | 230 | { |
208 | struct ext4_new_group_data *group_data = flex_gd->groups; | 231 | struct ext4_new_group_data *group_data = flex_gd->groups; |
209 | struct ext4_super_block *es = EXT4_SB(sb)->s_es; | ||
210 | ext4_fsblk_t start_blk; | 232 | ext4_fsblk_t start_blk; |
211 | ext4_fsblk_t last_blk; | 233 | ext4_fsblk_t last_blk; |
212 | ext4_group_t src_group; | 234 | ext4_group_t src_group; |
@@ -226,23 +248,24 @@ static void ext4_alloc_group_tables(struct super_block *sb, | |||
226 | (last_group & ~(flexbg_size - 1)))); | 248 | (last_group & ~(flexbg_size - 1)))); |
227 | next_group: | 249 | next_group: |
228 | group = group_data[0].group; | 250 | group = group_data[0].group; |
251 | if (src_group >= group_data[0].group + flex_gd->count) | ||
252 | return -ENOSPC; | ||
229 | start_blk = ext4_group_first_block_no(sb, src_group); | 253 | start_blk = ext4_group_first_block_no(sb, src_group); |
230 | last_blk = start_blk + group_data[src_group - group].blocks_count; | 254 | last_blk = start_blk + group_data[src_group - group].blocks_count; |
231 | 255 | ||
232 | overhead = ext4_bg_has_super(sb, src_group) ? | 256 | overhead = ext4_group_overhead_blocks(sb, src_group); |
233 | (1 + ext4_bg_num_gdb(sb, src_group) + | ||
234 | le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; | ||
235 | 257 | ||
236 | start_blk += overhead; | 258 | start_blk += overhead; |
237 | 259 | ||
238 | BUG_ON(src_group >= group_data[0].group + flex_gd->count); | ||
239 | /* We collect contiguous blocks as much as possible. */ | 260 | /* We collect contiguous blocks as much as possible. */ |
240 | src_group++; | 261 | src_group++; |
241 | for (; src_group <= last_group; src_group++) | 262 | for (; src_group <= last_group; src_group++) { |
242 | if (!ext4_bg_has_super(sb, src_group)) | 263 | overhead = ext4_group_overhead_blocks(sb, src_group); |
264 | if (overhead != 0) | ||
243 | last_blk += group_data[src_group - group].blocks_count; | 265 | last_blk += group_data[src_group - group].blocks_count; |
244 | else | 266 | else |
245 | break; | 267 | break; |
268 | } | ||
246 | 269 | ||
247 | /* Allocate block bitmaps */ | 270 | /* Allocate block bitmaps */ |
248 | for (; bb_index < flex_gd->count; bb_index++) { | 271 | for (; bb_index < flex_gd->count; bb_index++) { |
@@ -300,6 +323,7 @@ next_group: | |||
300 | group_data[i].free_blocks_count); | 323 | group_data[i].free_blocks_count); |
301 | } | 324 | } |
302 | } | 325 | } |
326 | return 0; | ||
303 | } | 327 | } |
304 | 328 | ||
305 | static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, | 329 | static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, |
@@ -433,11 +457,13 @@ static int setup_new_flex_group_blocks(struct super_block *sb, | |||
433 | ext4_group_t group, count; | 457 | ext4_group_t group, count; |
434 | struct buffer_head *bh = NULL; | 458 | struct buffer_head *bh = NULL; |
435 | int reserved_gdb, i, j, err = 0, err2; | 459 | int reserved_gdb, i, j, err = 0, err2; |
460 | int meta_bg; | ||
436 | 461 | ||
437 | BUG_ON(!flex_gd->count || !group_data || | 462 | BUG_ON(!flex_gd->count || !group_data || |
438 | group_data[0].group != sbi->s_groups_count); | 463 | group_data[0].group != sbi->s_groups_count); |
439 | 464 | ||
440 | reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks); | 465 | reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks); |
466 | meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG); | ||
441 | 467 | ||
442 | /* This transaction may be extended/restarted along the way */ | 468 | /* This transaction may be extended/restarted along the way */ |
443 | handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA); | 469 | handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA); |
@@ -447,12 +473,25 @@ static int setup_new_flex_group_blocks(struct super_block *sb, | |||
447 | group = group_data[0].group; | 473 | group = group_data[0].group; |
448 | for (i = 0; i < flex_gd->count; i++, group++) { | 474 | for (i = 0; i < flex_gd->count; i++, group++) { |
449 | unsigned long gdblocks; | 475 | unsigned long gdblocks; |
476 | ext4_grpblk_t overhead; | ||
450 | 477 | ||
451 | gdblocks = ext4_bg_num_gdb(sb, group); | 478 | gdblocks = ext4_bg_num_gdb(sb, group); |
452 | start = ext4_group_first_block_no(sb, group); | 479 | start = ext4_group_first_block_no(sb, group); |
453 | 480 | ||
481 | if (meta_bg == 0 && !ext4_bg_has_super(sb, group)) | ||
482 | goto handle_itb; | ||
483 | |||
484 | if (meta_bg == 1) { | ||
485 | ext4_group_t first_group; | ||
486 | first_group = ext4_meta_bg_first_group(sb, group); | ||
487 | if (first_group != group + 1 && | ||
488 | first_group != group + EXT4_DESC_PER_BLOCK(sb) - 1) | ||
489 | goto handle_itb; | ||
490 | } | ||
491 | |||
492 | block = start + ext4_bg_has_super(sb, group); | ||
454 | /* Copy all of the GDT blocks into the backup in this group */ | 493 | /* Copy all of the GDT blocks into the backup in this group */ |
455 | for (j = 0, block = start + 1; j < gdblocks; j++, block++) { | 494 | for (j = 0; j < gdblocks; j++, block++) { |
456 | struct buffer_head *gdb; | 495 | struct buffer_head *gdb; |
457 | 496 | ||
458 | ext4_debug("update backup group %#04llx\n", block); | 497 | ext4_debug("update backup group %#04llx\n", block); |
@@ -493,6 +532,7 @@ static int setup_new_flex_group_blocks(struct super_block *sb, | |||
493 | goto out; | 532 | goto out; |
494 | } | 533 | } |
495 | 534 | ||
535 | handle_itb: | ||
496 | /* Initialize group tables of the grop @group */ | 536 | /* Initialize group tables of the grop @group */ |
497 | if (!(bg_flags[i] & EXT4_BG_INODE_ZEROED)) | 537 | if (!(bg_flags[i] & EXT4_BG_INODE_ZEROED)) |
498 | goto handle_bb; | 538 | goto handle_bb; |
@@ -521,11 +561,11 @@ handle_bb: | |||
521 | err = PTR_ERR(bh); | 561 | err = PTR_ERR(bh); |
522 | goto out; | 562 | goto out; |
523 | } | 563 | } |
524 | if (ext4_bg_has_super(sb, group)) { | 564 | overhead = ext4_group_overhead_blocks(sb, group); |
565 | if (overhead != 0) { | ||
525 | ext4_debug("mark backup superblock %#04llx (+0)\n", | 566 | ext4_debug("mark backup superblock %#04llx (+0)\n", |
526 | start); | 567 | start); |
527 | ext4_set_bits(bh->b_data, 0, gdblocks + reserved_gdb + | 568 | ext4_set_bits(bh->b_data, 0, overhead); |
528 | 1); | ||
529 | } | 569 | } |
530 | ext4_mark_bitmap_end(group_data[i].blocks_count, | 570 | ext4_mark_bitmap_end(group_data[i].blocks_count, |
531 | sb->s_blocksize * 8, bh->b_data); | 571 | sb->s_blocksize * 8, bh->b_data); |
@@ -822,6 +862,45 @@ exit_bh: | |||
822 | } | 862 | } |
823 | 863 | ||
824 | /* | 864 | /* |
865 | * add_new_gdb_meta_bg is the sister of add_new_gdb. | ||
866 | */ | ||
867 | static int add_new_gdb_meta_bg(struct super_block *sb, | ||
868 | handle_t *handle, ext4_group_t group) { | ||
869 | ext4_fsblk_t gdblock; | ||
870 | struct buffer_head *gdb_bh; | ||
871 | struct buffer_head **o_group_desc, **n_group_desc; | ||
872 | unsigned long gdb_num = group / EXT4_DESC_PER_BLOCK(sb); | ||
873 | int err; | ||
874 | |||
875 | gdblock = ext4_meta_bg_first_block_no(sb, group) + | ||
876 | ext4_bg_has_super(sb, group); | ||
877 | gdb_bh = sb_bread(sb, gdblock); | ||
878 | if (!gdb_bh) | ||
879 | return -EIO; | ||
880 | n_group_desc = ext4_kvmalloc((gdb_num + 1) * | ||
881 | sizeof(struct buffer_head *), | ||
882 | GFP_NOFS); | ||
883 | if (!n_group_desc) { | ||
884 | err = -ENOMEM; | ||
885 | ext4_warning(sb, "not enough memory for %lu groups", | ||
886 | gdb_num + 1); | ||
887 | return err; | ||
888 | } | ||
889 | |||
890 | o_group_desc = EXT4_SB(sb)->s_group_desc; | ||
891 | memcpy(n_group_desc, o_group_desc, | ||
892 | EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); | ||
893 | n_group_desc[gdb_num] = gdb_bh; | ||
894 | EXT4_SB(sb)->s_group_desc = n_group_desc; | ||
895 | EXT4_SB(sb)->s_gdb_count++; | ||
896 | ext4_kvfree(o_group_desc); | ||
897 | err = ext4_journal_get_write_access(handle, gdb_bh); | ||
898 | if (unlikely(err)) | ||
899 | brelse(gdb_bh); | ||
900 | return err; | ||
901 | } | ||
902 | |||
903 | /* | ||
825 | * Called when we are adding a new group which has a backup copy of each of | 904 | * Called when we are adding a new group which has a backup copy of each of |
826 | * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks. | 905 | * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks. |
827 | * We need to add these reserved backup GDT blocks to the resize inode, so | 906 | * We need to add these reserved backup GDT blocks to the resize inode, so |
@@ -949,16 +1028,16 @@ exit_free: | |||
949 | * do not copy the full number of backups at this time. The resize | 1028 | * do not copy the full number of backups at this time. The resize |
950 | * which changed s_groups_count will backup again. | 1029 | * which changed s_groups_count will backup again. |
951 | */ | 1030 | */ |
952 | static void update_backups(struct super_block *sb, | 1031 | static void update_backups(struct super_block *sb, int blk_off, char *data, |
953 | int blk_off, char *data, int size) | 1032 | int size, int meta_bg) |
954 | { | 1033 | { |
955 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 1034 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
956 | const ext4_group_t last = sbi->s_groups_count; | 1035 | ext4_group_t last; |
957 | const int bpg = EXT4_BLOCKS_PER_GROUP(sb); | 1036 | const int bpg = EXT4_BLOCKS_PER_GROUP(sb); |
958 | unsigned three = 1; | 1037 | unsigned three = 1; |
959 | unsigned five = 5; | 1038 | unsigned five = 5; |
960 | unsigned seven = 7; | 1039 | unsigned seven = 7; |
961 | ext4_group_t group; | 1040 | ext4_group_t group = 0; |
962 | int rest = sb->s_blocksize - size; | 1041 | int rest = sb->s_blocksize - size; |
963 | handle_t *handle; | 1042 | handle_t *handle; |
964 | int err = 0, err2; | 1043 | int err = 0, err2; |
@@ -970,10 +1049,17 @@ static void update_backups(struct super_block *sb, | |||
970 | goto exit_err; | 1049 | goto exit_err; |
971 | } | 1050 | } |
972 | 1051 | ||
973 | ext4_superblock_csum_set(sb, (struct ext4_super_block *)data); | 1052 | if (meta_bg == 0) { |
1053 | group = ext4_list_backups(sb, &three, &five, &seven); | ||
1054 | last = sbi->s_groups_count; | ||
1055 | } else { | ||
1056 | group = ext4_meta_bg_first_group(sb, group) + 1; | ||
1057 | last = (ext4_group_t)(group + EXT4_DESC_PER_BLOCK(sb) - 2); | ||
1058 | } | ||
974 | 1059 | ||
975 | while ((group = ext4_list_backups(sb, &three, &five, &seven)) < last) { | 1060 | while (group < sbi->s_groups_count) { |
976 | struct buffer_head *bh; | 1061 | struct buffer_head *bh; |
1062 | ext4_fsblk_t backup_block; | ||
977 | 1063 | ||
978 | /* Out of journal space, and can't get more - abort - so sad */ | 1064 | /* Out of journal space, and can't get more - abort - so sad */ |
979 | if (ext4_handle_valid(handle) && | 1065 | if (ext4_handle_valid(handle) && |
@@ -982,13 +1068,20 @@ static void update_backups(struct super_block *sb, | |||
982 | (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) | 1068 | (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) |
983 | break; | 1069 | break; |
984 | 1070 | ||
985 | bh = sb_getblk(sb, group * bpg + blk_off); | 1071 | if (meta_bg == 0) |
1072 | backup_block = group * bpg + blk_off; | ||
1073 | else | ||
1074 | backup_block = (ext4_group_first_block_no(sb, group) + | ||
1075 | ext4_bg_has_super(sb, group)); | ||
1076 | |||
1077 | bh = sb_getblk(sb, backup_block); | ||
986 | if (!bh) { | 1078 | if (!bh) { |
987 | err = -EIO; | 1079 | err = -EIO; |
988 | break; | 1080 | break; |
989 | } | 1081 | } |
990 | ext4_debug("update metadata backup %#04lx\n", | 1082 | ext4_debug("update metadata backup %llu(+%llu)\n", |
991 | (unsigned long)bh->b_blocknr); | 1083 | backup_block, backup_block - |
1084 | ext4_group_first_block_no(sb, group)); | ||
992 | if ((err = ext4_journal_get_write_access(handle, bh))) | 1085 | if ((err = ext4_journal_get_write_access(handle, bh))) |
993 | break; | 1086 | break; |
994 | lock_buffer(bh); | 1087 | lock_buffer(bh); |
@@ -1001,6 +1094,13 @@ static void update_backups(struct super_block *sb, | |||
1001 | if (unlikely(err)) | 1094 | if (unlikely(err)) |
1002 | ext4_std_error(sb, err); | 1095 | ext4_std_error(sb, err); |
1003 | brelse(bh); | 1096 | brelse(bh); |
1097 | |||
1098 | if (meta_bg == 0) | ||
1099 | group = ext4_list_backups(sb, &three, &five, &seven); | ||
1100 | else if (group == last) | ||
1101 | break; | ||
1102 | else | ||
1103 | group = last; | ||
1004 | } | 1104 | } |
1005 | if ((err2 = ext4_journal_stop(handle)) && !err) | 1105 | if ((err2 = ext4_journal_stop(handle)) && !err) |
1006 | err = err2; | 1106 | err = err2; |
@@ -1043,7 +1143,9 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb, | |||
1043 | struct ext4_super_block *es = sbi->s_es; | 1143 | struct ext4_super_block *es = sbi->s_es; |
1044 | struct buffer_head *gdb_bh; | 1144 | struct buffer_head *gdb_bh; |
1045 | int i, gdb_off, gdb_num, err = 0; | 1145 | int i, gdb_off, gdb_num, err = 0; |
1146 | int meta_bg; | ||
1046 | 1147 | ||
1148 | meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG); | ||
1047 | for (i = 0; i < count; i++, group++) { | 1149 | for (i = 0; i < count; i++, group++) { |
1048 | int reserved_gdb = ext4_bg_has_super(sb, group) ? | 1150 | int reserved_gdb = ext4_bg_has_super(sb, group) ? |
1049 | le16_to_cpu(es->s_reserved_gdt_blocks) : 0; | 1151 | le16_to_cpu(es->s_reserved_gdt_blocks) : 0; |
@@ -1063,8 +1165,11 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb, | |||
1063 | 1165 | ||
1064 | if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group)) | 1166 | if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group)) |
1065 | err = reserve_backup_gdb(handle, resize_inode, group); | 1167 | err = reserve_backup_gdb(handle, resize_inode, group); |
1066 | } else | 1168 | } else if (meta_bg != 0) { |
1169 | err = add_new_gdb_meta_bg(sb, handle, group); | ||
1170 | } else { | ||
1067 | err = add_new_gdb(handle, resize_inode, group); | 1171 | err = add_new_gdb(handle, resize_inode, group); |
1172 | } | ||
1068 | if (err) | 1173 | if (err) |
1069 | break; | 1174 | break; |
1070 | } | 1175 | } |
@@ -1076,17 +1181,12 @@ static struct buffer_head *ext4_get_bitmap(struct super_block *sb, __u64 block) | |||
1076 | struct buffer_head *bh = sb_getblk(sb, block); | 1181 | struct buffer_head *bh = sb_getblk(sb, block); |
1077 | if (!bh) | 1182 | if (!bh) |
1078 | return NULL; | 1183 | return NULL; |
1079 | 1184 | if (!bh_uptodate_or_lock(bh)) { | |
1080 | if (bitmap_uptodate(bh)) | 1185 | if (bh_submit_read(bh) < 0) { |
1081 | return bh; | 1186 | brelse(bh); |
1082 | 1187 | return NULL; | |
1083 | lock_buffer(bh); | 1188 | } |
1084 | if (bh_submit_read(bh) < 0) { | ||
1085 | unlock_buffer(bh); | ||
1086 | brelse(bh); | ||
1087 | return NULL; | ||
1088 | } | 1189 | } |
1089 | unlock_buffer(bh); | ||
1090 | 1190 | ||
1091 | return bh; | 1191 | return bh; |
1092 | } | 1192 | } |
@@ -1161,6 +1261,9 @@ static int ext4_setup_new_descs(handle_t *handle, struct super_block *sb, | |||
1161 | ext4_free_group_clusters_set(sb, gdp, | 1261 | ext4_free_group_clusters_set(sb, gdp, |
1162 | EXT4_B2C(sbi, group_data->free_blocks_count)); | 1262 | EXT4_B2C(sbi, group_data->free_blocks_count)); |
1163 | ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb)); | 1263 | ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb)); |
1264 | if (ext4_has_group_desc_csum(sb)) | ||
1265 | ext4_itable_unused_set(sb, gdp, | ||
1266 | EXT4_INODES_PER_GROUP(sb)); | ||
1164 | gdp->bg_flags = cpu_to_le16(*bg_flags); | 1267 | gdp->bg_flags = cpu_to_le16(*bg_flags); |
1165 | ext4_group_desc_csum_set(sb, group, gdp); | 1268 | ext4_group_desc_csum_set(sb, group, gdp); |
1166 | 1269 | ||
@@ -1216,7 +1319,7 @@ static void ext4_update_super(struct super_block *sb, | |||
1216 | } | 1319 | } |
1217 | 1320 | ||
1218 | reserved_blocks = ext4_r_blocks_count(es) * 100; | 1321 | reserved_blocks = ext4_r_blocks_count(es) * 100; |
1219 | do_div(reserved_blocks, ext4_blocks_count(es)); | 1322 | reserved_blocks = div64_u64(reserved_blocks, ext4_blocks_count(es)); |
1220 | reserved_blocks *= blocks_count; | 1323 | reserved_blocks *= blocks_count; |
1221 | do_div(reserved_blocks, 100); | 1324 | do_div(reserved_blocks, 100); |
1222 | 1325 | ||
@@ -1227,6 +1330,7 @@ static void ext4_update_super(struct super_block *sb, | |||
1227 | le32_add_cpu(&es->s_free_inodes_count, EXT4_INODES_PER_GROUP(sb) * | 1330 | le32_add_cpu(&es->s_free_inodes_count, EXT4_INODES_PER_GROUP(sb) * |
1228 | flex_gd->count); | 1331 | flex_gd->count); |
1229 | 1332 | ||
1333 | ext4_debug("free blocks count %llu", ext4_free_blocks_count(es)); | ||
1230 | /* | 1334 | /* |
1231 | * We need to protect s_groups_count against other CPUs seeing | 1335 | * We need to protect s_groups_count against other CPUs seeing |
1232 | * inconsistent state in the superblock. | 1336 | * inconsistent state in the superblock. |
@@ -1261,6 +1365,8 @@ static void ext4_update_super(struct super_block *sb, | |||
1261 | percpu_counter_add(&sbi->s_freeinodes_counter, | 1365 | percpu_counter_add(&sbi->s_freeinodes_counter, |
1262 | EXT4_INODES_PER_GROUP(sb) * flex_gd->count); | 1366 | EXT4_INODES_PER_GROUP(sb) * flex_gd->count); |
1263 | 1367 | ||
1368 | ext4_debug("free blocks count %llu", | ||
1369 | percpu_counter_read(&sbi->s_freeclusters_counter)); | ||
1264 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, | 1370 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, |
1265 | EXT4_FEATURE_INCOMPAT_FLEX_BG) && | 1371 | EXT4_FEATURE_INCOMPAT_FLEX_BG) && |
1266 | sbi->s_log_groups_per_flex) { | 1372 | sbi->s_log_groups_per_flex) { |
@@ -1349,16 +1455,24 @@ exit_journal: | |||
1349 | err = err2; | 1455 | err = err2; |
1350 | 1456 | ||
1351 | if (!err) { | 1457 | if (!err) { |
1352 | int i; | 1458 | int gdb_num = group / EXT4_DESC_PER_BLOCK(sb); |
1459 | int gdb_num_end = ((group + flex_gd->count - 1) / | ||
1460 | EXT4_DESC_PER_BLOCK(sb)); | ||
1461 | int meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, | ||
1462 | EXT4_FEATURE_INCOMPAT_META_BG); | ||
1463 | sector_t old_gdb = 0; | ||
1464 | |||
1353 | update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, | 1465 | update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, |
1354 | sizeof(struct ext4_super_block)); | 1466 | sizeof(struct ext4_super_block), 0); |
1355 | for (i = 0; i < flex_gd->count; i++, group++) { | 1467 | for (; gdb_num <= gdb_num_end; gdb_num++) { |
1356 | struct buffer_head *gdb_bh; | 1468 | struct buffer_head *gdb_bh; |
1357 | int gdb_num; | 1469 | |
1358 | gdb_num = group / EXT4_BLOCKS_PER_GROUP(sb); | ||
1359 | gdb_bh = sbi->s_group_desc[gdb_num]; | 1470 | gdb_bh = sbi->s_group_desc[gdb_num]; |
1471 | if (old_gdb == gdb_bh->b_blocknr) | ||
1472 | continue; | ||
1360 | update_backups(sb, gdb_bh->b_blocknr, gdb_bh->b_data, | 1473 | update_backups(sb, gdb_bh->b_blocknr, gdb_bh->b_data, |
1361 | gdb_bh->b_size); | 1474 | gdb_bh->b_size, meta_bg); |
1475 | old_gdb = gdb_bh->b_blocknr; | ||
1362 | } | 1476 | } |
1363 | } | 1477 | } |
1364 | exit: | 1478 | exit: |
@@ -1402,9 +1516,7 @@ static int ext4_setup_next_flex_gd(struct super_block *sb, | |||
1402 | 1516 | ||
1403 | group_data[i].group = group + i; | 1517 | group_data[i].group = group + i; |
1404 | group_data[i].blocks_count = blocks_per_group; | 1518 | group_data[i].blocks_count = blocks_per_group; |
1405 | overhead = ext4_bg_has_super(sb, group + i) ? | 1519 | overhead = ext4_group_overhead_blocks(sb, group + i); |
1406 | (1 + ext4_bg_num_gdb(sb, group + i) + | ||
1407 | le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; | ||
1408 | group_data[i].free_blocks_count = blocks_per_group - overhead; | 1520 | group_data[i].free_blocks_count = blocks_per_group - overhead; |
1409 | if (ext4_has_group_desc_csum(sb)) | 1521 | if (ext4_has_group_desc_csum(sb)) |
1410 | flex_gd->bg_flags[i] = EXT4_BG_BLOCK_UNINIT | | 1522 | flex_gd->bg_flags[i] = EXT4_BG_BLOCK_UNINIT | |
@@ -1492,6 +1604,14 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
1492 | if (err) | 1604 | if (err) |
1493 | goto out; | 1605 | goto out; |
1494 | 1606 | ||
1607 | err = ext4_alloc_flex_bg_array(sb, input->group + 1); | ||
1608 | if (err) | ||
1609 | return err; | ||
1610 | |||
1611 | err = ext4_mb_alloc_groupinfo(sb, input->group + 1); | ||
1612 | if (err) | ||
1613 | goto out; | ||
1614 | |||
1495 | flex_gd.count = 1; | 1615 | flex_gd.count = 1; |
1496 | flex_gd.groups = input; | 1616 | flex_gd.groups = input; |
1497 | flex_gd.bg_flags = &bg_flags; | 1617 | flex_gd.bg_flags = &bg_flags; |
@@ -1544,11 +1664,13 @@ errout: | |||
1544 | err = err2; | 1664 | err = err2; |
1545 | 1665 | ||
1546 | if (!err) { | 1666 | if (!err) { |
1667 | ext4_fsblk_t first_block; | ||
1668 | first_block = ext4_group_first_block_no(sb, 0); | ||
1547 | if (test_opt(sb, DEBUG)) | 1669 | if (test_opt(sb, DEBUG)) |
1548 | printk(KERN_DEBUG "EXT4-fs: extended group to %llu " | 1670 | printk(KERN_DEBUG "EXT4-fs: extended group to %llu " |
1549 | "blocks\n", ext4_blocks_count(es)); | 1671 | "blocks\n", ext4_blocks_count(es)); |
1550 | update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es, | 1672 | update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr - first_block, |
1551 | sizeof(struct ext4_super_block)); | 1673 | (char *)es, sizeof(struct ext4_super_block), 0); |
1552 | } | 1674 | } |
1553 | return err; | 1675 | return err; |
1554 | } | 1676 | } |
@@ -1631,6 +1753,94 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, | |||
1631 | return err; | 1753 | return err; |
1632 | } /* ext4_group_extend */ | 1754 | } /* ext4_group_extend */ |
1633 | 1755 | ||
1756 | |||
1757 | static int num_desc_blocks(struct super_block *sb, ext4_group_t groups) | ||
1758 | { | ||
1759 | return (groups + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); | ||
1760 | } | ||
1761 | |||
1762 | /* | ||
1763 | * Release the resize inode and drop the resize_inode feature if there | ||
1764 | * are no more reserved gdt blocks, and then convert the file system | ||
1765 | * to enable meta_bg | ||
1766 | */ | ||
1767 | static int ext4_convert_meta_bg(struct super_block *sb, struct inode *inode) | ||
1768 | { | ||
1769 | handle_t *handle; | ||
1770 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
1771 | struct ext4_super_block *es = sbi->s_es; | ||
1772 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
1773 | ext4_fsblk_t nr; | ||
1774 | int i, ret, err = 0; | ||
1775 | int credits = 1; | ||
1776 | |||
1777 | ext4_msg(sb, KERN_INFO, "Converting file system to meta_bg"); | ||
1778 | if (inode) { | ||
1779 | if (es->s_reserved_gdt_blocks) { | ||
1780 | ext4_error(sb, "Unexpected non-zero " | ||
1781 | "s_reserved_gdt_blocks"); | ||
1782 | return -EPERM; | ||
1783 | } | ||
1784 | |||
1785 | /* Do a quick sanity check of the resize inode */ | ||
1786 | if (inode->i_blocks != 1 << (inode->i_blkbits - 9)) | ||
1787 | goto invalid_resize_inode; | ||
1788 | for (i = 0; i < EXT4_N_BLOCKS; i++) { | ||
1789 | if (i == EXT4_DIND_BLOCK) { | ||
1790 | if (ei->i_data[i]) | ||
1791 | continue; | ||
1792 | else | ||
1793 | goto invalid_resize_inode; | ||
1794 | } | ||
1795 | if (ei->i_data[i]) | ||
1796 | goto invalid_resize_inode; | ||
1797 | } | ||
1798 | credits += 3; /* block bitmap, bg descriptor, resize inode */ | ||
1799 | } | ||
1800 | |||
1801 | handle = ext4_journal_start_sb(sb, credits); | ||
1802 | if (IS_ERR(handle)) | ||
1803 | return PTR_ERR(handle); | ||
1804 | |||
1805 | err = ext4_journal_get_write_access(handle, sbi->s_sbh); | ||
1806 | if (err) | ||
1807 | goto errout; | ||
1808 | |||
1809 | EXT4_CLEAR_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_RESIZE_INODE); | ||
1810 | EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG); | ||
1811 | sbi->s_es->s_first_meta_bg = | ||
1812 | cpu_to_le32(num_desc_blocks(sb, sbi->s_groups_count)); | ||
1813 | |||
1814 | err = ext4_handle_dirty_super(handle, sb); | ||
1815 | if (err) { | ||
1816 | ext4_std_error(sb, err); | ||
1817 | goto errout; | ||
1818 | } | ||
1819 | |||
1820 | if (inode) { | ||
1821 | nr = le32_to_cpu(ei->i_data[EXT4_DIND_BLOCK]); | ||
1822 | ext4_free_blocks(handle, inode, NULL, nr, 1, | ||
1823 | EXT4_FREE_BLOCKS_METADATA | | ||
1824 | EXT4_FREE_BLOCKS_FORGET); | ||
1825 | ei->i_data[EXT4_DIND_BLOCK] = 0; | ||
1826 | inode->i_blocks = 0; | ||
1827 | |||
1828 | err = ext4_mark_inode_dirty(handle, inode); | ||
1829 | if (err) | ||
1830 | ext4_std_error(sb, err); | ||
1831 | } | ||
1832 | |||
1833 | errout: | ||
1834 | ret = ext4_journal_stop(handle); | ||
1835 | if (!err) | ||
1836 | err = ret; | ||
1837 | return ret; | ||
1838 | |||
1839 | invalid_resize_inode: | ||
1840 | ext4_error(sb, "corrupted/inconsistent resize inode"); | ||
1841 | return -EINVAL; | ||
1842 | } | ||
1843 | |||
1634 | /* | 1844 | /* |
1635 | * ext4_resize_fs() resizes a fs to new size specified by @n_blocks_count | 1845 | * ext4_resize_fs() resizes a fs to new size specified by @n_blocks_count |
1636 | * | 1846 | * |
@@ -1643,21 +1853,31 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) | |||
1643 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 1853 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
1644 | struct ext4_super_block *es = sbi->s_es; | 1854 | struct ext4_super_block *es = sbi->s_es; |
1645 | struct buffer_head *bh; | 1855 | struct buffer_head *bh; |
1646 | struct inode *resize_inode; | 1856 | struct inode *resize_inode = NULL; |
1647 | ext4_fsblk_t o_blocks_count; | 1857 | ext4_grpblk_t add, offset; |
1648 | ext4_group_t o_group; | ||
1649 | ext4_group_t n_group; | ||
1650 | ext4_grpblk_t offset, add; | ||
1651 | unsigned long n_desc_blocks; | 1858 | unsigned long n_desc_blocks; |
1652 | unsigned long o_desc_blocks; | 1859 | unsigned long o_desc_blocks; |
1653 | unsigned long desc_blocks; | 1860 | ext4_group_t o_group; |
1654 | int err = 0, flexbg_size = 1; | 1861 | ext4_group_t n_group; |
1862 | ext4_fsblk_t o_blocks_count; | ||
1863 | ext4_fsblk_t n_blocks_count_retry = 0; | ||
1864 | unsigned long last_update_time = 0; | ||
1865 | int err = 0, flexbg_size = 1 << sbi->s_log_groups_per_flex; | ||
1866 | int meta_bg; | ||
1655 | 1867 | ||
1868 | /* See if the device is actually as big as what was requested */ | ||
1869 | bh = sb_bread(sb, n_blocks_count - 1); | ||
1870 | if (!bh) { | ||
1871 | ext4_warning(sb, "can't read last block, resize aborted"); | ||
1872 | return -ENOSPC; | ||
1873 | } | ||
1874 | brelse(bh); | ||
1875 | |||
1876 | retry: | ||
1656 | o_blocks_count = ext4_blocks_count(es); | 1877 | o_blocks_count = ext4_blocks_count(es); |
1657 | 1878 | ||
1658 | if (test_opt(sb, DEBUG)) | 1879 | ext4_msg(sb, KERN_INFO, "resizing filesystem from %llu " |
1659 | ext4_msg(sb, KERN_DEBUG, "resizing filesystem from %llu " | 1880 | "to %llu blocks", o_blocks_count, n_blocks_count); |
1660 | "to %llu blocks", o_blocks_count, n_blocks_count); | ||
1661 | 1881 | ||
1662 | if (n_blocks_count < o_blocks_count) { | 1882 | if (n_blocks_count < o_blocks_count) { |
1663 | /* On-line shrinking not supported */ | 1883 | /* On-line shrinking not supported */ |
@@ -1672,32 +1892,49 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) | |||
1672 | ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset); | 1892 | ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset); |
1673 | ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset); | 1893 | ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset); |
1674 | 1894 | ||
1675 | n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK(sb)) / | 1895 | n_desc_blocks = num_desc_blocks(sb, n_group + 1); |
1676 | EXT4_DESC_PER_BLOCK(sb); | 1896 | o_desc_blocks = num_desc_blocks(sb, sbi->s_groups_count); |
1677 | o_desc_blocks = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / | ||
1678 | EXT4_DESC_PER_BLOCK(sb); | ||
1679 | desc_blocks = n_desc_blocks - o_desc_blocks; | ||
1680 | 1897 | ||
1681 | if (desc_blocks && | 1898 | meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG); |
1682 | (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_RESIZE_INODE) || | ||
1683 | le16_to_cpu(es->s_reserved_gdt_blocks) < desc_blocks)) { | ||
1684 | ext4_warning(sb, "No reserved GDT blocks, can't resize"); | ||
1685 | return -EPERM; | ||
1686 | } | ||
1687 | 1899 | ||
1688 | resize_inode = ext4_iget(sb, EXT4_RESIZE_INO); | 1900 | if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_RESIZE_INODE)) { |
1689 | if (IS_ERR(resize_inode)) { | 1901 | if (meta_bg) { |
1690 | ext4_warning(sb, "Error opening resize inode"); | 1902 | ext4_error(sb, "resize_inode and meta_bg enabled " |
1691 | return PTR_ERR(resize_inode); | 1903 | "simultaneously"); |
1904 | return -EINVAL; | ||
1905 | } | ||
1906 | if (n_desc_blocks > o_desc_blocks + | ||
1907 | le16_to_cpu(es->s_reserved_gdt_blocks)) { | ||
1908 | n_blocks_count_retry = n_blocks_count; | ||
1909 | n_desc_blocks = o_desc_blocks + | ||
1910 | le16_to_cpu(es->s_reserved_gdt_blocks); | ||
1911 | n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb); | ||
1912 | n_blocks_count = n_group * EXT4_BLOCKS_PER_GROUP(sb); | ||
1913 | n_group--; /* set to last group number */ | ||
1914 | } | ||
1915 | |||
1916 | if (!resize_inode) | ||
1917 | resize_inode = ext4_iget(sb, EXT4_RESIZE_INO); | ||
1918 | if (IS_ERR(resize_inode)) { | ||
1919 | ext4_warning(sb, "Error opening resize inode"); | ||
1920 | return PTR_ERR(resize_inode); | ||
1921 | } | ||
1692 | } | 1922 | } |
1693 | 1923 | ||
1694 | /* See if the device is actually as big as what was requested */ | 1924 | if ((!resize_inode && !meta_bg) || n_blocks_count == o_blocks_count) { |
1695 | bh = sb_bread(sb, n_blocks_count - 1); | 1925 | err = ext4_convert_meta_bg(sb, resize_inode); |
1696 | if (!bh) { | 1926 | if (err) |
1697 | ext4_warning(sb, "can't read last block, resize aborted"); | 1927 | goto out; |
1698 | return -ENOSPC; | 1928 | if (resize_inode) { |
1929 | iput(resize_inode); | ||
1930 | resize_inode = NULL; | ||
1931 | } | ||
1932 | if (n_blocks_count_retry) { | ||
1933 | n_blocks_count = n_blocks_count_retry; | ||
1934 | n_blocks_count_retry = 0; | ||
1935 | goto retry; | ||
1936 | } | ||
1699 | } | 1937 | } |
1700 | brelse(bh); | ||
1701 | 1938 | ||
1702 | /* extend the last group */ | 1939 | /* extend the last group */ |
1703 | if (n_group == o_group) | 1940 | if (n_group == o_group) |
@@ -1710,12 +1947,15 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) | |||
1710 | goto out; | 1947 | goto out; |
1711 | } | 1948 | } |
1712 | 1949 | ||
1713 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG) && | 1950 | if (ext4_blocks_count(es) == n_blocks_count) |
1714 | es->s_log_groups_per_flex) | 1951 | goto out; |
1715 | flexbg_size = 1 << es->s_log_groups_per_flex; | ||
1716 | 1952 | ||
1717 | o_blocks_count = ext4_blocks_count(es); | 1953 | err = ext4_alloc_flex_bg_array(sb, n_group + 1); |
1718 | if (o_blocks_count == n_blocks_count) | 1954 | if (err) |
1955 | return err; | ||
1956 | |||
1957 | err = ext4_mb_alloc_groupinfo(sb, n_group + 1); | ||
1958 | if (err) | ||
1719 | goto out; | 1959 | goto out; |
1720 | 1960 | ||
1721 | flex_gd = alloc_flex_gd(flexbg_size); | 1961 | flex_gd = alloc_flex_gd(flexbg_size); |
@@ -1729,19 +1969,33 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) | |||
1729 | */ | 1969 | */ |
1730 | while (ext4_setup_next_flex_gd(sb, flex_gd, n_blocks_count, | 1970 | while (ext4_setup_next_flex_gd(sb, flex_gd, n_blocks_count, |
1731 | flexbg_size)) { | 1971 | flexbg_size)) { |
1732 | ext4_alloc_group_tables(sb, flex_gd, flexbg_size); | 1972 | if (jiffies - last_update_time > HZ * 10) { |
1973 | if (last_update_time) | ||
1974 | ext4_msg(sb, KERN_INFO, | ||
1975 | "resized to %llu blocks", | ||
1976 | ext4_blocks_count(es)); | ||
1977 | last_update_time = jiffies; | ||
1978 | } | ||
1979 | if (ext4_alloc_group_tables(sb, flex_gd, flexbg_size) != 0) | ||
1980 | break; | ||
1733 | err = ext4_flex_group_add(sb, resize_inode, flex_gd); | 1981 | err = ext4_flex_group_add(sb, resize_inode, flex_gd); |
1734 | if (unlikely(err)) | 1982 | if (unlikely(err)) |
1735 | break; | 1983 | break; |
1736 | } | 1984 | } |
1737 | 1985 | ||
1986 | if (!err && n_blocks_count_retry) { | ||
1987 | n_blocks_count = n_blocks_count_retry; | ||
1988 | n_blocks_count_retry = 0; | ||
1989 | free_flex_gd(flex_gd); | ||
1990 | flex_gd = NULL; | ||
1991 | goto retry; | ||
1992 | } | ||
1993 | |||
1738 | out: | 1994 | out: |
1739 | if (flex_gd) | 1995 | if (flex_gd) |
1740 | free_flex_gd(flex_gd); | 1996 | free_flex_gd(flex_gd); |
1741 | 1997 | if (resize_inode != NULL) | |
1742 | iput(resize_inode); | 1998 | iput(resize_inode); |
1743 | if (test_opt(sb, DEBUG)) | 1999 | ext4_msg(sb, KERN_INFO, "resized filesystem to %llu", n_blocks_count); |
1744 | ext4_msg(sb, KERN_DEBUG, "resized filesystem from %llu " | ||
1745 | "upto %llu blocks", o_blocks_count, n_blocks_count); | ||
1746 | return err; | 2000 | return err; |
1747 | } | 2001 | } |