Skip to content

Commit

Permalink
[PATCH] md: avoid possible BUG_ON in md bitmap handling
Browse files Browse the repository at this point in the history
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 <neilb@suse.de>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Neil Brown authored and Linus Torvalds committed Feb 9, 2007
1 parent aaf68cf commit da6e1a3
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 1 deletion.
22 changes: 21 additions & 1 deletion drivers/md/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,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);
Expand All @@ -1169,7 +1185,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
case 1:
*bmc = 2;
}
BUG_ON((*bmc & COUNTER_MAX) == COUNTER_MAX);

(*bmc)++;

spin_unlock_irq(&bitmap->lock);
Expand Down Expand Up @@ -1207,6 +1223,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,
Expand Down Expand Up @@ -1431,6 +1450,7 @@ int bitmap_create(mddev_t *mddev)
spin_lock_init(&bitmap->lock);
atomic_set(&bitmap->pending_writes, 0);
init_waitqueue_head(&bitmap->write_wait);
init_waitqueue_head(&bitmap->overflow_wait);

bitmap->mddev = mddev;

Expand Down
1 change: 1 addition & 0 deletions include/linux/raid/bitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ struct bitmap {

atomic_t pending_writes; /* pending writes to the bitmap file */
wait_queue_head_t write_wait;
wait_queue_head_t overflow_wait;

};

Expand Down

0 comments on commit da6e1a3

Please sign in to comment.