aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2009-03-30 23:27:02 -0400
committerNeilBrown <neilb@suse.de>2009-03-30 23:27:02 -0400
commit1187cf0a3c8b647d08bc86e043563c8d2a327adc (patch)
tree759515a3fdcbf962f35255f90ea6c4d7c708391a
parenteea1bf384e05b5ab747f8530c4fba9e9e6907fff (diff)
md: Allow write-intent bitmaps to have chunksize < PAGE_SIZE
md currently insists that the chunk size used for write-intent bitmaps (the amount of data that corresponds to one chunk) be at least one page. The reason for this restriction is lost in the mists of time, but a review of the code (and a vague memory) suggests that the only problem would be related to resync. Resync tries very hard to work in multiples of a page, but also needs to sync with units of a bitmap_chunk too. This connection comes out in the bitmap_start_sync call. So change bitmap_start_sync to always work in multiples of a page. If the bitmap chunk size is less that one page, we flag multiple chunks as 'syncing' and generally make them all appear to the resync routines like one chunk. All other code either already works with data ranges that could span multiple chunks, or explicitly only cares about a single chunk. Signed-off-by: Neil Brown <neilb@suse.de>
-rw-r--r--drivers/md/bitmap.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 719943763391..8fa3277f72dc 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -111,9 +111,10 @@ static int bitmap_checkpage(struct bitmap *bitmap, unsigned long page, int creat
111 unsigned char *mappage; 111 unsigned char *mappage;
112 112
113 if (page >= bitmap->pages) { 113 if (page >= bitmap->pages) {
114 printk(KERN_ALERT 114 /* This can happen if bitmap_start_sync goes beyond
115 "%s: invalid bitmap page request: %lu (> %lu)\n", 115 * End-of-device while looking for a whole page.
116 bmname(bitmap), page, bitmap->pages-1); 116 * It is harmless.
117 */
117 return -EINVAL; 118 return -EINVAL;
118 } 119 }
119 120
@@ -570,7 +571,7 @@ static int bitmap_read_sb(struct bitmap *bitmap)
570 else if (le32_to_cpu(sb->version) < BITMAP_MAJOR_LO || 571 else if (le32_to_cpu(sb->version) < BITMAP_MAJOR_LO ||
571 le32_to_cpu(sb->version) > BITMAP_MAJOR_HI) 572 le32_to_cpu(sb->version) > BITMAP_MAJOR_HI)
572 reason = "unrecognized superblock version"; 573 reason = "unrecognized superblock version";
573 else if (chunksize < PAGE_SIZE) 574 else if (chunksize < 512)
574 reason = "bitmap chunksize too small"; 575 reason = "bitmap chunksize too small";
575 else if ((1 << ffz(~chunksize)) != chunksize) 576 else if ((1 << ffz(~chunksize)) != chunksize)
576 reason = "bitmap chunksize not a power of 2"; 577 reason = "bitmap chunksize not a power of 2";
@@ -1345,8 +1346,8 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
1345 } 1346 }
1346} 1347}
1347 1348
1348int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, 1349static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks,
1349 int degraded) 1350 int degraded)
1350{ 1351{
1351 bitmap_counter_t *bmc; 1352 bitmap_counter_t *bmc;
1352 int rv; 1353 int rv;
@@ -1374,6 +1375,29 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks,
1374 return rv; 1375 return rv;
1375} 1376}
1376 1377
1378int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks,
1379 int degraded)
1380{
1381 /* bitmap_start_sync must always report on multiples of whole
1382 * pages, otherwise resync (which is very PAGE_SIZE based) will
1383 * get confused.
1384 * So call __bitmap_start_sync repeatedly (if needed) until
1385 * At least PAGE_SIZE>>9 blocks are covered.
1386 * Return the 'or' of the result.
1387 */
1388 int rv = 0;
1389 int blocks1;
1390
1391 *blocks = 0;
1392 while (*blocks < (PAGE_SIZE>>9)) {
1393 rv |= __bitmap_start_sync(bitmap, offset,
1394 &blocks1, degraded);
1395 offset += blocks1;
1396 *blocks += blocks1;
1397 }
1398 return rv;
1399}
1400
1377void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted) 1401void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted)
1378{ 1402{
1379 bitmap_counter_t *bmc; 1403 bitmap_counter_t *bmc;