| From a2ed9615e3222645007fc19991aedf30eed3ecfd Mon Sep 17 00:00:00 2001 |
| From: NeilBrown <neilb@suse.de> |
| Date: Fri, 19 Dec 2008 16:25:01 +1100 |
| Subject: md: Don't read past end of bitmap when reading bitmap. |
| |
| From: NeilBrown <neilb@suse.de> |
| |
| commit a2ed9615e3222645007fc19991aedf30eed3ecfd upstream. |
| |
| When we read the write-intent-bitmap off the device, we currently |
| read a whole number of pages. |
| When PAGE_SIZE is 4K, this works due to the alignment we enforce |
| on the superblock and bitmap. |
| When PAGE_SIZE is 64K, this case read past the end-of-device |
| which causes an error. |
| |
| When we write the superblock, we ensure to clip the last page |
| to just be the required size. Copy that code into the read path |
| to just read the required number of sectors. |
| |
| Signed-off-by: Neil Brown <neilb@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/md/bitmap.c | 22 +++++++++++++++++----- |
| 1 file changed, 17 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/md/bitmap.c |
| +++ b/drivers/md/bitmap.c |
| @@ -208,16 +208,19 @@ static void bitmap_checkfree(struct bitm |
| */ |
| |
| /* IO operations when bitmap is stored near all superblocks */ |
| -static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long index) |
| +static struct page *read_sb_page(mddev_t *mddev, long offset, |
| + struct page *page, |
| + unsigned long index, int size) |
| { |
| /* choose a good rdev and read the page from there */ |
| |
| mdk_rdev_t *rdev; |
| struct list_head *tmp; |
| - struct page *page = alloc_page(GFP_KERNEL); |
| sector_t target; |
| |
| if (!page) |
| + page = alloc_page(GFP_KERNEL); |
| + if (!page) |
| return ERR_PTR(-ENOMEM); |
| |
| rdev_for_each(rdev, tmp, mddev) { |
| @@ -227,7 +230,9 @@ static struct page *read_sb_page(mddev_t |
| |
| target = rdev->sb_start + offset + index * (PAGE_SIZE/512); |
| |
| - if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) { |
| + if (sync_page_io(rdev->bdev, target, |
| + roundup(size, bdev_hardsect_size(rdev->bdev)), |
| + page, READ)) { |
| page->index = index; |
| attach_page_buffers(page, NULL); /* so that free_buffer will |
| * quietly no-op */ |
| @@ -544,7 +549,9 @@ static int bitmap_read_sb(struct bitmap |
| |
| bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes); |
| } else { |
| - bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0); |
| + bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, |
| + NULL, |
| + 0, sizeof(bitmap_super_t)); |
| } |
| if (IS_ERR(bitmap->sb_page)) { |
| err = PTR_ERR(bitmap->sb_page); |
| @@ -957,11 +964,16 @@ static int bitmap_init_from_disk(struct |
| */ |
| page = bitmap->sb_page; |
| offset = sizeof(bitmap_super_t); |
| + read_sb_page(bitmap->mddev, bitmap->offset, |
| + page, |
| + index, count); |
| } else if (file) { |
| page = read_page(file, index, bitmap, count); |
| offset = 0; |
| } else { |
| - page = read_sb_page(bitmap->mddev, bitmap->offset, index); |
| + page = read_sb_page(bitmap->mddev, bitmap->offset, |
| + NULL, |
| + index, count); |
| offset = 0; |
| } |
| if (IS_ERR(page)) { /* read error */ |