aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nilfs2/sb.h1
-rw-r--r--fs/nilfs2/super.c42
-rw-r--r--fs/nilfs2/the_nilfs.c50
-rw-r--r--fs/nilfs2/the_nilfs.h7
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
1015struct nilfs_super_data { 1016struct 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)
1071static int nilfs_test_bdev_super(struct super_block *s, void *data) 1073static 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
1097static int 1080static 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 */
679struct 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
667int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, 717int 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 *);
201int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); 201int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
202int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); 202int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);
203int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); 203int nilfs_count_free_blocks(struct the_nilfs *, sector_t *);
204struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
204int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); 205int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int);
205int nilfs_near_disk_full(struct the_nilfs *); 206int nilfs_near_disk_full(struct the_nilfs *);
206void nilfs_fall_back_super_block(struct the_nilfs *); 207void 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
247static 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
246static inline void 253static inline void
247nilfs_get_segment_range(struct the_nilfs *nilfs, __u64 segnum, 254nilfs_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)