aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2008-12-19 00:25:01 -0500
committerNeilBrown <neilb@suse.de>2008-12-19 00:25:01 -0500
commita2ed9615e3222645007fc19991aedf30eed3ecfd (patch)
tree2a07cc815f5c348f085ad96a5660e3213da955f4
parent55dac3a5553b13891f0ae4bbd11920619b5436d4 (diff)
md: Don't read past end of bitmap when reading bitmap.
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> Cc: stable@kernel.org
-rw-r--r--drivers/md/bitmap.c22
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index ac89a5deaca2..ab7c8e4a61f9 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -208,16 +208,19 @@ static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
208 */ 208 */
209 209
210/* IO operations when bitmap is stored near all superblocks */ 210/* IO operations when bitmap is stored near all superblocks */
211static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long index) 211static struct page *read_sb_page(mddev_t *mddev, long offset,
212 struct page *page,
213 unsigned long index, int size)
212{ 214{
213 /* choose a good rdev and read the page from there */ 215 /* choose a good rdev and read the page from there */
214 216
215 mdk_rdev_t *rdev; 217 mdk_rdev_t *rdev;
216 struct list_head *tmp; 218 struct list_head *tmp;
217 struct page *page = alloc_page(GFP_KERNEL);
218 sector_t target; 219 sector_t target;
219 220
220 if (!page) 221 if (!page)
222 page = alloc_page(GFP_KERNEL);
223 if (!page)
221 return ERR_PTR(-ENOMEM); 224 return ERR_PTR(-ENOMEM);
222 225
223 rdev_for_each(rdev, tmp, mddev) { 226 rdev_for_each(rdev, tmp, mddev) {
@@ -227,7 +230,9 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde
227 230
228 target = rdev->sb_start + offset + index * (PAGE_SIZE/512); 231 target = rdev->sb_start + offset + index * (PAGE_SIZE/512);
229 232
230 if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) { 233 if (sync_page_io(rdev->bdev, target,
234 roundup(size, bdev_hardsect_size(rdev->bdev)),
235 page, READ)) {
231 page->index = index; 236 page->index = index;
232 attach_page_buffers(page, NULL); /* so that free_buffer will 237 attach_page_buffers(page, NULL); /* so that free_buffer will
233 * quietly no-op */ 238 * quietly no-op */
@@ -544,7 +549,9 @@ static int bitmap_read_sb(struct bitmap *bitmap)
544 549
545 bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes); 550 bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes);
546 } else { 551 } else {
547 bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0); 552 bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset,
553 NULL,
554 0, sizeof(bitmap_super_t));
548 } 555 }
549 if (IS_ERR(bitmap->sb_page)) { 556 if (IS_ERR(bitmap->sb_page)) {
550 err = PTR_ERR(bitmap->sb_page); 557 err = PTR_ERR(bitmap->sb_page);
@@ -957,11 +964,16 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
957 */ 964 */
958 page = bitmap->sb_page; 965 page = bitmap->sb_page;
959 offset = sizeof(bitmap_super_t); 966 offset = sizeof(bitmap_super_t);
967 read_sb_page(bitmap->mddev, bitmap->offset,
968 page,
969 index, count);
960 } else if (file) { 970 } else if (file) {
961 page = read_page(file, index, bitmap, count); 971 page = read_page(file, index, bitmap, count);
962 offset = 0; 972 offset = 0;
963 } else { 973 } else {
964 page = read_sb_page(bitmap->mddev, bitmap->offset, index); 974 page = read_sb_page(bitmap->mddev, bitmap->offset,
975 NULL,
976 index, count);
965 offset = 0; 977 offset = 0;
966 } 978 }
967 if (IS_ERR(page)) { /* read error */ 979 if (IS_ERR(page)) { /* read error */