aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_bitmap.c
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2010-12-15 17:21:39 -0500
committerPhilipp Reisner <philipp.reisner@linbit.com>2011-03-10 05:36:38 -0500
commit7777a8ba1fc980e5edfe492ebf5a1676497b8db2 (patch)
tree9eb81d2bee5bf63a796ae4df0b9cf352b3f0360b /drivers/block/drbd/drbd_bitmap.c
parent1b881ef77537f1077482f9946a6a99b4e2dd54b2 (diff)
drbd: bitmap: don't count unused bits (fix non-terminating resync)
We trusted the on-disk bitmap to have unused bits cleared. In case that is not true for whatever reason, and we take a code path where the unused bits don't get cleared elsewhere (bm_clear_surplus is not called), we may miscount the bits, and get confused during resync, waiting for bits to get cleared that we don't even use: the resync process would not terminate. Fix this by masking out unused bits in __bm_count_bits. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_bitmap.c')
-rw-r--r--drivers/block/drbd/drbd_bitmap.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index 9390e9526786..c5361487cf47 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -376,9 +376,16 @@ static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endia
376 unsigned long *p_addr, *bm, offset = 0; 376 unsigned long *p_addr, *bm, offset = 0;
377 unsigned long bits = 0; 377 unsigned long bits = 0;
378 unsigned long i, do_now; 378 unsigned long i, do_now;
379 unsigned long words;
379 380
380 while (offset < b->bm_words) { 381 /* due to 64bit alignment, the last long on a 32bit arch
381 i = do_now = min_t(size_t, b->bm_words-offset, LWPP); 382 * may be not used at all. The last used long will likely
383 * be only partially used, always. Don't count those bits,
384 * but mask them out. */
385 words = (b->bm_bits + BITS_PER_LONG - 1) >> LN2_BPL;
386
387 while (offset < words) {
388 i = do_now = min_t(size_t, words-offset, LWPP);
382 p_addr = __bm_map_paddr(b, offset, KM_USER0); 389 p_addr = __bm_map_paddr(b, offset, KM_USER0);
383 bm = p_addr + MLPP(offset); 390 bm = p_addr + MLPP(offset);
384 while (i--) { 391 while (i--) {
@@ -388,8 +395,20 @@ static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endia
388#endif 395#endif
389 bits += hweight_long(*bm++); 396 bits += hweight_long(*bm++);
390 } 397 }
391 __bm_unmap(p_addr, KM_USER0);
392 offset += do_now; 398 offset += do_now;
399 if (offset == words) {
400 /* last word may only be partially used,
401 * see also bm_clear_surplus. */
402 i = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1;
403 if (i) {
404 bits -= hweight_long(p_addr[do_now-1] & ~i);
405 p_addr[do_now-1] &= i;
406 }
407 /* 32bit arch, may have an unused padding long */
408 if (words != b->bm_words)
409 p_addr[do_now] = 0;
410 }
411 __bm_unmap(p_addr, KM_USER0);
393 cond_resched(); 412 cond_resched();
394 } 413 }
395 414