]> git.neil.brown.name Git - LaFS.git/commitdiff
Fix lafs_seg_next to talk write-cluster properly.
authorNeilBrown <neilb@suse.de>
Mon, 18 Oct 2010 00:48:22 +0000 (11:48 +1100)
committerNeilBrown <neilb@suse.de>
Mon, 18 Oct 2010 01:29:08 +0000 (12:29 +1100)
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 <neilb@suse.de>
cluster.c
roll.c

index 5e188ce6231f093e0ee5dc2e73f92e63bb10ca2e..a76b0f5b9037007dc7f07149fbaedfe22fdde702 100644 (file)
--- 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 1649be311f0fe4689e97dae7812c4a781d5d1ba0..4a6938d2694aa05ad264b3763e7fd4332f69a034 100644 (file)
--- 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,