]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Neil Brown <neilb@suse.de> |
2 | Subject: md: Allow write-intent bitmaps to have chunksize < PAGE_SIZE | |
3 | Patch-mainline: no | |
4 | References: 459557 | |
5 | ||
6 | md currently insists that the chunk size used for write-intent | |
7 | bitmaps (the amount of data that corresponds to one chunk) | |
8 | be at least one page. | |
9 | ||
10 | The reason for this list restriction is lost in the mists of time, | |
11 | but a review of the code (and a vague memory) suggests that the only | |
12 | problem would be related to resync. Resync tries very hard to | |
13 | work in multiples of a page, but also needs to sync with units | |
14 | of a bitmap_chunk too. | |
15 | ||
16 | This connection comes out in the bitmap_start_sync call. | |
17 | ||
18 | So change bitmap_start_sync to always work in multiples of a page. | |
19 | If the bitmap chunk size is less that one page, we flag multiple | |
20 | chunks as 'syncing' and generally make them all appear to the | |
21 | resync routines like one chunk. | |
22 | ||
23 | All other code either already works with data ranges that could | |
24 | span multiple chunks, or explicitly only cares about a single chunk. | |
25 | ||
26 | This is needed because some architectures use 64K pages in SLES11 | |
27 | where they used 4K pages in SLES10. So arrays created on SLES10 | |
28 | might not work with SLES11 without this change. | |
29 | ||
30 | Also, the default chunk size is 4K, and so newly create arrays | |
31 | that use the default will not work. | |
32 | ||
33 | Signed-off-by: Neil Brown <neilb@suse.de> | |
34 | ||
35 | --- | |
36 | drivers/md/bitmap.c | 41 ++++++++++++++++++++++++++++++++--------- | |
37 | 1 file changed, 32 insertions(+), 9 deletions(-) | |
38 | ||
39 | --- a/drivers/md/bitmap.c | |
40 | +++ b/drivers/md/bitmap.c | |
41 | @@ -110,13 +110,12 @@ static int bitmap_checkpage(struct bitma | |
42 | { | |
43 | unsigned char *mappage; | |
44 | ||
45 | - if (page >= bitmap->pages) { | |
46 | - printk(KERN_ALERT | |
47 | - "%s: invalid bitmap page request: %lu (> %lu)\n", | |
48 | - bmname(bitmap), page, bitmap->pages-1); | |
49 | + if (page >= bitmap->pages) | |
50 | + /* This can happen if bitmap_start_sync goes beyond | |
51 | + * End-of-device while looking for a whole page. | |
52 | + * It is harmless. | |
53 | + */ | |
54 | return -EINVAL; | |
55 | - } | |
56 | - | |
57 | ||
58 | if (bitmap->bp[page].hijacked) /* it's hijacked, don't try to alloc */ | |
59 | return 0; | |
60 | @@ -571,7 +570,7 @@ static int bitmap_read_sb(struct bitmap | |
61 | else if (le32_to_cpu(sb->version) < BITMAP_MAJOR_LO || | |
62 | le32_to_cpu(sb->version) > BITMAP_MAJOR_HI) | |
63 | reason = "unrecognized superblock version"; | |
64 | - else if (chunksize < PAGE_SIZE) | |
65 | + else if (chunksize < 512) | |
66 | reason = "bitmap chunksize too small"; | |
67 | else if ((1 << ffz(~chunksize)) != chunksize) | |
68 | reason = "bitmap chunksize not a power of 2"; | |
69 | @@ -1347,8 +1346,8 @@ void bitmap_endwrite(struct bitmap *bitm | |
70 | } | |
71 | } | |
72 | ||
73 | -int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, | |
74 | - int degraded) | |
75 | +static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, | |
76 | + int degraded) | |
77 | { | |
78 | bitmap_counter_t *bmc; | |
79 | int rv; | |
80 | @@ -1376,6 +1375,30 @@ int bitmap_start_sync(struct bitmap *bit | |
81 | return rv; | |
82 | } | |
83 | ||
84 | +int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, | |
85 | + int degraded) | |
86 | +{ | |
87 | + /* bitmap_start_sync must always report on multiples of whole | |
88 | + * pages, otherwise resync (which is very PAGE_SIZE based) will | |
89 | + * get confused. | |
90 | + * So call __bitmap_start_sync repeatedly (if needed) until | |
91 | + * At least PAGE_SIZE>>9 blocks are covered. | |
92 | + * Return the 'or' of the result. | |
93 | + */ | |
94 | + int rv = 0; | |
95 | + int blocks1; | |
96 | + | |
97 | + *blocks = 0; | |
98 | + while (*blocks < (PAGE_SIZE>>9)) { | |
99 | + rv |= __bitmap_start_sync(bitmap, offset, | |
100 | + &blocks1, degraded); | |
101 | + offset += blocks1; | |
102 | + *blocks += blocks1; | |
103 | + } | |
104 | + return rv; | |
105 | +} | |
106 | + | |
107 | + | |
108 | void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted) | |
109 | { | |
110 | bitmap_counter_t *bmc; |