aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bitmap.c22
-rw-r--r--include/linux/raid/bitmap.h2
2 files changed, 23 insertions, 1 deletions
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);
diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h
index 48e2d93d23fb..a9b7629b0e23 100644
--- a/include/linux/raid/bitmap.h
+++ b/include/linux/raid/bitmap.h
@@ -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 */