diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2009-04-06 22:01:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-07 11:31:19 -0400 |
commit | 2c2e52fc4fca251e68f90821c9ff5cb18be4df58 (patch) | |
tree | fb0b86203bb5f4dda4d5907e29bd2b1b6cc0be90 /fs/nilfs2 | |
parent | 7a9461939a46345860622ea36ff267ee4446f00f (diff) |
nilfs2: extend nilfs_sustat ioctl struct
This adds a new argument to the nilfs_sustat structure.
The extended field allows to delete volatile active state of segments,
which was needed to protect freshly-created segments from garbage
collection but has confused code dealing with segments. This
extension alleviates the mess and gives room for further
simplifications.
The volatile active flag is not persistent, so it's eliminable on this
occasion without affecting compatibility other than the ioctl change.
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/nilfs2')
-rw-r--r-- | fs/nilfs2/recovery.c | 32 | ||||
-rw-r--r-- | fs/nilfs2/segment.c | 39 | ||||
-rw-r--r-- | fs/nilfs2/sufile.c | 8 | ||||
-rw-r--r-- | fs/nilfs2/super.c | 4 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 18 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.h | 5 |
6 files changed, 37 insertions, 69 deletions
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index 877dc1ba23f3..a4253f34e138 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c | |||
@@ -416,6 +416,7 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, | |||
416 | struct nilfs_segment_entry *ent, *n; | 416 | struct nilfs_segment_entry *ent, *n; |
417 | struct inode *sufile = nilfs->ns_sufile; | 417 | struct inode *sufile = nilfs->ns_sufile; |
418 | __u64 segnum[4]; | 418 | __u64 segnum[4]; |
419 | time_t mtime; | ||
419 | int err; | 420 | int err; |
420 | int i; | 421 | int i; |
421 | 422 | ||
@@ -442,9 +443,9 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, | |||
442 | 443 | ||
443 | /* | 444 | /* |
444 | * Collecting segments written after the latest super root. | 445 | * Collecting segments written after the latest super root. |
445 | * These are marked volatile active, and won't be reallocated in | 446 | * These are marked dirty to avoid being reallocated in the next write. |
446 | * the next construction. | ||
447 | */ | 447 | */ |
448 | mtime = get_seconds(); | ||
448 | list_for_each_entry_safe(ent, n, head, list) { | 449 | list_for_each_entry_safe(ent, n, head, list) { |
449 | if (ent->segnum == segnum[0]) { | 450 | if (ent->segnum == segnum[0]) { |
450 | list_del(&ent->list); | 451 | list_del(&ent->list); |
@@ -454,17 +455,16 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, | |||
454 | err = nilfs_open_segment_entry(ent, sufile); | 455 | err = nilfs_open_segment_entry(ent, sufile); |
455 | if (unlikely(err)) | 456 | if (unlikely(err)) |
456 | goto failed; | 457 | goto failed; |
457 | if (nilfs_segment_usage_clean(ent->raw_su)) { | 458 | if (!nilfs_segment_usage_dirty(ent->raw_su)) { |
458 | nilfs_segment_usage_set_volatile_active(ent->raw_su); | 459 | /* make the segment garbage */ |
459 | /* Keep it open */ | 460 | ent->raw_su->su_nblocks = cpu_to_le32(0); |
460 | } else { | 461 | ent->raw_su->su_lastmod = cpu_to_le32(mtime); |
461 | /* Removing duplicated entries */ | 462 | nilfs_segment_usage_set_dirty(ent->raw_su); |
462 | list_del(&ent->list); | ||
463 | nilfs_close_segment_entry(ent, sufile); | ||
464 | nilfs_free_segment_entry(ent); | ||
465 | } | 463 | } |
464 | list_del(&ent->list); | ||
465 | nilfs_close_segment_entry(ent, sufile); | ||
466 | nilfs_free_segment_entry(ent); | ||
466 | } | 467 | } |
467 | list_splice_init(head, nilfs->ns_used_segments.prev); | ||
468 | 468 | ||
469 | /* | 469 | /* |
470 | * The segment having the latest super root is active, and | 470 | * The segment having the latest super root is active, and |
@@ -882,10 +882,12 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, | |||
882 | 882 | ||
883 | if (scan_newer) | 883 | if (scan_newer) |
884 | ri->ri_need_recovery = NILFS_RECOVERY_SR_UPDATED; | 884 | ri->ri_need_recovery = NILFS_RECOVERY_SR_UPDATED; |
885 | else if (nilfs->ns_mount_state & NILFS_VALID_FS) | 885 | else { |
886 | goto super_root_found; | 886 | nilfs->ns_prot_seq = ssi.seg_seq; |
887 | 887 | if (nilfs->ns_mount_state & NILFS_VALID_FS) | |
888 | scan_newer = 1; | 888 | goto super_root_found; |
889 | scan_newer = 1; | ||
890 | } | ||
889 | 891 | ||
890 | /* reset region for roll-forward */ | 892 | /* reset region for roll-forward */ |
891 | pseg_start += ssi.nblocks; | 893 | pseg_start += ssi.nblocks; |
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 5db12d774a03..24d0fbd4271c 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
@@ -2229,13 +2229,6 @@ static void nilfs_segctor_reactivate_segments(struct nilfs_sc_info *sci, | |||
2229 | nilfs_segment_usage_set_active(ent->raw_su); | 2229 | nilfs_segment_usage_set_active(ent->raw_su); |
2230 | nilfs_close_segment_entry(ent, sufile); | 2230 | nilfs_close_segment_entry(ent, sufile); |
2231 | } | 2231 | } |
2232 | |||
2233 | down_write(&nilfs->ns_sem); | ||
2234 | head = &nilfs->ns_used_segments; | ||
2235 | list_for_each_entry(ent, head, list) { | ||
2236 | nilfs_segment_usage_set_volatile_active(ent->raw_su); | ||
2237 | } | ||
2238 | up_write(&nilfs->ns_sem); | ||
2239 | } | 2232 | } |
2240 | 2233 | ||
2241 | static int nilfs_segctor_deactivate_segments(struct nilfs_sc_info *sci, | 2234 | static int nilfs_segctor_deactivate_segments(struct nilfs_sc_info *sci, |
@@ -2244,7 +2237,6 @@ static int nilfs_segctor_deactivate_segments(struct nilfs_sc_info *sci, | |||
2244 | struct nilfs_segment_buffer *segbuf, *last; | 2237 | struct nilfs_segment_buffer *segbuf, *last; |
2245 | struct nilfs_segment_entry *ent; | 2238 | struct nilfs_segment_entry *ent; |
2246 | struct inode *sufile = nilfs->ns_sufile; | 2239 | struct inode *sufile = nilfs->ns_sufile; |
2247 | struct list_head *head; | ||
2248 | int err; | 2240 | int err; |
2249 | 2241 | ||
2250 | last = NILFS_LAST_SEGBUF(&sci->sc_segbufs); | 2242 | last = NILFS_LAST_SEGBUF(&sci->sc_segbufs); |
@@ -2265,22 +2257,13 @@ static int nilfs_segctor_deactivate_segments(struct nilfs_sc_info *sci, | |||
2265 | BUG_ON(!buffer_dirty(ent->bh_su)); | 2257 | BUG_ON(!buffer_dirty(ent->bh_su)); |
2266 | } | 2258 | } |
2267 | 2259 | ||
2268 | head = &sci->sc_active_segments; | 2260 | list_for_each_entry(ent, &sci->sc_active_segments, list) { |
2269 | list_for_each_entry(ent, head, list) { | ||
2270 | err = nilfs_open_segment_entry(ent, sufile); | 2261 | err = nilfs_open_segment_entry(ent, sufile); |
2271 | if (unlikely(err)) | 2262 | if (unlikely(err)) |
2272 | goto failed; | 2263 | goto failed; |
2273 | nilfs_segment_usage_clear_active(ent->raw_su); | 2264 | nilfs_segment_usage_clear_active(ent->raw_su); |
2274 | BUG_ON(!buffer_dirty(ent->bh_su)); | 2265 | BUG_ON(!buffer_dirty(ent->bh_su)); |
2275 | } | 2266 | } |
2276 | |||
2277 | down_write(&nilfs->ns_sem); | ||
2278 | head = &nilfs->ns_used_segments; | ||
2279 | list_for_each_entry(ent, head, list) { | ||
2280 | /* clear volatile active for segments of older generations */ | ||
2281 | nilfs_segment_usage_clear_volatile_active(ent->raw_su); | ||
2282 | } | ||
2283 | up_write(&nilfs->ns_sem); | ||
2284 | return 0; | 2267 | return 0; |
2285 | 2268 | ||
2286 | failed: | 2269 | failed: |
@@ -2304,19 +2287,15 @@ static void nilfs_segctor_bead_completed_segments(struct nilfs_sc_info *sci) | |||
2304 | } | 2287 | } |
2305 | } | 2288 | } |
2306 | 2289 | ||
2307 | static void | 2290 | static void nilfs_segctor_commit_deactivate_segments(struct nilfs_sc_info *sci, |
2308 | __nilfs_segctor_commit_deactivate_segments(struct nilfs_sc_info *sci, | 2291 | struct the_nilfs *nilfs) |
2309 | struct the_nilfs *nilfs) | ||
2310 | |||
2311 | { | 2292 | { |
2312 | struct nilfs_segment_entry *ent; | 2293 | struct nilfs_segment_entry *ent, *n; |
2313 | |||
2314 | list_splice_init(&sci->sc_active_segments, | ||
2315 | nilfs->ns_used_segments.prev); | ||
2316 | 2294 | ||
2317 | list_for_each_entry(ent, &nilfs->ns_used_segments, list) { | 2295 | list_for_each_entry_safe(ent, n, &sci->sc_active_segments, list) { |
2318 | nilfs_segment_usage_set_volatile_active(ent->raw_su); | 2296 | list_del(&ent->list); |
2319 | /* These segments are kept open */ | 2297 | nilfs_close_segment_entry(ent, nilfs->ns_sufile); |
2298 | nilfs_free_segment_entry(ent); | ||
2320 | } | 2299 | } |
2321 | } | 2300 | } |
2322 | 2301 | ||
@@ -2405,8 +2384,8 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) | |||
2405 | if (has_sr) { | 2384 | if (has_sr) { |
2406 | down_write(&nilfs->ns_sem); | 2385 | down_write(&nilfs->ns_sem); |
2407 | nilfs_update_last_segment(sbi, 1); | 2386 | nilfs_update_last_segment(sbi, 1); |
2408 | __nilfs_segctor_commit_deactivate_segments(sci, nilfs); | ||
2409 | up_write(&nilfs->ns_sem); | 2387 | up_write(&nilfs->ns_sem); |
2388 | nilfs_segctor_commit_deactivate_segments(sci, nilfs); | ||
2410 | nilfs_segctor_commit_free_segments(sci); | 2389 | nilfs_segctor_commit_free_segments(sci); |
2411 | nilfs_segctor_clear_metadata_dirty(sci); | 2390 | nilfs_segctor_clear_metadata_dirty(sci); |
2412 | } | 2391 | } |
diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index b3674a8162a1..cc714c72b138 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c | |||
@@ -446,6 +446,7 @@ int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat) | |||
446 | { | 446 | { |
447 | struct buffer_head *header_bh; | 447 | struct buffer_head *header_bh; |
448 | struct nilfs_sufile_header *header; | 448 | struct nilfs_sufile_header *header; |
449 | struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; | ||
449 | void *kaddr; | 450 | void *kaddr; |
450 | int ret; | 451 | int ret; |
451 | 452 | ||
@@ -460,8 +461,11 @@ int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat) | |||
460 | sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile); | 461 | sustat->ss_nsegs = nilfs_sufile_get_nsegments(sufile); |
461 | sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs); | 462 | sustat->ss_ncleansegs = le64_to_cpu(header->sh_ncleansegs); |
462 | sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs); | 463 | sustat->ss_ndirtysegs = le64_to_cpu(header->sh_ndirtysegs); |
463 | sustat->ss_ctime = NILFS_MDT(sufile)->mi_nilfs->ns_ctime; | 464 | sustat->ss_ctime = nilfs->ns_ctime; |
464 | sustat->ss_nongc_ctime = NILFS_MDT(sufile)->mi_nilfs->ns_nongc_ctime; | 465 | sustat->ss_nongc_ctime = nilfs->ns_nongc_ctime; |
466 | spin_lock(&nilfs->ns_last_segment_lock); | ||
467 | sustat->ss_prot_seq = nilfs->ns_prot_seq; | ||
468 | spin_unlock(&nilfs->ns_last_segment_lock); | ||
465 | kunmap_atomic(kaddr, KM_USER0); | 469 | kunmap_atomic(kaddr, KM_USER0); |
466 | brelse(header_bh); | 470 | brelse(header_bh); |
467 | 471 | ||
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 268b563d215a..2f0e9f7bf152 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -262,8 +262,10 @@ static int nilfs_sync_super(struct nilfs_sb_info *sbi) | |||
262 | printk(KERN_ERR | 262 | printk(KERN_ERR |
263 | "NILFS: unable to write superblock (err=%d)\n", err); | 263 | "NILFS: unable to write superblock (err=%d)\n", err); |
264 | else { | 264 | else { |
265 | nilfs_dispose_used_segments(nilfs); | ||
266 | clear_nilfs_discontinued(nilfs); | 265 | clear_nilfs_discontinued(nilfs); |
266 | spin_lock(&nilfs->ns_last_segment_lock); | ||
267 | nilfs->ns_prot_seq = le64_to_cpu(nilfs->ns_sbp->s_last_seq); | ||
268 | spin_unlock(&nilfs->ns_last_segment_lock); | ||
267 | } | 269 | } |
268 | 270 | ||
269 | return err; | 271 | return err; |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 69b625586226..661ab762d765 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -71,7 +71,6 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
71 | INIT_LIST_HEAD(&nilfs->ns_supers); | 71 | INIT_LIST_HEAD(&nilfs->ns_supers); |
72 | spin_lock_init(&nilfs->ns_last_segment_lock); | 72 | spin_lock_init(&nilfs->ns_last_segment_lock); |
73 | nilfs->ns_gc_inodes_h = NULL; | 73 | nilfs->ns_gc_inodes_h = NULL; |
74 | INIT_LIST_HEAD(&nilfs->ns_used_segments); | ||
75 | init_rwsem(&nilfs->ns_segctor_sem); | 74 | init_rwsem(&nilfs->ns_segctor_sem); |
76 | 75 | ||
77 | return nilfs; | 76 | return nilfs; |
@@ -95,7 +94,6 @@ void put_nilfs(struct the_nilfs *nilfs) | |||
95 | */ | 94 | */ |
96 | might_sleep(); | 95 | might_sleep(); |
97 | if (nilfs_loaded(nilfs)) { | 96 | if (nilfs_loaded(nilfs)) { |
98 | nilfs_dispose_used_segments(nilfs); | ||
99 | nilfs_mdt_clear(nilfs->ns_sufile); | 97 | nilfs_mdt_clear(nilfs->ns_sufile); |
100 | nilfs_mdt_destroy(nilfs->ns_sufile); | 98 | nilfs_mdt_destroy(nilfs->ns_sufile); |
101 | nilfs_mdt_clear(nilfs->ns_cpfile); | 99 | nilfs_mdt_clear(nilfs->ns_cpfile); |
@@ -463,22 +461,6 @@ int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks) | |||
463 | return err; | 461 | return err; |
464 | } | 462 | } |
465 | 463 | ||
466 | void nilfs_dispose_used_segments(struct the_nilfs *nilfs) | ||
467 | { | ||
468 | struct nilfs_segment_entry *ent, *n; | ||
469 | |||
470 | /* nilfs->sem must be locked by the caller. */ | ||
471 | if (!nilfs_loaded(nilfs)) | ||
472 | return; | ||
473 | |||
474 | list_for_each_entry_safe(ent, n, &nilfs->ns_used_segments, list) { | ||
475 | list_del_init(&ent->list); | ||
476 | nilfs_segment_usage_clear_volatile_active(ent->raw_su); | ||
477 | nilfs_close_segment_entry(ent, nilfs->ns_sufile); | ||
478 | nilfs_free_segment_entry(ent); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | int nilfs_near_disk_full(struct the_nilfs *nilfs) | 464 | int nilfs_near_disk_full(struct the_nilfs *nilfs) |
483 | { | 465 | { |
484 | struct inode *sufile = nilfs->ns_sufile; | 466 | struct inode *sufile = nilfs->ns_sufile; |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 75da37306964..af566e78f7af 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
@@ -51,7 +51,6 @@ enum { | |||
51 | * @ns_writer_refcount: number of referrers on ns_writer | 51 | * @ns_writer_refcount: number of referrers on ns_writer |
52 | * @ns_sbh: buffer head of the on-disk super block | 52 | * @ns_sbh: buffer head of the on-disk super block |
53 | * @ns_sbp: pointer to the super block data | 53 | * @ns_sbp: pointer to the super block data |
54 | * @ns_used_segments: list of full segments in volatile active state | ||
55 | * @ns_supers: list of nilfs super block structs | 54 | * @ns_supers: list of nilfs super block structs |
56 | * @ns_seg_seq: segment sequence counter | 55 | * @ns_seg_seq: segment sequence counter |
57 | * @ns_segnum: index number of the latest full segment. | 56 | * @ns_segnum: index number of the latest full segment. |
@@ -65,6 +64,7 @@ enum { | |||
65 | * @ns_last_pseg: start block number of the latest segment | 64 | * @ns_last_pseg: start block number of the latest segment |
66 | * @ns_last_seq: sequence value of the latest segment | 65 | * @ns_last_seq: sequence value of the latest segment |
67 | * @ns_last_cno: checkpoint number of the latest segment | 66 | * @ns_last_cno: checkpoint number of the latest segment |
67 | * @ns_prot_seq: least sequence number of segments which must not be reclaimed | ||
68 | * @ns_free_segments_count: counter of free segments | 68 | * @ns_free_segments_count: counter of free segments |
69 | * @ns_segctor_sem: segment constructor semaphore | 69 | * @ns_segctor_sem: segment constructor semaphore |
70 | * @ns_dat: DAT file inode | 70 | * @ns_dat: DAT file inode |
@@ -103,7 +103,6 @@ struct the_nilfs { | |||
103 | */ | 103 | */ |
104 | struct buffer_head *ns_sbh; | 104 | struct buffer_head *ns_sbh; |
105 | struct nilfs_super_block *ns_sbp; | 105 | struct nilfs_super_block *ns_sbp; |
106 | struct list_head ns_used_segments; | ||
107 | unsigned ns_mount_state; | 106 | unsigned ns_mount_state; |
108 | struct list_head ns_supers; | 107 | struct list_head ns_supers; |
109 | 108 | ||
@@ -132,6 +131,7 @@ struct the_nilfs { | |||
132 | sector_t ns_last_pseg; | 131 | sector_t ns_last_pseg; |
133 | u64 ns_last_seq; | 132 | u64 ns_last_seq; |
134 | __u64 ns_last_cno; | 133 | __u64 ns_last_cno; |
134 | u64 ns_prot_seq; | ||
135 | unsigned long ns_free_segments_count; | 135 | unsigned long ns_free_segments_count; |
136 | 136 | ||
137 | struct rw_semaphore ns_segctor_sem; | 137 | struct rw_semaphore ns_segctor_sem; |
@@ -188,7 +188,6 @@ void put_nilfs(struct the_nilfs *); | |||
188 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); | 188 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); |
189 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); | 189 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); |
190 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); | 190 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); |
191 | void nilfs_dispose_used_segments(struct the_nilfs *); | ||
192 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); | 191 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); |
193 | int nilfs_near_disk_full(struct the_nilfs *); | 192 | int nilfs_near_disk_full(struct the_nilfs *); |
194 | 193 | ||