]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
md: avoid possible BUG_ON in md bitmap handling
authorNeil Brown <neilb@suse.de>
Thu, 23 Aug 2007 00:13:17 +0000 (02:13 +0200)
committerAdrian Bunk <bunk@stusta.de>
Thu, 23 Aug 2007 00:13:17 +0000 (02:13 +0200)
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>
Signed-off-by: Adrian Bunk <bunk@kernel.org>
drivers/md/bitmap.c
include/linux/raid/bitmap.h

index 2150693145fcba57468dd97736dfeae54279fef5..b7d9759be6043ea413a0346622a25396526a8c78 100644 (file)
@@ -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);
index 48e2d93d23fb18c8bb1d731a1dc49893ea2c00cc..a9b7629b0e2338d146b9765e2792a1e8097a0d81 100644 (file)
@@ -253,6 +253,8 @@ struct bitmap {
        wait_queue_head_t write_wait;
        struct list_head complete_pages;
        mempool_t *write_pool;
+
+       wait_queue_head_t overflow_wait;
 };
 
 /* the bitmap API */