From: NeilBrown Date: Sun, 19 Sep 2010 04:39:31 +0000 (+1000) Subject: roll-forward: update youth block for new segments. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=aac6fbd423e1761b97cd7d035a9f30801a18c112;p=LaFS.git roll-forward: update youth block for new segments. Any new segments found during roll-forward need their youth value set. Signed-off-by: NeilBrown --- diff --git a/lafs.h b/lafs.h index a8e5951..5426ee2 100644 --- a/lafs.h +++ b/lafs.h @@ -716,6 +716,7 @@ void lafs_seg_move(struct fs *fs, u64 oldaddr, u64 newaddr, int ssnum, int phase, int moveref); int lafs_segtrack_init(struct segtracker *st); void lafs_segtrack_free(struct segtracker *st); +void lafs_update_youth(struct fs *fs, int dev, u32 seg); extern int temp_credits;/* debugging */ void lafs_free_get(struct fs *fs, unsigned int *dev, u32 *seg, diff --git a/roll.c b/roll.c index e9a20fa..400f966 100644 --- a/roll.c +++ b/roll.c @@ -480,6 +480,9 @@ static int roll_forward(struct fs *fs) char *buf; int err; int blocksize = fs->blocksize; + int dev; + u32 seg; + u32 offset; fs->phase = 1; fs->qphase = 0; @@ -509,23 +512,37 @@ static int roll_forward(struct fs *fs) } lafs_cluster_init(fs, 1, 0, 0, 0); + virttoseg(fs, first, &dev, &seg, &offset); max = ((max + blocksize - 1) / blocksize) * blocksize; dprintk("Max = %d\n", max); buf = kmalloc(max, GFP_KERNEL); if (buf) while (first != next) { - /* FIXME if this cluster is in a new segment, - * we need to set the youth number for it. - */ + int dev2; + u32 seg2; + + virttoseg(fs, first, &dev2, &seg2, &offset); err = roll_one(fs, &first, p, pg, max); if (err) break; + if (fs->qphase == fs->phase && fs->checkpointing) { fs->checkpointing = 0; clear_bit(DelayYouth, &fs->fsstate); lafs_seg_apply_all(fs); } + + if (dev2 != dev || seg2 != seg) { + /* New segment - need to make sure youth is correct */ + dev = dev2; + seg = seg2; + /* if fs->checkpointing, seg_apply_all will do the youth + * update + */ + if (fs->checkpointing == 0) + lafs_update_youth(fs, dev, seg); + } } else err = -ENOMEM; diff --git a/segments.c b/segments.c index 346102b..eb4b8bf 100644 --- a/segments.c +++ b/segments.c @@ -87,9 +87,7 @@ struct segsum { atomic_t delayed; struct datablock *ssblk; - /* youthblk is only set when ssnum is 0 and - * usage is zero we are cleaning. - */ + /* youthblk is only set when ssnum is 0 */ struct datablock *youthblk; }; @@ -141,9 +139,10 @@ retry: spin_unlock(&fs->stable_lock); if (new) ss_put(new, fs); + if (!fs->rolled && fs->qphase != fs->phase) + return ss; if (ss->ssblk && - !test_bit(B_Valid, &ss->ssblk->b.flags) && - (fs->rolled || fs->qphase == fs->phase)) { + !test_bit(B_Valid, &ss->ssblk->b.flags) ) { /* need to read this now that roll forward * has progressed. */ @@ -153,6 +152,17 @@ retry: return ERR_PTR(err); } } + if (ss->youthblk && + !test_bit(B_Valid, &ss->youthblk->b.flags)) { + /* need to read this now that roll forward + * has progressed. + */ + err = lafs_read_block(ss->youthblk); + if (err) { + ss_put(ss, fs); + return ERR_PTR(err); + } + } return ss; } if (new) { @@ -193,6 +203,8 @@ retry: goto retry; } err = lafs_read_block(new->ssblk); + if (new->youthblk && err == 0) + err = lafs_read_block(new->youthblk); if (err) { ss_put(new, fs); return ERR_PTR(err); @@ -445,6 +457,9 @@ static void seg_apply(struct fs *fs, struct segsum *ss) dprintk("Seg apply %d %d\n", (int)ss->segnum, diff); err = lafs_read_block(ss->ssblk); BUG_ON(err); // FIXME do something useful here + if (ss->youthblk) + err = lafs_read_block(ss->youthblk); + BUG_ON(err); seg_inc(fs, ss, diff, 1); if (diff > 0 && ss->youthblk) @@ -1175,12 +1190,6 @@ again: *dev = ss->dev; *seg = ss->segment; - /* On the final checkpoint we skip the youth update as - * rollforward will do it for us, and it is too late - * the write the new youth block anyway. - * FIXME there should be a more general way to delay - * updates to the Youth block. - */ if (!test_bit(DelayYouth, &fs->fsstate) && !(ssum && ssum->devnum == ss->dev && @@ -1240,6 +1249,18 @@ again: /* Note that we return an implicit reference to the ssum */ } +void lafs_update_youth(struct fs *fs, int dev, u32 seg) +{ + struct segsum *ssum = NULL; + ssum = segsum_find(fs, seg, dev, 0); + set_bit(B_PinPending, &ssum->youthblk->b.flags); + lafs_pin_dblock(ssum->youthblk, AccountSpace); + spin_lock(&fs->lock); + set_youth(fs, ssum); + spin_unlock(&fs->lock); + ss_put(ssum, fs); +} + void lafs_seg_forget(struct fs *fs, int dev, u32 seg) { /* this segment was being filled and is now full.