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 | |
| 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>
| -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 | */ |
