Commit 6dd4740662405a68bb229ac2b9e0aeaaf2188bf2
Committed by
Al Viro
1 parent
3f82ff5516
Exists in
master
and in
39 other branches
nilfs2: simplify remaining sget() use
This simplifies the test function passed on the remaining sget() callsite in nilfs. Instead of checking mount type (i.e. ro-mount/rw-mount/snapshot mount) in the test function passed to sget(), this patch first looks up the nilfs_sb_info struct which the given mount type matches, and then acquires the super block instance holding the nilfs_sb_info. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 4 changed files with 75 additions and 25 deletions Side-by-side Diff
fs/nilfs2/sb.h
... | ... | @@ -60,6 +60,7 @@ |
60 | 60 | struct super_block *s_super; /* reverse pointer to super_block */ |
61 | 61 | struct the_nilfs *s_nilfs; |
62 | 62 | struct list_head s_list; /* list head for nilfs->ns_supers */ |
63 | + atomic_t s_count; /* reference count */ | |
63 | 64 | |
64 | 65 | /* Segment constructor */ |
65 | 66 | struct list_head s_dirty_files; /* dirty files list */ |
fs/nilfs2/super.c
... | ... | @@ -336,7 +336,7 @@ |
336 | 336 | put_nilfs(sbi->s_nilfs); |
337 | 337 | sbi->s_super = NULL; |
338 | 338 | sb->s_fs_info = NULL; |
339 | - kfree(sbi); | |
339 | + nilfs_put_sbinfo(sbi); | |
340 | 340 | |
341 | 341 | unlock_kernel(); |
342 | 342 | } |
... | ... | @@ -785,6 +785,7 @@ |
785 | 785 | get_nilfs(nilfs); |
786 | 786 | sbi->s_nilfs = nilfs; |
787 | 787 | sbi->s_super = sb; |
788 | + atomic_set(&sbi->s_count, 1); | |
788 | 789 | |
789 | 790 | err = init_nilfs(nilfs, sbi, (char *)data); |
790 | 791 | if (err) |
... | ... | @@ -902,7 +903,7 @@ |
902 | 903 | failed_sbi: |
903 | 904 | put_nilfs(nilfs); |
904 | 905 | sb->s_fs_info = NULL; |
905 | - kfree(sbi); | |
906 | + nilfs_put_sbinfo(sbi); | |
906 | 907 | return err; |
907 | 908 | } |
908 | 909 | |
... | ... | @@ -1014,6 +1015,7 @@ |
1014 | 1015 | |
1015 | 1016 | struct nilfs_super_data { |
1016 | 1017 | struct block_device *bdev; |
1018 | + struct nilfs_sb_info *sbi; | |
1017 | 1019 | __u64 cno; |
1018 | 1020 | int flags; |
1019 | 1021 | }; |
1020 | 1022 | |
... | ... | @@ -1071,27 +1073,8 @@ |
1071 | 1073 | static int nilfs_test_bdev_super(struct super_block *s, void *data) |
1072 | 1074 | { |
1073 | 1075 | struct nilfs_super_data *sd = data; |
1074 | - int ret; | |
1075 | 1076 | |
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; | |
1077 | + return sd->sbi && s->s_fs_info == (void *)sd->sbi; | |
1095 | 1078 | } |
1096 | 1079 | |
1097 | 1080 | static int |
... | ... | @@ -1112,7 +1095,6 @@ |
1112 | 1095 | * much more information than normal filesystems to identify mount |
1113 | 1096 | * instance. For snapshot mounts, not only a mount type (ro-mount |
1114 | 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 | 1099 | sd.cno = 0; |
1118 | 1100 | sd.flags = flags; |
1119 | 1101 | |
1120 | 1102 | |
1121 | 1103 | |
... | ... | @@ -1148,13 +1130,23 @@ |
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 | 1137 | if (!sd.cno) |
1154 | 1138 | /* trying to get the latest checkpoint. */ |
1155 | 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 | 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 | 1150 | if (IS_ERR(s)) { |
1159 | 1151 | err = PTR_ERR(s); |
1160 | 1152 | goto failed_unlock; |
fs/nilfs2/the_nilfs.c
... | ... | @@ -664,6 +664,56 @@ |
664 | 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 | 717 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, |
668 | 718 | int snapshot_mount) |
669 | 719 | { |
fs/nilfs2/the_nilfs.h
... | ... | @@ -201,6 +201,7 @@ |
201 | 201 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); |
202 | 202 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); |
203 | 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 | 205 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); |
205 | 206 | int nilfs_near_disk_full(struct the_nilfs *); |
206 | 207 | void nilfs_fall_back_super_block(struct the_nilfs *); |
... | ... | @@ -241,6 +242,12 @@ |
241 | 242 | if (sbi == nilfs->ns_writer) |
242 | 243 | nilfs->ns_writer = NULL; |
243 | 244 | mutex_unlock(&nilfs->ns_writer_mutex); |
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); | |
244 | 251 | } |
245 | 252 | |
246 | 253 | static inline void |