diff options
author | NeilBrown <neilb@cse.unsw.edu.au> | 2005-06-21 20:17:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-21 22:07:47 -0400 |
commit | 8a5e9cf1d6626586ff08e49f400a006a9f0c3275 (patch) | |
tree | 3a3135209c0dcb5dd2899b8afcc1701e2fdcf732 /drivers/md | |
parent | 39730960d94306d7be414e8d54f4e5c071af1278 (diff) |
[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>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/bitmap.c | 68 |
1 files changed, 38 insertions, 30 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 030d6861051a..95980ad6b27b 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) | |||
313 | if (bitmap->file == NULL) | 313 | if (bitmap->file == NULL) |
314 | return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); | 314 | return write_sb_page(bitmap->mddev, bitmap->offset, page, wait); |
315 | 315 | ||
316 | lock_page(page); | 316 | if (wait) |
317 | lock_page(page); | ||
318 | else { | ||
319 | if (TestSetPageLocked(page)) | ||
320 | return -EAGAIN; /* already locked */ | ||
321 | if (PageWriteback(page)) { | ||
322 | unlock_page(page); | ||
323 | return -EAGAIN; | ||
324 | } | ||
325 | } | ||
317 | 326 | ||
318 | ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); | 327 | ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); |
319 | if (!ret) | 328 | if (!ret) |
@@ -400,7 +409,7 @@ int bitmap_update_sb(struct bitmap *bitmap) | |||
400 | if (!bitmap->mddev->degraded) | 409 | if (!bitmap->mddev->degraded) |
401 | sb->events_cleared = cpu_to_le64(bitmap->mddev->events); | 410 | sb->events_cleared = cpu_to_le64(bitmap->mddev->events); |
402 | kunmap(bitmap->sb_page); | 411 | kunmap(bitmap->sb_page); |
403 | return write_page(bitmap, bitmap->sb_page, 0); | 412 | return write_page(bitmap, bitmap->sb_page, 1); |
404 | } | 413 | } |
405 | 414 | ||
406 | /* print out the bitmap file superblock */ | 415 | /* print out the bitmap file superblock */ |
@@ -762,6 +771,7 @@ int bitmap_unplug(struct bitmap *bitmap) | |||
762 | unsigned long i, attr, flags; | 771 | unsigned long i, attr, flags; |
763 | struct page *page; | 772 | struct page *page; |
764 | int wait = 0; | 773 | int wait = 0; |
774 | int err; | ||
765 | 775 | ||
766 | if (!bitmap) | 776 | if (!bitmap) |
767 | return 0; | 777 | return 0; |
@@ -782,9 +792,17 @@ int bitmap_unplug(struct bitmap *bitmap) | |||
782 | wait = 1; | 792 | wait = 1; |
783 | spin_unlock_irqrestore(&bitmap->lock, flags); | 793 | spin_unlock_irqrestore(&bitmap->lock, flags); |
784 | 794 | ||
785 | if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) | 795 | if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) { |
786 | if (write_page(bitmap, page, 0)) | 796 | err = write_page(bitmap, page, 0); |
797 | if (err == -EAGAIN) { | ||
798 | if (attr & BITMAP_PAGE_DIRTY) | ||
799 | err = write_page(bitmap, page, 1); | ||
800 | else | ||
801 | err = 0; | ||
802 | } | ||
803 | if (err) | ||
787 | return 1; | 804 | return 1; |
805 | } | ||
788 | } | 806 | } |
789 | if (wait) { /* if any writes were performed, we need to wait on them */ | 807 | if (wait) { /* if any writes were performed, we need to wait on them */ |
790 | if (bitmap->file) { | 808 | if (bitmap->file) { |
@@ -1006,8 +1024,15 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
1006 | } | 1024 | } |
1007 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1025 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1008 | if (attr & BITMAP_PAGE_NEEDWRITE) { | 1026 | if (attr & BITMAP_PAGE_NEEDWRITE) { |
1009 | if (write_page(bitmap, page, 0)) | 1027 | switch (write_page(bitmap, page, 0)) { |
1028 | case -EAGAIN: | ||
1029 | set_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE); | ||
1030 | break; | ||
1031 | case 0: | ||
1032 | break; | ||
1033 | default: | ||
1010 | bitmap_file_kick(bitmap); | 1034 | bitmap_file_kick(bitmap); |
1035 | } | ||
1011 | page_cache_release(page); | 1036 | page_cache_release(page); |
1012 | } | 1037 | } |
1013 | continue; | 1038 | continue; |
@@ -1020,6 +1045,10 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
1020 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1045 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1021 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1046 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1022 | err = write_page(bitmap, lastpage, 0); | 1047 | err = write_page(bitmap, lastpage, 0); |
1048 | if (err == -EAGAIN) { | ||
1049 | err = 0; | ||
1050 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | ||
1051 | } | ||
1023 | } else { | 1052 | } else { |
1024 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1053 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1025 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1054 | spin_unlock_irqrestore(&bitmap->lock, flags); |
@@ -1068,6 +1097,10 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
1068 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1097 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1069 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1098 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1070 | err = write_page(bitmap, lastpage, 0); | 1099 | err = write_page(bitmap, lastpage, 0); |
1100 | if (err == -EAGAIN) { | ||
1101 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | ||
1102 | err = 0; | ||
1103 | } | ||
1071 | } else { | 1104 | } else { |
1072 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 1105 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1073 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1106 | spin_unlock_irqrestore(&bitmap->lock, flags); |
@@ -1421,31 +1454,6 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, | |||
1421 | } | 1454 | } |
1422 | } | 1455 | } |
1423 | 1456 | ||
1424 | /* dirty the entire bitmap */ | ||
1425 | int bitmap_setallbits(struct bitmap *bitmap) | ||
1426 | { | ||
1427 | unsigned long flags; | ||
1428 | unsigned long j; | ||
1429 | |||
1430 | /* dirty the in-memory bitmap */ | ||
1431 | bitmap_set_memory_bits(bitmap, 0, bitmap->chunks << CHUNK_BLOCK_SHIFT(bitmap), 1); | ||
1432 | |||
1433 | /* dirty the bitmap file */ | ||
1434 | for (j = 0; j < bitmap->file_pages; j++) { | ||
1435 | struct page *page = bitmap->filemap[j]; | ||
1436 | |||
1437 | spin_lock_irqsave(&bitmap->lock, flags); | ||
1438 | page_cache_get(page); | ||
1439 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
1440 | memset(kmap(page), 0xff, PAGE_SIZE); | ||
1441 | kunmap(page); | ||
1442 | if (write_page(bitmap, page, 0)) | ||
1443 | return 1; | ||
1444 | } | ||
1445 | |||
1446 | return 0; | ||
1447 | } | ||
1448 | |||
1449 | /* | 1457 | /* |
1450 | * free memory that was allocated | 1458 | * free memory that was allocated |
1451 | */ | 1459 | */ |