* 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)
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]) >=
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
*/
(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)