aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/resize.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/resize.c')
-rw-r--r--fs/ext4/resize.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index 6076d5e4b513..e8ccb2f8f45b 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -234,6 +234,256 @@ static int extend_or_restart_transaction(handle_t *handle, int thresh)
234} 234}
235 235
236/* 236/*
237 * set_flexbg_block_bitmap() mark @count blocks starting from @block used.
238 *
239 * Helper function for ext4_setup_new_group_blocks() which set .
240 *
241 * @sb: super block
242 * @handle: journal handle
243 * @flex_gd: flex group data
244 */
245static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
246 struct ext4_new_flex_group_data *flex_gd,
247 ext4_fsblk_t block, ext4_group_t count)
248{
249 ext4_group_t count2;
250
251 ext4_debug("mark blocks [%llu/%u] used\n", block, count);
252 for (count2 = count; count > 0; count -= count2, block += count2) {
253 ext4_fsblk_t start;
254 struct buffer_head *bh;
255 ext4_group_t group;
256 int err;
257
258 ext4_get_group_no_and_offset(sb, block, &group, NULL);
259 start = ext4_group_first_block_no(sb, group);
260 group -= flex_gd->groups[0].group;
261
262 count2 = sb->s_blocksize * 8 - (block - start);
263 if (count2 > count)
264 count2 = count;
265
266 if (flex_gd->bg_flags[group] & EXT4_BG_BLOCK_UNINIT) {
267 BUG_ON(flex_gd->count > 1);
268 continue;
269 }
270
271 err = extend_or_restart_transaction(handle, 1);
272 if (err)
273 return err;
274
275 bh = sb_getblk(sb, flex_gd->groups[group].block_bitmap);
276 if (!bh)
277 return -EIO;
278
279 err = ext4_journal_get_write_access(handle, bh);
280 if (err)
281 return err;
282 ext4_debug("mark block bitmap %#04llx (+%llu/%u)\n", block,
283 block - start, count2);
284 ext4_set_bits(bh->b_data, block - start, count2);
285
286 err = ext4_handle_dirty_metadata(handle, NULL, bh);
287 if (unlikely(err))
288 return err;
289 brelse(bh);
290 }
291
292 return 0;
293}
294
295/*
296 * Set up the block and inode bitmaps, and the inode table for the new groups.
297 * This doesn't need to be part of the main transaction, since we are only
298 * changing blocks outside the actual filesystem. We still do journaling to
299 * ensure the recovery is correct in case of a failure just after resize.
300 * If any part of this fails, we simply abort the resize.
301 *
302 * setup_new_flex_group_blocks handles a flex group as follow:
303 * 1. copy super block and GDT, and initialize group tables if necessary.
304 * In this step, we only set bits in blocks bitmaps for blocks taken by
305 * super block and GDT.
306 * 2. allocate group tables in block bitmaps, that is, set bits in block
307 * bitmap for blocks taken by group tables.
308 */
309static int setup_new_flex_group_blocks(struct super_block *sb,
310 struct ext4_new_flex_group_data *flex_gd)
311{
312 int group_table_count[] = {1, 1, EXT4_SB(sb)->s_itb_per_group};
313 ext4_fsblk_t start;
314 ext4_fsblk_t block;
315 struct ext4_sb_info *sbi = EXT4_SB(sb);
316 struct ext4_super_block *es = sbi->s_es;
317 struct ext4_new_group_data *group_data = flex_gd->groups;
318 __u16 *bg_flags = flex_gd->bg_flags;
319 handle_t *handle;
320 ext4_group_t group, count;
321 struct buffer_head *bh = NULL;
322 int reserved_gdb, i, j, err = 0, err2;
323
324 BUG_ON(!flex_gd->count || !group_data ||
325 group_data[0].group != sbi->s_groups_count);
326
327 reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks);
328
329 /* This transaction may be extended/restarted along the way */
330 handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA);
331 if (IS_ERR(handle))
332 return PTR_ERR(handle);
333
334 group = group_data[0].group;
335 for (i = 0; i < flex_gd->count; i++, group++) {
336 unsigned long gdblocks;
337
338 gdblocks = ext4_bg_num_gdb(sb, group);
339 start = ext4_group_first_block_no(sb, group);
340
341 /* Copy all of the GDT blocks into the backup in this group */
342 for (j = 0, block = start + 1; j < gdblocks; j++, block++) {
343 struct buffer_head *gdb;
344
345 ext4_debug("update backup group %#04llx\n", block);
346 err = extend_or_restart_transaction(handle, 1);
347 if (err)
348 goto out;
349
350 gdb = sb_getblk(sb, block);
351 if (!gdb) {
352 err = -EIO;
353 goto out;
354 }
355
356 err = ext4_journal_get_write_access(handle, gdb);
357 if (err) {
358 brelse(gdb);
359 goto out;
360 }
361 memcpy(gdb->b_data, sbi->s_group_desc[j]->b_data,
362 gdb->b_size);
363 set_buffer_uptodate(gdb);
364
365 err = ext4_handle_dirty_metadata(handle, NULL, gdb);
366 if (unlikely(err)) {
367 brelse(gdb);
368 goto out;
369 }
370 brelse(gdb);
371 }
372
373 /* Zero out all of the reserved backup group descriptor
374 * table blocks
375 */
376 if (ext4_bg_has_super(sb, group)) {
377 err = sb_issue_zeroout(sb, gdblocks + start + 1,
378 reserved_gdb, GFP_NOFS);
379 if (err)
380 goto out;
381 }
382
383 /* Initialize group tables of the grop @group */
384 if (!(bg_flags[i] & EXT4_BG_INODE_ZEROED))
385 goto handle_bb;
386
387 /* Zero out all of the inode table blocks */
388 block = group_data[i].inode_table;
389 ext4_debug("clear inode table blocks %#04llx -> %#04lx\n",
390 block, sbi->s_itb_per_group);
391 err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group,
392 GFP_NOFS);
393 if (err)
394 goto out;
395
396handle_bb:
397 if (bg_flags[i] & EXT4_BG_BLOCK_UNINIT)
398 goto handle_ib;
399
400 /* Initialize block bitmap of the @group */
401 block = group_data[i].block_bitmap;
402 err = extend_or_restart_transaction(handle, 1);
403 if (err)
404 goto out;
405
406 bh = bclean(handle, sb, block);
407 if (IS_ERR(bh)) {
408 err = PTR_ERR(bh);
409 goto out;
410 }
411 if (ext4_bg_has_super(sb, group)) {
412 ext4_debug("mark backup superblock %#04llx (+0)\n",
413 start);
414 ext4_set_bits(bh->b_data, 0, gdblocks + reserved_gdb +
415 1);
416 }
417 ext4_mark_bitmap_end(group_data[i].blocks_count,
418 sb->s_blocksize * 8, bh->b_data);
419 err = ext4_handle_dirty_metadata(handle, NULL, bh);
420 if (err)
421 goto out;
422 brelse(bh);
423
424handle_ib:
425 if (bg_flags[i] & EXT4_BG_INODE_UNINIT)
426 continue;
427
428 /* Initialize inode bitmap of the @group */
429 block = group_data[i].inode_bitmap;
430 err = extend_or_restart_transaction(handle, 1);
431 if (err)
432 goto out;
433 /* Mark unused entries in inode bitmap used */
434 bh = bclean(handle, sb, block);
435 if (IS_ERR(bh)) {
436 err = PTR_ERR(bh);
437 goto out;
438 }
439
440 ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb),
441 sb->s_blocksize * 8, bh->b_data);
442 err = ext4_handle_dirty_metadata(handle, NULL, bh);
443 if (err)
444 goto out;
445 brelse(bh);
446 }
447 bh = NULL;
448
449 /* Mark group tables in block bitmap */
450 for (j = 0; j < GROUP_TABLE_COUNT; j++) {
451 count = group_table_count[j];
452 start = (&group_data[0].block_bitmap)[j];
453 block = start;
454 for (i = 1; i < flex_gd->count; i++) {
455 block += group_table_count[j];
456 if (block == (&group_data[i].block_bitmap)[j]) {
457 count += group_table_count[j];
458 continue;
459 }
460 err = set_flexbg_block_bitmap(sb, handle,
461 flex_gd, start, count);
462 if (err)
463 goto out;
464 count = group_table_count[j];
465 start = group_data[i].block_bitmap;
466 block = start;
467 }
468
469 if (count) {
470 err = set_flexbg_block_bitmap(sb, handle,
471 flex_gd, start, count);
472 if (err)
473 goto out;
474 }
475 }
476
477out:
478 brelse(bh);
479 err2 = ext4_journal_stop(handle);
480 if (err2 && !err)
481 err = err2;
482
483 return err;
484}
485
486/*
237 * Set up the block and inode bitmaps, and the inode table for the new group. 487 * Set up the block and inode bitmaps, and the inode table for the new group.
238 * This doesn't need to be part of the main transaction, since we are only 488 * This doesn't need to be part of the main transaction, since we are only
239 * changing blocks outside the actual filesystem. We still do journaling to 489 * changing blocks outside the actual filesystem. We still do journaling to