Commit 8a5e9cf1 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] md: make sure md/bitmap doesn't try to write a page with active writeback

Due to the use of write-behind, it is possible for md to write a page to
the bitmap file that is still completing writeback.  This is not allowed.

With this patch, we detect those cases and either force a sync write, or
back off and try later, as appropriate.
Signed-off-by: default avatarNeil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 39730960
...@@ -313,7 +313,16 @@ static int write_page(struct bitmap *bitmap, struct page *page, int wait) ...@@ -313,7 +313,16 @@ static int write_page(struct bitmap *bitmap, struct page *page, int wait)
if (bitmap->file == NULL) if (bitmap->file == NULL)
return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); return write_sb_page(bitmap->mddev, bitmap->offset, page, wait);
if (wait)
lock_page(page); lock_page(page);
else {
if (TestSetPageLocked(page))
return -EAGAIN; /* already locked */
if (PageWriteback(page)) {
unlock_page(page);
return -EAGAIN;
}
}
ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE);
if (!ret) if (!ret)
...@@ -400,7 +409,7 @@ int bitmap_update_sb(struct bitmap *bitmap) ...@@ -400,7 +409,7 @@ int bitmap_update_sb(struct bitmap *bitmap)
if (!bitmap->mddev->degraded) if (!bitmap->mddev->degraded)
sb->events_cleared = cpu_to_le64(bitmap->mddev->events); sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
kunmap(bitmap->sb_page); kunmap(bitmap->sb_page);
return write_page(bitmap, bitmap->sb_page, 0); return write_page(bitmap, bitmap->sb_page, 1);
} }
/* print out the bitmap file superblock */ /* print out the bitmap file superblock */
...@@ -762,6 +771,7 @@ int bitmap_unplug(struct bitmap *bitmap) ...@@ -762,6 +771,7 @@ int bitmap_unplug(struct bitmap *bitmap)
unsigned long i, attr, flags; unsigned long i, attr, flags;
struct page *page; struct page *page;
int wait = 0; int wait = 0;
int err;
if (!bitmap) if (!bitmap)
return 0; return 0;
...@@ -782,10 +792,18 @@ int bitmap_unplug(struct bitmap *bitmap) ...@@ -782,10 +792,18 @@ int bitmap_unplug(struct bitmap *bitmap)
wait = 1; wait = 1;
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) {
if (write_page(bitmap, page, 0)) err = write_page(bitmap, page, 0);
if (err == -EAGAIN) {
if (attr & BITMAP_PAGE_DIRTY)
err = write_page(bitmap, page, 1);
else
err = 0;
}
if (err)
return 1; return 1;
} }
}
if (wait) { /* if any writes were performed, we need to wait on them */ if (wait) { /* if any writes were performed, we need to wait on them */
if (bitmap->file) { if (bitmap->file) {
spin_lock_irq(&bitmap->write_lock); spin_lock_irq(&bitmap->write_lock);
...@@ -1006,8 +1024,15 @@ int bitmap_daemon_work(struct bitmap *bitmap) ...@@ -1006,8 +1024,15 @@ int bitmap_daemon_work(struct bitmap *bitmap)
} }
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
if (attr & BITMAP_PAGE_NEEDWRITE) { if (attr & BITMAP_PAGE_NEEDWRITE) {
if (write_page(bitmap, page, 0)) switch (write_page(bitmap, page, 0)) {
case -EAGAIN:
set_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
break;
case 0:
break;
default:
bitmap_file_kick(bitmap); bitmap_file_kick(bitmap);
}
page_cache_release(page); page_cache_release(page);
} }
continue; continue;
...@@ -1020,6 +1045,10 @@ int bitmap_daemon_work(struct bitmap *bitmap) ...@@ -1020,6 +1045,10 @@ int bitmap_daemon_work(struct bitmap *bitmap)
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
err = write_page(bitmap, lastpage, 0); err = write_page(bitmap, lastpage, 0);
if (err == -EAGAIN) {
err = 0;
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
}
} else { } else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
...@@ -1068,6 +1097,10 @@ int bitmap_daemon_work(struct bitmap *bitmap) ...@@ -1068,6 +1097,10 @@ int bitmap_daemon_work(struct bitmap *bitmap)
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
err = write_page(bitmap, lastpage, 0); err = write_page(bitmap, lastpage, 0);
if (err == -EAGAIN) {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
err = 0;
}
} else { } else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
...@@ -1421,31 +1454,6 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, ...@@ -1421,31 +1454,6 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset,
} }
} }
/* dirty the entire bitmap */
int bitmap_setallbits(struct bitmap *bitmap)
{
unsigned long flags;
unsigned long j;
/* dirty the in-memory bitmap */
bitmap_set_memory_bits(bitmap, 0, bitmap->chunks << CHUNK_BLOCK_SHIFT(bitmap), 1);
/* dirty the bitmap file */
for (j = 0; j < bitmap->file_pages; j++) {
struct page *page = bitmap->filemap[j];
spin_lock_irqsave(&bitmap->lock, flags);
page_cache_get(page);
spin_unlock_irqrestore(&bitmap->lock, flags);
memset(kmap(page), 0xff, PAGE_SIZE);
kunmap(page);
if (write_page(bitmap, page, 0))
return 1;
}
return 0;
}
/* /*
* free memory that was allocated * free memory that was allocated
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment