diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 04:26:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 04:26:47 -0400 |
commit | ab34c02afeafd047a831e6fe2a4dd875ce86bee0 (patch) | |
tree | 833e385e8387e3d4d4531ade23c1d92fba8ed075 /fs/nilfs2/super.c | |
parent | 7f3883962870dd28b5f2322ac44a9d03640ef448 (diff) | |
parent | 6b81e14e645016597c81e71cd27ee5c57c3a3c36 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2: (36 commits)
nilfs2: eliminate sparse warning - "context imbalance"
nilfs2: eliminate sparse warnings - "symbol not declared"
nilfs2: get rid of bdi from nilfs object
nilfs2: change license of exported header file
nilfs2: add bdev freeze/thaw support
nilfs2: accept 64-bit checkpoint numbers in cp mount option
nilfs2: remove own inode allocator and destructor for metadata files
nilfs2: get rid of back pointer to writable sb instance
nilfs2: get rid of mi_nilfs back pointer to nilfs object
nilfs2: see state of root dentry for mount check of snapshots
nilfs2: use iget for all metadata files
nilfs2: get rid of GCDAT inode
nilfs2: add routines to redirect access to buffers of DAT file
nilfs2: add routines to roll back state of DAT file
nilfs2: add routines to save and restore bmap state
nilfs2: do not allocate nilfs_mdt_info structure to gc-inodes
nilfs2: allow nilfs_clear_inode to clear metadata file inodes
nilfs2: get rid of snapshot mount flag
nilfs2: simplify life cycle management of nilfs object
nilfs2: do not allocate multiple super block instances for a device
...
Diffstat (limited to 'fs/nilfs2/super.c')
-rw-r--r-- | fs/nilfs2/super.c | 609 |
1 files changed, 327 insertions, 282 deletions
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index f3b75206e95..35ae03c0db8 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -48,10 +48,10 @@ | |||
48 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
49 | #include <linux/writeback.h> | 49 | #include <linux/writeback.h> |
50 | #include <linux/kobject.h> | 50 | #include <linux/kobject.h> |
51 | #include <linux/exportfs.h> | ||
52 | #include <linux/seq_file.h> | 51 | #include <linux/seq_file.h> |
53 | #include <linux/mount.h> | 52 | #include <linux/mount.h> |
54 | #include "nilfs.h" | 53 | #include "nilfs.h" |
54 | #include "export.h" | ||
55 | #include "mdt.h" | 55 | #include "mdt.h" |
56 | #include "alloc.h" | 56 | #include "alloc.h" |
57 | #include "btree.h" | 57 | #include "btree.h" |
@@ -68,11 +68,12 @@ MODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem " | |||
68 | "(NILFS)"); | 68 | "(NILFS)"); |
69 | MODULE_LICENSE("GPL"); | 69 | MODULE_LICENSE("GPL"); |
70 | 70 | ||
71 | struct kmem_cache *nilfs_inode_cachep; | 71 | static struct kmem_cache *nilfs_inode_cachep; |
72 | struct kmem_cache *nilfs_transaction_cachep; | 72 | struct kmem_cache *nilfs_transaction_cachep; |
73 | struct kmem_cache *nilfs_segbuf_cachep; | 73 | struct kmem_cache *nilfs_segbuf_cachep; |
74 | struct kmem_cache *nilfs_btree_path_cache; | 74 | struct kmem_cache *nilfs_btree_path_cache; |
75 | 75 | ||
76 | static int nilfs_setup_super(struct nilfs_sb_info *sbi, int is_mount); | ||
76 | static int nilfs_remount(struct super_block *sb, int *flags, char *data); | 77 | static int nilfs_remount(struct super_block *sb, int *flags, char *data); |
77 | 78 | ||
78 | static void nilfs_set_error(struct nilfs_sb_info *sbi) | 79 | static void nilfs_set_error(struct nilfs_sb_info *sbi) |
@@ -146,7 +147,7 @@ void nilfs_warning(struct super_block *sb, const char *function, | |||
146 | } | 147 | } |
147 | 148 | ||
148 | 149 | ||
149 | struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs) | 150 | struct inode *nilfs_alloc_inode(struct super_block *sb) |
150 | { | 151 | { |
151 | struct nilfs_inode_info *ii; | 152 | struct nilfs_inode_info *ii; |
152 | 153 | ||
@@ -155,18 +156,20 @@ struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs) | |||
155 | return NULL; | 156 | return NULL; |
156 | ii->i_bh = NULL; | 157 | ii->i_bh = NULL; |
157 | ii->i_state = 0; | 158 | ii->i_state = 0; |
159 | ii->i_cno = 0; | ||
158 | ii->vfs_inode.i_version = 1; | 160 | ii->vfs_inode.i_version = 1; |
159 | nilfs_btnode_cache_init(&ii->i_btnode_cache, nilfs->ns_bdi); | 161 | nilfs_btnode_cache_init(&ii->i_btnode_cache, sb->s_bdi); |
160 | return &ii->vfs_inode; | 162 | return &ii->vfs_inode; |
161 | } | 163 | } |
162 | 164 | ||
163 | struct inode *nilfs_alloc_inode(struct super_block *sb) | ||
164 | { | ||
165 | return nilfs_alloc_inode_common(NILFS_SB(sb)->s_nilfs); | ||
166 | } | ||
167 | |||
168 | void nilfs_destroy_inode(struct inode *inode) | 165 | void nilfs_destroy_inode(struct inode *inode) |
169 | { | 166 | { |
167 | struct nilfs_mdt_info *mdi = NILFS_MDT(inode); | ||
168 | |||
169 | if (mdi) { | ||
170 | kfree(mdi->mi_bgl); /* kfree(NULL) is safe */ | ||
171 | kfree(mdi); | ||
172 | } | ||
170 | kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); | 173 | kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); |
171 | } | 174 | } |
172 | 175 | ||
@@ -340,16 +343,15 @@ static void nilfs_put_super(struct super_block *sb) | |||
340 | nilfs_cleanup_super(sbi); | 343 | nilfs_cleanup_super(sbi); |
341 | up_write(&nilfs->ns_sem); | 344 | up_write(&nilfs->ns_sem); |
342 | } | 345 | } |
343 | down_write(&nilfs->ns_super_sem); | ||
344 | if (nilfs->ns_current == sbi) | ||
345 | nilfs->ns_current = NULL; | ||
346 | up_write(&nilfs->ns_super_sem); | ||
347 | 346 | ||
348 | nilfs_detach_checkpoint(sbi); | 347 | iput(nilfs->ns_sufile); |
349 | put_nilfs(sbi->s_nilfs); | 348 | iput(nilfs->ns_cpfile); |
349 | iput(nilfs->ns_dat); | ||
350 | |||
351 | destroy_nilfs(nilfs); | ||
350 | sbi->s_super = NULL; | 352 | sbi->s_super = NULL; |
351 | sb->s_fs_info = NULL; | 353 | sb->s_fs_info = NULL; |
352 | nilfs_put_sbinfo(sbi); | 354 | kfree(sbi); |
353 | } | 355 | } |
354 | 356 | ||
355 | static int nilfs_sync_fs(struct super_block *sb, int wait) | 357 | static int nilfs_sync_fs(struct super_block *sb, int wait) |
@@ -376,21 +378,22 @@ static int nilfs_sync_fs(struct super_block *sb, int wait) | |||
376 | return err; | 378 | return err; |
377 | } | 379 | } |
378 | 380 | ||
379 | int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) | 381 | int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, |
382 | struct nilfs_root **rootp) | ||
380 | { | 383 | { |
381 | struct the_nilfs *nilfs = sbi->s_nilfs; | 384 | struct the_nilfs *nilfs = sbi->s_nilfs; |
385 | struct nilfs_root *root; | ||
382 | struct nilfs_checkpoint *raw_cp; | 386 | struct nilfs_checkpoint *raw_cp; |
383 | struct buffer_head *bh_cp; | 387 | struct buffer_head *bh_cp; |
384 | int err; | 388 | int err = -ENOMEM; |
385 | 389 | ||
386 | down_write(&nilfs->ns_super_sem); | 390 | root = nilfs_find_or_create_root( |
387 | list_add(&sbi->s_list, &nilfs->ns_supers); | 391 | nilfs, curr_mnt ? NILFS_CPTREE_CURRENT_CNO : cno); |
388 | up_write(&nilfs->ns_super_sem); | 392 | if (!root) |
393 | return err; | ||
389 | 394 | ||
390 | err = -ENOMEM; | 395 | if (root->ifile) |
391 | sbi->s_ifile = nilfs_ifile_new(sbi, nilfs->ns_inode_size); | 396 | goto reuse; /* already attached checkpoint */ |
392 | if (!sbi->s_ifile) | ||
393 | goto delist; | ||
394 | 397 | ||
395 | down_read(&nilfs->ns_segctor_sem); | 398 | down_read(&nilfs->ns_segctor_sem); |
396 | err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp, | 399 | err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp, |
@@ -406,45 +409,64 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) | |||
406 | } | 409 | } |
407 | goto failed; | 410 | goto failed; |
408 | } | 411 | } |
409 | err = nilfs_read_inode_common(sbi->s_ifile, &raw_cp->cp_ifile_inode); | 412 | |
410 | if (unlikely(err)) | 413 | err = nilfs_ifile_read(sbi->s_super, root, nilfs->ns_inode_size, |
414 | &raw_cp->cp_ifile_inode, &root->ifile); | ||
415 | if (err) | ||
411 | goto failed_bh; | 416 | goto failed_bh; |
412 | atomic_set(&sbi->s_inodes_count, le64_to_cpu(raw_cp->cp_inodes_count)); | 417 | |
413 | atomic_set(&sbi->s_blocks_count, le64_to_cpu(raw_cp->cp_blocks_count)); | 418 | atomic_set(&root->inodes_count, le64_to_cpu(raw_cp->cp_inodes_count)); |
419 | atomic_set(&root->blocks_count, le64_to_cpu(raw_cp->cp_blocks_count)); | ||
414 | 420 | ||
415 | nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); | 421 | nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); |
422 | |||
423 | reuse: | ||
424 | *rootp = root; | ||
416 | return 0; | 425 | return 0; |
417 | 426 | ||
418 | failed_bh: | 427 | failed_bh: |
419 | nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); | 428 | nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); |
420 | failed: | 429 | failed: |
421 | nilfs_mdt_destroy(sbi->s_ifile); | 430 | nilfs_put_root(root); |
422 | sbi->s_ifile = NULL; | 431 | |
432 | return err; | ||
433 | } | ||
423 | 434 | ||
424 | delist: | 435 | static int nilfs_freeze(struct super_block *sb) |
425 | down_write(&nilfs->ns_super_sem); | 436 | { |
426 | list_del_init(&sbi->s_list); | 437 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
427 | up_write(&nilfs->ns_super_sem); | 438 | struct the_nilfs *nilfs = sbi->s_nilfs; |
439 | int err; | ||
440 | |||
441 | if (sb->s_flags & MS_RDONLY) | ||
442 | return 0; | ||
428 | 443 | ||
444 | /* Mark super block clean */ | ||
445 | down_write(&nilfs->ns_sem); | ||
446 | err = nilfs_cleanup_super(sbi); | ||
447 | up_write(&nilfs->ns_sem); | ||
429 | return err; | 448 | return err; |
430 | } | 449 | } |
431 | 450 | ||
432 | void nilfs_detach_checkpoint(struct nilfs_sb_info *sbi) | 451 | static int nilfs_unfreeze(struct super_block *sb) |
433 | { | 452 | { |
453 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | ||
434 | struct the_nilfs *nilfs = sbi->s_nilfs; | 454 | struct the_nilfs *nilfs = sbi->s_nilfs; |
435 | 455 | ||
436 | nilfs_mdt_destroy(sbi->s_ifile); | 456 | if (sb->s_flags & MS_RDONLY) |
437 | sbi->s_ifile = NULL; | 457 | return 0; |
438 | down_write(&nilfs->ns_super_sem); | 458 | |
439 | list_del_init(&sbi->s_list); | 459 | down_write(&nilfs->ns_sem); |
440 | up_write(&nilfs->ns_super_sem); | 460 | nilfs_setup_super(sbi, false); |
461 | up_write(&nilfs->ns_sem); | ||
462 | return 0; | ||
441 | } | 463 | } |
442 | 464 | ||
443 | static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 465 | static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
444 | { | 466 | { |
445 | struct super_block *sb = dentry->d_sb; | 467 | struct super_block *sb = dentry->d_sb; |
446 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 468 | struct nilfs_root *root = NILFS_I(dentry->d_inode)->i_root; |
447 | struct the_nilfs *nilfs = sbi->s_nilfs; | 469 | struct the_nilfs *nilfs = root->nilfs; |
448 | u64 id = huge_encode_dev(sb->s_bdev->bd_dev); | 470 | u64 id = huge_encode_dev(sb->s_bdev->bd_dev); |
449 | unsigned long long blocks; | 471 | unsigned long long blocks; |
450 | unsigned long overhead; | 472 | unsigned long overhead; |
@@ -480,7 +502,7 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
480 | buf->f_bfree = nfreeblocks; | 502 | buf->f_bfree = nfreeblocks; |
481 | buf->f_bavail = (buf->f_bfree >= nrsvblocks) ? | 503 | buf->f_bavail = (buf->f_bfree >= nrsvblocks) ? |
482 | (buf->f_bfree - nrsvblocks) : 0; | 504 | (buf->f_bfree - nrsvblocks) : 0; |
483 | buf->f_files = atomic_read(&sbi->s_inodes_count); | 505 | buf->f_files = atomic_read(&root->inodes_count); |
484 | buf->f_ffree = 0; /* nilfs_count_free_inodes(sb); */ | 506 | buf->f_ffree = 0; /* nilfs_count_free_inodes(sb); */ |
485 | buf->f_namelen = NILFS_NAME_LEN; | 507 | buf->f_namelen = NILFS_NAME_LEN; |
486 | buf->f_fsid.val[0] = (u32)id; | 508 | buf->f_fsid.val[0] = (u32)id; |
@@ -493,12 +515,12 @@ static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
493 | { | 515 | { |
494 | struct super_block *sb = vfs->mnt_sb; | 516 | struct super_block *sb = vfs->mnt_sb; |
495 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 517 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
518 | struct nilfs_root *root = NILFS_I(vfs->mnt_root->d_inode)->i_root; | ||
496 | 519 | ||
497 | if (!nilfs_test_opt(sbi, BARRIER)) | 520 | if (!nilfs_test_opt(sbi, BARRIER)) |
498 | seq_puts(seq, ",nobarrier"); | 521 | seq_puts(seq, ",nobarrier"); |
499 | if (nilfs_test_opt(sbi, SNAPSHOT)) | 522 | if (root->cno != NILFS_CPTREE_CURRENT_CNO) |
500 | seq_printf(seq, ",cp=%llu", | 523 | seq_printf(seq, ",cp=%llu", (unsigned long long)root->cno); |
501 | (unsigned long long int)sbi->s_snapshot_cno); | ||
502 | if (nilfs_test_opt(sbi, ERRORS_PANIC)) | 524 | if (nilfs_test_opt(sbi, ERRORS_PANIC)) |
503 | seq_puts(seq, ",errors=panic"); | 525 | seq_puts(seq, ",errors=panic"); |
504 | if (nilfs_test_opt(sbi, ERRORS_CONT)) | 526 | if (nilfs_test_opt(sbi, ERRORS_CONT)) |
@@ -524,6 +546,8 @@ static const struct super_operations nilfs_sops = { | |||
524 | .put_super = nilfs_put_super, | 546 | .put_super = nilfs_put_super, |
525 | /* .write_super = nilfs_write_super, */ | 547 | /* .write_super = nilfs_write_super, */ |
526 | .sync_fs = nilfs_sync_fs, | 548 | .sync_fs = nilfs_sync_fs, |
549 | .freeze_fs = nilfs_freeze, | ||
550 | .unfreeze_fs = nilfs_unfreeze, | ||
527 | /* .write_super_lockfs */ | 551 | /* .write_super_lockfs */ |
528 | /* .unlockfs */ | 552 | /* .unlockfs */ |
529 | .statfs = nilfs_statfs, | 553 | .statfs = nilfs_statfs, |
@@ -532,48 +556,6 @@ static const struct super_operations nilfs_sops = { | |||
532 | .show_options = nilfs_show_options | 556 | .show_options = nilfs_show_options |
533 | }; | 557 | }; |
534 | 558 | ||
535 | static struct inode * | ||
536 | nilfs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation) | ||
537 | { | ||
538 | struct inode *inode; | ||
539 | |||
540 | if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO && | ||
541 | ino != NILFS_SKETCH_INO) | ||
542 | return ERR_PTR(-ESTALE); | ||
543 | |||
544 | inode = nilfs_iget(sb, ino); | ||
545 | if (IS_ERR(inode)) | ||
546 | return ERR_CAST(inode); | ||
547 | if (generation && inode->i_generation != generation) { | ||
548 | iput(inode); | ||
549 | return ERR_PTR(-ESTALE); | ||
550 | } | ||
551 | |||
552 | return inode; | ||
553 | } | ||
554 | |||
555 | static struct dentry * | ||
556 | nilfs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, | ||
557 | int fh_type) | ||
558 | { | ||
559 | return generic_fh_to_dentry(sb, fid, fh_len, fh_type, | ||
560 | nilfs_nfs_get_inode); | ||
561 | } | ||
562 | |||
563 | static struct dentry * | ||
564 | nilfs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, | ||
565 | int fh_type) | ||
566 | { | ||
567 | return generic_fh_to_parent(sb, fid, fh_len, fh_type, | ||
568 | nilfs_nfs_get_inode); | ||
569 | } | ||
570 | |||
571 | static const struct export_operations nilfs_export_ops = { | ||
572 | .fh_to_dentry = nilfs_fh_to_dentry, | ||
573 | .fh_to_parent = nilfs_fh_to_parent, | ||
574 | .get_parent = nilfs_get_parent, | ||
575 | }; | ||
576 | |||
577 | enum { | 559 | enum { |
578 | Opt_err_cont, Opt_err_panic, Opt_err_ro, | 560 | Opt_err_cont, Opt_err_panic, Opt_err_ro, |
579 | Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery, | 561 | Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery, |
@@ -599,7 +581,6 @@ static int parse_options(char *options, struct super_block *sb, int is_remount) | |||
599 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 581 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
600 | char *p; | 582 | char *p; |
601 | substring_t args[MAX_OPT_ARGS]; | 583 | substring_t args[MAX_OPT_ARGS]; |
602 | int option; | ||
603 | 584 | ||
604 | if (!options) | 585 | if (!options) |
605 | return 1; | 586 | return 1; |
@@ -637,30 +618,12 @@ static int parse_options(char *options, struct super_block *sb, int is_remount) | |||
637 | nilfs_write_opt(sbi, ERROR_MODE, ERRORS_CONT); | 618 | nilfs_write_opt(sbi, ERROR_MODE, ERRORS_CONT); |
638 | break; | 619 | break; |
639 | case Opt_snapshot: | 620 | case Opt_snapshot: |
640 | if (match_int(&args[0], &option) || option <= 0) | ||
641 | return 0; | ||
642 | if (is_remount) { | 621 | if (is_remount) { |
643 | if (!nilfs_test_opt(sbi, SNAPSHOT)) { | 622 | printk(KERN_ERR |
644 | printk(KERN_ERR | 623 | "NILFS: \"%s\" option is invalid " |
645 | "NILFS: cannot change regular " | 624 | "for remount.\n", p); |
646 | "mount to snapshot.\n"); | ||
647 | return 0; | ||
648 | } else if (option != sbi->s_snapshot_cno) { | ||
649 | printk(KERN_ERR | ||
650 | "NILFS: cannot remount to a " | ||
651 | "different snapshot.\n"); | ||
652 | return 0; | ||
653 | } | ||
654 | break; | ||
655 | } | ||
656 | if (!(sb->s_flags & MS_RDONLY)) { | ||
657 | printk(KERN_ERR "NILFS: cannot mount snapshot " | ||
658 | "read/write. A read-only option is " | ||
659 | "required.\n"); | ||
660 | return 0; | 625 | return 0; |
661 | } | 626 | } |
662 | sbi->s_snapshot_cno = option; | ||
663 | nilfs_set_opt(sbi, SNAPSHOT); | ||
664 | break; | 627 | break; |
665 | case Opt_norecovery: | 628 | case Opt_norecovery: |
666 | nilfs_set_opt(sbi, NORECOVERY); | 629 | nilfs_set_opt(sbi, NORECOVERY); |
@@ -688,7 +651,7 @@ nilfs_set_default_options(struct nilfs_sb_info *sbi, | |||
688 | NILFS_MOUNT_ERRORS_RO | NILFS_MOUNT_BARRIER; | 651 | NILFS_MOUNT_ERRORS_RO | NILFS_MOUNT_BARRIER; |
689 | } | 652 | } |
690 | 653 | ||
691 | static int nilfs_setup_super(struct nilfs_sb_info *sbi) | 654 | static int nilfs_setup_super(struct nilfs_sb_info *sbi, int is_mount) |
692 | { | 655 | { |
693 | struct the_nilfs *nilfs = sbi->s_nilfs; | 656 | struct the_nilfs *nilfs = sbi->s_nilfs; |
694 | struct nilfs_super_block **sbp; | 657 | struct nilfs_super_block **sbp; |
@@ -700,6 +663,9 @@ static int nilfs_setup_super(struct nilfs_sb_info *sbi) | |||
700 | if (!sbp) | 663 | if (!sbp) |
701 | return -EIO; | 664 | return -EIO; |
702 | 665 | ||
666 | if (!is_mount) | ||
667 | goto skip_mount_setup; | ||
668 | |||
703 | max_mnt_count = le16_to_cpu(sbp[0]->s_max_mnt_count); | 669 | max_mnt_count = le16_to_cpu(sbp[0]->s_max_mnt_count); |
704 | mnt_count = le16_to_cpu(sbp[0]->s_mnt_count); | 670 | mnt_count = le16_to_cpu(sbp[0]->s_mnt_count); |
705 | 671 | ||
@@ -716,9 +682,11 @@ static int nilfs_setup_super(struct nilfs_sb_info *sbi) | |||
716 | sbp[0]->s_max_mnt_count = cpu_to_le16(NILFS_DFL_MAX_MNT_COUNT); | 682 | sbp[0]->s_max_mnt_count = cpu_to_le16(NILFS_DFL_MAX_MNT_COUNT); |
717 | 683 | ||
718 | sbp[0]->s_mnt_count = cpu_to_le16(mnt_count + 1); | 684 | sbp[0]->s_mnt_count = cpu_to_le16(mnt_count + 1); |
685 | sbp[0]->s_mtime = cpu_to_le64(get_seconds()); | ||
686 | |||
687 | skip_mount_setup: | ||
719 | sbp[0]->s_state = | 688 | sbp[0]->s_state = |
720 | cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS); | 689 | cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS); |
721 | sbp[0]->s_mtime = cpu_to_le64(get_seconds()); | ||
722 | /* synchronize sbp[1] with sbp[0] */ | 690 | /* synchronize sbp[1] with sbp[0] */ |
723 | memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); | 691 | memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); |
724 | return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL); | 692 | return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL); |
@@ -785,22 +753,156 @@ int nilfs_check_feature_compatibility(struct super_block *sb, | |||
785 | return 0; | 753 | return 0; |
786 | } | 754 | } |
787 | 755 | ||
756 | static int nilfs_get_root_dentry(struct super_block *sb, | ||
757 | struct nilfs_root *root, | ||
758 | struct dentry **root_dentry) | ||
759 | { | ||
760 | struct inode *inode; | ||
761 | struct dentry *dentry; | ||
762 | int ret = 0; | ||
763 | |||
764 | inode = nilfs_iget(sb, root, NILFS_ROOT_INO); | ||
765 | if (IS_ERR(inode)) { | ||
766 | printk(KERN_ERR "NILFS: get root inode failed\n"); | ||
767 | ret = PTR_ERR(inode); | ||
768 | goto out; | ||
769 | } | ||
770 | if (!S_ISDIR(inode->i_mode) || !inode->i_blocks || !inode->i_size) { | ||
771 | iput(inode); | ||
772 | printk(KERN_ERR "NILFS: corrupt root inode.\n"); | ||
773 | ret = -EINVAL; | ||
774 | goto out; | ||
775 | } | ||
776 | |||
777 | if (root->cno == NILFS_CPTREE_CURRENT_CNO) { | ||
778 | dentry = d_find_alias(inode); | ||
779 | if (!dentry) { | ||
780 | dentry = d_alloc_root(inode); | ||
781 | if (!dentry) { | ||
782 | iput(inode); | ||
783 | ret = -ENOMEM; | ||
784 | goto failed_dentry; | ||
785 | } | ||
786 | } else { | ||
787 | iput(inode); | ||
788 | } | ||
789 | } else { | ||
790 | dentry = d_obtain_alias(inode); | ||
791 | if (IS_ERR(dentry)) { | ||
792 | ret = PTR_ERR(dentry); | ||
793 | goto failed_dentry; | ||
794 | } | ||
795 | } | ||
796 | *root_dentry = dentry; | ||
797 | out: | ||
798 | return ret; | ||
799 | |||
800 | failed_dentry: | ||
801 | printk(KERN_ERR "NILFS: get root dentry failed\n"); | ||
802 | goto out; | ||
803 | } | ||
804 | |||
805 | static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, | ||
806 | struct dentry **root_dentry) | ||
807 | { | ||
808 | struct the_nilfs *nilfs = NILFS_SB(s)->s_nilfs; | ||
809 | struct nilfs_root *root; | ||
810 | int ret; | ||
811 | |||
812 | down_read(&nilfs->ns_segctor_sem); | ||
813 | ret = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, cno); | ||
814 | up_read(&nilfs->ns_segctor_sem); | ||
815 | if (ret < 0) { | ||
816 | ret = (ret == -ENOENT) ? -EINVAL : ret; | ||
817 | goto out; | ||
818 | } else if (!ret) { | ||
819 | printk(KERN_ERR "NILFS: The specified checkpoint is " | ||
820 | "not a snapshot (checkpoint number=%llu).\n", | ||
821 | (unsigned long long)cno); | ||
822 | ret = -EINVAL; | ||
823 | goto out; | ||
824 | } | ||
825 | |||
826 | ret = nilfs_attach_checkpoint(NILFS_SB(s), cno, false, &root); | ||
827 | if (ret) { | ||
828 | printk(KERN_ERR "NILFS: error loading snapshot " | ||
829 | "(checkpoint number=%llu).\n", | ||
830 | (unsigned long long)cno); | ||
831 | goto out; | ||
832 | } | ||
833 | ret = nilfs_get_root_dentry(s, root, root_dentry); | ||
834 | nilfs_put_root(root); | ||
835 | out: | ||
836 | return ret; | ||
837 | } | ||
838 | |||
839 | static int nilfs_tree_was_touched(struct dentry *root_dentry) | ||
840 | { | ||
841 | return atomic_read(&root_dentry->d_count) > 1; | ||
842 | } | ||
843 | |||
844 | /** | ||
845 | * nilfs_try_to_shrink_tree() - try to shrink dentries of a checkpoint | ||
846 | * @root_dentry: root dentry of the tree to be shrunk | ||
847 | * | ||
848 | * This function returns true if the tree was in-use. | ||
849 | */ | ||
850 | static int nilfs_try_to_shrink_tree(struct dentry *root_dentry) | ||
851 | { | ||
852 | if (have_submounts(root_dentry)) | ||
853 | return true; | ||
854 | shrink_dcache_parent(root_dentry); | ||
855 | return nilfs_tree_was_touched(root_dentry); | ||
856 | } | ||
857 | |||
858 | int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno) | ||
859 | { | ||
860 | struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs; | ||
861 | struct nilfs_root *root; | ||
862 | struct inode *inode; | ||
863 | struct dentry *dentry; | ||
864 | int ret; | ||
865 | |||
866 | if (cno < 0 || cno > nilfs->ns_cno) | ||
867 | return false; | ||
868 | |||
869 | if (cno >= nilfs_last_cno(nilfs)) | ||
870 | return true; /* protect recent checkpoints */ | ||
871 | |||
872 | ret = false; | ||
873 | root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, cno); | ||
874 | if (root) { | ||
875 | inode = nilfs_ilookup(sb, root, NILFS_ROOT_INO); | ||
876 | if (inode) { | ||
877 | dentry = d_find_alias(inode); | ||
878 | if (dentry) { | ||
879 | if (nilfs_tree_was_touched(dentry)) | ||
880 | ret = nilfs_try_to_shrink_tree(dentry); | ||
881 | dput(dentry); | ||
882 | } | ||
883 | iput(inode); | ||
884 | } | ||
885 | nilfs_put_root(root); | ||
886 | } | ||
887 | return ret; | ||
888 | } | ||
889 | |||
788 | /** | 890 | /** |
789 | * nilfs_fill_super() - initialize a super block instance | 891 | * nilfs_fill_super() - initialize a super block instance |
790 | * @sb: super_block | 892 | * @sb: super_block |
791 | * @data: mount options | 893 | * @data: mount options |
792 | * @silent: silent mode flag | 894 | * @silent: silent mode flag |
793 | * @nilfs: the_nilfs struct | ||
794 | * | 895 | * |
795 | * This function is called exclusively by nilfs->ns_mount_mutex. | 896 | * This function is called exclusively by nilfs->ns_mount_mutex. |
796 | * So, the recovery process is protected from other simultaneous mounts. | 897 | * So, the recovery process is protected from other simultaneous mounts. |
797 | */ | 898 | */ |
798 | static int | 899 | static int |
799 | nilfs_fill_super(struct super_block *sb, void *data, int silent, | 900 | nilfs_fill_super(struct super_block *sb, void *data, int silent) |
800 | struct the_nilfs *nilfs) | ||
801 | { | 901 | { |
902 | struct the_nilfs *nilfs; | ||
802 | struct nilfs_sb_info *sbi; | 903 | struct nilfs_sb_info *sbi; |
803 | struct inode *root; | 904 | struct nilfs_root *fsroot; |
905 | struct backing_dev_info *bdi; | ||
804 | __u64 cno; | 906 | __u64 cno; |
805 | int err; | 907 | int err; |
806 | 908 | ||
@@ -809,19 +911,21 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
809 | return -ENOMEM; | 911 | return -ENOMEM; |
810 | 912 | ||
811 | sb->s_fs_info = sbi; | 913 | sb->s_fs_info = sbi; |
914 | sbi->s_super = sb; | ||
812 | 915 | ||
813 | get_nilfs(nilfs); | 916 | nilfs = alloc_nilfs(sb->s_bdev); |
917 | if (!nilfs) { | ||
918 | err = -ENOMEM; | ||
919 | goto failed_sbi; | ||
920 | } | ||
814 | sbi->s_nilfs = nilfs; | 921 | sbi->s_nilfs = nilfs; |
815 | sbi->s_super = sb; | ||
816 | atomic_set(&sbi->s_count, 1); | ||
817 | 922 | ||
818 | err = init_nilfs(nilfs, sbi, (char *)data); | 923 | err = init_nilfs(nilfs, sbi, (char *)data); |
819 | if (err) | 924 | if (err) |
820 | goto failed_sbi; | 925 | goto failed_nilfs; |
821 | 926 | ||
822 | spin_lock_init(&sbi->s_inode_lock); | 927 | spin_lock_init(&sbi->s_inode_lock); |
823 | INIT_LIST_HEAD(&sbi->s_dirty_files); | 928 | INIT_LIST_HEAD(&sbi->s_dirty_files); |
824 | INIT_LIST_HEAD(&sbi->s_list); | ||
825 | 929 | ||
826 | /* | 930 | /* |
827 | * Following initialization is overlapped because | 931 | * Following initialization is overlapped because |
@@ -837,94 +941,59 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
837 | sb->s_export_op = &nilfs_export_ops; | 941 | sb->s_export_op = &nilfs_export_ops; |
838 | sb->s_root = NULL; | 942 | sb->s_root = NULL; |
839 | sb->s_time_gran = 1; | 943 | sb->s_time_gran = 1; |
840 | sb->s_bdi = nilfs->ns_bdi; | 944 | |
945 | bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; | ||
946 | sb->s_bdi = bdi ? : &default_backing_dev_info; | ||
841 | 947 | ||
842 | err = load_nilfs(nilfs, sbi); | 948 | err = load_nilfs(nilfs, sbi); |
843 | if (err) | 949 | if (err) |
844 | goto failed_sbi; | 950 | goto failed_nilfs; |
845 | 951 | ||
846 | cno = nilfs_last_cno(nilfs); | 952 | cno = nilfs_last_cno(nilfs); |
847 | 953 | err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot); | |
848 | if (sb->s_flags & MS_RDONLY) { | ||
849 | if (nilfs_test_opt(sbi, SNAPSHOT)) { | ||
850 | down_read(&nilfs->ns_segctor_sem); | ||
851 | err = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, | ||
852 | sbi->s_snapshot_cno); | ||
853 | up_read(&nilfs->ns_segctor_sem); | ||
854 | if (err < 0) { | ||
855 | if (err == -ENOENT) | ||
856 | err = -EINVAL; | ||
857 | goto failed_sbi; | ||
858 | } | ||
859 | if (!err) { | ||
860 | printk(KERN_ERR | ||
861 | "NILFS: The specified checkpoint is " | ||
862 | "not a snapshot " | ||
863 | "(checkpoint number=%llu).\n", | ||
864 | (unsigned long long)sbi->s_snapshot_cno); | ||
865 | err = -EINVAL; | ||
866 | goto failed_sbi; | ||
867 | } | ||
868 | cno = sbi->s_snapshot_cno; | ||
869 | } | ||
870 | } | ||
871 | |||
872 | err = nilfs_attach_checkpoint(sbi, cno); | ||
873 | if (err) { | 954 | if (err) { |
874 | printk(KERN_ERR "NILFS: error loading a checkpoint" | 955 | printk(KERN_ERR "NILFS: error loading last checkpoint " |
875 | " (checkpoint number=%llu).\n", (unsigned long long)cno); | 956 | "(checkpoint number=%llu).\n", (unsigned long long)cno); |
876 | goto failed_sbi; | 957 | goto failed_unload; |
877 | } | 958 | } |
878 | 959 | ||
879 | if (!(sb->s_flags & MS_RDONLY)) { | 960 | if (!(sb->s_flags & MS_RDONLY)) { |
880 | err = nilfs_attach_segment_constructor(sbi); | 961 | err = nilfs_attach_segment_constructor(sbi, fsroot); |
881 | if (err) | 962 | if (err) |
882 | goto failed_checkpoint; | 963 | goto failed_checkpoint; |
883 | } | 964 | } |
884 | 965 | ||
885 | root = nilfs_iget(sb, NILFS_ROOT_INO); | 966 | err = nilfs_get_root_dentry(sb, fsroot, &sb->s_root); |
886 | if (IS_ERR(root)) { | 967 | if (err) |
887 | printk(KERN_ERR "NILFS: get root inode failed\n"); | ||
888 | err = PTR_ERR(root); | ||
889 | goto failed_segctor; | ||
890 | } | ||
891 | if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { | ||
892 | iput(root); | ||
893 | printk(KERN_ERR "NILFS: corrupt root inode.\n"); | ||
894 | err = -EINVAL; | ||
895 | goto failed_segctor; | ||
896 | } | ||
897 | sb->s_root = d_alloc_root(root); | ||
898 | if (!sb->s_root) { | ||
899 | iput(root); | ||
900 | printk(KERN_ERR "NILFS: get root dentry failed\n"); | ||
901 | err = -ENOMEM; | ||
902 | goto failed_segctor; | 968 | goto failed_segctor; |
903 | } | 969 | |
970 | nilfs_put_root(fsroot); | ||
904 | 971 | ||
905 | if (!(sb->s_flags & MS_RDONLY)) { | 972 | if (!(sb->s_flags & MS_RDONLY)) { |
906 | down_write(&nilfs->ns_sem); | 973 | down_write(&nilfs->ns_sem); |
907 | nilfs_setup_super(sbi); | 974 | nilfs_setup_super(sbi, true); |
908 | up_write(&nilfs->ns_sem); | 975 | up_write(&nilfs->ns_sem); |
909 | } | 976 | } |
910 | 977 | ||
911 | down_write(&nilfs->ns_super_sem); | ||
912 | if (!nilfs_test_opt(sbi, SNAPSHOT)) | ||
913 | nilfs->ns_current = sbi; | ||
914 | up_write(&nilfs->ns_super_sem); | ||
915 | |||
916 | return 0; | 978 | return 0; |
917 | 979 | ||
918 | failed_segctor: | 980 | failed_segctor: |
919 | nilfs_detach_segment_constructor(sbi); | 981 | nilfs_detach_segment_constructor(sbi); |
920 | 982 | ||
921 | failed_checkpoint: | 983 | failed_checkpoint: |
922 | nilfs_detach_checkpoint(sbi); | 984 | nilfs_put_root(fsroot); |
985 | |||
986 | failed_unload: | ||
987 | iput(nilfs->ns_sufile); | ||
988 | iput(nilfs->ns_cpfile); | ||
989 | iput(nilfs->ns_dat); | ||
990 | |||
991 | failed_nilfs: | ||
992 | destroy_nilfs(nilfs); | ||
923 | 993 | ||
924 | failed_sbi: | 994 | failed_sbi: |
925 | put_nilfs(nilfs); | ||
926 | sb->s_fs_info = NULL; | 995 | sb->s_fs_info = NULL; |
927 | nilfs_put_sbinfo(sbi); | 996 | kfree(sbi); |
928 | return err; | 997 | return err; |
929 | } | 998 | } |
930 | 999 | ||
@@ -934,13 +1003,10 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
934 | struct the_nilfs *nilfs = sbi->s_nilfs; | 1003 | struct the_nilfs *nilfs = sbi->s_nilfs; |
935 | unsigned long old_sb_flags; | 1004 | unsigned long old_sb_flags; |
936 | struct nilfs_mount_options old_opts; | 1005 | struct nilfs_mount_options old_opts; |
937 | int was_snapshot, err; | 1006 | int err; |
938 | 1007 | ||
939 | down_write(&nilfs->ns_super_sem); | ||
940 | old_sb_flags = sb->s_flags; | 1008 | old_sb_flags = sb->s_flags; |
941 | old_opts.mount_opt = sbi->s_mount_opt; | 1009 | old_opts.mount_opt = sbi->s_mount_opt; |
942 | old_opts.snapshot_cno = sbi->s_snapshot_cno; | ||
943 | was_snapshot = nilfs_test_opt(sbi, SNAPSHOT); | ||
944 | 1010 | ||
945 | if (!parse_options(data, sb, 1)) { | 1011 | if (!parse_options(data, sb, 1)) { |
946 | err = -EINVAL; | 1012 | err = -EINVAL; |
@@ -949,11 +1015,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
949 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL); | 1015 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL); |
950 | 1016 | ||
951 | err = -EINVAL; | 1017 | err = -EINVAL; |
952 | if (was_snapshot && !(*flags & MS_RDONLY)) { | ||
953 | printk(KERN_ERR "NILFS (device %s): cannot remount snapshot " | ||
954 | "read/write.\n", sb->s_id); | ||
955 | goto restore_opts; | ||
956 | } | ||
957 | 1018 | ||
958 | if (!nilfs_valid_fs(nilfs)) { | 1019 | if (!nilfs_valid_fs(nilfs)) { |
959 | printk(KERN_WARNING "NILFS (device %s): couldn't " | 1020 | printk(KERN_WARNING "NILFS (device %s): couldn't " |
@@ -978,6 +1039,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
978 | up_write(&nilfs->ns_sem); | 1039 | up_write(&nilfs->ns_sem); |
979 | } else { | 1040 | } else { |
980 | __u64 features; | 1041 | __u64 features; |
1042 | struct nilfs_root *root; | ||
981 | 1043 | ||
982 | /* | 1044 | /* |
983 | * Mounting a RDONLY partition read-write, so reread and | 1045 | * Mounting a RDONLY partition read-write, so reread and |
@@ -999,23 +1061,21 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
999 | 1061 | ||
1000 | sb->s_flags &= ~MS_RDONLY; | 1062 | sb->s_flags &= ~MS_RDONLY; |
1001 | 1063 | ||
1002 | err = nilfs_attach_segment_constructor(sbi); | 1064 | root = NILFS_I(sb->s_root->d_inode)->i_root; |
1065 | err = nilfs_attach_segment_constructor(sbi, root); | ||
1003 | if (err) | 1066 | if (err) |
1004 | goto restore_opts; | 1067 | goto restore_opts; |
1005 | 1068 | ||
1006 | down_write(&nilfs->ns_sem); | 1069 | down_write(&nilfs->ns_sem); |
1007 | nilfs_setup_super(sbi); | 1070 | nilfs_setup_super(sbi, true); |
1008 | up_write(&nilfs->ns_sem); | 1071 | up_write(&nilfs->ns_sem); |
1009 | } | 1072 | } |
1010 | out: | 1073 | out: |
1011 | up_write(&nilfs->ns_super_sem); | ||
1012 | return 0; | 1074 | return 0; |
1013 | 1075 | ||
1014 | restore_opts: | 1076 | restore_opts: |
1015 | sb->s_flags = old_sb_flags; | 1077 | sb->s_flags = old_sb_flags; |
1016 | sbi->s_mount_opt = old_opts.mount_opt; | 1078 | sbi->s_mount_opt = old_opts.mount_opt; |
1017 | sbi->s_snapshot_cno = old_opts.snapshot_cno; | ||
1018 | up_write(&nilfs->ns_super_sem); | ||
1019 | return err; | 1079 | return err; |
1020 | } | 1080 | } |
1021 | 1081 | ||
@@ -1035,7 +1095,7 @@ static int nilfs_identify(char *data, struct nilfs_super_data *sd) | |||
1035 | { | 1095 | { |
1036 | char *p, *options = data; | 1096 | char *p, *options = data; |
1037 | substring_t args[MAX_OPT_ARGS]; | 1097 | substring_t args[MAX_OPT_ARGS]; |
1038 | int option, token; | 1098 | int token; |
1039 | int ret = 0; | 1099 | int ret = 0; |
1040 | 1100 | ||
1041 | do { | 1101 | do { |
@@ -1043,16 +1103,18 @@ static int nilfs_identify(char *data, struct nilfs_super_data *sd) | |||
1043 | if (p != NULL && *p) { | 1103 | if (p != NULL && *p) { |
1044 | token = match_token(p, tokens, args); | 1104 | token = match_token(p, tokens, args); |
1045 | if (token == Opt_snapshot) { | 1105 | if (token == Opt_snapshot) { |
1046 | if (!(sd->flags & MS_RDONLY)) | 1106 | if (!(sd->flags & MS_RDONLY)) { |
1047 | ret++; | 1107 | ret++; |
1048 | else { | 1108 | } else { |
1049 | ret = match_int(&args[0], &option); | 1109 | sd->cno = simple_strtoull(args[0].from, |
1050 | if (!ret) { | 1110 | NULL, 0); |
1051 | if (option > 0) | 1111 | /* |
1052 | sd->cno = option; | 1112 | * No need to see the end pointer; |
1053 | else | 1113 | * match_token() has done syntax |
1054 | ret++; | 1114 | * checking. |
1055 | } | 1115 | */ |
1116 | if (sd->cno == 0) | ||
1117 | ret++; | ||
1056 | } | 1118 | } |
1057 | } | 1119 | } |
1058 | if (ret) | 1120 | if (ret) |
@@ -1069,18 +1131,14 @@ static int nilfs_identify(char *data, struct nilfs_super_data *sd) | |||
1069 | 1131 | ||
1070 | static int nilfs_set_bdev_super(struct super_block *s, void *data) | 1132 | static int nilfs_set_bdev_super(struct super_block *s, void *data) |
1071 | { | 1133 | { |
1072 | struct nilfs_super_data *sd = data; | 1134 | s->s_bdev = data; |
1073 | |||
1074 | s->s_bdev = sd->bdev; | ||
1075 | s->s_dev = s->s_bdev->bd_dev; | 1135 | s->s_dev = s->s_bdev->bd_dev; |
1076 | return 0; | 1136 | return 0; |
1077 | } | 1137 | } |
1078 | 1138 | ||
1079 | static int nilfs_test_bdev_super(struct super_block *s, void *data) | 1139 | static int nilfs_test_bdev_super(struct super_block *s, void *data) |
1080 | { | 1140 | { |
1081 | struct nilfs_super_data *sd = data; | 1141 | return (void *)s->s_bdev == data; |
1082 | |||
1083 | return sd->sbi && s->s_fs_info == (void *)sd->sbi; | ||
1084 | } | 1142 | } |
1085 | 1143 | ||
1086 | static int | 1144 | static int |
@@ -1090,8 +1148,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1090 | struct nilfs_super_data sd; | 1148 | struct nilfs_super_data sd; |
1091 | struct super_block *s; | 1149 | struct super_block *s; |
1092 | fmode_t mode = FMODE_READ; | 1150 | fmode_t mode = FMODE_READ; |
1093 | struct the_nilfs *nilfs; | 1151 | struct dentry *root_dentry; |
1094 | int err, need_to_close = 1; | 1152 | int err, s_new = false; |
1095 | 1153 | ||
1096 | if (!(flags & MS_RDONLY)) | 1154 | if (!(flags & MS_RDONLY)) |
1097 | mode |= FMODE_WRITE; | 1155 | mode |= FMODE_WRITE; |
@@ -1100,12 +1158,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1100 | if (IS_ERR(sd.bdev)) | 1158 | if (IS_ERR(sd.bdev)) |
1101 | return PTR_ERR(sd.bdev); | 1159 | return PTR_ERR(sd.bdev); |
1102 | 1160 | ||
1103 | /* | ||
1104 | * To get mount instance using sget() vfs-routine, NILFS needs | ||
1105 | * much more information than normal filesystems to identify mount | ||
1106 | * instance. For snapshot mounts, not only a mount type (ro-mount | ||
1107 | * or rw-mount) but also a checkpoint number is required. | ||
1108 | */ | ||
1109 | sd.cno = 0; | 1161 | sd.cno = 0; |
1110 | sd.flags = flags; | 1162 | sd.flags = flags; |
1111 | if (nilfs_identify((char *)data, &sd)) { | 1163 | if (nilfs_identify((char *)data, &sd)) { |
@@ -1113,93 +1165,86 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1113 | goto failed; | 1165 | goto failed; |
1114 | } | 1166 | } |
1115 | 1167 | ||
1116 | nilfs = find_or_create_nilfs(sd.bdev); | ||
1117 | if (!nilfs) { | ||
1118 | err = -ENOMEM; | ||
1119 | goto failed; | ||
1120 | } | ||
1121 | |||
1122 | mutex_lock(&nilfs->ns_mount_mutex); | ||
1123 | |||
1124 | if (!sd.cno) { | ||
1125 | /* | ||
1126 | * Check if an exclusive mount exists or not. | ||
1127 | * Snapshot mounts coexist with a current mount | ||
1128 | * (i.e. rw-mount or ro-mount), whereas rw-mount and | ||
1129 | * ro-mount are mutually exclusive. | ||
1130 | */ | ||
1131 | down_read(&nilfs->ns_super_sem); | ||
1132 | if (nilfs->ns_current && | ||
1133 | ((nilfs->ns_current->s_super->s_flags ^ flags) | ||
1134 | & MS_RDONLY)) { | ||
1135 | up_read(&nilfs->ns_super_sem); | ||
1136 | err = -EBUSY; | ||
1137 | goto failed_unlock; | ||
1138 | } | ||
1139 | up_read(&nilfs->ns_super_sem); | ||
1140 | } | ||
1141 | |||
1142 | /* | ||
1143 | * Find existing nilfs_sb_info struct | ||
1144 | */ | ||
1145 | sd.sbi = nilfs_find_sbinfo(nilfs, !(flags & MS_RDONLY), sd.cno); | ||
1146 | |||
1147 | /* | 1168 | /* |
1148 | * Get super block instance holding the nilfs_sb_info struct. | 1169 | * once the super is inserted into the list by sget, s_umount |
1149 | * A new instance is allocated if no existing mount is present or | 1170 | * will protect the lockfs code from trying to start a snapshot |
1150 | * existing instance has been unmounted. | 1171 | * while we are mounting |
1151 | */ | 1172 | */ |
1152 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); | 1173 | mutex_lock(&sd.bdev->bd_fsfreeze_mutex); |
1153 | if (sd.sbi) | 1174 | if (sd.bdev->bd_fsfreeze_count > 0) { |
1154 | nilfs_put_sbinfo(sd.sbi); | 1175 | mutex_unlock(&sd.bdev->bd_fsfreeze_mutex); |
1155 | 1176 | err = -EBUSY; | |
1177 | goto failed; | ||
1178 | } | ||
1179 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev); | ||
1180 | mutex_unlock(&sd.bdev->bd_fsfreeze_mutex); | ||
1156 | if (IS_ERR(s)) { | 1181 | if (IS_ERR(s)) { |
1157 | err = PTR_ERR(s); | 1182 | err = PTR_ERR(s); |
1158 | goto failed_unlock; | 1183 | goto failed; |
1159 | } | 1184 | } |
1160 | 1185 | ||
1161 | if (!s->s_root) { | 1186 | if (!s->s_root) { |
1162 | char b[BDEVNAME_SIZE]; | 1187 | char b[BDEVNAME_SIZE]; |
1163 | 1188 | ||
1189 | s_new = true; | ||
1190 | |||
1164 | /* New superblock instance created */ | 1191 | /* New superblock instance created */ |
1165 | s->s_flags = flags; | 1192 | s->s_flags = flags; |
1166 | s->s_mode = mode; | 1193 | s->s_mode = mode; |
1167 | strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); | 1194 | strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); |
1168 | sb_set_blocksize(s, block_size(sd.bdev)); | 1195 | sb_set_blocksize(s, block_size(sd.bdev)); |
1169 | 1196 | ||
1170 | err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0, | 1197 | err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0); |
1171 | nilfs); | ||
1172 | if (err) | 1198 | if (err) |
1173 | goto cancel_new; | 1199 | goto failed_super; |
1174 | 1200 | ||
1175 | s->s_flags |= MS_ACTIVE; | 1201 | s->s_flags |= MS_ACTIVE; |
1176 | need_to_close = 0; | 1202 | } else if (!sd.cno) { |
1203 | int busy = false; | ||
1204 | |||
1205 | if (nilfs_tree_was_touched(s->s_root)) { | ||
1206 | busy = nilfs_try_to_shrink_tree(s->s_root); | ||
1207 | if (busy && (flags ^ s->s_flags) & MS_RDONLY) { | ||
1208 | printk(KERN_ERR "NILFS: the device already " | ||
1209 | "has a %s mount.\n", | ||
1210 | (s->s_flags & MS_RDONLY) ? | ||
1211 | "read-only" : "read/write"); | ||
1212 | err = -EBUSY; | ||
1213 | goto failed_super; | ||
1214 | } | ||
1215 | } | ||
1216 | if (!busy) { | ||
1217 | /* | ||
1218 | * Try remount to setup mount states if the current | ||
1219 | * tree is not mounted and only snapshots use this sb. | ||
1220 | */ | ||
1221 | err = nilfs_remount(s, &flags, data); | ||
1222 | if (err) | ||
1223 | goto failed_super; | ||
1224 | } | ||
1177 | } | 1225 | } |
1178 | 1226 | ||
1179 | mutex_unlock(&nilfs->ns_mount_mutex); | 1227 | if (sd.cno) { |
1180 | put_nilfs(nilfs); | 1228 | err = nilfs_attach_snapshot(s, sd.cno, &root_dentry); |
1181 | if (need_to_close) | 1229 | if (err) |
1230 | goto failed_super; | ||
1231 | } else { | ||
1232 | root_dentry = dget(s->s_root); | ||
1233 | } | ||
1234 | |||
1235 | if (!s_new) | ||
1182 | close_bdev_exclusive(sd.bdev, mode); | 1236 | close_bdev_exclusive(sd.bdev, mode); |
1183 | simple_set_mnt(mnt, s); | ||
1184 | return 0; | ||
1185 | 1237 | ||
1186 | failed_unlock: | 1238 | mnt->mnt_sb = s; |
1187 | mutex_unlock(&nilfs->ns_mount_mutex); | 1239 | mnt->mnt_root = root_dentry; |
1188 | put_nilfs(nilfs); | 1240 | return 0; |
1189 | failed: | ||
1190 | close_bdev_exclusive(sd.bdev, mode); | ||
1191 | return err; | ||
1192 | 1241 | ||
1193 | cancel_new: | 1242 | failed_super: |
1194 | /* Abandoning the newly allocated superblock */ | ||
1195 | mutex_unlock(&nilfs->ns_mount_mutex); | ||
1196 | put_nilfs(nilfs); | ||
1197 | deactivate_locked_super(s); | 1243 | deactivate_locked_super(s); |
1198 | /* | 1244 | |
1199 | * deactivate_locked_super() invokes close_bdev_exclusive(). | 1245 | failed: |
1200 | * We must finish all post-cleaning before this call; | 1246 | if (!s_new) |
1201 | * put_nilfs() needs the block device. | 1247 | close_bdev_exclusive(sd.bdev, mode); |
1202 | */ | ||
1203 | return err; | 1248 | return err; |
1204 | } | 1249 | } |
1205 | 1250 | ||