Commit 6a07997f authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] md: improve handling of bitmap initialisation.

When we find a 'stale' bitmap, possibly because it is new, we should just
assume every bit needs to be set, but rather base the setting of bits on the
current state of the array (degraded and recovery_cp).
Signed-off-by: default avatarNeil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1923b99a
...@@ -520,6 +520,8 @@ success: ...@@ -520,6 +520,8 @@ success:
bitmap->daemon_sleep = daemon_sleep; bitmap->daemon_sleep = daemon_sleep;
bitmap->flags |= sb->state; bitmap->flags |= sb->state;
bitmap->events_cleared = le64_to_cpu(sb->events_cleared); bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
if (sb->state & BITMAP_STALE)
bitmap->events_cleared = bitmap->mddev->events;
err = 0; err = 0;
out: out:
kunmap(bitmap->sb_page); kunmap(bitmap->sb_page);
...@@ -818,7 +820,7 @@ int bitmap_unplug(struct bitmap *bitmap) ...@@ -818,7 +820,7 @@ int bitmap_unplug(struct bitmap *bitmap)
return 0; return 0;
} }
static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset); static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed);
/* * bitmap_init_from_disk -- called at bitmap_create time to initialize /* * bitmap_init_from_disk -- called at bitmap_create time to initialize
* the in-memory bitmap from the on-disk bitmap -- also, sets up the * the in-memory bitmap from the on-disk bitmap -- also, sets up the
* memory mapping of the bitmap file * memory mapping of the bitmap file
...@@ -826,8 +828,11 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset); ...@@ -826,8 +828,11 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset);
* if there's no bitmap file, or if the bitmap file had been * if there's no bitmap file, or if the bitmap file had been
* previously kicked from the array, we mark all the bits as * previously kicked from the array, we mark all the bits as
* 1's in order to cause a full resync. * 1's in order to cause a full resync.
*
* We ignore all bits for sectors that end earlier than 'start'.
* This is used when reading an out-of-date bitmap...
*/ */
static int bitmap_init_from_disk(struct bitmap *bitmap) static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
{ {
unsigned long i, chunks, index, oldindex, bit; unsigned long i, chunks, index, oldindex, bit;
struct page *page = NULL, *oldpage = NULL; struct page *page = NULL, *oldpage = NULL;
...@@ -914,7 +919,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) ...@@ -914,7 +919,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap)
* whole page and write it out * whole page and write it out
*/ */
memset(page_address(page) + offset, 0xff, memset(page_address(page) + offset, 0xff,
PAGE_SIZE - offset); PAGE_SIZE - offset);
ret = write_page(bitmap, page, 1); ret = write_page(bitmap, page, 1);
if (ret) { if (ret) {
kunmap(page); kunmap(page);
...@@ -928,8 +933,11 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) ...@@ -928,8 +933,11 @@ static int bitmap_init_from_disk(struct bitmap *bitmap)
} }
if (test_bit(bit, page_address(page))) { if (test_bit(bit, page_address(page))) {
/* if the disk bit is set, set the memory bit */ /* if the disk bit is set, set the memory bit */
bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap)); bitmap_set_memory_bits(bitmap, i << CHUNK_BLOCK_SHIFT(bitmap),
((i+1) << (CHUNK_BLOCK_SHIFT(bitmap)) >= start)
);
bit_cnt++; bit_cnt++;
set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
} }
} }
...@@ -1424,7 +1432,7 @@ void bitmap_close_sync(struct bitmap *bitmap) ...@@ -1424,7 +1432,7 @@ void bitmap_close_sync(struct bitmap *bitmap)
} }
} }
static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset) static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed)
{ {
/* For each chunk covered by any of these sectors, set the /* For each chunk covered by any of these sectors, set the
* counter to 1 and set resync_needed. They should all * counter to 1 and set resync_needed. They should all
...@@ -1441,7 +1449,7 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset) ...@@ -1441,7 +1449,7 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset)
} }
if (! *bmc) { if (! *bmc) {
struct page *page; struct page *page;
*bmc = 1 | NEEDED_MASK; *bmc = 1 | (needed?NEEDED_MASK:0);
bitmap_count_page(bitmap, offset, 1); bitmap_count_page(bitmap, offset, 1);
page = filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)); page = filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap));
set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN);
...@@ -1517,6 +1525,7 @@ int bitmap_create(mddev_t *mddev) ...@@ -1517,6 +1525,7 @@ int bitmap_create(mddev_t *mddev)
unsigned long pages; unsigned long pages;
struct file *file = mddev->bitmap_file; struct file *file = mddev->bitmap_file;
int err; int err;
sector_t start;
BUG_ON(sizeof(bitmap_super_t) != 256); BUG_ON(sizeof(bitmap_super_t) != 256);
...@@ -1581,7 +1590,12 @@ int bitmap_create(mddev_t *mddev) ...@@ -1581,7 +1590,12 @@ int bitmap_create(mddev_t *mddev)
/* now that we have some pages available, initialize the in-memory /* now that we have some pages available, initialize the in-memory
* bitmap from the on-disk bitmap */ * bitmap from the on-disk bitmap */
err = bitmap_init_from_disk(bitmap); start = 0;
if (mddev->degraded == 0
|| bitmap->events_cleared == mddev->events)
/* no need to keep dirty bits to optimise a re-add of a missing device */
start = mddev->recovery_cp;
err = bitmap_init_from_disk(bitmap, start);
if (err) if (err)
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment