aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-04-05 05:30:58 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-04-12 20:53:52 -0400
commitc85399c2da8b86de8f6877980294fa1a4a88a5a4 (patch)
tree0319b8ab4d8b7da4d614e46949755b8a9ba4eab0
parenta703018f7bbec8109419318f5d51f235fdce5155 (diff)
nilfs2: fix possible mismatch of sufile counters on recovery
On-disk counters ndirtysegs and ncleansegs of sufile, can go wrong after roll-forward recovery because nilfs_prepare_segment_for_recovery() function marks segments dirty without adjusting value of these counters. This fixes the problem by adding a function to sufile which does the operation adjusting the counters, and by letting the recovery function use it. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
-rw-r--r--fs/nilfs2/recovery.c20
-rw-r--r--fs/nilfs2/sufile.c29
-rw-r--r--fs/nilfs2/sufile.h12
3 files changed, 45 insertions, 16 deletions
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c
index 6ade0963fc1d..4fc081e47d70 100644
--- a/fs/nilfs2/recovery.c
+++ b/fs/nilfs2/recovery.c
@@ -413,7 +413,6 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
413 struct nilfs_segment_entry *ent, *n; 413 struct nilfs_segment_entry *ent, *n;
414 struct inode *sufile = nilfs->ns_sufile; 414 struct inode *sufile = nilfs->ns_sufile;
415 __u64 segnum[4]; 415 __u64 segnum[4];
416 time_t mtime;
417 int err; 416 int err;
418 int i; 417 int i;
419 418
@@ -442,24 +441,13 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
442 * Collecting segments written after the latest super root. 441 * Collecting segments written after the latest super root.
443 * These are marked dirty to avoid being reallocated in the next write. 442 * These are marked dirty to avoid being reallocated in the next write.
444 */ 443 */
445 mtime = get_seconds();
446 list_for_each_entry_safe(ent, n, head, list) { 444 list_for_each_entry_safe(ent, n, head, list) {
447 if (ent->segnum == segnum[0]) { 445 if (ent->segnum != segnum[0]) {
448 list_del(&ent->list); 446 err = nilfs_sufile_scrap(sufile, ent->segnum);
449 nilfs_free_segment_entry(ent); 447 if (unlikely(err))
450 continue; 448 goto failed;
451 }
452 err = nilfs_open_segment_entry(ent, sufile);
453 if (unlikely(err))
454 goto failed;
455 if (!nilfs_segment_usage_dirty(ent->raw_su)) {
456 /* make the segment garbage */
457 ent->raw_su->su_nblocks = cpu_to_le32(0);
458 ent->raw_su->su_lastmod = cpu_to_le32(mtime);
459 nilfs_segment_usage_set_dirty(ent->raw_su);
460 } 449 }
461 list_del(&ent->list); 450 list_del(&ent->list);
462 nilfs_close_segment_entry(ent, sufile);
463 nilfs_free_segment_entry(ent); 451 nilfs_free_segment_entry(ent);
464 } 452 }
465 453
diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c
index 07013f58dfe9..98e68677f045 100644
--- a/fs/nilfs2/sufile.c
+++ b/fs/nilfs2/sufile.c
@@ -258,6 +258,35 @@ void nilfs_sufile_do_cancel_free(struct inode *sufile, __u64 segnum,
258 nilfs_mdt_mark_dirty(sufile); 258 nilfs_mdt_mark_dirty(sufile);
259} 259}
260 260
261void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
262 struct buffer_head *header_bh,
263 struct buffer_head *su_bh)
264{
265 struct nilfs_segment_usage *su;
266 void *kaddr;
267 int clean, dirty;
268
269 kaddr = kmap_atomic(su_bh->b_page, KM_USER0);
270 su = nilfs_sufile_block_get_segment_usage(sufile, segnum, su_bh, kaddr);
271 if (su->su_flags == cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY) &&
272 su->su_nblocks == cpu_to_le32(0)) {
273 kunmap_atomic(kaddr, KM_USER0);
274 return;
275 }
276 clean = nilfs_segment_usage_clean(su);
277 dirty = nilfs_segment_usage_dirty(su);
278
279 /* make the segment garbage */
280 su->su_lastmod = cpu_to_le64(0);
281 su->su_nblocks = cpu_to_le32(0);
282 su->su_flags = cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY);
283 kunmap_atomic(kaddr, KM_USER0);
284
285 nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1);
286 nilfs_mdt_mark_buffer_dirty(su_bh);
287 nilfs_mdt_mark_dirty(sufile);
288}
289
261void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum, 290void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
262 struct buffer_head *header_bh, 291 struct buffer_head *header_bh,
263 struct buffer_head *su_bh) 292 struct buffer_head *su_bh)
diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h
index 449a6e2671b0..a2e2efd4ade1 100644
--- a/fs/nilfs2/sufile.h
+++ b/fs/nilfs2/sufile.h
@@ -52,6 +52,8 @@ int nilfs_sufile_update(struct inode *, __u64, int,
52 struct buffer_head *)); 52 struct buffer_head *));
53void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *, 53void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *,
54 struct buffer_head *); 54 struct buffer_head *);
55void nilfs_sufile_do_scrap(struct inode *, __u64, struct buffer_head *,
56 struct buffer_head *);
55void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *, 57void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *,
56 struct buffer_head *); 58 struct buffer_head *);
57void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *, 59void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *,
@@ -78,6 +80,16 @@ static inline int nilfs_sufile_cancel_free(struct inode *sufile, __u64 segnum)
78} 80}
79 81
80/** 82/**
83 * nilfs_sufile_scrap - make a segment garbage
84 * @sufile: inode of segment usage file
85 * @segnum: segment number to be freed
86 */
87static inline int nilfs_sufile_scrap(struct inode *sufile, __u64 segnum)
88{
89 return nilfs_sufile_update(sufile, segnum, 1, nilfs_sufile_do_scrap);
90}
91
92/**
81 * nilfs_sufile_free - free segment 93 * nilfs_sufile_free - free segment
82 * @sufile: inode of segment usage file 94 * @sufile: inode of segment usage file
83 * @segnum: segment number to be freed 95 * @segnum: segment number to be freed