]> git.neil.brown.name Git - LaFS.git/commitdiff
devblock: validate the addresses of the state blocks a bit better.
authorNeilBrown <neilb@suse.de>
Fri, 4 Mar 2011 01:47:30 +0000 (12:47 +1100)
committerNeilBrown <neilb@suse.de>
Fri, 4 Mar 2011 01:47:30 +0000 (12:47 +1100)
Allow all to be at start or end, but ensure they don't overlap data.

Signed-off-by: NeilBrown <neilb@suse.de>
super.c

diff --git a/super.c b/super.c
index 853ed7bd6282a9169b1c39dfe3cabb9b9e3cb24f..c68eb6865ac1aaf5a53d7f230516acc15fd6ee5c 100644 (file)
--- a/super.c
+++ b/super.c
@@ -70,6 +70,10 @@ valid_devblock(struct lafs_dev *db, sector_t addr)
         * it was found at sector 'addr'
         */
        u32 crc, crc2;
+       u64 byteaddr;
+       sector_t segsize;
+       int i;
+
        if (strncmp(db->idtag, "LaFS-DeviceBlock", 16) != 0)
                return 0;
        if (strncmp(db->version, "AlphaDevel      ", 16) != 0)
@@ -85,18 +89,18 @@ valid_devblock(struct lafs_dev *db, sector_t addr)
                return 0;
        }
 
-       addr = addr << 9; /* convert to byte */
-       if (le64_to_cpu(db->devaddr[0]) != addr &&
-           le64_to_cpu(db->devaddr[1]) != addr)
+       byteaddr = (u64)addr << 9; /* convert to byte */
+       if (le64_to_cpu(db->devaddr[0]) != byteaddr &&
+           le64_to_cpu(db->devaddr[1]) != byteaddr)
                return 0;
 
        if (db->statebits < 10 || db->statebits > 16)
                return 0;
        if (db->blockbits < 9 || db->blockbits > 20)
                return 0;
-       if (db->width < 1 || db->width > 500)
+       if (le16_to_cpu(db->width) < 1 || le16_to_cpu(db->width) >= 512)
                return 0;
-       if (db->stride < 1)
+       if (le32_to_cpu(db->stride) < 1)
                return 0;
        /* devaddr[0] must be early, [1] must be late */
        if (le64_to_cpu(db->devaddr[0]) >=
@@ -107,15 +111,9 @@ valid_devblock(struct lafs_dev *db, sector_t addr)
            le64_to_cpu(db->segment_offset) +
            ((((sector_t)le32_to_cpu(db->segment_count)
               * le32_to_cpu(db->segment_size)))
-            << le32_to_cpu(db->blockbits)))
+            << db->blockbits))
                return 0;
 
-       /* we should be fairly flexable about addresses of state blocks,
-        * we should probably allow more, and we should just make sure
-        * they do not overlap any true segments....
-        * FIXME
-        */
-
        /* 2 is an absolute minimum segment size, a few hundred is more
         * likely. We'll put a lower limit of 8, and an upper of 800000
         */
@@ -127,6 +125,31 @@ valid_devblock(struct lafs_dev *db, sector_t addr)
            (le32_to_cpu(db->segment_size)<<db->blockbits) * 10)
                return 0;
 
+       /* The 4 state blocks live before the first or after the last segment.
+        * The distance from start of first to end of last is either:
+        * - segment_count * segment_size  if width*stride <= segment_size
+        * - (width-1) * stride + segment_size / width * segment_count
+        *                if width * stride > segment_size
+        */
+       segsize = le32_to_cpu(db->segment_size);
+       segsize *= le32_to_cpu(db->segment_count);
+       if (le16_to_cpu(db->width) *  le32_to_cpu(db->stride)
+           > le32_to_cpu(db->segment_size)) {
+               int stride = le32_to_cpu(db->stride);
+               int width = le16_to_cpu(db->width);
+
+               sector_div(segsize, width);
+               segsize += (width - 1) * stride;
+       }
+       segsize <<= db->blockbits;
+       for (i = 0; i < 4; i++) {
+               sector_t addr = le64_to_cpu(db->stateaddr[i]);
+               int offset = le32_to_cpu(db->segment_offset);
+               if (addr + (1<<db->statebits) > offset &&
+                   addr < offset + segsize)
+                       return 0;
+       }
+
        /* FIXME should range check segment_count, but need to know
         * size for that */
        if (le32_to_cpu(db->level) > 10)