[PATCH] md: make sure md/bitmap doesn't try to write a page with active writeback
authorNeilBrown <neilb@cse.unsw.edu.au>
Wed, 22 Jun 2005 00:17:29 +0000 (17:17 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Wed, 22 Jun 2005 02:07:47 +0000 (19:07 -0700)
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>
drivers/md/bitmap.c

index 030d686..95980ad 100644 (file)
@@ -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
  */