diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nilfs2/sb.h | 1 | ||||
-rw-r--r-- | fs/nilfs2/super.c | 42 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 50 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.h | 7 |
4 files changed, 75 insertions, 25 deletions
diff --git a/fs/nilfs2/sb.h b/fs/nilfs2/sb.h index adccd4fc654e..0776ccc2504a 100644 --- a/fs/nilfs2/sb.h +++ b/fs/nilfs2/sb.h | |||
@@ -60,6 +60,7 @@ struct nilfs_sb_info { | |||
60 | struct super_block *s_super; /* reverse pointer to super_block */ | 60 | struct super_block *s_super; /* reverse pointer to super_block */ |
61 | struct the_nilfs *s_nilfs; | 61 | struct the_nilfs *s_nilfs; |
62 | struct list_head s_list; /* list head for nilfs->ns_supers */ | 62 | struct list_head s_list; /* list head for nilfs->ns_supers */ |
63 | atomic_t s_count; /* reference count */ | ||
63 | 64 | ||
64 | /* Segment constructor */ | 65 | /* Segment constructor */ |
65 | struct list_head s_dirty_files; /* dirty files list */ | 66 | struct list_head s_dirty_files; /* dirty files list */ |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 5a8c5e4731b3..1d1b6e125159 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -336,7 +336,7 @@ static void nilfs_put_super(struct super_block *sb) | |||
336 | put_nilfs(sbi->s_nilfs); | 336 | put_nilfs(sbi->s_nilfs); |
337 | sbi->s_super = NULL; | 337 | sbi->s_super = NULL; |
338 | sb->s_fs_info = NULL; | 338 | sb->s_fs_info = NULL; |
339 | kfree(sbi); | 339 | nilfs_put_sbinfo(sbi); |
340 | 340 | ||
341 | unlock_kernel(); | 341 | unlock_kernel(); |
342 | } | 342 | } |
@@ -785,6 +785,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
785 | get_nilfs(nilfs); | 785 | get_nilfs(nilfs); |
786 | sbi->s_nilfs = nilfs; | 786 | sbi->s_nilfs = nilfs; |
787 | sbi->s_super = sb; | 787 | sbi->s_super = sb; |
788 | atomic_set(&sbi->s_count, 1); | ||
788 | 789 | ||
789 | err = init_nilfs(nilfs, sbi, (char *)data); | 790 | err = init_nilfs(nilfs, sbi, (char *)data); |
790 | if (err) | 791 | if (err) |
@@ -902,7 +903,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
902 | failed_sbi: | 903 | failed_sbi: |
903 | put_nilfs(nilfs); | 904 | put_nilfs(nilfs); |
904 | sb->s_fs_info = NULL; | 905 | sb->s_fs_info = NULL; |
905 | kfree(sbi); | 906 | nilfs_put_sbinfo(sbi); |
906 | return err; | 907 | return err; |
907 | } | 908 | } |
908 | 909 | ||
@@ -1014,6 +1015,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
1014 | 1015 | ||
1015 | struct nilfs_super_data { | 1016 | struct nilfs_super_data { |
1016 | struct block_device *bdev; | 1017 | struct block_device *bdev; |
1018 | struct nilfs_sb_info *sbi; | ||
1017 | __u64 cno; | 1019 | __u64 cno; |
1018 | int flags; | 1020 | int flags; |
1019 | }; | 1021 | }; |
@@ -1071,27 +1073,8 @@ static int nilfs_set_bdev_super(struct super_block *s, void *data) | |||
1071 | static int nilfs_test_bdev_super(struct super_block *s, void *data) | 1073 | static int nilfs_test_bdev_super(struct super_block *s, void *data) |
1072 | { | 1074 | { |
1073 | struct nilfs_super_data *sd = data; | 1075 | struct nilfs_super_data *sd = data; |
1074 | int ret; | 1076 | |
1075 | 1077 | return sd->sbi && s->s_fs_info == (void *)sd->sbi; | |
1076 | if (s->s_bdev != sd->bdev) | ||
1077 | return 0; | ||
1078 | |||
1079 | if (!((s->s_flags | sd->flags) & MS_RDONLY)) | ||
1080 | return 1; /* Reuse an old R/W-mode super_block */ | ||
1081 | |||
1082 | if (s->s_flags & sd->flags & MS_RDONLY) { | ||
1083 | if (down_read_trylock(&s->s_umount)) { | ||
1084 | ret = s->s_root && | ||
1085 | (sd->cno == NILFS_SB(s)->s_snapshot_cno); | ||
1086 | up_read(&s->s_umount); | ||
1087 | /* | ||
1088 | * This path is locked with sb_lock by sget(). | ||
1089 | * So, drop_super() causes deadlock. | ||
1090 | */ | ||
1091 | return ret; | ||
1092 | } | ||
1093 | } | ||
1094 | return 0; | ||
1095 | } | 1078 | } |
1096 | 1079 | ||
1097 | static int | 1080 | static int |
@@ -1112,7 +1095,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1112 | * much more information than normal filesystems to identify mount | 1095 | * much more information than normal filesystems to identify mount |
1113 | * instance. For snapshot mounts, not only a mount type (ro-mount | 1096 | * instance. For snapshot mounts, not only a mount type (ro-mount |
1114 | * or rw-mount) but also a checkpoint number is required. | 1097 | * or rw-mount) but also a checkpoint number is required. |
1115 | * The results are passed in sget() using nilfs_super_data. | ||
1116 | */ | 1098 | */ |
1117 | sd.cno = 0; | 1099 | sd.cno = 0; |
1118 | sd.flags = flags; | 1100 | sd.flags = flags; |
@@ -1148,13 +1130,23 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1148 | } | 1130 | } |
1149 | 1131 | ||
1150 | /* | 1132 | /* |
1151 | * Search specified snapshot or R/W mode super_block | 1133 | * Find existing nilfs_sb_info struct |
1152 | */ | 1134 | */ |
1135 | sd.sbi = nilfs_find_sbinfo(nilfs, !(flags & MS_RDONLY), sd.cno); | ||
1136 | |||
1153 | if (!sd.cno) | 1137 | if (!sd.cno) |
1154 | /* trying to get the latest checkpoint. */ | 1138 | /* trying to get the latest checkpoint. */ |
1155 | sd.cno = nilfs_last_cno(nilfs); | 1139 | sd.cno = nilfs_last_cno(nilfs); |
1156 | 1140 | ||
1141 | /* | ||
1142 | * Get super block instance holding the nilfs_sb_info struct. | ||
1143 | * A new instance is allocated if no existing mount is present or | ||
1144 | * existing instance has been unmounted. | ||
1145 | */ | ||
1157 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); | 1146 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); |
1147 | if (sd.sbi) | ||
1148 | nilfs_put_sbinfo(sd.sbi); | ||
1149 | |||
1158 | if (IS_ERR(s)) { | 1150 | if (IS_ERR(s)) { |
1159 | err = PTR_ERR(s); | 1151 | err = PTR_ERR(s); |
1160 | goto failed_unlock; | 1152 | goto failed_unlock; |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 45dbf6a61744..221953bfc859 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -664,6 +664,56 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs) | |||
664 | return ret; | 664 | return ret; |
665 | } | 665 | } |
666 | 666 | ||
667 | /** | ||
668 | * nilfs_find_sbinfo - find existing nilfs_sb_info structure | ||
669 | * @nilfs: nilfs object | ||
670 | * @rw_mount: mount type (non-zero value for read/write mount) | ||
671 | * @cno: checkpoint number (zero for read-only mount) | ||
672 | * | ||
673 | * nilfs_find_sbinfo() returns the nilfs_sb_info structure which | ||
674 | * @rw_mount and @cno (in case of snapshots) matched. If no instance | ||
675 | * was found, NULL is returned. Although the super block instance can | ||
676 | * be unmounted after this function returns, the nilfs_sb_info struct | ||
677 | * is kept on memory until nilfs_put_sbinfo() is called. | ||
678 | */ | ||
679 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs, | ||
680 | int rw_mount, __u64 cno) | ||
681 | { | ||
682 | struct nilfs_sb_info *sbi; | ||
683 | |||
684 | down_read(&nilfs->ns_sem); | ||
685 | /* | ||
686 | * The SNAPSHOT flag and sb->s_flags are supposed to be | ||
687 | * protected with nilfs->ns_sem. | ||
688 | */ | ||
689 | sbi = nilfs->ns_current; | ||
690 | if (rw_mount) { | ||
691 | if (sbi && !(sbi->s_super->s_flags & MS_RDONLY)) | ||
692 | goto found; /* read/write mount */ | ||
693 | else | ||
694 | goto out; | ||
695 | } else if (cno == 0) { | ||
696 | if (sbi && (sbi->s_super->s_flags & MS_RDONLY)) | ||
697 | goto found; /* read-only mount */ | ||
698 | else | ||
699 | goto out; | ||
700 | } | ||
701 | |||
702 | list_for_each_entry(sbi, &nilfs->ns_supers, s_list) { | ||
703 | if (nilfs_test_opt(sbi, SNAPSHOT) && | ||
704 | sbi->s_snapshot_cno == cno) | ||
705 | goto found; /* snapshot mount */ | ||
706 | } | ||
707 | out: | ||
708 | up_read(&nilfs->ns_sem); | ||
709 | return NULL; | ||
710 | |||
711 | found: | ||
712 | atomic_inc(&sbi->s_count); | ||
713 | up_read(&nilfs->ns_sem); | ||
714 | return sbi; | ||
715 | } | ||
716 | |||
667 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, | 717 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, |
668 | int snapshot_mount) | 718 | int snapshot_mount) |
669 | { | 719 | { |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 99f7e29a5335..be4c040fd629 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
@@ -201,6 +201,7 @@ void put_nilfs(struct the_nilfs *); | |||
201 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); | 201 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); |
202 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); | 202 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); |
203 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); | 203 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); |
204 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64); | ||
204 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); | 205 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); |
205 | int nilfs_near_disk_full(struct the_nilfs *); | 206 | int nilfs_near_disk_full(struct the_nilfs *); |
206 | void nilfs_fall_back_super_block(struct the_nilfs *); | 207 | void nilfs_fall_back_super_block(struct the_nilfs *); |
@@ -243,6 +244,12 @@ nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
243 | mutex_unlock(&nilfs->ns_writer_mutex); | 244 | mutex_unlock(&nilfs->ns_writer_mutex); |
244 | } | 245 | } |
245 | 246 | ||
247 | static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi) | ||
248 | { | ||
249 | if (!atomic_dec_and_test(&sbi->s_count)) | ||
250 | kfree(sbi); | ||
251 | } | ||
252 | |||
246 | static inline void | 253 | static inline void |
247 | nilfs_get_segment_range(struct the_nilfs *nilfs, __u64 segnum, | 254 | nilfs_get_segment_range(struct the_nilfs *nilfs, __u64 segnum, |
248 | sector_t *seg_start, sector_t *seg_end) | 255 | sector_t *seg_start, sector_t *seg_end) |