diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/nilfs2/the_nilfs.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'fs/nilfs2/the_nilfs.c')
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 418 |
1 files changed, 154 insertions, 264 deletions
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index ba7c10c917fc..d32714094375 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/blkdev.h> | 26 | #include <linux/blkdev.h> |
27 | #include <linux/backing-dev.h> | 27 | #include <linux/backing-dev.h> |
28 | #include <linux/random.h> | ||
28 | #include <linux/crc32.h> | 29 | #include <linux/crc32.h> |
29 | #include "nilfs.h" | 30 | #include "nilfs.h" |
30 | #include "segment.h" | 31 | #include "segment.h" |
@@ -35,9 +36,6 @@ | |||
35 | #include "segbuf.h" | 36 | #include "segbuf.h" |
36 | 37 | ||
37 | 38 | ||
38 | static LIST_HEAD(nilfs_objects); | ||
39 | static DEFINE_SPINLOCK(nilfs_lock); | ||
40 | |||
41 | static int nilfs_valid_sb(struct nilfs_super_block *sbp); | 39 | static int nilfs_valid_sb(struct nilfs_super_block *sbp); |
42 | 40 | ||
43 | void nilfs_set_last_segment(struct the_nilfs *nilfs, | 41 | void nilfs_set_last_segment(struct the_nilfs *nilfs, |
@@ -61,16 +59,13 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs, | |||
61 | } | 59 | } |
62 | 60 | ||
63 | /** | 61 | /** |
64 | * alloc_nilfs - allocate the_nilfs structure | 62 | * alloc_nilfs - allocate a nilfs object |
65 | * @bdev: block device to which the_nilfs is related | 63 | * @bdev: block device to which the_nilfs is related |
66 | * | 64 | * |
67 | * alloc_nilfs() allocates memory for the_nilfs and | ||
68 | * initializes its reference count and locks. | ||
69 | * | ||
70 | * Return Value: On success, pointer to the_nilfs is returned. | 65 | * Return Value: On success, pointer to the_nilfs is returned. |
71 | * On error, NULL is returned. | 66 | * On error, NULL is returned. |
72 | */ | 67 | */ |
73 | static struct the_nilfs *alloc_nilfs(struct block_device *bdev) | 68 | struct the_nilfs *alloc_nilfs(struct block_device *bdev) |
74 | { | 69 | { |
75 | struct the_nilfs *nilfs; | 70 | struct the_nilfs *nilfs; |
76 | 71 | ||
@@ -79,103 +74,41 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
79 | return NULL; | 74 | return NULL; |
80 | 75 | ||
81 | nilfs->ns_bdev = bdev; | 76 | nilfs->ns_bdev = bdev; |
82 | atomic_set(&nilfs->ns_count, 1); | ||
83 | atomic_set(&nilfs->ns_ndirtyblks, 0); | 77 | atomic_set(&nilfs->ns_ndirtyblks, 0); |
84 | init_rwsem(&nilfs->ns_sem); | 78 | init_rwsem(&nilfs->ns_sem); |
85 | init_rwsem(&nilfs->ns_super_sem); | 79 | INIT_LIST_HEAD(&nilfs->ns_dirty_files); |
86 | mutex_init(&nilfs->ns_mount_mutex); | 80 | INIT_LIST_HEAD(&nilfs->ns_gc_inodes); |
87 | init_rwsem(&nilfs->ns_writer_sem); | 81 | spin_lock_init(&nilfs->ns_inode_lock); |
88 | INIT_LIST_HEAD(&nilfs->ns_list); | 82 | spin_lock_init(&nilfs->ns_next_gen_lock); |
89 | INIT_LIST_HEAD(&nilfs->ns_supers); | ||
90 | spin_lock_init(&nilfs->ns_last_segment_lock); | 83 | spin_lock_init(&nilfs->ns_last_segment_lock); |
91 | nilfs->ns_gc_inodes_h = NULL; | 84 | nilfs->ns_cptree = RB_ROOT; |
85 | spin_lock_init(&nilfs->ns_cptree_lock); | ||
92 | init_rwsem(&nilfs->ns_segctor_sem); | 86 | init_rwsem(&nilfs->ns_segctor_sem); |
93 | 87 | ||
94 | return nilfs; | 88 | return nilfs; |
95 | } | 89 | } |
96 | 90 | ||
97 | /** | 91 | /** |
98 | * find_or_create_nilfs - find or create nilfs object | 92 | * destroy_nilfs - destroy nilfs object |
99 | * @bdev: block device to which the_nilfs is related | 93 | * @nilfs: nilfs object to be released |
100 | * | ||
101 | * find_nilfs() looks up an existent nilfs object created on the | ||
102 | * device and gets the reference count of the object. If no nilfs object | ||
103 | * is found on the device, a new nilfs object is allocated. | ||
104 | * | ||
105 | * Return Value: On success, pointer to the nilfs object is returned. | ||
106 | * On error, NULL is returned. | ||
107 | */ | ||
108 | struct the_nilfs *find_or_create_nilfs(struct block_device *bdev) | ||
109 | { | ||
110 | struct the_nilfs *nilfs, *new = NULL; | ||
111 | |||
112 | retry: | ||
113 | spin_lock(&nilfs_lock); | ||
114 | list_for_each_entry(nilfs, &nilfs_objects, ns_list) { | ||
115 | if (nilfs->ns_bdev == bdev) { | ||
116 | get_nilfs(nilfs); | ||
117 | spin_unlock(&nilfs_lock); | ||
118 | if (new) | ||
119 | put_nilfs(new); | ||
120 | return nilfs; /* existing object */ | ||
121 | } | ||
122 | } | ||
123 | if (new) { | ||
124 | list_add_tail(&new->ns_list, &nilfs_objects); | ||
125 | spin_unlock(&nilfs_lock); | ||
126 | return new; /* new object */ | ||
127 | } | ||
128 | spin_unlock(&nilfs_lock); | ||
129 | |||
130 | new = alloc_nilfs(bdev); | ||
131 | if (new) | ||
132 | goto retry; | ||
133 | return NULL; /* insufficient memory */ | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * put_nilfs - release a reference to the_nilfs | ||
138 | * @nilfs: the_nilfs structure to be released | ||
139 | * | ||
140 | * put_nilfs() decrements a reference counter of the_nilfs. | ||
141 | * If the reference count reaches zero, the_nilfs is freed. | ||
142 | */ | 94 | */ |
143 | void put_nilfs(struct the_nilfs *nilfs) | 95 | void destroy_nilfs(struct the_nilfs *nilfs) |
144 | { | 96 | { |
145 | spin_lock(&nilfs_lock); | ||
146 | if (!atomic_dec_and_test(&nilfs->ns_count)) { | ||
147 | spin_unlock(&nilfs_lock); | ||
148 | return; | ||
149 | } | ||
150 | list_del_init(&nilfs->ns_list); | ||
151 | spin_unlock(&nilfs_lock); | ||
152 | |||
153 | /* | ||
154 | * Increment of ns_count never occurs below because the caller | ||
155 | * of get_nilfs() holds at least one reference to the_nilfs. | ||
156 | * Thus its exclusion control is not required here. | ||
157 | */ | ||
158 | |||
159 | might_sleep(); | 97 | might_sleep(); |
160 | if (nilfs_loaded(nilfs)) { | ||
161 | nilfs_mdt_destroy(nilfs->ns_sufile); | ||
162 | nilfs_mdt_destroy(nilfs->ns_cpfile); | ||
163 | nilfs_mdt_destroy(nilfs->ns_dat); | ||
164 | nilfs_mdt_destroy(nilfs->ns_gc_dat); | ||
165 | } | ||
166 | if (nilfs_init(nilfs)) { | 98 | if (nilfs_init(nilfs)) { |
167 | nilfs_destroy_gccache(nilfs); | ||
168 | brelse(nilfs->ns_sbh[0]); | 99 | brelse(nilfs->ns_sbh[0]); |
169 | brelse(nilfs->ns_sbh[1]); | 100 | brelse(nilfs->ns_sbh[1]); |
170 | } | 101 | } |
171 | kfree(nilfs); | 102 | kfree(nilfs); |
172 | } | 103 | } |
173 | 104 | ||
174 | static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) | 105 | static int nilfs_load_super_root(struct the_nilfs *nilfs, |
106 | struct super_block *sb, sector_t sr_block) | ||
175 | { | 107 | { |
176 | struct buffer_head *bh_sr; | 108 | struct buffer_head *bh_sr; |
177 | struct nilfs_super_root *raw_sr; | 109 | struct nilfs_super_root *raw_sr; |
178 | struct nilfs_super_block **sbp = nilfs->ns_sbp; | 110 | struct nilfs_super_block **sbp = nilfs->ns_sbp; |
111 | struct nilfs_inode *rawi; | ||
179 | unsigned dat_entry_size, segment_usage_size, checkpoint_size; | 112 | unsigned dat_entry_size, segment_usage_size, checkpoint_size; |
180 | unsigned inode_size; | 113 | unsigned inode_size; |
181 | int err; | 114 | int err; |
@@ -192,40 +125,22 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) | |||
192 | 125 | ||
193 | inode_size = nilfs->ns_inode_size; | 126 | inode_size = nilfs->ns_inode_size; |
194 | 127 | ||
195 | err = -ENOMEM; | 128 | rawi = (void *)bh_sr->b_data + NILFS_SR_DAT_OFFSET(inode_size); |
196 | nilfs->ns_dat = nilfs_dat_new(nilfs, dat_entry_size); | 129 | err = nilfs_dat_read(sb, dat_entry_size, rawi, &nilfs->ns_dat); |
197 | if (unlikely(!nilfs->ns_dat)) | 130 | if (err) |
198 | goto failed; | 131 | goto failed; |
199 | 132 | ||
200 | nilfs->ns_gc_dat = nilfs_dat_new(nilfs, dat_entry_size); | 133 | rawi = (void *)bh_sr->b_data + NILFS_SR_CPFILE_OFFSET(inode_size); |
201 | if (unlikely(!nilfs->ns_gc_dat)) | 134 | err = nilfs_cpfile_read(sb, checkpoint_size, rawi, &nilfs->ns_cpfile); |
135 | if (err) | ||
202 | goto failed_dat; | 136 | goto failed_dat; |
203 | 137 | ||
204 | nilfs->ns_cpfile = nilfs_cpfile_new(nilfs, checkpoint_size); | 138 | rawi = (void *)bh_sr->b_data + NILFS_SR_SUFILE_OFFSET(inode_size); |
205 | if (unlikely(!nilfs->ns_cpfile)) | 139 | err = nilfs_sufile_read(sb, segment_usage_size, rawi, |
206 | goto failed_gc_dat; | 140 | &nilfs->ns_sufile); |
207 | 141 | if (err) | |
208 | nilfs->ns_sufile = nilfs_sufile_new(nilfs, segment_usage_size); | ||
209 | if (unlikely(!nilfs->ns_sufile)) | ||
210 | goto failed_cpfile; | 142 | goto failed_cpfile; |
211 | 143 | ||
212 | nilfs_mdt_set_shadow(nilfs->ns_dat, nilfs->ns_gc_dat); | ||
213 | |||
214 | err = nilfs_dat_read(nilfs->ns_dat, (void *)bh_sr->b_data + | ||
215 | NILFS_SR_DAT_OFFSET(inode_size)); | ||
216 | if (unlikely(err)) | ||
217 | goto failed_sufile; | ||
218 | |||
219 | err = nilfs_cpfile_read(nilfs->ns_cpfile, (void *)bh_sr->b_data + | ||
220 | NILFS_SR_CPFILE_OFFSET(inode_size)); | ||
221 | if (unlikely(err)) | ||
222 | goto failed_sufile; | ||
223 | |||
224 | err = nilfs_sufile_read(nilfs->ns_sufile, (void *)bh_sr->b_data + | ||
225 | NILFS_SR_SUFILE_OFFSET(inode_size)); | ||
226 | if (unlikely(err)) | ||
227 | goto failed_sufile; | ||
228 | |||
229 | raw_sr = (struct nilfs_super_root *)bh_sr->b_data; | 144 | raw_sr = (struct nilfs_super_root *)bh_sr->b_data; |
230 | nilfs->ns_nongc_ctime = le64_to_cpu(raw_sr->sr_nongc_ctime); | 145 | nilfs->ns_nongc_ctime = le64_to_cpu(raw_sr->sr_nongc_ctime); |
231 | 146 | ||
@@ -233,17 +148,11 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) | |||
233 | brelse(bh_sr); | 148 | brelse(bh_sr); |
234 | return err; | 149 | return err; |
235 | 150 | ||
236 | failed_sufile: | ||
237 | nilfs_mdt_destroy(nilfs->ns_sufile); | ||
238 | |||
239 | failed_cpfile: | 151 | failed_cpfile: |
240 | nilfs_mdt_destroy(nilfs->ns_cpfile); | 152 | iput(nilfs->ns_cpfile); |
241 | |||
242 | failed_gc_dat: | ||
243 | nilfs_mdt_destroy(nilfs->ns_gc_dat); | ||
244 | 153 | ||
245 | failed_dat: | 154 | failed_dat: |
246 | nilfs_mdt_destroy(nilfs->ns_dat); | 155 | iput(nilfs->ns_dat); |
247 | goto failed; | 156 | goto failed; |
248 | } | 157 | } |
249 | 158 | ||
@@ -292,29 +201,20 @@ static int nilfs_store_log_cursor(struct the_nilfs *nilfs, | |||
292 | /** | 201 | /** |
293 | * load_nilfs - load and recover the nilfs | 202 | * load_nilfs - load and recover the nilfs |
294 | * @nilfs: the_nilfs structure to be released | 203 | * @nilfs: the_nilfs structure to be released |
295 | * @sbi: nilfs_sb_info used to recover past segment | 204 | * @sb: super block isntance used to recover past segment |
296 | * | 205 | * |
297 | * load_nilfs() searches and load the latest super root, | 206 | * load_nilfs() searches and load the latest super root, |
298 | * attaches the last segment, and does recovery if needed. | 207 | * attaches the last segment, and does recovery if needed. |
299 | * The caller must call this exclusively for simultaneous mounts. | 208 | * The caller must call this exclusively for simultaneous mounts. |
300 | */ | 209 | */ |
301 | int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | 210 | int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb) |
302 | { | 211 | { |
303 | struct nilfs_recovery_info ri; | 212 | struct nilfs_recovery_info ri; |
304 | unsigned int s_flags = sbi->s_super->s_flags; | 213 | unsigned int s_flags = sb->s_flags; |
305 | int really_read_only = bdev_read_only(nilfs->ns_bdev); | 214 | int really_read_only = bdev_read_only(nilfs->ns_bdev); |
306 | int valid_fs = nilfs_valid_fs(nilfs); | 215 | int valid_fs = nilfs_valid_fs(nilfs); |
307 | int err; | 216 | int err; |
308 | 217 | ||
309 | if (nilfs_loaded(nilfs)) { | ||
310 | if (valid_fs || | ||
311 | ((s_flags & MS_RDONLY) && nilfs_test_opt(sbi, NORECOVERY))) | ||
312 | return 0; | ||
313 | printk(KERN_ERR "NILFS: the filesystem is in an incomplete " | ||
314 | "recovery state.\n"); | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | if (!valid_fs) { | 218 | if (!valid_fs) { |
319 | printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n"); | 219 | printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n"); |
320 | if (s_flags & MS_RDONLY) { | 220 | if (s_flags & MS_RDONLY) { |
@@ -375,7 +275,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
375 | goto scan_error; | 275 | goto scan_error; |
376 | } | 276 | } |
377 | 277 | ||
378 | err = nilfs_load_super_root(nilfs, ri.ri_super_root); | 278 | err = nilfs_load_super_root(nilfs, sb, ri.ri_super_root); |
379 | if (unlikely(err)) { | 279 | if (unlikely(err)) { |
380 | printk(KERN_ERR "NILFS: error loading super root.\n"); | 280 | printk(KERN_ERR "NILFS: error loading super root.\n"); |
381 | goto failed; | 281 | goto failed; |
@@ -387,7 +287,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
387 | if (s_flags & MS_RDONLY) { | 287 | if (s_flags & MS_RDONLY) { |
388 | __u64 features; | 288 | __u64 features; |
389 | 289 | ||
390 | if (nilfs_test_opt(sbi, NORECOVERY)) { | 290 | if (nilfs_test_opt(nilfs, NORECOVERY)) { |
391 | printk(KERN_INFO "NILFS: norecovery option specified. " | 291 | printk(KERN_INFO "NILFS: norecovery option specified. " |
392 | "skipping roll-forward recovery\n"); | 292 | "skipping roll-forward recovery\n"); |
393 | goto skip_recovery; | 293 | goto skip_recovery; |
@@ -408,21 +308,21 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
408 | err = -EROFS; | 308 | err = -EROFS; |
409 | goto failed_unload; | 309 | goto failed_unload; |
410 | } | 310 | } |
411 | sbi->s_super->s_flags &= ~MS_RDONLY; | 311 | sb->s_flags &= ~MS_RDONLY; |
412 | } else if (nilfs_test_opt(sbi, NORECOVERY)) { | 312 | } else if (nilfs_test_opt(nilfs, NORECOVERY)) { |
413 | printk(KERN_ERR "NILFS: recovery cancelled because norecovery " | 313 | printk(KERN_ERR "NILFS: recovery cancelled because norecovery " |
414 | "option was specified for a read/write mount\n"); | 314 | "option was specified for a read/write mount\n"); |
415 | err = -EINVAL; | 315 | err = -EINVAL; |
416 | goto failed_unload; | 316 | goto failed_unload; |
417 | } | 317 | } |
418 | 318 | ||
419 | err = nilfs_salvage_orphan_logs(nilfs, sbi, &ri); | 319 | err = nilfs_salvage_orphan_logs(nilfs, sb, &ri); |
420 | if (err) | 320 | if (err) |
421 | goto failed_unload; | 321 | goto failed_unload; |
422 | 322 | ||
423 | down_write(&nilfs->ns_sem); | 323 | down_write(&nilfs->ns_sem); |
424 | nilfs->ns_mount_state |= NILFS_VALID_FS; /* set "clean" flag */ | 324 | nilfs->ns_mount_state |= NILFS_VALID_FS; /* set "clean" flag */ |
425 | err = nilfs_cleanup_super(sbi); | 325 | err = nilfs_cleanup_super(sb); |
426 | up_write(&nilfs->ns_sem); | 326 | up_write(&nilfs->ns_sem); |
427 | 327 | ||
428 | if (err) { | 328 | if (err) { |
@@ -433,9 +333,8 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
433 | printk(KERN_INFO "NILFS: recovery complete.\n"); | 333 | printk(KERN_INFO "NILFS: recovery complete.\n"); |
434 | 334 | ||
435 | skip_recovery: | 335 | skip_recovery: |
436 | set_nilfs_loaded(nilfs); | ||
437 | nilfs_clear_recovery_info(&ri); | 336 | nilfs_clear_recovery_info(&ri); |
438 | sbi->s_super->s_flags = s_flags; | 337 | sb->s_flags = s_flags; |
439 | return 0; | 338 | return 0; |
440 | 339 | ||
441 | scan_error: | 340 | scan_error: |
@@ -443,14 +342,13 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
443 | goto failed; | 342 | goto failed; |
444 | 343 | ||
445 | failed_unload: | 344 | failed_unload: |
446 | nilfs_mdt_destroy(nilfs->ns_cpfile); | 345 | iput(nilfs->ns_cpfile); |
447 | nilfs_mdt_destroy(nilfs->ns_sufile); | 346 | iput(nilfs->ns_sufile); |
448 | nilfs_mdt_destroy(nilfs->ns_dat); | 347 | iput(nilfs->ns_dat); |
449 | nilfs_mdt_destroy(nilfs->ns_gc_dat); | ||
450 | 348 | ||
451 | failed: | 349 | failed: |
452 | nilfs_clear_recovery_info(&ri); | 350 | nilfs_clear_recovery_info(&ri); |
453 | sbi->s_super->s_flags = s_flags; | 351 | sb->s_flags = s_flags; |
454 | return err; | 352 | return err; |
455 | } | 353 | } |
456 | 354 | ||
@@ -465,11 +363,29 @@ static unsigned long long nilfs_max_size(unsigned int blkbits) | |||
465 | return res; | 363 | return res; |
466 | } | 364 | } |
467 | 365 | ||
366 | /** | ||
367 | * nilfs_nrsvsegs - calculate the number of reserved segments | ||
368 | * @nilfs: nilfs object | ||
369 | * @nsegs: total number of segments | ||
370 | */ | ||
371 | unsigned long nilfs_nrsvsegs(struct the_nilfs *nilfs, unsigned long nsegs) | ||
372 | { | ||
373 | return max_t(unsigned long, NILFS_MIN_NRSVSEGS, | ||
374 | DIV_ROUND_UP(nsegs * nilfs->ns_r_segments_percentage, | ||
375 | 100)); | ||
376 | } | ||
377 | |||
378 | void nilfs_set_nsegments(struct the_nilfs *nilfs, unsigned long nsegs) | ||
379 | { | ||
380 | nilfs->ns_nsegments = nsegs; | ||
381 | nilfs->ns_nrsvsegs = nilfs_nrsvsegs(nilfs, nsegs); | ||
382 | } | ||
383 | |||
468 | static int nilfs_store_disk_layout(struct the_nilfs *nilfs, | 384 | static int nilfs_store_disk_layout(struct the_nilfs *nilfs, |
469 | struct nilfs_super_block *sbp) | 385 | struct nilfs_super_block *sbp) |
470 | { | 386 | { |
471 | if (le32_to_cpu(sbp->s_rev_level) != NILFS_CURRENT_REV) { | 387 | if (le32_to_cpu(sbp->s_rev_level) < NILFS_MIN_SUPP_REV) { |
472 | printk(KERN_ERR "NILFS: revision mismatch " | 388 | printk(KERN_ERR "NILFS: unsupported revision " |
473 | "(superblock rev.=%d.%d, current rev.=%d.%d). " | 389 | "(superblock rev.=%d.%d, current rev.=%d.%d). " |
474 | "Please check the version of mkfs.nilfs.\n", | 390 | "Please check the version of mkfs.nilfs.\n", |
475 | le32_to_cpu(sbp->s_rev_level), | 391 | le32_to_cpu(sbp->s_rev_level), |
@@ -491,13 +407,9 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs, | |||
491 | } | 407 | } |
492 | 408 | ||
493 | nilfs->ns_first_data_block = le64_to_cpu(sbp->s_first_data_block); | 409 | nilfs->ns_first_data_block = le64_to_cpu(sbp->s_first_data_block); |
494 | nilfs->ns_nsegments = le64_to_cpu(sbp->s_nsegments); | ||
495 | nilfs->ns_r_segments_percentage = | 410 | nilfs->ns_r_segments_percentage = |
496 | le32_to_cpu(sbp->s_r_segments_percentage); | 411 | le32_to_cpu(sbp->s_r_segments_percentage); |
497 | nilfs->ns_nrsvsegs = | 412 | nilfs_set_nsegments(nilfs, le64_to_cpu(sbp->s_nsegments)); |
498 | max_t(unsigned long, NILFS_MIN_NRSVSEGS, | ||
499 | DIV_ROUND_UP(nilfs->ns_nsegments * | ||
500 | nilfs->ns_r_segments_percentage, 100)); | ||
501 | nilfs->ns_crc_seed = le32_to_cpu(sbp->s_crc_seed); | 413 | nilfs->ns_crc_seed = le32_to_cpu(sbp->s_crc_seed); |
502 | return 0; | 414 | return 0; |
503 | } | 415 | } |
@@ -581,10 +493,13 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, | |||
581 | return -EIO; | 493 | return -EIO; |
582 | } | 494 | } |
583 | printk(KERN_WARNING | 495 | printk(KERN_WARNING |
584 | "NILFS warning: unable to read primary superblock\n"); | 496 | "NILFS warning: unable to read primary superblock " |
585 | } else if (!sbp[1]) | 497 | "(blocksize = %d)\n", blocksize); |
498 | } else if (!sbp[1]) { | ||
586 | printk(KERN_WARNING | 499 | printk(KERN_WARNING |
587 | "NILFS warning: unable to read secondary superblock\n"); | 500 | "NILFS warning: unable to read secondary superblock " |
501 | "(blocksize = %d)\n", blocksize); | ||
502 | } | ||
588 | 503 | ||
589 | /* | 504 | /* |
590 | * Compare two super blocks and set 1 in swp if the secondary | 505 | * Compare two super blocks and set 1 in swp if the secondary |
@@ -611,7 +526,7 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, | |||
611 | 526 | ||
612 | if (!valid[!swp]) | 527 | if (!valid[!swp]) |
613 | printk(KERN_WARNING "NILFS warning: broken superblock. " | 528 | printk(KERN_WARNING "NILFS warning: broken superblock. " |
614 | "using spare superblock.\n"); | 529 | "using spare superblock (blocksize = %d).\n", blocksize); |
615 | if (swp) | 530 | if (swp) |
616 | nilfs_swap_super_block(nilfs); | 531 | nilfs_swap_super_block(nilfs); |
617 | 532 | ||
@@ -625,52 +540,23 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, | |||
625 | /** | 540 | /** |
626 | * init_nilfs - initialize a NILFS instance. | 541 | * init_nilfs - initialize a NILFS instance. |
627 | * @nilfs: the_nilfs structure | 542 | * @nilfs: the_nilfs structure |
628 | * @sbi: nilfs_sb_info | ||
629 | * @sb: super block | 543 | * @sb: super block |
630 | * @data: mount options | 544 | * @data: mount options |
631 | * | 545 | * |
632 | * init_nilfs() performs common initialization per block device (e.g. | 546 | * init_nilfs() performs common initialization per block device (e.g. |
633 | * reading the super block, getting disk layout information, initializing | 547 | * reading the super block, getting disk layout information, initializing |
634 | * shared fields in the_nilfs). It takes on some portion of the jobs | 548 | * shared fields in the_nilfs). |
635 | * typically done by a fill_super() routine. This division arises from | ||
636 | * the nature that multiple NILFS instances may be simultaneously | ||
637 | * mounted on a device. | ||
638 | * For multiple mounts on the same device, only the first mount | ||
639 | * invokes these tasks. | ||
640 | * | 549 | * |
641 | * Return Value: On success, 0 is returned. On error, a negative error | 550 | * Return Value: On success, 0 is returned. On error, a negative error |
642 | * code is returned. | 551 | * code is returned. |
643 | */ | 552 | */ |
644 | int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | 553 | int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb, char *data) |
645 | { | 554 | { |
646 | struct super_block *sb = sbi->s_super; | ||
647 | struct nilfs_super_block *sbp; | 555 | struct nilfs_super_block *sbp; |
648 | struct backing_dev_info *bdi; | ||
649 | int blocksize; | 556 | int blocksize; |
650 | int err; | 557 | int err; |
651 | 558 | ||
652 | down_write(&nilfs->ns_sem); | 559 | down_write(&nilfs->ns_sem); |
653 | if (nilfs_init(nilfs)) { | ||
654 | /* Load values from existing the_nilfs */ | ||
655 | sbp = nilfs->ns_sbp[0]; | ||
656 | err = nilfs_store_magic_and_option(sb, sbp, data); | ||
657 | if (err) | ||
658 | goto out; | ||
659 | |||
660 | err = nilfs_check_feature_compatibility(sb, sbp); | ||
661 | if (err) | ||
662 | goto out; | ||
663 | |||
664 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); | ||
665 | if (sb->s_blocksize != blocksize && | ||
666 | !sb_set_blocksize(sb, blocksize)) { | ||
667 | printk(KERN_ERR "NILFS: blocksize %d unfit to device\n", | ||
668 | blocksize); | ||
669 | err = -EINVAL; | ||
670 | } | ||
671 | sb->s_maxbytes = nilfs_max_size(sb->s_blocksize_bits); | ||
672 | goto out; | ||
673 | } | ||
674 | 560 | ||
675 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); | 561 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); |
676 | if (!blocksize) { | 562 | if (!blocksize) { |
@@ -721,6 +607,9 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
721 | nilfs->ns_blocksize_bits = sb->s_blocksize_bits; | 607 | nilfs->ns_blocksize_bits = sb->s_blocksize_bits; |
722 | nilfs->ns_blocksize = blocksize; | 608 | nilfs->ns_blocksize = blocksize; |
723 | 609 | ||
610 | get_random_bytes(&nilfs->ns_next_generation, | ||
611 | sizeof(nilfs->ns_next_generation)); | ||
612 | |||
724 | err = nilfs_store_disk_layout(nilfs, sbp); | 613 | err = nilfs_store_disk_layout(nilfs, sbp); |
725 | if (err) | 614 | if (err) |
726 | goto failed_sbh; | 615 | goto failed_sbh; |
@@ -729,18 +618,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
729 | 618 | ||
730 | nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); | 619 | nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); |
731 | 620 | ||
732 | bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info; | ||
733 | nilfs->ns_bdi = bdi ? : &default_backing_dev_info; | ||
734 | |||
735 | err = nilfs_store_log_cursor(nilfs, sbp); | 621 | err = nilfs_store_log_cursor(nilfs, sbp); |
736 | if (err) | 622 | if (err) |
737 | goto failed_sbh; | 623 | goto failed_sbh; |
738 | 624 | ||
739 | /* Initialize gcinode cache */ | ||
740 | err = nilfs_init_gccache(nilfs); | ||
741 | if (err) | ||
742 | goto failed_sbh; | ||
743 | |||
744 | set_nilfs_init(nilfs); | 625 | set_nilfs_init(nilfs); |
745 | err = 0; | 626 | err = 0; |
746 | out: | 627 | out: |
@@ -775,9 +656,7 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump, | |||
775 | ret = blkdev_issue_discard(nilfs->ns_bdev, | 656 | ret = blkdev_issue_discard(nilfs->ns_bdev, |
776 | start * sects_per_block, | 657 | start * sects_per_block, |
777 | nblocks * sects_per_block, | 658 | nblocks * sects_per_block, |
778 | GFP_NOFS, | 659 | GFP_NOFS, 0); |
779 | BLKDEV_IFL_WAIT | | ||
780 | BLKDEV_IFL_BARRIER); | ||
781 | if (ret < 0) | 660 | if (ret < 0) |
782 | return ret; | 661 | return ret; |
783 | nblocks = 0; | 662 | nblocks = 0; |
@@ -787,19 +666,17 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump, | |||
787 | ret = blkdev_issue_discard(nilfs->ns_bdev, | 666 | ret = blkdev_issue_discard(nilfs->ns_bdev, |
788 | start * sects_per_block, | 667 | start * sects_per_block, |
789 | nblocks * sects_per_block, | 668 | nblocks * sects_per_block, |
790 | GFP_NOFS, | 669 | GFP_NOFS, 0); |
791 | BLKDEV_IFL_WAIT | BLKDEV_IFL_BARRIER); | ||
792 | return ret; | 670 | return ret; |
793 | } | 671 | } |
794 | 672 | ||
795 | int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks) | 673 | int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks) |
796 | { | 674 | { |
797 | struct inode *dat = nilfs_dat_inode(nilfs); | ||
798 | unsigned long ncleansegs; | 675 | unsigned long ncleansegs; |
799 | 676 | ||
800 | down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 677 | down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); |
801 | ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile); | 678 | ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile); |
802 | up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 679 | up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); |
803 | *nblocks = (sector_t)ncleansegs * nilfs->ns_blocks_per_segment; | 680 | *nblocks = (sector_t)ncleansegs * nilfs->ns_blocks_per_segment; |
804 | return 0; | 681 | return 0; |
805 | } | 682 | } |
@@ -815,79 +692,92 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs) | |||
815 | return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs; | 692 | return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs; |
816 | } | 693 | } |
817 | 694 | ||
818 | /** | 695 | struct nilfs_root *nilfs_lookup_root(struct the_nilfs *nilfs, __u64 cno) |
819 | * nilfs_find_sbinfo - find existing nilfs_sb_info structure | ||
820 | * @nilfs: nilfs object | ||
821 | * @rw_mount: mount type (non-zero value for read/write mount) | ||
822 | * @cno: checkpoint number (zero for read-only mount) | ||
823 | * | ||
824 | * nilfs_find_sbinfo() returns the nilfs_sb_info structure which | ||
825 | * @rw_mount and @cno (in case of snapshots) matched. If no instance | ||
826 | * was found, NULL is returned. Although the super block instance can | ||
827 | * be unmounted after this function returns, the nilfs_sb_info struct | ||
828 | * is kept on memory until nilfs_put_sbinfo() is called. | ||
829 | */ | ||
830 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs, | ||
831 | int rw_mount, __u64 cno) | ||
832 | { | 696 | { |
833 | struct nilfs_sb_info *sbi; | 697 | struct rb_node *n; |
834 | 698 | struct nilfs_root *root; | |
835 | down_read(&nilfs->ns_super_sem); | 699 | |
836 | /* | 700 | spin_lock(&nilfs->ns_cptree_lock); |
837 | * The SNAPSHOT flag and sb->s_flags are supposed to be | 701 | n = nilfs->ns_cptree.rb_node; |
838 | * protected with nilfs->ns_super_sem. | 702 | while (n) { |
839 | */ | 703 | root = rb_entry(n, struct nilfs_root, rb_node); |
840 | sbi = nilfs->ns_current; | 704 | |
841 | if (rw_mount) { | 705 | if (cno < root->cno) { |
842 | if (sbi && !(sbi->s_super->s_flags & MS_RDONLY)) | 706 | n = n->rb_left; |
843 | goto found; /* read/write mount */ | 707 | } else if (cno > root->cno) { |
844 | else | 708 | n = n->rb_right; |
845 | goto out; | 709 | } else { |
846 | } else if (cno == 0) { | 710 | atomic_inc(&root->count); |
847 | if (sbi && (sbi->s_super->s_flags & MS_RDONLY)) | 711 | spin_unlock(&nilfs->ns_cptree_lock); |
848 | goto found; /* read-only mount */ | 712 | return root; |
849 | else | 713 | } |
850 | goto out; | ||
851 | } | 714 | } |
715 | spin_unlock(&nilfs->ns_cptree_lock); | ||
852 | 716 | ||
853 | list_for_each_entry(sbi, &nilfs->ns_supers, s_list) { | ||
854 | if (nilfs_test_opt(sbi, SNAPSHOT) && | ||
855 | sbi->s_snapshot_cno == cno) | ||
856 | goto found; /* snapshot mount */ | ||
857 | } | ||
858 | out: | ||
859 | up_read(&nilfs->ns_super_sem); | ||
860 | return NULL; | 717 | return NULL; |
861 | |||
862 | found: | ||
863 | atomic_inc(&sbi->s_count); | ||
864 | up_read(&nilfs->ns_super_sem); | ||
865 | return sbi; | ||
866 | } | 718 | } |
867 | 719 | ||
868 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, | 720 | struct nilfs_root * |
869 | int snapshot_mount) | 721 | nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) |
870 | { | 722 | { |
871 | struct nilfs_sb_info *sbi; | 723 | struct rb_node **p, *parent; |
872 | int ret = 0; | 724 | struct nilfs_root *root, *new; |
725 | |||
726 | root = nilfs_lookup_root(nilfs, cno); | ||
727 | if (root) | ||
728 | return root; | ||
729 | |||
730 | new = kmalloc(sizeof(*root), GFP_KERNEL); | ||
731 | if (!new) | ||
732 | return NULL; | ||
733 | |||
734 | spin_lock(&nilfs->ns_cptree_lock); | ||
873 | 735 | ||
874 | down_read(&nilfs->ns_super_sem); | 736 | p = &nilfs->ns_cptree.rb_node; |
875 | if (cno == 0 || cno > nilfs->ns_cno) | 737 | parent = NULL; |
876 | goto out_unlock; | ||
877 | 738 | ||
878 | list_for_each_entry(sbi, &nilfs->ns_supers, s_list) { | 739 | while (*p) { |
879 | if (sbi->s_snapshot_cno == cno && | 740 | parent = *p; |
880 | (!snapshot_mount || nilfs_test_opt(sbi, SNAPSHOT))) { | 741 | root = rb_entry(parent, struct nilfs_root, rb_node); |
881 | /* exclude read-only mounts */ | 742 | |
882 | ret++; | 743 | if (cno < root->cno) { |
883 | break; | 744 | p = &(*p)->rb_left; |
745 | } else if (cno > root->cno) { | ||
746 | p = &(*p)->rb_right; | ||
747 | } else { | ||
748 | atomic_inc(&root->count); | ||
749 | spin_unlock(&nilfs->ns_cptree_lock); | ||
750 | kfree(new); | ||
751 | return root; | ||
884 | } | 752 | } |
885 | } | 753 | } |
886 | /* for protecting recent checkpoints */ | ||
887 | if (cno >= nilfs_last_cno(nilfs)) | ||
888 | ret++; | ||
889 | 754 | ||
890 | out_unlock: | 755 | new->cno = cno; |
891 | up_read(&nilfs->ns_super_sem); | 756 | new->ifile = NULL; |
892 | return ret; | 757 | new->nilfs = nilfs; |
758 | atomic_set(&new->count, 1); | ||
759 | atomic_set(&new->inodes_count, 0); | ||
760 | atomic_set(&new->blocks_count, 0); | ||
761 | |||
762 | rb_link_node(&new->rb_node, parent, p); | ||
763 | rb_insert_color(&new->rb_node, &nilfs->ns_cptree); | ||
764 | |||
765 | spin_unlock(&nilfs->ns_cptree_lock); | ||
766 | |||
767 | return new; | ||
768 | } | ||
769 | |||
770 | void nilfs_put_root(struct nilfs_root *root) | ||
771 | { | ||
772 | if (atomic_dec_and_test(&root->count)) { | ||
773 | struct the_nilfs *nilfs = root->nilfs; | ||
774 | |||
775 | spin_lock(&nilfs->ns_cptree_lock); | ||
776 | rb_erase(&root->rb_node, &nilfs->ns_cptree); | ||
777 | spin_unlock(&nilfs->ns_cptree_lock); | ||
778 | if (root->ifile) | ||
779 | iput(root->ifile); | ||
780 | |||
781 | kfree(root); | ||
782 | } | ||
893 | } | 783 | } |