diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-08-15 12:54:52 -0400 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-10-22 20:24:36 -0400 |
commit | f11459ad7dab9e9eb5a05b8bd3bec338ea8f485d (patch) | |
tree | 91808a1f88f6ad24f381473e1bde22f10cac49e6 /fs/nilfs2 | |
parent | ab4d8f7ebf33beff97e766d18db47f1ea9635769 (diff) |
nilfs2: do not allocate multiple super block instances for a device
This stops allocating multiple super block instances for a device.
All snapshots and a current mode mount (i.e. latest tree) will be
controlled with nilfs_root objects that are kept within an sb
instance.
nilfs_get_sb() is rewritten so that it always has a root object for
the latest tree and snapshots make additional root objects.
The root dentry of the latest tree is binded to sb->s_root even if it
isn't attached on a directory. Root dentries of snapshots or the
latest tree are binded to mnt->mnt_root on which they are mounted.
With this patch, nilfs_find_sbinfo() function, nilfs->ns_supers list,
and nilfs->ns_current back pointer, are deleted. In addition,
init_nilfs() and load_nilfs() are simplified since they will be called
once for a device, not repeatedly called for mount points.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2')
-rw-r--r-- | fs/nilfs2/sb.h | 5 | ||||
-rw-r--r-- | fs/nilfs2/super.c | 216 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 89 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.h | 16 |
4 files changed, 101 insertions, 225 deletions
diff --git a/fs/nilfs2/sb.h b/fs/nilfs2/sb.h index 3cc3675c3abe..35a07157b980 100644 --- a/fs/nilfs2/sb.h +++ b/fs/nilfs2/sb.h | |||
@@ -42,9 +42,6 @@ struct nilfs_sc_info; | |||
42 | * NILFS super-block data in memory | 42 | * NILFS super-block data in memory |
43 | */ | 43 | */ |
44 | struct nilfs_sb_info { | 44 | struct nilfs_sb_info { |
45 | /* Snapshot status */ | ||
46 | __u64 s_snapshot_cno; /* Checkpoint number */ | ||
47 | |||
48 | /* Mount options */ | 45 | /* Mount options */ |
49 | unsigned long s_mount_opt; | 46 | unsigned long s_mount_opt; |
50 | uid_t s_resuid; | 47 | uid_t s_resuid; |
@@ -57,8 +54,6 @@ struct nilfs_sb_info { | |||
57 | /* Fundamental members */ | 54 | /* Fundamental members */ |
58 | struct super_block *s_super; /* reverse pointer to super_block */ | 55 | struct super_block *s_super; /* reverse pointer to super_block */ |
59 | struct the_nilfs *s_nilfs; | 56 | struct the_nilfs *s_nilfs; |
60 | struct list_head s_list; /* list head for nilfs->ns_supers */ | ||
61 | atomic_t s_count; /* reference count */ | ||
62 | 57 | ||
63 | /* Segment constructor */ | 58 | /* Segment constructor */ |
64 | struct list_head s_dirty_files; /* dirty files list */ | 59 | struct list_head s_dirty_files; /* dirty files list */ |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index ebeb746c4845..2e58e7c629b5 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -355,16 +355,11 @@ static void nilfs_put_super(struct super_block *sb) | |||
355 | nilfs_cleanup_super(sbi); | 355 | nilfs_cleanup_super(sbi); |
356 | up_write(&nilfs->ns_sem); | 356 | up_write(&nilfs->ns_sem); |
357 | } | 357 | } |
358 | down_write(&nilfs->ns_super_sem); | ||
359 | if (nilfs->ns_current == sbi) | ||
360 | nilfs->ns_current = NULL; | ||
361 | list_del_init(&sbi->s_list); | ||
362 | up_write(&nilfs->ns_super_sem); | ||
363 | 358 | ||
364 | put_nilfs(sbi->s_nilfs); | 359 | put_nilfs(sbi->s_nilfs); |
365 | sbi->s_super = NULL; | 360 | sbi->s_super = NULL; |
366 | sb->s_fs_info = NULL; | 361 | sb->s_fs_info = NULL; |
367 | nilfs_put_sbinfo(sbi); | 362 | kfree(sbi); |
368 | } | 363 | } |
369 | 364 | ||
370 | static int nilfs_sync_fs(struct super_block *sb, int wait) | 365 | static int nilfs_sync_fs(struct super_block *sb, int wait) |
@@ -500,12 +495,12 @@ static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
500 | { | 495 | { |
501 | struct super_block *sb = vfs->mnt_sb; | 496 | struct super_block *sb = vfs->mnt_sb; |
502 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 497 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
498 | struct nilfs_root *root = NILFS_I(vfs->mnt_root->d_inode)->i_root; | ||
503 | 499 | ||
504 | if (!nilfs_test_opt(sbi, BARRIER)) | 500 | if (!nilfs_test_opt(sbi, BARRIER)) |
505 | seq_puts(seq, ",nobarrier"); | 501 | seq_puts(seq, ",nobarrier"); |
506 | if (nilfs_test_opt(sbi, SNAPSHOT)) | 502 | if (root->cno != NILFS_CPTREE_CURRENT_CNO) |
507 | seq_printf(seq, ",cp=%llu", | 503 | seq_printf(seq, ",cp=%llu", (unsigned long long)root->cno); |
508 | (unsigned long long int)sbi->s_snapshot_cno); | ||
509 | if (nilfs_test_opt(sbi, ERRORS_PANIC)) | 504 | if (nilfs_test_opt(sbi, ERRORS_PANIC)) |
510 | seq_puts(seq, ",errors=panic"); | 505 | seq_puts(seq, ",errors=panic"); |
511 | if (nilfs_test_opt(sbi, ERRORS_CONT)) | 506 | if (nilfs_test_opt(sbi, ERRORS_CONT)) |
@@ -605,27 +600,11 @@ static int parse_options(char *options, struct super_block *sb, int is_remount) | |||
605 | if (match_int(&args[0], &option) || option <= 0) | 600 | if (match_int(&args[0], &option) || option <= 0) |
606 | return 0; | 601 | return 0; |
607 | if (is_remount) { | 602 | if (is_remount) { |
608 | if (!nilfs_test_opt(sbi, SNAPSHOT)) { | 603 | printk(KERN_ERR |
609 | printk(KERN_ERR | 604 | "NILFS: \"%s\" option is invalid " |
610 | "NILFS: cannot change regular " | 605 | "for remount.\n", p); |
611 | "mount to snapshot.\n"); | ||
612 | return 0; | ||
613 | } else if (option != sbi->s_snapshot_cno) { | ||
614 | printk(KERN_ERR | ||
615 | "NILFS: cannot remount to a " | ||
616 | "different snapshot.\n"); | ||
617 | return 0; | ||
618 | } | ||
619 | break; | ||
620 | } | ||
621 | if (!(sb->s_flags & MS_RDONLY)) { | ||
622 | printk(KERN_ERR "NILFS: cannot mount snapshot " | ||
623 | "read/write. A read-only option is " | ||
624 | "required.\n"); | ||
625 | return 0; | 606 | return 0; |
626 | } | 607 | } |
627 | sbi->s_snapshot_cno = option; | ||
628 | nilfs_set_opt(sbi, SNAPSHOT); | ||
629 | break; | 608 | break; |
630 | case Opt_norecovery: | 609 | case Opt_norecovery: |
631 | nilfs_set_opt(sbi, NORECOVERY); | 610 | nilfs_set_opt(sbi, NORECOVERY); |
@@ -771,16 +750,32 @@ static int nilfs_get_root_dentry(struct super_block *sb, | |||
771 | goto out; | 750 | goto out; |
772 | } | 751 | } |
773 | 752 | ||
774 | dentry = d_alloc_root(inode); | 753 | if (root->cno == NILFS_CPTREE_CURRENT_CNO) { |
775 | if (!dentry) { | 754 | dentry = d_find_alias(inode); |
776 | iput(inode); | 755 | if (!dentry) { |
777 | printk(KERN_ERR "NILFS: get root dentry failed\n"); | 756 | dentry = d_alloc_root(inode); |
778 | ret = -ENOMEM; | 757 | if (!dentry) { |
779 | goto out; | 758 | iput(inode); |
759 | ret = -ENOMEM; | ||
760 | goto failed_dentry; | ||
761 | } | ||
762 | } else { | ||
763 | iput(inode); | ||
764 | } | ||
765 | } else { | ||
766 | dentry = d_obtain_alias(inode); | ||
767 | if (IS_ERR(dentry)) { | ||
768 | ret = PTR_ERR(dentry); | ||
769 | goto failed_dentry; | ||
770 | } | ||
780 | } | 771 | } |
781 | *root_dentry = dentry; | 772 | *root_dentry = dentry; |
782 | out: | 773 | out: |
783 | return ret; | 774 | return ret; |
775 | |||
776 | failed_dentry: | ||
777 | printk(KERN_ERR "NILFS: get root dentry failed\n"); | ||
778 | goto out; | ||
784 | } | 779 | } |
785 | 780 | ||
786 | static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, | 781 | static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, |
@@ -817,6 +812,25 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, | |||
817 | return ret; | 812 | return ret; |
818 | } | 813 | } |
819 | 814 | ||
815 | static int nilfs_tree_was_touched(struct dentry *root_dentry) | ||
816 | { | ||
817 | return atomic_read(&root_dentry->d_count) > 1; | ||
818 | } | ||
819 | |||
820 | /** | ||
821 | * nilfs_try_to_shrink_tree() - try to shrink dentries of a checkpoint | ||
822 | * @root_dentry: root dentry of the tree to be shrunk | ||
823 | * | ||
824 | * This function returns true if the tree was in-use. | ||
825 | */ | ||
826 | static int nilfs_try_to_shrink_tree(struct dentry *root_dentry) | ||
827 | { | ||
828 | if (have_submounts(root_dentry)) | ||
829 | return true; | ||
830 | shrink_dcache_parent(root_dentry); | ||
831 | return nilfs_tree_was_touched(root_dentry); | ||
832 | } | ||
833 | |||
820 | /** | 834 | /** |
821 | * nilfs_fill_super() - initialize a super block instance | 835 | * nilfs_fill_super() - initialize a super block instance |
822 | * @sb: super_block | 836 | * @sb: super_block |
@@ -845,7 +859,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
845 | get_nilfs(nilfs); | 859 | get_nilfs(nilfs); |
846 | sbi->s_nilfs = nilfs; | 860 | sbi->s_nilfs = nilfs; |
847 | sbi->s_super = sb; | 861 | sbi->s_super = sb; |
848 | atomic_set(&sbi->s_count, 1); | ||
849 | 862 | ||
850 | err = init_nilfs(nilfs, sbi, (char *)data); | 863 | err = init_nilfs(nilfs, sbi, (char *)data); |
851 | if (err) | 864 | if (err) |
@@ -853,7 +866,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
853 | 866 | ||
854 | spin_lock_init(&sbi->s_inode_lock); | 867 | spin_lock_init(&sbi->s_inode_lock); |
855 | INIT_LIST_HEAD(&sbi->s_dirty_files); | 868 | INIT_LIST_HEAD(&sbi->s_dirty_files); |
856 | INIT_LIST_HEAD(&sbi->s_list); | ||
857 | 869 | ||
858 | /* | 870 | /* |
859 | * Following initialization is overlapped because | 871 | * Following initialization is overlapped because |
@@ -875,20 +887,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
875 | if (err) | 887 | if (err) |
876 | goto failed_sbi; | 888 | goto failed_sbi; |
877 | 889 | ||
878 | if (nilfs_test_opt(sbi, SNAPSHOT)) { | ||
879 | err = nilfs_attach_snapshot(sb, sbi->s_snapshot_cno, | ||
880 | &sb->s_root); | ||
881 | if (err) | ||
882 | goto failed_sbi; | ||
883 | |||
884 | goto add_to_supers; | ||
885 | } | ||
886 | |||
887 | cno = nilfs_last_cno(nilfs); | 890 | cno = nilfs_last_cno(nilfs); |
888 | err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot); | 891 | err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot); |
889 | if (err) { | 892 | if (err) { |
890 | printk(KERN_ERR "NILFS: error loading a checkpoint" | 893 | printk(KERN_ERR "NILFS: error loading last checkpoint " |
891 | " (checkpoint number=%llu).\n", (unsigned long long)cno); | 894 | "(checkpoint number=%llu).\n", (unsigned long long)cno); |
892 | goto failed_sbi; | 895 | goto failed_sbi; |
893 | } | 896 | } |
894 | 897 | ||
@@ -910,13 +913,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
910 | up_write(&nilfs->ns_sem); | 913 | up_write(&nilfs->ns_sem); |
911 | } | 914 | } |
912 | 915 | ||
913 | add_to_supers: | ||
914 | down_write(&nilfs->ns_super_sem); | ||
915 | list_add(&sbi->s_list, &nilfs->ns_supers); | ||
916 | if (!nilfs_test_opt(sbi, SNAPSHOT)) | ||
917 | nilfs->ns_current = sbi; | ||
918 | up_write(&nilfs->ns_super_sem); | ||
919 | |||
920 | return 0; | 916 | return 0; |
921 | 917 | ||
922 | failed_segctor: | 918 | failed_segctor: |
@@ -928,7 +924,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
928 | failed_sbi: | 924 | failed_sbi: |
929 | put_nilfs(nilfs); | 925 | put_nilfs(nilfs); |
930 | sb->s_fs_info = NULL; | 926 | sb->s_fs_info = NULL; |
931 | nilfs_put_sbinfo(sbi); | 927 | kfree(sbi); |
932 | return err; | 928 | return err; |
933 | } | 929 | } |
934 | 930 | ||
@@ -938,13 +934,10 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
938 | struct the_nilfs *nilfs = sbi->s_nilfs; | 934 | struct the_nilfs *nilfs = sbi->s_nilfs; |
939 | unsigned long old_sb_flags; | 935 | unsigned long old_sb_flags; |
940 | struct nilfs_mount_options old_opts; | 936 | struct nilfs_mount_options old_opts; |
941 | int was_snapshot, err; | 937 | int err; |
942 | 938 | ||
943 | down_write(&nilfs->ns_super_sem); | ||
944 | old_sb_flags = sb->s_flags; | 939 | old_sb_flags = sb->s_flags; |
945 | old_opts.mount_opt = sbi->s_mount_opt; | 940 | old_opts.mount_opt = sbi->s_mount_opt; |
946 | old_opts.snapshot_cno = sbi->s_snapshot_cno; | ||
947 | was_snapshot = nilfs_test_opt(sbi, SNAPSHOT); | ||
948 | 941 | ||
949 | if (!parse_options(data, sb, 1)) { | 942 | if (!parse_options(data, sb, 1)) { |
950 | err = -EINVAL; | 943 | err = -EINVAL; |
@@ -953,11 +946,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
953 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL); | 946 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL); |
954 | 947 | ||
955 | err = -EINVAL; | 948 | err = -EINVAL; |
956 | if (was_snapshot && !(*flags & MS_RDONLY)) { | ||
957 | printk(KERN_ERR "NILFS (device %s): cannot remount snapshot " | ||
958 | "read/write.\n", sb->s_id); | ||
959 | goto restore_opts; | ||
960 | } | ||
961 | 949 | ||
962 | if (!nilfs_valid_fs(nilfs)) { | 950 | if (!nilfs_valid_fs(nilfs)) { |
963 | printk(KERN_WARNING "NILFS (device %s): couldn't " | 951 | printk(KERN_WARNING "NILFS (device %s): couldn't " |
@@ -1014,14 +1002,11 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
1014 | up_write(&nilfs->ns_sem); | 1002 | up_write(&nilfs->ns_sem); |
1015 | } | 1003 | } |
1016 | out: | 1004 | out: |
1017 | up_write(&nilfs->ns_super_sem); | ||
1018 | return 0; | 1005 | return 0; |
1019 | 1006 | ||
1020 | restore_opts: | 1007 | restore_opts: |
1021 | sb->s_flags = old_sb_flags; | 1008 | sb->s_flags = old_sb_flags; |
1022 | sbi->s_mount_opt = old_opts.mount_opt; | 1009 | sbi->s_mount_opt = old_opts.mount_opt; |
1023 | sbi->s_snapshot_cno = old_opts.snapshot_cno; | ||
1024 | up_write(&nilfs->ns_super_sem); | ||
1025 | return err; | 1010 | return err; |
1026 | } | 1011 | } |
1027 | 1012 | ||
@@ -1075,18 +1060,14 @@ static int nilfs_identify(char *data, struct nilfs_super_data *sd) | |||
1075 | 1060 | ||
1076 | static int nilfs_set_bdev_super(struct super_block *s, void *data) | 1061 | static int nilfs_set_bdev_super(struct super_block *s, void *data) |
1077 | { | 1062 | { |
1078 | struct nilfs_super_data *sd = data; | 1063 | s->s_bdev = data; |
1079 | |||
1080 | s->s_bdev = sd->bdev; | ||
1081 | s->s_dev = s->s_bdev->bd_dev; | 1064 | s->s_dev = s->s_bdev->bd_dev; |
1082 | return 0; | 1065 | return 0; |
1083 | } | 1066 | } |
1084 | 1067 | ||
1085 | static int nilfs_test_bdev_super(struct super_block *s, void *data) | 1068 | static int nilfs_test_bdev_super(struct super_block *s, void *data) |
1086 | { | 1069 | { |
1087 | struct nilfs_super_data *sd = data; | 1070 | return (void *)s->s_bdev == data; |
1088 | |||
1089 | return sd->sbi && s->s_fs_info == (void *)sd->sbi; | ||
1090 | } | 1071 | } |
1091 | 1072 | ||
1092 | static int | 1073 | static int |
@@ -1097,7 +1078,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1097 | struct super_block *s; | 1078 | struct super_block *s; |
1098 | fmode_t mode = FMODE_READ; | 1079 | fmode_t mode = FMODE_READ; |
1099 | struct the_nilfs *nilfs; | 1080 | struct the_nilfs *nilfs; |
1100 | int err, need_to_close = 1; | 1081 | struct dentry *root_dentry; |
1082 | int err, s_new = false; | ||
1101 | 1083 | ||
1102 | if (!(flags & MS_RDONLY)) | 1084 | if (!(flags & MS_RDONLY)) |
1103 | mode |= FMODE_WRITE; | 1085 | mode |= FMODE_WRITE; |
@@ -1106,12 +1088,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1106 | if (IS_ERR(sd.bdev)) | 1088 | if (IS_ERR(sd.bdev)) |
1107 | return PTR_ERR(sd.bdev); | 1089 | return PTR_ERR(sd.bdev); |
1108 | 1090 | ||
1109 | /* | ||
1110 | * To get mount instance using sget() vfs-routine, NILFS needs | ||
1111 | * much more information than normal filesystems to identify mount | ||
1112 | * instance. For snapshot mounts, not only a mount type (ro-mount | ||
1113 | * or rw-mount) but also a checkpoint number is required. | ||
1114 | */ | ||
1115 | sd.cno = 0; | 1091 | sd.cno = 0; |
1116 | sd.flags = flags; | 1092 | sd.flags = flags; |
1117 | if (nilfs_identify((char *)data, &sd)) { | 1093 | if (nilfs_identify((char *)data, &sd)) { |
@@ -1127,38 +1103,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1127 | 1103 | ||
1128 | mutex_lock(&nilfs->ns_mount_mutex); | 1104 | mutex_lock(&nilfs->ns_mount_mutex); |
1129 | 1105 | ||
1130 | if (!sd.cno) { | 1106 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev); |
1131 | /* | ||
1132 | * Check if an exclusive mount exists or not. | ||
1133 | * Snapshot mounts coexist with a current mount | ||
1134 | * (i.e. rw-mount or ro-mount), whereas rw-mount and | ||
1135 | * ro-mount are mutually exclusive. | ||
1136 | */ | ||
1137 | down_read(&nilfs->ns_super_sem); | ||
1138 | if (nilfs->ns_current && | ||
1139 | ((nilfs->ns_current->s_super->s_flags ^ flags) | ||
1140 | & MS_RDONLY)) { | ||
1141 | up_read(&nilfs->ns_super_sem); | ||
1142 | err = -EBUSY; | ||
1143 | goto failed_unlock; | ||
1144 | } | ||
1145 | up_read(&nilfs->ns_super_sem); | ||
1146 | } | ||
1147 | |||
1148 | /* | ||
1149 | * Find existing nilfs_sb_info struct | ||
1150 | */ | ||
1151 | sd.sbi = nilfs_find_sbinfo(nilfs, !(flags & MS_RDONLY), sd.cno); | ||
1152 | |||
1153 | /* | ||
1154 | * Get super block instance holding the nilfs_sb_info struct. | ||
1155 | * A new instance is allocated if no existing mount is present or | ||
1156 | * existing instance has been unmounted. | ||
1157 | */ | ||
1158 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); | ||
1159 | if (sd.sbi) | ||
1160 | nilfs_put_sbinfo(sd.sbi); | ||
1161 | |||
1162 | if (IS_ERR(s)) { | 1107 | if (IS_ERR(s)) { |
1163 | err = PTR_ERR(s); | 1108 | err = PTR_ERR(s); |
1164 | goto failed_unlock; | 1109 | goto failed_unlock; |
@@ -1167,6 +1112,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1167 | if (!s->s_root) { | 1112 | if (!s->s_root) { |
1168 | char b[BDEVNAME_SIZE]; | 1113 | char b[BDEVNAME_SIZE]; |
1169 | 1114 | ||
1115 | s_new = true; | ||
1116 | |||
1170 | /* New superblock instance created */ | 1117 | /* New superblock instance created */ |
1171 | s->s_flags = flags; | 1118 | s->s_flags = flags; |
1172 | s->s_mode = mode; | 1119 | s->s_mode = mode; |
@@ -1179,16 +1126,53 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1179 | goto cancel_new; | 1126 | goto cancel_new; |
1180 | 1127 | ||
1181 | s->s_flags |= MS_ACTIVE; | 1128 | s->s_flags |= MS_ACTIVE; |
1182 | need_to_close = 0; | 1129 | } else if (!sd.cno) { |
1130 | int busy = false; | ||
1131 | |||
1132 | if (nilfs_tree_was_touched(s->s_root)) { | ||
1133 | busy = nilfs_try_to_shrink_tree(s->s_root); | ||
1134 | if (busy && (flags ^ s->s_flags) & MS_RDONLY) { | ||
1135 | printk(KERN_ERR "NILFS: the device already " | ||
1136 | "has a %s mount.\n", | ||
1137 | (s->s_flags & MS_RDONLY) ? | ||
1138 | "read-only" : "read/write"); | ||
1139 | err = -EBUSY; | ||
1140 | goto failed_super; | ||
1141 | } | ||
1142 | } | ||
1143 | if (!busy) { | ||
1144 | /* | ||
1145 | * Try remount to setup mount states if the current | ||
1146 | * tree is not mounted and only snapshots use this sb. | ||
1147 | */ | ||
1148 | err = nilfs_remount(s, &flags, data); | ||
1149 | if (err) | ||
1150 | goto failed_super; | ||
1151 | } | ||
1152 | } | ||
1153 | |||
1154 | if (sd.cno) { | ||
1155 | err = nilfs_attach_snapshot(s, sd.cno, &root_dentry); | ||
1156 | if (err) { | ||
1157 | if (s_new) | ||
1158 | goto cancel_new; | ||
1159 | goto failed_super; | ||
1160 | } | ||
1161 | } else { | ||
1162 | root_dentry = dget(s->s_root); | ||
1183 | } | 1163 | } |
1184 | 1164 | ||
1185 | mutex_unlock(&nilfs->ns_mount_mutex); | 1165 | mutex_unlock(&nilfs->ns_mount_mutex); |
1186 | put_nilfs(nilfs); | 1166 | put_nilfs(nilfs); |
1187 | if (need_to_close) | 1167 | if (!s_new) |
1188 | close_bdev_exclusive(sd.bdev, mode); | 1168 | close_bdev_exclusive(sd.bdev, mode); |
1189 | simple_set_mnt(mnt, s); | 1169 | |
1170 | mnt->mnt_sb = s; | ||
1171 | mnt->mnt_root = root_dentry; | ||
1190 | return 0; | 1172 | return 0; |
1191 | 1173 | ||
1174 | failed_super: | ||
1175 | deactivate_locked_super(s); | ||
1192 | failed_unlock: | 1176 | failed_unlock: |
1193 | mutex_unlock(&nilfs->ns_mount_mutex); | 1177 | mutex_unlock(&nilfs->ns_mount_mutex); |
1194 | put_nilfs(nilfs); | 1178 | put_nilfs(nilfs); |
@@ -1202,7 +1186,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1202 | put_nilfs(nilfs); | 1186 | put_nilfs(nilfs); |
1203 | deactivate_locked_super(s); | 1187 | deactivate_locked_super(s); |
1204 | /* | 1188 | /* |
1205 | * deactivate_locked_super() invokes close_bdev_exclusive(). | 1189 | * This deactivate_locked_super() invokes close_bdev_exclusive(). |
1206 | * We must finish all post-cleaning before this call; | 1190 | * We must finish all post-cleaning before this call; |
1207 | * put_nilfs() needs the block device. | 1191 | * put_nilfs() needs the block device. |
1208 | */ | 1192 | */ |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 89c78562d0e9..960c28797bb2 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -82,11 +82,9 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
82 | atomic_set(&nilfs->ns_count, 1); | 82 | atomic_set(&nilfs->ns_count, 1); |
83 | atomic_set(&nilfs->ns_ndirtyblks, 0); | 83 | atomic_set(&nilfs->ns_ndirtyblks, 0); |
84 | init_rwsem(&nilfs->ns_sem); | 84 | init_rwsem(&nilfs->ns_sem); |
85 | init_rwsem(&nilfs->ns_super_sem); | ||
86 | mutex_init(&nilfs->ns_mount_mutex); | 85 | mutex_init(&nilfs->ns_mount_mutex); |
87 | init_rwsem(&nilfs->ns_writer_sem); | 86 | init_rwsem(&nilfs->ns_writer_sem); |
88 | INIT_LIST_HEAD(&nilfs->ns_list); | 87 | INIT_LIST_HEAD(&nilfs->ns_list); |
89 | INIT_LIST_HEAD(&nilfs->ns_supers); | ||
90 | INIT_LIST_HEAD(&nilfs->ns_gc_inodes); | 88 | INIT_LIST_HEAD(&nilfs->ns_gc_inodes); |
91 | spin_lock_init(&nilfs->ns_last_segment_lock); | 89 | spin_lock_init(&nilfs->ns_last_segment_lock); |
92 | nilfs->ns_cptree = RB_ROOT; | 90 | nilfs->ns_cptree = RB_ROOT; |
@@ -307,15 +305,6 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
307 | int valid_fs = nilfs_valid_fs(nilfs); | 305 | int valid_fs = nilfs_valid_fs(nilfs); |
308 | int err; | 306 | int err; |
309 | 307 | ||
310 | if (nilfs_loaded(nilfs)) { | ||
311 | if (valid_fs || | ||
312 | ((s_flags & MS_RDONLY) && nilfs_test_opt(sbi, NORECOVERY))) | ||
313 | return 0; | ||
314 | printk(KERN_ERR "NILFS: the filesystem is in an incomplete " | ||
315 | "recovery state.\n"); | ||
316 | return -EINVAL; | ||
317 | } | ||
318 | |||
319 | if (!valid_fs) { | 308 | if (!valid_fs) { |
320 | printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n"); | 309 | printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n"); |
321 | if (s_flags & MS_RDONLY) { | 310 | if (s_flags & MS_RDONLY) { |
@@ -632,12 +621,7 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, | |||
632 | * | 621 | * |
633 | * init_nilfs() performs common initialization per block device (e.g. | 622 | * init_nilfs() performs common initialization per block device (e.g. |
634 | * reading the super block, getting disk layout information, initializing | 623 | * reading the super block, getting disk layout information, initializing |
635 | * shared fields in the_nilfs). It takes on some portion of the jobs | 624 | * shared fields in the_nilfs). |
636 | * typically done by a fill_super() routine. This division arises from | ||
637 | * the nature that multiple NILFS instances may be simultaneously | ||
638 | * mounted on a device. | ||
639 | * For multiple mounts on the same device, only the first mount | ||
640 | * invokes these tasks. | ||
641 | * | 625 | * |
642 | * Return Value: On success, 0 is returned. On error, a negative error | 626 | * Return Value: On success, 0 is returned. On error, a negative error |
643 | * code is returned. | 627 | * code is returned. |
@@ -651,27 +635,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
651 | int err; | 635 | int err; |
652 | 636 | ||
653 | down_write(&nilfs->ns_sem); | 637 | down_write(&nilfs->ns_sem); |
654 | if (nilfs_init(nilfs)) { | ||
655 | /* Load values from existing the_nilfs */ | ||
656 | sbp = nilfs->ns_sbp[0]; | ||
657 | err = nilfs_store_magic_and_option(sb, sbp, data); | ||
658 | if (err) | ||
659 | goto out; | ||
660 | |||
661 | err = nilfs_check_feature_compatibility(sb, sbp); | ||
662 | if (err) | ||
663 | goto out; | ||
664 | |||
665 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); | ||
666 | if (sb->s_blocksize != blocksize && | ||
667 | !sb_set_blocksize(sb, blocksize)) { | ||
668 | printk(KERN_ERR "NILFS: blocksize %d unfit to device\n", | ||
669 | blocksize); | ||
670 | err = -EINVAL; | ||
671 | } | ||
672 | sb->s_maxbytes = nilfs_max_size(sb->s_blocksize_bits); | ||
673 | goto out; | ||
674 | } | ||
675 | 638 | ||
676 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); | 639 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); |
677 | if (!blocksize) { | 640 | if (!blocksize) { |
@@ -901,56 +864,6 @@ void nilfs_put_root(struct nilfs_root *root) | |||
901 | } | 864 | } |
902 | } | 865 | } |
903 | 866 | ||
904 | /** | ||
905 | * nilfs_find_sbinfo - find existing nilfs_sb_info structure | ||
906 | * @nilfs: nilfs object | ||
907 | * @rw_mount: mount type (non-zero value for read/write mount) | ||
908 | * @cno: checkpoint number (zero for read-only mount) | ||
909 | * | ||
910 | * nilfs_find_sbinfo() returns the nilfs_sb_info structure which | ||
911 | * @rw_mount and @cno (in case of snapshots) matched. If no instance | ||
912 | * was found, NULL is returned. Although the super block instance can | ||
913 | * be unmounted after this function returns, the nilfs_sb_info struct | ||
914 | * is kept on memory until nilfs_put_sbinfo() is called. | ||
915 | */ | ||
916 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs, | ||
917 | int rw_mount, __u64 cno) | ||
918 | { | ||
919 | struct nilfs_sb_info *sbi; | ||
920 | |||
921 | down_read(&nilfs->ns_super_sem); | ||
922 | /* | ||
923 | * The SNAPSHOT flag and sb->s_flags are supposed to be | ||
924 | * protected with nilfs->ns_super_sem. | ||
925 | */ | ||
926 | sbi = nilfs->ns_current; | ||
927 | if (rw_mount) { | ||
928 | if (sbi && !(sbi->s_super->s_flags & MS_RDONLY)) | ||
929 | goto found; /* read/write mount */ | ||
930 | else | ||
931 | goto out; | ||
932 | } else if (cno == 0) { | ||
933 | if (sbi && (sbi->s_super->s_flags & MS_RDONLY)) | ||
934 | goto found; /* read-only mount */ | ||
935 | else | ||
936 | goto out; | ||
937 | } | ||
938 | |||
939 | list_for_each_entry(sbi, &nilfs->ns_supers, s_list) { | ||
940 | if (nilfs_test_opt(sbi, SNAPSHOT) && | ||
941 | sbi->s_snapshot_cno == cno) | ||
942 | goto found; /* snapshot mount */ | ||
943 | } | ||
944 | out: | ||
945 | up_read(&nilfs->ns_super_sem); | ||
946 | return NULL; | ||
947 | |||
948 | found: | ||
949 | atomic_inc(&sbi->s_count); | ||
950 | up_read(&nilfs->ns_super_sem); | ||
951 | return sbi; | ||
952 | } | ||
953 | |||
954 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, | 867 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, |
955 | int snapshot_mount) | 868 | int snapshot_mount) |
956 | { | 869 | { |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 0afede68a9e1..7b43693a69c5 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
@@ -52,16 +52,13 @@ enum { | |||
52 | * @ns_bdi: backing dev info | 52 | * @ns_bdi: backing dev info |
53 | * @ns_writer: back pointer to writable nilfs_sb_info | 53 | * @ns_writer: back pointer to writable nilfs_sb_info |
54 | * @ns_sem: semaphore for shared states | 54 | * @ns_sem: semaphore for shared states |
55 | * @ns_super_sem: semaphore for global operations across super block instances | ||
56 | * @ns_mount_mutex: mutex protecting mount process of nilfs | 55 | * @ns_mount_mutex: mutex protecting mount process of nilfs |
57 | * @ns_writer_sem: semaphore protecting ns_writer attach/detach | 56 | * @ns_writer_sem: semaphore protecting ns_writer attach/detach |
58 | * @ns_current: back pointer to current mount | ||
59 | * @ns_sbh: buffer heads of on-disk super blocks | 57 | * @ns_sbh: buffer heads of on-disk super blocks |
60 | * @ns_sbp: pointers to super block data | 58 | * @ns_sbp: pointers to super block data |
61 | * @ns_sbwtime: previous write time of super block | 59 | * @ns_sbwtime: previous write time of super block |
62 | * @ns_sbwcount: write count of super block | 60 | * @ns_sbwcount: write count of super block |
63 | * @ns_sbsize: size of valid data in super block | 61 | * @ns_sbsize: size of valid data in super block |
64 | * @ns_supers: list of nilfs super block structs | ||
65 | * @ns_seg_seq: segment sequence counter | 62 | * @ns_seg_seq: segment sequence counter |
66 | * @ns_segnum: index number of the latest full segment. | 63 | * @ns_segnum: index number of the latest full segment. |
67 | * @ns_nextnum: index number of the full segment index to be used next | 64 | * @ns_nextnum: index number of the full segment index to be used next |
@@ -104,17 +101,10 @@ struct the_nilfs { | |||
104 | struct backing_dev_info *ns_bdi; | 101 | struct backing_dev_info *ns_bdi; |
105 | struct nilfs_sb_info *ns_writer; | 102 | struct nilfs_sb_info *ns_writer; |
106 | struct rw_semaphore ns_sem; | 103 | struct rw_semaphore ns_sem; |
107 | struct rw_semaphore ns_super_sem; | ||
108 | struct mutex ns_mount_mutex; | 104 | struct mutex ns_mount_mutex; |
109 | struct rw_semaphore ns_writer_sem; | 105 | struct rw_semaphore ns_writer_sem; |
110 | 106 | ||
111 | /* | 107 | /* |
112 | * components protected by ns_super_sem | ||
113 | */ | ||
114 | struct nilfs_sb_info *ns_current; | ||
115 | struct list_head ns_supers; | ||
116 | |||
117 | /* | ||
118 | * used for | 108 | * used for |
119 | * - loading the latest checkpoint exclusively. | 109 | * - loading the latest checkpoint exclusively. |
120 | * - allocating a new full segment. | 110 | * - allocating a new full segment. |
@@ -294,12 +284,6 @@ nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
294 | up_write(&nilfs->ns_writer_sem); | 284 | up_write(&nilfs->ns_writer_sem); |
295 | } | 285 | } |
296 | 286 | ||
297 | static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi) | ||
298 | { | ||
299 | if (atomic_dec_and_test(&sbi->s_count)) | ||
300 | kfree(sbi); | ||
301 | } | ||
302 | |||
303 | static inline int nilfs_valid_fs(struct the_nilfs *nilfs) | 287 | static inline int nilfs_valid_fs(struct the_nilfs *nilfs) |
304 | { | 288 | { |
305 | unsigned valid_fs; | 289 | unsigned valid_fs; |