From 646edb4b5b9c472944af7d6016722fa4895f3bca Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 23 Aug 2007 02:13:17 +0200 Subject: md: avoid possible BUG_ON in md bitmap handling md/bitmap tracks how many active write requests are pending on blocks associated with each bit in the bitmap, so that it knows when it can clear the bit (when count hits zero). The counter has 14 bits of space, so if there are ever more than 16383, we cannot cope. Currently the code just calles BUG_ON as "all" drivers have request queue limits much smaller than this. However is seems that some don't. Apparently some multipath configurations can allow more than 16383 concurrent write requests. So, in this unlikely situation, instead of calling BUG_ON we now wait for the count to drop down a bit. This requires a new wait_queue_head, some waiting code, and a wakeup call. Tested by limiting the counter to 20 instead of 16383 (writes go a lot slower in that case...). Signed-off-by: Neil Brown Signed-off-by: Adrian Bunk --- drivers/md/bitmap.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 2150693145fc..b7d9759be604 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1266,6 +1266,22 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect return 0; } + if (unlikely((*bmc & COUNTER_MAX) == COUNTER_MAX)) { + DEFINE_WAIT(__wait); + /* note that it is safe to do the prepare_to_wait + * after the test as long as we do it before dropping + * the spinlock. + */ + prepare_to_wait(&bitmap->overflow_wait, &__wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&bitmap->lock); + bitmap->mddev->queue + ->unplug_fn(bitmap->mddev->queue); + schedule(); + finish_wait(&bitmap->overflow_wait, &__wait); + continue; + } + switch(*bmc) { case 0: bitmap_file_set_bit(bitmap, offset); @@ -1275,7 +1291,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect case 1: *bmc = 2; } - if ((*bmc & COUNTER_MAX) == COUNTER_MAX) BUG(); + (*bmc)++; spin_unlock_irq(&bitmap->lock); @@ -1313,6 +1329,9 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto if (!success && ! (*bmc & NEEDED_MASK)) *bmc |= NEEDED_MASK; + if ((*bmc & COUNTER_MAX) == COUNTER_MAX) + wake_up(&bitmap->overflow_wait); + (*bmc)--; if (*bmc <= 2) { set_page_attr(bitmap, @@ -1525,6 +1544,7 @@ int bitmap_create(mddev_t *mddev) return -ENOMEM; spin_lock_init(&bitmap->lock); + init_waitqueue_head(&bitmap->overflow_wait); bitmap->mddev = mddev; spin_lock_init(&bitmap->write_lock); -- cgit v1.2.3