[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: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
committed by
Linus Torvalds
parent
39730960d9
commit
8a5e9cf1d6
@@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user