From a8f4cc652396ab33894faf61e7918fc369f99ca6 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 15 Dec 2010 23:21:39 +0100 Subject: [PATCH] --- yaml --- r: 242865 b: refs/heads/master c: 7777a8ba1fc980e5edfe492ebf5a1676497b8db2 h: refs/heads/master i: 242863: 4c74133663325844c5c6adba704ba5c4a080b06b v: v3 --- [refs] | 2 +- trunk/drivers/block/drbd/drbd_bitmap.c | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/[refs] b/[refs] index f53fe91e6208..4bf1dee62dc2 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 1b881ef77537f1077482f9946a6a99b4e2dd54b2 +refs/heads/master: 7777a8ba1fc980e5edfe492ebf5a1676497b8db2 diff --git a/trunk/drivers/block/drbd/drbd_bitmap.c b/trunk/drivers/block/drbd/drbd_bitmap.c index 9390e9526786..c5361487cf47 100644 --- a/trunk/drivers/block/drbd/drbd_bitmap.c +++ b/trunk/drivers/block/drbd/drbd_bitmap.c @@ -376,9 +376,16 @@ static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endia unsigned long *p_addr, *bm, offset = 0; unsigned long bits = 0; unsigned long i, do_now; + unsigned long words; - while (offset < b->bm_words) { - i = do_now = min_t(size_t, b->bm_words-offset, LWPP); + /* due to 64bit alignment, the last long on a 32bit arch + * may be not used at all. The last used long will likely + * be only partially used, always. Don't count those bits, + * but mask them out. */ + words = (b->bm_bits + BITS_PER_LONG - 1) >> LN2_BPL; + + while (offset < words) { + i = do_now = min_t(size_t, words-offset, LWPP); p_addr = __bm_map_paddr(b, offset, KM_USER0); bm = p_addr + MLPP(offset); while (i--) { @@ -388,8 +395,20 @@ static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endia #endif bits += hweight_long(*bm++); } - __bm_unmap(p_addr, KM_USER0); offset += do_now; + if (offset == words) { + /* last word may only be partially used, + * see also bm_clear_surplus. */ + i = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1; + if (i) { + bits -= hweight_long(p_addr[do_now-1] & ~i); + p_addr[do_now-1] &= i; + } + /* 32bit arch, may have an unused padding long */ + if (words != b->bm_words) + p_addr[do_now] = 0; + } + __bm_unmap(p_addr, KM_USER0); cond_resched(); }