diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/bitmap.c | 28 |
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 41df4cda66e2..2925219f0881 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -520,6 +520,8 @@ success: bitmap->daemon_sleep = daemon_sleep; bitmap->flags |= sb->state; bitmap->events_cleared = le64_to_cpu(sb->events_cleared); + if (sb->state & BITMAP_STALE) + bitmap->events_cleared = bitmap->mddev->events; err = 0; out: kunmap(bitmap->sb_page); @@ -818,7 +820,7 @@ int bitmap_unplug(struct bitmap *bitmap) 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 * the in-memory bitmap from the on-disk bitmap -- also, sets up the * memory mapping of the bitmap file @@ -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 * previously kicked from the array, we mark all the bits as * 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; struct page *page = NULL, *oldpage = NULL; @@ -914,7 +919,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) * whole page and write it out */ memset(page_address(page) + offset, 0xff, - PAGE_SIZE - offset); + PAGE_SIZE - offset); ret = write_page(bitmap, page, 1); if (ret) { kunmap(page); @@ -928,8 +933,11 @@ static int bitmap_init_from_disk(struct bitmap *bitmap) } if (test_bit(bit, page_address(page))) { /* 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++; + set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); } } @@ -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 * 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) } if (! *bmc) { struct page *page; - *bmc = 1 | NEEDED_MASK; + *bmc = 1 | (needed?NEEDED_MASK:0); bitmap_count_page(bitmap, offset, 1); page = filemap_get_page(bitmap, offset >> CHUNK_BLOCK_SHIFT(bitmap)); set_page_attr(bitmap, page, BITMAP_PAGE_CLEAN); @@ -1517,6 +1525,7 @@ int bitmap_create(mddev_t *mddev) unsigned long pages; struct file *file = mddev->bitmap_file; int err; + sector_t start; BUG_ON(sizeof(bitmap_super_t) != 256); @@ -1581,7 +1590,12 @@ int bitmap_create(mddev_t *mddev) /* now that we have some pages available, initialize the in-memory * 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) return err; |