diff options
-rw-r--r-- | fs/ext4/ioctl.c | 15 | ||||
-rw-r--r-- | fs/ext4/resize.c | 215 |
2 files changed, 165 insertions, 65 deletions
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 7f7dad787603..8b84fe28ccaf 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -365,26 +365,11 @@ group_add_out: | |||
365 | return -EOPNOTSUPP; | 365 | return -EOPNOTSUPP; |
366 | } | 366 | } |
367 | 367 | ||
368 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, | ||
369 | EXT4_FEATURE_INCOMPAT_META_BG)) { | ||
370 | ext4_msg(sb, KERN_ERR, | ||
371 | "Online resizing not (yet) supported with meta_bg"); | ||
372 | return -EOPNOTSUPP; | ||
373 | } | ||
374 | |||
375 | if (copy_from_user(&n_blocks_count, (__u64 __user *)arg, | 368 | if (copy_from_user(&n_blocks_count, (__u64 __user *)arg, |
376 | sizeof(__u64))) { | 369 | sizeof(__u64))) { |
377 | return -EFAULT; | 370 | return -EFAULT; |
378 | } | 371 | } |
379 | 372 | ||
380 | if (n_blocks_count > MAX_32_NUM && | ||
381 | !EXT4_HAS_INCOMPAT_FEATURE(sb, | ||
382 | EXT4_FEATURE_INCOMPAT_64BIT)) { | ||
383 | ext4_msg(sb, KERN_ERR, | ||
384 | "File system only supports 32-bit block numbers"); | ||
385 | return -EOPNOTSUPP; | ||
386 | } | ||
387 | |||
388 | err = ext4_resize_begin(sb); | 373 | err = ext4_resize_begin(sb); |
389 | if (err) | 374 | if (err) |
390 | return err; | 375 | return err; |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index f288933bf4c0..7adc08854588 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; |
@@ -209,7 +229,6 @@ static int ext4_alloc_group_tables(struct super_block *sb, | |||
209 | int flexbg_size) | 229 | int flexbg_size) |
210 | { | 230 | { |
211 | struct ext4_new_group_data *group_data = flex_gd->groups; | 231 | struct ext4_new_group_data *group_data = flex_gd->groups; |
212 | struct ext4_super_block *es = EXT4_SB(sb)->s_es; | ||
213 | ext4_fsblk_t start_blk; | 232 | ext4_fsblk_t start_blk; |
214 | ext4_fsblk_t last_blk; | 233 | ext4_fsblk_t last_blk; |
215 | ext4_group_t src_group; | 234 | ext4_group_t src_group; |
@@ -234,19 +253,19 @@ next_group: | |||
234 | start_blk = ext4_group_first_block_no(sb, src_group); | 253 | start_blk = ext4_group_first_block_no(sb, src_group); |
235 | last_blk = start_blk + group_data[src_group - group].blocks_count; | 254 | last_blk = start_blk + group_data[src_group - group].blocks_count; |
236 | 255 | ||
237 | overhead = ext4_bg_has_super(sb, src_group) ? | 256 | overhead = ext4_group_overhead_blocks(sb, src_group); |
238 | (1 + ext4_bg_num_gdb(sb, src_group) + | ||
239 | le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; | ||
240 | 257 | ||
241 | start_blk += overhead; | 258 | start_blk += overhead; |
242 | 259 | ||
243 | /* We collect contiguous blocks as much as possible. */ | 260 | /* We collect contiguous blocks as much as possible. */ |
244 | src_group++; | 261 | src_group++; |
245 | for (; src_group <= last_group; src_group++) | 262 | for (; src_group <= last_group; src_group++) { |
246 | if (!ext4_bg_has_super(sb, src_group)) | 263 | overhead = ext4_group_overhead_blocks(sb, src_group); |
264 | if (overhead != 0) | ||
247 | last_blk += group_data[src_group - group].blocks_count; | 265 | last_blk += group_data[src_group - group].blocks_count; |
248 | else | 266 | else |
249 | break; | 267 | break; |
268 | } | ||
250 | 269 | ||
251 | /* Allocate block bitmaps */ | 270 | /* Allocate block bitmaps */ |
252 | for (; bb_index < flex_gd->count; bb_index++) { | 271 | for (; bb_index < flex_gd->count; bb_index++) { |
@@ -438,11 +457,13 @@ static int setup_new_flex_group_blocks(struct super_block *sb, | |||
438 | ext4_group_t group, count; | 457 | ext4_group_t group, count; |
439 | struct buffer_head *bh = NULL; | 458 | struct buffer_head *bh = NULL; |
440 | int reserved_gdb, i, j, err = 0, err2; | 459 | int reserved_gdb, i, j, err = 0, err2; |
460 | int meta_bg; | ||
441 | 461 | ||
442 | BUG_ON(!flex_gd->count || !group_data || | 462 | BUG_ON(!flex_gd->count || !group_data || |
443 | group_data[0].group != sbi->s_groups_count); | 463 | group_data[0].group != sbi->s_groups_count); |
444 | 464 | ||
445 | 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); | ||
446 | 467 | ||
447 | /* This transaction may be extended/restarted along the way */ | 468 | /* This transaction may be extended/restarted along the way */ |
448 | handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA); | 469 | handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA); |
@@ -452,15 +473,25 @@ static int setup_new_flex_group_blocks(struct super_block *sb, | |||
452 | group = group_data[0].group; | 473 | group = group_data[0].group; |
453 | for (i = 0; i < flex_gd->count; i++, group++) { | 474 | for (i = 0; i < flex_gd->count; i++, group++) { |
454 | unsigned long gdblocks; | 475 | unsigned long gdblocks; |
476 | ext4_grpblk_t overhead; | ||
455 | 477 | ||
456 | gdblocks = ext4_bg_num_gdb(sb, group); | 478 | gdblocks = ext4_bg_num_gdb(sb, group); |
457 | start = ext4_group_first_block_no(sb, group); | 479 | start = ext4_group_first_block_no(sb, group); |
458 | 480 | ||
459 | if (!ext4_bg_has_super(sb, group)) | 481 | if (meta_bg == 0 && !ext4_bg_has_super(sb, group)) |
460 | goto handle_itb; | 482 | goto handle_itb; |
461 | 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); | ||
462 | /* 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 */ |
463 | for (j = 0, block = start + 1; j < gdblocks; j++, block++) { | 494 | for (j = 0; j < gdblocks; j++, block++) { |
464 | struct buffer_head *gdb; | 495 | struct buffer_head *gdb; |
465 | 496 | ||
466 | ext4_debug("update backup group %#04llx\n", block); | 497 | ext4_debug("update backup group %#04llx\n", block); |
@@ -530,11 +561,11 @@ handle_bb: | |||
530 | err = PTR_ERR(bh); | 561 | err = PTR_ERR(bh); |
531 | goto out; | 562 | goto out; |
532 | } | 563 | } |
533 | if (ext4_bg_has_super(sb, group)) { | 564 | overhead = ext4_group_overhead_blocks(sb, group); |
565 | if (overhead != 0) { | ||
534 | ext4_debug("mark backup superblock %#04llx (+0)\n", | 566 | ext4_debug("mark backup superblock %#04llx (+0)\n", |
535 | start); | 567 | start); |
536 | ext4_set_bits(bh->b_data, 0, gdblocks + reserved_gdb + | 568 | ext4_set_bits(bh->b_data, 0, overhead); |
537 | 1); | ||
538 | } | 569 | } |
539 | ext4_mark_bitmap_end(group_data[i].blocks_count, | 570 | ext4_mark_bitmap_end(group_data[i].blocks_count, |
540 | sb->s_blocksize * 8, bh->b_data); | 571 | sb->s_blocksize * 8, bh->b_data); |
@@ -831,6 +862,45 @@ exit_bh: | |||
831 | } | 862 | } |
832 | 863 | ||
833 | /* | 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 | /* | ||
834 | * 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 |
835 | * 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. |
836 | * 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 |
@@ -958,16 +1028,16 @@ exit_free: | |||
958 | * 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 |
959 | * which changed s_groups_count will backup again. | 1029 | * which changed s_groups_count will backup again. |
960 | */ | 1030 | */ |
961 | static void update_backups(struct super_block *sb, | 1031 | static void update_backups(struct super_block *sb, int blk_off, char *data, |
962 | int blk_off, char *data, int size) | 1032 | int size, int meta_bg) |
963 | { | 1033 | { |
964 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 1034 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
965 | const ext4_group_t last = sbi->s_groups_count; | 1035 | ext4_group_t last; |
966 | const int bpg = EXT4_BLOCKS_PER_GROUP(sb); | 1036 | const int bpg = EXT4_BLOCKS_PER_GROUP(sb); |
967 | unsigned three = 1; | 1037 | unsigned three = 1; |
968 | unsigned five = 5; | 1038 | unsigned five = 5; |
969 | unsigned seven = 7; | 1039 | unsigned seven = 7; |
970 | ext4_group_t group; | 1040 | ext4_group_t group = 0; |
971 | int rest = sb->s_blocksize - size; | 1041 | int rest = sb->s_blocksize - size; |
972 | handle_t *handle; | 1042 | handle_t *handle; |
973 | int err = 0, err2; | 1043 | int err = 0, err2; |
@@ -981,8 +1051,17 @@ static void update_backups(struct super_block *sb, | |||
981 | 1051 | ||
982 | ext4_superblock_csum_set(sb, (struct ext4_super_block *)data); | 1052 | ext4_superblock_csum_set(sb, (struct ext4_super_block *)data); |
983 | 1053 | ||
984 | while ((group = ext4_list_backups(sb, &three, &five, &seven)) < last) { | 1054 | if (meta_bg == 0) { |
1055 | group = ext4_list_backups(sb, &three, &five, &seven); | ||
1056 | last = sbi->s_groups_count; | ||
1057 | } else { | ||
1058 | group = ext4_meta_bg_first_group(sb, group) + 1; | ||
1059 | last = (ext4_group_t)(group + EXT4_DESC_PER_BLOCK(sb) - 2); | ||
1060 | } | ||
1061 | |||
1062 | while (group < sbi->s_groups_count) { | ||
985 | struct buffer_head *bh; | 1063 | struct buffer_head *bh; |
1064 | ext4_fsblk_t backup_block; | ||
986 | 1065 | ||
987 | /* Out of journal space, and can't get more - abort - so sad */ | 1066 | /* Out of journal space, and can't get more - abort - so sad */ |
988 | if (ext4_handle_valid(handle) && | 1067 | if (ext4_handle_valid(handle) && |
@@ -991,13 +1070,20 @@ static void update_backups(struct super_block *sb, | |||
991 | (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) | 1070 | (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) |
992 | break; | 1071 | break; |
993 | 1072 | ||
994 | bh = sb_getblk(sb, group * bpg + blk_off); | 1073 | if (meta_bg == 0) |
1074 | backup_block = group * bpg + blk_off; | ||
1075 | else | ||
1076 | backup_block = (ext4_group_first_block_no(sb, group) + | ||
1077 | ext4_bg_has_super(sb, group)); | ||
1078 | |||
1079 | bh = sb_getblk(sb, backup_block); | ||
995 | if (!bh) { | 1080 | if (!bh) { |
996 | err = -EIO; | 1081 | err = -EIO; |
997 | break; | 1082 | break; |
998 | } | 1083 | } |
999 | ext4_debug("update metadata backup %#04lx\n", | 1084 | ext4_debug("update metadata backup %llu(+%llu)\n", |
1000 | (unsigned long)bh->b_blocknr); | 1085 | backup_block, backup_block - |
1086 | ext4_group_first_block_no(sb, group)); | ||
1001 | if ((err = ext4_journal_get_write_access(handle, bh))) | 1087 | if ((err = ext4_journal_get_write_access(handle, bh))) |
1002 | break; | 1088 | break; |
1003 | lock_buffer(bh); | 1089 | lock_buffer(bh); |
@@ -1010,6 +1096,13 @@ static void update_backups(struct super_block *sb, | |||
1010 | if (unlikely(err)) | 1096 | if (unlikely(err)) |
1011 | ext4_std_error(sb, err); | 1097 | ext4_std_error(sb, err); |
1012 | brelse(bh); | 1098 | brelse(bh); |
1099 | |||
1100 | if (meta_bg == 0) | ||
1101 | group = ext4_list_backups(sb, &three, &five, &seven); | ||
1102 | else if (group == last) | ||
1103 | break; | ||
1104 | else | ||
1105 | group = last; | ||
1013 | } | 1106 | } |
1014 | if ((err2 = ext4_journal_stop(handle)) && !err) | 1107 | if ((err2 = ext4_journal_stop(handle)) && !err) |
1015 | err = err2; | 1108 | err = err2; |
@@ -1052,7 +1145,9 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb, | |||
1052 | struct ext4_super_block *es = sbi->s_es; | 1145 | struct ext4_super_block *es = sbi->s_es; |
1053 | struct buffer_head *gdb_bh; | 1146 | struct buffer_head *gdb_bh; |
1054 | int i, gdb_off, gdb_num, err = 0; | 1147 | int i, gdb_off, gdb_num, err = 0; |
1148 | int meta_bg; | ||
1055 | 1149 | ||
1150 | meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG); | ||
1056 | for (i = 0; i < count; i++, group++) { | 1151 | for (i = 0; i < count; i++, group++) { |
1057 | int reserved_gdb = ext4_bg_has_super(sb, group) ? | 1152 | int reserved_gdb = ext4_bg_has_super(sb, group) ? |
1058 | le16_to_cpu(es->s_reserved_gdt_blocks) : 0; | 1153 | le16_to_cpu(es->s_reserved_gdt_blocks) : 0; |
@@ -1072,8 +1167,11 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb, | |||
1072 | 1167 | ||
1073 | if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group)) | 1168 | if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group)) |
1074 | err = reserve_backup_gdb(handle, resize_inode, group); | 1169 | err = reserve_backup_gdb(handle, resize_inode, group); |
1075 | } else | 1170 | } else if (meta_bg != 0) { |
1171 | err = add_new_gdb_meta_bg(sb, handle, group); | ||
1172 | } else { | ||
1076 | err = add_new_gdb(handle, resize_inode, group); | 1173 | err = add_new_gdb(handle, resize_inode, group); |
1174 | } | ||
1077 | if (err) | 1175 | if (err) |
1078 | break; | 1176 | break; |
1079 | } | 1177 | } |
@@ -1225,7 +1323,7 @@ static void ext4_update_super(struct super_block *sb, | |||
1225 | } | 1323 | } |
1226 | 1324 | ||
1227 | reserved_blocks = ext4_r_blocks_count(es) * 100; | 1325 | reserved_blocks = ext4_r_blocks_count(es) * 100; |
1228 | do_div(reserved_blocks, ext4_blocks_count(es)); | 1326 | reserved_blocks = div64_u64(reserved_blocks, ext4_blocks_count(es)); |
1229 | reserved_blocks *= blocks_count; | 1327 | reserved_blocks *= blocks_count; |
1230 | do_div(reserved_blocks, 100); | 1328 | do_div(reserved_blocks, 100); |
1231 | 1329 | ||
@@ -1236,6 +1334,7 @@ static void ext4_update_super(struct super_block *sb, | |||
1236 | le32_add_cpu(&es->s_free_inodes_count, EXT4_INODES_PER_GROUP(sb) * | 1334 | le32_add_cpu(&es->s_free_inodes_count, EXT4_INODES_PER_GROUP(sb) * |
1237 | flex_gd->count); | 1335 | flex_gd->count); |
1238 | 1336 | ||
1337 | ext4_debug("free blocks count %llu", ext4_free_blocks_count(es)); | ||
1239 | /* | 1338 | /* |
1240 | * We need to protect s_groups_count against other CPUs seeing | 1339 | * We need to protect s_groups_count against other CPUs seeing |
1241 | * inconsistent state in the superblock. | 1340 | * inconsistent state in the superblock. |
@@ -1270,6 +1369,8 @@ static void ext4_update_super(struct super_block *sb, | |||
1270 | percpu_counter_add(&sbi->s_freeinodes_counter, | 1369 | percpu_counter_add(&sbi->s_freeinodes_counter, |
1271 | EXT4_INODES_PER_GROUP(sb) * flex_gd->count); | 1370 | EXT4_INODES_PER_GROUP(sb) * flex_gd->count); |
1272 | 1371 | ||
1372 | ext4_debug("free blocks count %llu", | ||
1373 | percpu_counter_read(&sbi->s_freeclusters_counter)); | ||
1273 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, | 1374 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, |
1274 | EXT4_FEATURE_INCOMPAT_FLEX_BG) && | 1375 | EXT4_FEATURE_INCOMPAT_FLEX_BG) && |
1275 | sbi->s_log_groups_per_flex) { | 1376 | sbi->s_log_groups_per_flex) { |
@@ -1361,15 +1462,17 @@ exit_journal: | |||
1361 | int gdb_num = group / EXT4_DESC_PER_BLOCK(sb); | 1462 | int gdb_num = group / EXT4_DESC_PER_BLOCK(sb); |
1362 | int gdb_num_end = ((group + flex_gd->count - 1) / | 1463 | int gdb_num_end = ((group + flex_gd->count - 1) / |
1363 | EXT4_DESC_PER_BLOCK(sb)); | 1464 | EXT4_DESC_PER_BLOCK(sb)); |
1465 | int meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, | ||
1466 | EXT4_FEATURE_INCOMPAT_META_BG); | ||
1364 | 1467 | ||
1365 | update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, | 1468 | update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, |
1366 | sizeof(struct ext4_super_block)); | 1469 | sizeof(struct ext4_super_block), 0); |
1367 | for (; gdb_num <= gdb_num_end; gdb_num++) { | 1470 | for (; gdb_num <= gdb_num_end; gdb_num++) { |
1368 | struct buffer_head *gdb_bh; | 1471 | struct buffer_head *gdb_bh; |
1369 | 1472 | ||
1370 | gdb_bh = sbi->s_group_desc[gdb_num]; | 1473 | gdb_bh = sbi->s_group_desc[gdb_num]; |
1371 | update_backups(sb, gdb_bh->b_blocknr, gdb_bh->b_data, | 1474 | update_backups(sb, gdb_bh->b_blocknr, gdb_bh->b_data, |
1372 | gdb_bh->b_size); | 1475 | gdb_bh->b_size, meta_bg); |
1373 | } | 1476 | } |
1374 | } | 1477 | } |
1375 | exit: | 1478 | exit: |
@@ -1413,9 +1516,7 @@ static int ext4_setup_next_flex_gd(struct super_block *sb, | |||
1413 | 1516 | ||
1414 | group_data[i].group = group + i; | 1517 | group_data[i].group = group + i; |
1415 | group_data[i].blocks_count = blocks_per_group; | 1518 | group_data[i].blocks_count = blocks_per_group; |
1416 | overhead = ext4_bg_has_super(sb, group + i) ? | 1519 | overhead = ext4_group_overhead_blocks(sb, group + i); |
1417 | (1 + ext4_bg_num_gdb(sb, group + i) + | ||
1418 | le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; | ||
1419 | group_data[i].free_blocks_count = blocks_per_group - overhead; | 1520 | group_data[i].free_blocks_count = blocks_per_group - overhead; |
1420 | if (ext4_has_group_desc_csum(sb)) | 1521 | if (ext4_has_group_desc_csum(sb)) |
1421 | flex_gd->bg_flags[i] = EXT4_BG_BLOCK_UNINIT | | 1522 | flex_gd->bg_flags[i] = EXT4_BG_BLOCK_UNINIT | |
@@ -1563,11 +1664,13 @@ errout: | |||
1563 | err = err2; | 1664 | err = err2; |
1564 | 1665 | ||
1565 | if (!err) { | 1666 | if (!err) { |
1667 | ext4_fsblk_t first_block; | ||
1668 | first_block = ext4_group_first_block_no(sb, 0); | ||
1566 | if (test_opt(sb, DEBUG)) | 1669 | if (test_opt(sb, DEBUG)) |
1567 | printk(KERN_DEBUG "EXT4-fs: extended group to %llu " | 1670 | printk(KERN_DEBUG "EXT4-fs: extended group to %llu " |
1568 | "blocks\n", ext4_blocks_count(es)); | 1671 | "blocks\n", ext4_blocks_count(es)); |
1569 | 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, |
1570 | sizeof(struct ext4_super_block)); | 1673 | (char *)es, sizeof(struct ext4_super_block), 0); |
1571 | } | 1674 | } |
1572 | return err; | 1675 | return err; |
1573 | } | 1676 | } |
@@ -1662,15 +1765,16 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) | |||
1662 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 1765 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
1663 | struct ext4_super_block *es = sbi->s_es; | 1766 | struct ext4_super_block *es = sbi->s_es; |
1664 | struct buffer_head *bh; | 1767 | struct buffer_head *bh; |
1665 | struct inode *resize_inode; | 1768 | struct inode *resize_inode = NULL; |
1666 | ext4_fsblk_t o_blocks_count; | 1769 | ext4_grpblk_t add, offset; |
1667 | ext4_group_t o_group; | ||
1668 | ext4_group_t n_group; | ||
1669 | ext4_grpblk_t offset, add; | ||
1670 | unsigned long n_desc_blocks; | 1770 | unsigned long n_desc_blocks; |
1671 | unsigned long o_desc_blocks; | 1771 | unsigned long o_desc_blocks; |
1672 | unsigned long desc_blocks; | 1772 | unsigned long desc_blocks; |
1773 | ext4_group_t o_group; | ||
1774 | ext4_group_t n_group; | ||
1775 | ext4_fsblk_t o_blocks_count; | ||
1673 | int err = 0, flexbg_size = 1 << sbi->s_log_groups_per_flex; | 1776 | int err = 0, flexbg_size = 1 << sbi->s_log_groups_per_flex; |
1777 | int meta_bg; | ||
1674 | 1778 | ||
1675 | o_blocks_count = ext4_blocks_count(es); | 1779 | o_blocks_count = ext4_blocks_count(es); |
1676 | 1780 | ||
@@ -1692,22 +1796,33 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) | |||
1692 | ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset); | 1796 | ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset); |
1693 | 1797 | ||
1694 | n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK(sb)) / | 1798 | n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK(sb)) / |
1695 | EXT4_DESC_PER_BLOCK(sb); | 1799 | EXT4_DESC_PER_BLOCK(sb); |
1696 | o_desc_blocks = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / | 1800 | o_desc_blocks = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / |
1697 | EXT4_DESC_PER_BLOCK(sb); | 1801 | EXT4_DESC_PER_BLOCK(sb); |
1698 | desc_blocks = n_desc_blocks - o_desc_blocks; | 1802 | desc_blocks = n_desc_blocks - o_desc_blocks; |
1699 | 1803 | ||
1700 | if (desc_blocks && | 1804 | meta_bg = EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG); |
1701 | (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_RESIZE_INODE) || | ||
1702 | le16_to_cpu(es->s_reserved_gdt_blocks) < desc_blocks)) { | ||
1703 | ext4_warning(sb, "No reserved GDT blocks, can't resize"); | ||
1704 | return -EPERM; | ||
1705 | } | ||
1706 | 1805 | ||
1707 | resize_inode = ext4_iget(sb, EXT4_RESIZE_INO); | 1806 | if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_RESIZE_INODE)) { |
1708 | if (IS_ERR(resize_inode)) { | 1807 | if (meta_bg) { |
1709 | ext4_warning(sb, "Error opening resize inode"); | 1808 | ext4_error(sb, "resize_inode and meta_bg enabled " |
1710 | return PTR_ERR(resize_inode); | 1809 | "simultaneously"); |
1810 | return -EINVAL; | ||
1811 | } | ||
1812 | if (le16_to_cpu(es->s_reserved_gdt_blocks) < desc_blocks) { | ||
1813 | ext4_warning(sb, | ||
1814 | "No reserved GDT blocks, can't resize"); | ||
1815 | return -EPERM; | ||
1816 | } | ||
1817 | resize_inode = ext4_iget(sb, EXT4_RESIZE_INO); | ||
1818 | if (IS_ERR(resize_inode)) { | ||
1819 | ext4_warning(sb, "Error opening resize inode"); | ||
1820 | return PTR_ERR(resize_inode); | ||
1821 | } | ||
1822 | } else if (!meta_bg) { | ||
1823 | ext4_warning(sb, "File system features do not permit " | ||
1824 | "online resize"); | ||
1825 | return -EPERM; | ||
1711 | } | 1826 | } |
1712 | 1827 | ||
1713 | /* See if the device is actually as big as what was requested */ | 1828 | /* See if the device is actually as big as what was requested */ |
@@ -1761,8 +1876,8 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) | |||
1761 | out: | 1876 | out: |
1762 | if (flex_gd) | 1877 | if (flex_gd) |
1763 | free_flex_gd(flex_gd); | 1878 | free_flex_gd(flex_gd); |
1764 | 1879 | if (resize_inode != NULL) | |
1765 | iput(resize_inode); | 1880 | iput(resize_inode); |
1766 | if (test_opt(sb, DEBUG)) | 1881 | if (test_opt(sb, DEBUG)) |
1767 | ext4_msg(sb, KERN_DEBUG, "resized filesystem from %llu " | 1882 | ext4_msg(sb, KERN_DEBUG, "resized filesystem from %llu " |
1768 | "upto %llu blocks", o_blocks_count, n_blocks_count); | 1883 | "upto %llu blocks", o_blocks_count, n_blocks_count); |