diff options
Diffstat (limited to 'fs/nilfs2/super.c')
-rw-r--r-- | fs/nilfs2/super.c | 131 |
1 files changed, 130 insertions, 1 deletions
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 062cca065195..8351c44a7320 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" |
@@ -165,7 +166,7 @@ struct inode *nilfs_alloc_inode(struct super_block *sb) | |||
165 | ii->i_state = 0; | 166 | ii->i_state = 0; |
166 | ii->i_cno = 0; | 167 | ii->i_cno = 0; |
167 | ii->vfs_inode.i_version = 1; | 168 | ii->vfs_inode.i_version = 1; |
168 | nilfs_btnode_cache_init(&ii->i_btnode_cache, sb->s_bdi); | 169 | nilfs_mapping_init(&ii->i_btnode_cache, &ii->vfs_inode, sb->s_bdi); |
169 | return &ii->vfs_inode; | 170 | return &ii->vfs_inode; |
170 | } | 171 | } |
171 | 172 | ||
@@ -347,6 +348,134 @@ int nilfs_cleanup_super(struct super_block *sb) | |||
347 | return ret; | 348 | return ret; |
348 | } | 349 | } |
349 | 350 | ||
351 | /** | ||
352 | * nilfs_move_2nd_super - relocate secondary super block | ||
353 | * @sb: super block instance | ||
354 | * @sb2off: new offset of the secondary super block (in bytes) | ||
355 | */ | ||
356 | static int nilfs_move_2nd_super(struct super_block *sb, loff_t sb2off) | ||
357 | { | ||
358 | struct the_nilfs *nilfs = sb->s_fs_info; | ||
359 | struct buffer_head *nsbh; | ||
360 | struct nilfs_super_block *nsbp; | ||
361 | sector_t blocknr, newblocknr; | ||
362 | unsigned long offset; | ||
363 | int sb2i = -1; /* array index of the secondary superblock */ | ||
364 | int ret = 0; | ||
365 | |||
366 | /* nilfs->ns_sem must be locked by the caller. */ | ||
367 | if (nilfs->ns_sbh[1] && | ||
368 | nilfs->ns_sbh[1]->b_blocknr > nilfs->ns_first_data_block) { | ||
369 | sb2i = 1; | ||
370 | blocknr = nilfs->ns_sbh[1]->b_blocknr; | ||
371 | } else if (nilfs->ns_sbh[0]->b_blocknr > nilfs->ns_first_data_block) { | ||
372 | sb2i = 0; | ||
373 | blocknr = nilfs->ns_sbh[0]->b_blocknr; | ||
374 | } | ||
375 | if (sb2i >= 0 && (u64)blocknr << nilfs->ns_blocksize_bits == sb2off) | ||
376 | goto out; /* super block location is unchanged */ | ||
377 | |||
378 | /* Get new super block buffer */ | ||
379 | newblocknr = sb2off >> nilfs->ns_blocksize_bits; | ||
380 | offset = sb2off & (nilfs->ns_blocksize - 1); | ||
381 | nsbh = sb_getblk(sb, newblocknr); | ||
382 | if (!nsbh) { | ||
383 | printk(KERN_WARNING | ||
384 | "NILFS warning: unable to move secondary superblock " | ||
385 | "to block %llu\n", (unsigned long long)newblocknr); | ||
386 | ret = -EIO; | ||
387 | goto out; | ||
388 | } | ||
389 | nsbp = (void *)nsbh->b_data + offset; | ||
390 | memset(nsbp, 0, nilfs->ns_blocksize); | ||
391 | |||
392 | if (sb2i >= 0) { | ||
393 | memcpy(nsbp, nilfs->ns_sbp[sb2i], nilfs->ns_sbsize); | ||
394 | brelse(nilfs->ns_sbh[sb2i]); | ||
395 | nilfs->ns_sbh[sb2i] = nsbh; | ||
396 | nilfs->ns_sbp[sb2i] = nsbp; | ||
397 | } else if (nilfs->ns_sbh[0]->b_blocknr < nilfs->ns_first_data_block) { | ||
398 | /* secondary super block will be restored to index 1 */ | ||
399 | nilfs->ns_sbh[1] = nsbh; | ||
400 | nilfs->ns_sbp[1] = nsbp; | ||
401 | } else { | ||
402 | brelse(nsbh); | ||
403 | } | ||
404 | out: | ||
405 | return ret; | ||
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 | |||
350 | static void nilfs_put_super(struct super_block *sb) | 479 | static void nilfs_put_super(struct super_block *sb) |
351 | { | 480 | { |
352 | struct the_nilfs *nilfs = sb->s_fs_info; | 481 | struct the_nilfs *nilfs = sb->s_fs_info; |