From: NeilBrown Date: Mon, 18 Oct 2010 00:48:22 +0000 (+1100) Subject: Fix lafs_seg_next to talk write-cluster properly. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=19fd807f2b4e86d2f19ae2f345415e140df350de;p=LaFS.git Fix lafs_seg_next to talk write-cluster properly. When we have a 2D layout, we want to walk down columns before across rows, as that encourages adjacent blocks. So fix lafs_seg_next to do the right thing. Also check for exceeding the declared size of the segment and react accordingly. Signed-off-by: NeilBrown --- diff --git a/cluster.c b/cluster.c index 5e188ce..a76b0f5 100644 --- a/cluster.c +++ b/cluster.c @@ -340,6 +340,13 @@ static u64 seg_addr(struct fs *fs, struct segpos *seg) /* Setting 'next' address for last cluster in * a cleaner segment */ return 0; + if (seg->table > seg->nxt_table || + (seg->table == seg->nxt_table && + seg->row >= seg->nxt_row)) + /* We have gone beyond the end of the cluster, + * must be bad data during roll-forward + */ + return 0; addr = seg->col * dv->stride; addr += seg->row; addr += seg->table * dv->rows_per_table; @@ -352,19 +359,38 @@ u64 lafs_seg_next(struct fs *fs, struct segpos *seg) { /* step forward one block, returning the address of * the block stepped over + * The write cluster can have three sections: + * - the tail end of one table + * - a number of complete tables + * - the head of one table + * + * For each table or partial table we want to talk a full + * column at a time, then go to the next column. + * So we step to the next row. If it is beyond the range of + * the current table, go to 'start' of next column, or to + * next table. */ struct fs_dev *dv = &fs->devs[seg->dev]; u64 addr = seg_addr(fs, seg); + if (!addr) + /* Beyond end of cluster */ + return 0; + /* now step forward in column or table or seg */ - seg->col++; - if (seg->col >= dv->width) { - seg->col = 0; - seg->row++; - if (seg->row >= dv->rows_per_table) { - seg->row = 0; + seg->row++; + if (seg->row >= dv->rows_per_table || + (seg->table == seg->nxt_table + && seg->row >= seg->nxt_row)) { + seg->col++; + if (seg->col >= dv->width) { + seg->col = 0; seg->table++; } + if (seg->table == seg->st_table) + seg->row = seg->st_row; + else + seg->row = 0; } return addr; } @@ -1176,6 +1202,7 @@ static void cluster_flush(struct fs *fs, int cnum) current_block++; cluster_incdesc(wc, desc_start, b, fs->blocksize_bits); addr = lafs_seg_next(fs, &wc->seg); + BUG_ON(!addr); if (cnum && test_bit(B_Dirty, &b->flags)) /* We are cleaning but this block is now dirty. * Don't waste the UnincCredit on recording the diff --git a/roll.c b/roll.c index 1649be3..4a6938d 100644 --- a/roll.c +++ b/roll.c @@ -568,6 +568,15 @@ roll_one(struct fs *fs, u64 *addrp, struct page *p, struct page *pg, * response */ /* FIXME range check count */ while (!err && cnt--) { + if (bytes != DescHole && + !baddr) { + /* We have fallen off the end of + * the write-cluster - something + * is wrong with the header + */ + printk(KERN_WARNING "LAFS: cluster size is wrong\n"); + return -EIO; + } if (!flg && bytes != DescIndex) err = roll_block(fs, fsnum, inum, trunc, bnum, baddr,