diff options
Diffstat (limited to 'fs/nilfs2/super.c')
-rw-r--r-- | fs/nilfs2/super.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index eba5b53b1080..2846491071ce 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include "btnode.h" | 56 | #include "btnode.h" |
57 | #include "page.h" | 57 | #include "page.h" |
58 | #include "cpfile.h" | 58 | #include "cpfile.h" |
59 | #include "sufile.h" /* nilfs_sufile_resize(), nilfs_sufile_set_alloc_range() */ | ||
59 | #include "ifile.h" | 60 | #include "ifile.h" |
60 | #include "dat.h" | 61 | #include "dat.h" |
61 | #include "segment.h" | 62 | #include "segment.h" |
@@ -404,6 +405,77 @@ out: | |||
404 | return ret; | 405 | return ret; |
405 | } | 406 | } |
406 | 407 | ||
408 | /** | ||
409 | * nilfs_resize_fs - resize the filesystem | ||
410 | * @sb: super block instance | ||
411 | * @newsize: new size of the filesystem (in bytes) | ||
412 | */ | ||
413 | int nilfs_resize_fs(struct super_block *sb, __u64 newsize) | ||
414 | { | ||
415 | struct the_nilfs *nilfs = sb->s_fs_info; | ||
416 | struct nilfs_super_block **sbp; | ||
417 | __u64 devsize, newnsegs; | ||
418 | loff_t sb2off; | ||
419 | int ret; | ||
420 | |||
421 | ret = -ERANGE; | ||
422 | devsize = i_size_read(sb->s_bdev->bd_inode); | ||
423 | if (newsize > devsize) | ||
424 | goto out; | ||
425 | |||
426 | /* | ||
427 | * Write lock is required to protect some functions depending | ||
428 | * on the number of segments, the number of reserved segments, | ||
429 | * and so forth. | ||
430 | */ | ||
431 | down_write(&nilfs->ns_segctor_sem); | ||
432 | |||
433 | sb2off = NILFS_SB2_OFFSET_BYTES(newsize); | ||
434 | newnsegs = sb2off >> nilfs->ns_blocksize_bits; | ||
435 | do_div(newnsegs, nilfs->ns_blocks_per_segment); | ||
436 | |||
437 | ret = nilfs_sufile_resize(nilfs->ns_sufile, newnsegs); | ||
438 | up_write(&nilfs->ns_segctor_sem); | ||
439 | if (ret < 0) | ||
440 | goto out; | ||
441 | |||
442 | ret = nilfs_construct_segment(sb); | ||
443 | if (ret < 0) | ||
444 | goto out; | ||
445 | |||
446 | down_write(&nilfs->ns_sem); | ||
447 | nilfs_move_2nd_super(sb, sb2off); | ||
448 | ret = -EIO; | ||
449 | sbp = nilfs_prepare_super(sb, 0); | ||
450 | if (likely(sbp)) { | ||
451 | nilfs_set_log_cursor(sbp[0], nilfs); | ||
452 | /* | ||
453 | * Drop NILFS_RESIZE_FS flag for compatibility with | ||
454 | * mount-time resize which may be implemented in a | ||
455 | * future release. | ||
456 | */ | ||
457 | sbp[0]->s_state = cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & | ||
458 | ~NILFS_RESIZE_FS); | ||
459 | sbp[0]->s_dev_size = cpu_to_le64(newsize); | ||
460 | sbp[0]->s_nsegments = cpu_to_le64(nilfs->ns_nsegments); | ||
461 | if (sbp[1]) | ||
462 | memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); | ||
463 | ret = nilfs_commit_super(sb, NILFS_SB_COMMIT_ALL); | ||
464 | } | ||
465 | up_write(&nilfs->ns_sem); | ||
466 | |||
467 | /* | ||
468 | * Reset the range of allocatable segments last. This order | ||
469 | * is important in the case of expansion because the secondary | ||
470 | * superblock must be protected from log write until migration | ||
471 | * completes. | ||
472 | */ | ||
473 | if (!ret) | ||
474 | nilfs_sufile_set_alloc_range(nilfs->ns_sufile, 0, newnsegs - 1); | ||
475 | out: | ||
476 | return ret; | ||
477 | } | ||
478 | |||
407 | static void nilfs_put_super(struct super_block *sb) | 479 | static void nilfs_put_super(struct super_block *sb) |
408 | { | 480 | { |
409 | struct the_nilfs *nilfs = sb->s_fs_info; | 481 | struct the_nilfs *nilfs = sb->s_fs_info; |