diff options
-rw-r--r-- | fs/nilfs2/super.c | 80 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 57 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.h | 4 |
3 files changed, 76 insertions, 65 deletions
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1c505d0e031e..3c9833e3e74a 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -1061,13 +1061,6 @@ static int nilfs_set_bdev_super(struct super_block *s, void *data) | |||
1061 | static int nilfs_test_bdev_super(struct super_block *s, void *data) | 1061 | static int nilfs_test_bdev_super(struct super_block *s, void *data) |
1062 | { | 1062 | { |
1063 | struct nilfs_super_data *sd = data; | 1063 | struct nilfs_super_data *sd = data; |
1064 | |||
1065 | return s->s_bdev == sd->bdev; | ||
1066 | } | ||
1067 | |||
1068 | static int nilfs_test_bdev_super2(struct super_block *s, void *data) | ||
1069 | { | ||
1070 | struct nilfs_super_data *sd = data; | ||
1071 | int ret; | 1064 | int ret; |
1072 | 1065 | ||
1073 | if (s->s_bdev != sd->bdev) | 1066 | if (s->s_bdev != sd->bdev) |
@@ -1096,8 +1089,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1096 | const char *dev_name, void *data, struct vfsmount *mnt) | 1089 | const char *dev_name, void *data, struct vfsmount *mnt) |
1097 | { | 1090 | { |
1098 | struct nilfs_super_data sd; | 1091 | struct nilfs_super_data sd; |
1099 | struct super_block *s, *s2; | 1092 | struct super_block *s; |
1100 | struct the_nilfs *nilfs = NULL; | 1093 | struct the_nilfs *nilfs; |
1101 | int err, need_to_close = 1; | 1094 | int err, need_to_close = 1; |
1102 | 1095 | ||
1103 | sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type); | 1096 | sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type); |
@@ -1118,11 +1111,12 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1118 | goto failed; | 1111 | goto failed; |
1119 | } | 1112 | } |
1120 | 1113 | ||
1121 | /* | 1114 | nilfs = find_or_create_nilfs(sd.bdev); |
1122 | * once the super is inserted into the list by sget, s_umount | 1115 | if (!nilfs) { |
1123 | * will protect the lockfs code from trying to start a snapshot | 1116 | err = -ENOMEM; |
1124 | * while we are mounting | 1117 | goto failed; |
1125 | */ | 1118 | } |
1119 | |||
1126 | down(&sd.bdev->bd_mount_sem); | 1120 | down(&sd.bdev->bd_mount_sem); |
1127 | if (!sd.cno && | 1121 | if (!sd.cno && |
1128 | (err = test_exclusive_mount(fs_type, sd.bdev, flags ^ MS_RDONLY))) { | 1122 | (err = test_exclusive_mount(fs_type, sd.bdev, flags ^ MS_RDONLY))) { |
@@ -1131,51 +1125,22 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1131 | } | 1125 | } |
1132 | 1126 | ||
1133 | /* | 1127 | /* |
1134 | * Phase-1: search any existent instance and get the_nilfs | 1128 | * Search specified snapshot or R/W mode super_block |
1135 | */ | 1129 | */ |
1136 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); | 1130 | if (!sd.cno) |
1137 | if (IS_ERR(s)) | 1131 | /* trying to get the latest checkpoint. */ |
1138 | goto error_s; | 1132 | sd.cno = nilfs_last_cno(nilfs); |
1139 | |||
1140 | if (!s->s_root) { | ||
1141 | err = -ENOMEM; | ||
1142 | nilfs = alloc_nilfs(sd.bdev); | ||
1143 | if (!nilfs) | ||
1144 | goto cancel_new; | ||
1145 | } else { | ||
1146 | struct nilfs_sb_info *sbi = NILFS_SB(s); | ||
1147 | 1133 | ||
1148 | /* | 1134 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); |
1149 | * s_umount protects super_block from unmount process; | 1135 | if (IS_ERR(s)) { |
1150 | * It covers pointers of nilfs_sb_info and the_nilfs. | 1136 | err = PTR_ERR(s); |
1151 | */ | 1137 | goto failed_unlock; |
1152 | nilfs = sbi->s_nilfs; | ||
1153 | get_nilfs(nilfs); | ||
1154 | up_write(&s->s_umount); | ||
1155 | |||
1156 | /* | ||
1157 | * Phase-2: search specified snapshot or R/W mode super_block | ||
1158 | */ | ||
1159 | if (!sd.cno) | ||
1160 | /* trying to get the latest checkpoint. */ | ||
1161 | sd.cno = nilfs_last_cno(nilfs); | ||
1162 | |||
1163 | s2 = sget(fs_type, nilfs_test_bdev_super2, | ||
1164 | nilfs_set_bdev_super, &sd); | ||
1165 | deactivate_super(s); | ||
1166 | /* | ||
1167 | * Although deactivate_super() invokes close_bdev_exclusive() at | ||
1168 | * kill_block_super(). Here, s is an existent mount; we need | ||
1169 | * one more close_bdev_exclusive() call. | ||
1170 | */ | ||
1171 | s = s2; | ||
1172 | if (IS_ERR(s)) | ||
1173 | goto error_s; | ||
1174 | } | 1138 | } |
1175 | 1139 | ||
1176 | if (!s->s_root) { | 1140 | if (!s->s_root) { |
1177 | char b[BDEVNAME_SIZE]; | 1141 | char b[BDEVNAME_SIZE]; |
1178 | 1142 | ||
1143 | /* New superblock instance created */ | ||
1179 | s->s_flags = flags; | 1144 | s->s_flags = flags; |
1180 | strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); | 1145 | strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); |
1181 | sb_set_blocksize(s, block_size(sd.bdev)); | 1146 | sb_set_blocksize(s, block_size(sd.bdev)); |
@@ -1195,15 +1160,9 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1195 | simple_set_mnt(mnt, s); | 1160 | simple_set_mnt(mnt, s); |
1196 | return 0; | 1161 | return 0; |
1197 | 1162 | ||
1198 | error_s: | ||
1199 | up(&sd.bdev->bd_mount_sem); | ||
1200 | if (nilfs) | ||
1201 | put_nilfs(nilfs); | ||
1202 | close_bdev_exclusive(sd.bdev, flags); | ||
1203 | return PTR_ERR(s); | ||
1204 | |||
1205 | failed_unlock: | 1163 | failed_unlock: |
1206 | up(&sd.bdev->bd_mount_sem); | 1164 | up(&sd.bdev->bd_mount_sem); |
1165 | put_nilfs(nilfs); | ||
1207 | failed: | 1166 | failed: |
1208 | close_bdev_exclusive(sd.bdev, flags); | 1167 | close_bdev_exclusive(sd.bdev, flags); |
1209 | 1168 | ||
@@ -1212,8 +1171,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
1212 | cancel_new: | 1171 | cancel_new: |
1213 | /* Abandoning the newly allocated superblock */ | 1172 | /* Abandoning the newly allocated superblock */ |
1214 | up(&sd.bdev->bd_mount_sem); | 1173 | up(&sd.bdev->bd_mount_sem); |
1215 | if (nilfs) | 1174 | put_nilfs(nilfs); |
1216 | put_nilfs(nilfs); | ||
1217 | up_write(&s->s_umount); | 1175 | up_write(&s->s_umount); |
1218 | deactivate_super(s); | 1176 | deactivate_super(s); |
1219 | /* | 1177 | /* |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index a91f15b8673c..45dbf6a61744 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -35,6 +35,10 @@ | |||
35 | #include "seglist.h" | 35 | #include "seglist.h" |
36 | #include "segbuf.h" | 36 | #include "segbuf.h" |
37 | 37 | ||
38 | |||
39 | static LIST_HEAD(nilfs_objects); | ||
40 | static DEFINE_SPINLOCK(nilfs_lock); | ||
41 | |||
38 | void nilfs_set_last_segment(struct the_nilfs *nilfs, | 42 | void nilfs_set_last_segment(struct the_nilfs *nilfs, |
39 | sector_t start_blocknr, u64 seq, __u64 cno) | 43 | sector_t start_blocknr, u64 seq, __u64 cno) |
40 | { | 44 | { |
@@ -55,7 +59,7 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs, | |||
55 | * Return Value: On success, pointer to the_nilfs is returned. | 59 | * Return Value: On success, pointer to the_nilfs is returned. |
56 | * On error, NULL is returned. | 60 | * On error, NULL is returned. |
57 | */ | 61 | */ |
58 | struct the_nilfs *alloc_nilfs(struct block_device *bdev) | 62 | static struct the_nilfs *alloc_nilfs(struct block_device *bdev) |
59 | { | 63 | { |
60 | struct the_nilfs *nilfs; | 64 | struct the_nilfs *nilfs; |
61 | 65 | ||
@@ -69,6 +73,7 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
69 | atomic_set(&nilfs->ns_ndirtyblks, 0); | 73 | atomic_set(&nilfs->ns_ndirtyblks, 0); |
70 | init_rwsem(&nilfs->ns_sem); | 74 | init_rwsem(&nilfs->ns_sem); |
71 | mutex_init(&nilfs->ns_writer_mutex); | 75 | mutex_init(&nilfs->ns_writer_mutex); |
76 | INIT_LIST_HEAD(&nilfs->ns_list); | ||
72 | INIT_LIST_HEAD(&nilfs->ns_supers); | 77 | INIT_LIST_HEAD(&nilfs->ns_supers); |
73 | spin_lock_init(&nilfs->ns_last_segment_lock); | 78 | spin_lock_init(&nilfs->ns_last_segment_lock); |
74 | nilfs->ns_gc_inodes_h = NULL; | 79 | nilfs->ns_gc_inodes_h = NULL; |
@@ -78,6 +83,45 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
78 | } | 83 | } |
79 | 84 | ||
80 | /** | 85 | /** |
86 | * find_or_create_nilfs - find or create nilfs object | ||
87 | * @bdev: block device to which the_nilfs is related | ||
88 | * | ||
89 | * find_nilfs() looks up an existent nilfs object created on the | ||
90 | * device and gets the reference count of the object. If no nilfs object | ||
91 | * is found on the device, a new nilfs object is allocated. | ||
92 | * | ||
93 | * Return Value: On success, pointer to the nilfs object is returned. | ||
94 | * On error, NULL is returned. | ||
95 | */ | ||
96 | struct the_nilfs *find_or_create_nilfs(struct block_device *bdev) | ||
97 | { | ||
98 | struct the_nilfs *nilfs, *new = NULL; | ||
99 | |||
100 | retry: | ||
101 | spin_lock(&nilfs_lock); | ||
102 | list_for_each_entry(nilfs, &nilfs_objects, ns_list) { | ||
103 | if (nilfs->ns_bdev == bdev) { | ||
104 | get_nilfs(nilfs); | ||
105 | spin_unlock(&nilfs_lock); | ||
106 | if (new) | ||
107 | put_nilfs(new); | ||
108 | return nilfs; /* existing object */ | ||
109 | } | ||
110 | } | ||
111 | if (new) { | ||
112 | list_add_tail(&new->ns_list, &nilfs_objects); | ||
113 | spin_unlock(&nilfs_lock); | ||
114 | return new; /* new object */ | ||
115 | } | ||
116 | spin_unlock(&nilfs_lock); | ||
117 | |||
118 | new = alloc_nilfs(bdev); | ||
119 | if (new) | ||
120 | goto retry; | ||
121 | return NULL; /* insufficient memory */ | ||
122 | } | ||
123 | |||
124 | /** | ||
81 | * put_nilfs - release a reference to the_nilfs | 125 | * put_nilfs - release a reference to the_nilfs |
82 | * @nilfs: the_nilfs structure to be released | 126 | * @nilfs: the_nilfs structure to be released |
83 | * | 127 | * |
@@ -86,13 +130,20 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
86 | */ | 130 | */ |
87 | void put_nilfs(struct the_nilfs *nilfs) | 131 | void put_nilfs(struct the_nilfs *nilfs) |
88 | { | 132 | { |
89 | if (!atomic_dec_and_test(&nilfs->ns_count)) | 133 | spin_lock(&nilfs_lock); |
134 | if (!atomic_dec_and_test(&nilfs->ns_count)) { | ||
135 | spin_unlock(&nilfs_lock); | ||
90 | return; | 136 | return; |
137 | } | ||
138 | list_del_init(&nilfs->ns_list); | ||
139 | spin_unlock(&nilfs_lock); | ||
140 | |||
91 | /* | 141 | /* |
92 | * Increment of ns_count never occur below because the caller | 142 | * Increment of ns_count never occurs below because the caller |
93 | * of get_nilfs() holds at least one reference to the_nilfs. | 143 | * of get_nilfs() holds at least one reference to the_nilfs. |
94 | * Thus its exclusion control is not required here. | 144 | * Thus its exclusion control is not required here. |
95 | */ | 145 | */ |
146 | |||
96 | might_sleep(); | 147 | might_sleep(); |
97 | if (nilfs_loaded(nilfs)) { | 148 | if (nilfs_loaded(nilfs)) { |
98 | nilfs_mdt_clear(nilfs->ns_sufile); | 149 | nilfs_mdt_clear(nilfs->ns_sufile); |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 30fe58778d05..116caf96e7f3 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
@@ -43,6 +43,7 @@ enum { | |||
43 | * struct the_nilfs - struct to supervise multiple nilfs mount points | 43 | * struct the_nilfs - struct to supervise multiple nilfs mount points |
44 | * @ns_flags: flags | 44 | * @ns_flags: flags |
45 | * @ns_count: reference count | 45 | * @ns_count: reference count |
46 | * @ns_list: list head for nilfs_list | ||
46 | * @ns_bdev: block device | 47 | * @ns_bdev: block device |
47 | * @ns_bdi: backing dev info | 48 | * @ns_bdi: backing dev info |
48 | * @ns_writer: back pointer to writable nilfs_sb_info | 49 | * @ns_writer: back pointer to writable nilfs_sb_info |
@@ -88,6 +89,7 @@ enum { | |||
88 | struct the_nilfs { | 89 | struct the_nilfs { |
89 | unsigned long ns_flags; | 90 | unsigned long ns_flags; |
90 | atomic_t ns_count; | 91 | atomic_t ns_count; |
92 | struct list_head ns_list; | ||
91 | 93 | ||
92 | struct block_device *ns_bdev; | 94 | struct block_device *ns_bdev; |
93 | struct backing_dev_info *ns_bdi; | 95 | struct backing_dev_info *ns_bdi; |
@@ -191,7 +193,7 @@ THE_NILFS_FNS(DISCONTINUED, discontinued) | |||
191 | #define NILFS_ALTSB_FREQ 60 /* spare superblock */ | 193 | #define NILFS_ALTSB_FREQ 60 /* spare superblock */ |
192 | 194 | ||
193 | void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); | 195 | void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); |
194 | struct the_nilfs *alloc_nilfs(struct block_device *); | 196 | struct the_nilfs *find_or_create_nilfs(struct block_device *); |
195 | void put_nilfs(struct the_nilfs *); | 197 | void put_nilfs(struct the_nilfs *); |
196 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); | 198 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); |
197 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); | 199 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); |