From 8a5e9cf1d6626586ff08e49f400a006a9f0c3275 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 21 Jun 2005 17:17:29 -0700 Subject: [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 Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 030d686..95980ad 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -313,7 +313,16 @@ static int write_page(struct bitmap *bitmap, struct page *page, int wait) if (bitmap->file == NULL) return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); - lock_page(page); + if (wait) + 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); if (!ret) @@ -400,7 +409,7 @@ int bitmap_update_sb(struct bitmap *bitmap) if (!bitmap->mddev->degraded) sb->events_cleared = cpu_to_le64(bitmap->mddev->events); 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 */ @@ -762,6 +771,7 @@ int bitmap_unplug(struct bitmap *bitmap) unsigned long i, attr, flags; struct page *page; int wait = 0; + int err; if (!bitmap) return 0; @@ -782,9 +792,17 @@ int bitmap_unplug(struct bitmap *bitmap) wait = 1; spin_unlock_irqrestore(&bitmap->lock, flags); - if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) - if (write_page(bitmap, page, 0)) + if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) { + 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; + } } if (wait) { /* if any writes were performed, we need to wait on them */ if (bitmap->file) { @@ -1006,8 +1024,15 @@ int bitmap_daemon_work(struct bitmap *bitmap) } spin_unlock_irqrestore(&bitmap->lock, flags); 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); + } page_cache_release(page); } continue; @@ -1020,6 +1045,10 @@ int bitmap_daemon_work(struct bitmap *bitmap) clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); spin_unlock_irqrestore(&bitmap->lock, flags); err = write_page(bitmap, lastpage, 0); + if (err == -EAGAIN) { + err = 0; + set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); + } } else { set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); 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); spin_unlock_irqrestore(&bitmap->lock, flags); err = write_page(bitmap, lastpage, 0); + if (err == -EAGAIN) { + set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); + err = 0; + } } else { set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); 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 */ -- cgit v0.10.2