diff options
-rw-r--r-- | drivers/md/bitmap.c | 35 | ||||
-rw-r--r-- | drivers/md/md.c | 22 |
2 files changed, 54 insertions, 3 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 9620d452d03..ae94f3beb5f 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -268,6 +268,31 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) if (page->index == bitmap->file_pages-1) size = roundup(bitmap->last_page_size, bdev_hardsect_size(rdev->bdev)); + /* Just make sure we aren't corrupting data or + * metadata + */ + if (bitmap->offset < 0) { + /* DATA BITMAP METADATA */ + if (bitmap->offset + + page->index * (PAGE_SIZE/512) + + size/512 > 0) + /* bitmap runs in to metadata */ + return -EINVAL; + if (rdev->data_offset + mddev->size*2 + > rdev->sb_offset*2 + bitmap->offset) + /* data runs in to bitmap */ + return -EINVAL; + } else if (rdev->sb_offset*2 < rdev->data_offset) { + /* METADATA BITMAP DATA */ + if (rdev->sb_offset*2 + + bitmap->offset + + page->index*(PAGE_SIZE/512) + size/512 + > rdev->data_offset) + /* bitmap runs in to data */ + return -EINVAL; + } else { + /* DATA METADATA BITMAP - no problems */ + } md_super_write(mddev, rdev, (rdev->sb_offset<<1) + bitmap->offset + page->index * (PAGE_SIZE/512), @@ -287,8 +312,14 @@ static int write_page(struct bitmap *bitmap, struct page *page, int wait) { struct buffer_head *bh; - if (bitmap->file == NULL) - return write_sb_page(bitmap, page, wait); + if (bitmap->file == NULL) { + switch (write_sb_page(bitmap, page, wait)) { + case -EINVAL: + bitmap->flags |= BITMAP_WRITE_ERROR; + return -EIO; + } + return 0; + } bh = page_buffers(page); diff --git a/drivers/md/md.c b/drivers/md/md.c index bae42331182..36c05ba7855 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3176,13 +3176,33 @@ static int do_md_run(mddev_t * mddev) * Drop all container device buffers, from now on * the only valid external interface is through the md * device. - * Also find largest hardsector size */ ITERATE_RDEV(mddev,rdev,tmp) { if (test_bit(Faulty, &rdev->flags)) continue; sync_blockdev(rdev->bdev); invalidate_bdev(rdev->bdev); + + /* perform some consistency tests on the device. + * We don't want the data to overlap the metadata, + * Internal Bitmap issues has handled elsewhere. + */ + if (rdev->data_offset < rdev->sb_offset) { + if (mddev->size && + rdev->data_offset + mddev->size*2 + > rdev->sb_offset*2) { + printk("md: %s: data overlaps metadata\n", + mdname(mddev)); + return -EINVAL; + } + } else { + if (rdev->sb_offset*2 + rdev->sb_size/512 + > rdev->data_offset) { + printk("md: %s: metadata overlaps data\n", + mdname(mddev)); + return -EINVAL; + } + } } md_probe(mddev->unit, NULL, NULL); |