aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2011-06-03 15:18:13 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2011-06-30 03:23:41 -0400
commit829c60878626be290a4c248e8f1b86a0d5cbd38b (patch)
tree3774c1a3abb72bcc5ab0b37a23fdd9727ca188e4 /drivers/block
parent0cfdd247d1779d5ffc8f685b172a526ecdc6773f (diff)
drbd: add missing spinlock to bitmap receive
During bitmap exchange, when using the RLE bitmap compression scheme, we have a code path that can set the whole bitmap at once. To avoid holding spin_lock_irq() for too long, we used to lock out other bitmap modifications during bitmap exchange by other means, and then, knowing we have exclusive access to the bitmap, modify it without the spinlock, and with IRQs enabled. Since we now allow local IO to continue, potentially setting additional bits during the bitmap receive phase, this is no longer true, and we get uncoordinated updates of bitmap members, causing bm_set to no longer accurately reflect the total number of set bits. To actually see this, you'd need to have a large bitmap, use RLE bitmap compression, and have busy IO during sync handshake and bitmap exchange. Fix this by taking the spin_lock_irq() in this code path as well, but calling cond_resched_lock() after each page worth of bits processed. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/drbd/drbd_bitmap.c34
1 files changed, 19 insertions, 15 deletions
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index f440a02dfdb1..1e89a74ddb17 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -112,9 +112,6 @@ struct drbd_bitmap {
112 struct task_struct *bm_task; 112 struct task_struct *bm_task;
113}; 113};
114 114
115static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
116 unsigned long e, int val, const enum km_type km);
117
118#define bm_print_lock_info(m) __bm_print_lock_info(m, __func__) 115#define bm_print_lock_info(m) __bm_print_lock_info(m, __func__)
119static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) 116static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func)
120{ 117{
@@ -1256,7 +1253,7 @@ unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_f
1256 * expected to be called for only a few bits (e - s about BITS_PER_LONG). 1253 * expected to be called for only a few bits (e - s about BITS_PER_LONG).
1257 * Must hold bitmap lock already. */ 1254 * Must hold bitmap lock already. */
1258static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, 1255static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
1259 unsigned long e, int val, const enum km_type km) 1256 unsigned long e, int val)
1260{ 1257{
1261 struct drbd_bitmap *b = mdev->bitmap; 1258 struct drbd_bitmap *b = mdev->bitmap;
1262 unsigned long *p_addr = NULL; 1259 unsigned long *p_addr = NULL;
@@ -1274,14 +1271,14 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
1274 unsigned int page_nr = bm_bit_to_page_idx(b, bitnr); 1271 unsigned int page_nr = bm_bit_to_page_idx(b, bitnr);
1275 if (page_nr != last_page_nr) { 1272 if (page_nr != last_page_nr) {
1276 if (p_addr) 1273 if (p_addr)
1277 __bm_unmap(p_addr, km); 1274 __bm_unmap(p_addr, KM_IRQ1);
1278 if (c < 0) 1275 if (c < 0)
1279 bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); 1276 bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]);
1280 else if (c > 0) 1277 else if (c > 0)
1281 bm_set_page_need_writeout(b->bm_pages[last_page_nr]); 1278 bm_set_page_need_writeout(b->bm_pages[last_page_nr]);
1282 changed_total += c; 1279 changed_total += c;
1283 c = 0; 1280 c = 0;
1284 p_addr = __bm_map_pidx(b, page_nr, km); 1281 p_addr = __bm_map_pidx(b, page_nr, KM_IRQ1);
1285 last_page_nr = page_nr; 1282 last_page_nr = page_nr;
1286 } 1283 }
1287 if (val) 1284 if (val)
@@ -1290,7 +1287,7 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
1290 c -= (0 != __test_and_clear_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr)); 1287 c -= (0 != __test_and_clear_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr));
1291 } 1288 }
1292 if (p_addr) 1289 if (p_addr)
1293 __bm_unmap(p_addr, km); 1290 __bm_unmap(p_addr, KM_IRQ1);
1294 if (c < 0) 1291 if (c < 0)
1295 bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); 1292 bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]);
1296 else if (c > 0) 1293 else if (c > 0)
@@ -1318,7 +1315,7 @@ static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s,
1318 if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags) 1315 if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags)
1319 bm_print_lock_info(mdev); 1316 bm_print_lock_info(mdev);
1320 1317
1321 c = __bm_change_bits_to(mdev, s, e, val, KM_IRQ1); 1318 c = __bm_change_bits_to(mdev, s, e, val);
1322 1319
1323 spin_unlock_irqrestore(&b->bm_lock, flags); 1320 spin_unlock_irqrestore(&b->bm_lock, flags);
1324 return c; 1321 return c;
@@ -1343,16 +1340,17 @@ static inline void bm_set_full_words_within_one_page(struct drbd_bitmap *b,
1343{ 1340{
1344 int i; 1341 int i;
1345 int bits; 1342 int bits;
1346 unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr], KM_USER0); 1343 unsigned long *paddr = kmap_atomic(b->bm_pages[page_nr], KM_IRQ1);
1347 for (i = first_word; i < last_word; i++) { 1344 for (i = first_word; i < last_word; i++) {
1348 bits = hweight_long(paddr[i]); 1345 bits = hweight_long(paddr[i]);
1349 paddr[i] = ~0UL; 1346 paddr[i] = ~0UL;
1350 b->bm_set += BITS_PER_LONG - bits; 1347 b->bm_set += BITS_PER_LONG - bits;
1351 } 1348 }
1352 kunmap_atomic(paddr, KM_USER0); 1349 kunmap_atomic(paddr, KM_IRQ1);
1353} 1350}
1354 1351
1355/* Same thing as drbd_bm_set_bits, but without taking the spin_lock_irqsave. 1352/* Same thing as drbd_bm_set_bits,
1353 * but more efficient for a large bit range.
1356 * You must first drbd_bm_lock(). 1354 * You must first drbd_bm_lock().
1357 * Can be called to set the whole bitmap in one go. 1355 * Can be called to set the whole bitmap in one go.
1358 * Sets bits from s to e _inclusive_. */ 1356 * Sets bits from s to e _inclusive_. */
@@ -1366,6 +1364,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
1366 * Do not use memset, because we must account for changes, 1364 * Do not use memset, because we must account for changes,
1367 * so we need to loop over the words with hweight() anyways. 1365 * so we need to loop over the words with hweight() anyways.
1368 */ 1366 */
1367 struct drbd_bitmap *b = mdev->bitmap;
1369 unsigned long sl = ALIGN(s,BITS_PER_LONG); 1368 unsigned long sl = ALIGN(s,BITS_PER_LONG);
1370 unsigned long el = (e+1) & ~((unsigned long)BITS_PER_LONG-1); 1369 unsigned long el = (e+1) & ~((unsigned long)BITS_PER_LONG-1);
1371 int first_page; 1370 int first_page;
@@ -1376,15 +1375,19 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
1376 1375
1377 if (e - s <= 3*BITS_PER_LONG) { 1376 if (e - s <= 3*BITS_PER_LONG) {
1378 /* don't bother; el and sl may even be wrong. */ 1377 /* don't bother; el and sl may even be wrong. */
1379 __bm_change_bits_to(mdev, s, e, 1, KM_USER0); 1378 spin_lock_irq(&b->bm_lock);
1379 __bm_change_bits_to(mdev, s, e, 1);
1380 spin_unlock_irq(&b->bm_lock);
1380 return; 1381 return;
1381 } 1382 }
1382 1383
1383 /* difference is large enough that we can trust sl and el */ 1384 /* difference is large enough that we can trust sl and el */
1384 1385
1386 spin_lock_irq(&b->bm_lock);
1387
1385 /* bits filling the current long */ 1388 /* bits filling the current long */
1386 if (sl) 1389 if (sl)
1387 __bm_change_bits_to(mdev, s, sl-1, 1, KM_USER0); 1390 __bm_change_bits_to(mdev, s, sl-1, 1);
1388 1391
1389 first_page = sl >> (3 + PAGE_SHIFT); 1392 first_page = sl >> (3 + PAGE_SHIFT);
1390 last_page = el >> (3 + PAGE_SHIFT); 1393 last_page = el >> (3 + PAGE_SHIFT);
@@ -1397,7 +1400,7 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
1397 /* first and full pages, unless first page == last page */ 1400 /* first and full pages, unless first page == last page */
1398 for (page_nr = first_page; page_nr < last_page; page_nr++) { 1401 for (page_nr = first_page; page_nr < last_page; page_nr++) {
1399 bm_set_full_words_within_one_page(mdev->bitmap, page_nr, first_word, last_word); 1402 bm_set_full_words_within_one_page(mdev->bitmap, page_nr, first_word, last_word);
1400 cond_resched(); 1403 cond_resched_lock(&b->bm_lock);
1401 first_word = 0; 1404 first_word = 0;
1402 } 1405 }
1403 1406
@@ -1411,7 +1414,8 @@ void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsi
1411 * it would trigger an assert in __bm_change_bits_to() 1414 * it would trigger an assert in __bm_change_bits_to()
1412 */ 1415 */
1413 if (el <= e) 1416 if (el <= e)
1414 __bm_change_bits_to(mdev, el, e, 1, KM_USER0); 1417 __bm_change_bits_to(mdev, el, e, 1);
1418 spin_unlock_irq(&b->bm_lock);
1415} 1419}
1416 1420
1417/* returns bit state 1421/* returns bit state