diff options
author | NeilBrown <neilb@cse.unsw.edu.au> | 2005-06-21 20:17:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-21 22:07:45 -0400 |
commit | 77ad4bc706fe6c52ab953f31c287a6af712d080c (patch) | |
tree | 6823261d0e111a93c5190ebb1f2ecd8c4905a559 /drivers/md | |
parent | bfb39fba4e8cdda091f9ebee29fbb8331c4bb605 (diff) |
[PATCH] md: enable the bitmap write-back daemon and wait for it.
Currently we don't wait for updates to the bitmap to be flushed to disk
properly. The infrastructure all there, but it isn't being used....
A separate kernel thread (bitmap_writeback_daemon) is needed to wait for each
page as we cannot get callbacks when a page write completes.
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 | 119 |
1 files changed, 53 insertions, 66 deletions
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 9462fdd517c0..86b6b037fa44 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c | |||
@@ -261,30 +261,33 @@ char *file_path(struct file *file, char *buf, int count) | |||
261 | /* | 261 | /* |
262 | * write out a page | 262 | * write out a page |
263 | */ | 263 | */ |
264 | static int write_page(struct page *page, int wait) | 264 | static int write_page(struct bitmap *bitmap, struct page *page, int wait) |
265 | { | 265 | { |
266 | int ret = -ENOMEM; | 266 | int ret = -ENOMEM; |
267 | 267 | ||
268 | lock_page(page); | 268 | lock_page(page); |
269 | 269 | ||
270 | if (page->mapping == NULL) | ||
271 | goto unlock_out; | ||
272 | else if (i_size_read(page->mapping->host) < page->index << PAGE_SHIFT) { | ||
273 | ret = -ENOENT; | ||
274 | goto unlock_out; | ||
275 | } | ||
276 | |||
277 | ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); | 270 | ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); |
278 | if (!ret) | 271 | if (!ret) |
279 | ret = page->mapping->a_ops->commit_write(NULL, page, 0, | 272 | ret = page->mapping->a_ops->commit_write(NULL, page, 0, |
280 | PAGE_SIZE); | 273 | PAGE_SIZE); |
281 | if (ret) { | 274 | if (ret) { |
282 | unlock_out: | ||
283 | unlock_page(page); | 275 | unlock_page(page); |
284 | return ret; | 276 | return ret; |
285 | } | 277 | } |
286 | 278 | ||
287 | set_page_dirty(page); /* force it to be written out */ | 279 | set_page_dirty(page); /* force it to be written out */ |
280 | |||
281 | if (!wait) { | ||
282 | /* add to list to be waited for by daemon */ | ||
283 | struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO); | ||
284 | item->page = page; | ||
285 | page_cache_get(page); | ||
286 | spin_lock(&bitmap->write_lock); | ||
287 | list_add(&item->list, &bitmap->complete_pages); | ||
288 | spin_unlock(&bitmap->write_lock); | ||
289 | md_wakeup_thread(bitmap->writeback_daemon); | ||
290 | } | ||
288 | return write_one_page(page, wait); | 291 | return write_one_page(page, wait); |
289 | } | 292 | } |
290 | 293 | ||
@@ -343,14 +346,13 @@ int bitmap_update_sb(struct bitmap *bitmap) | |||
343 | spin_unlock_irqrestore(&bitmap->lock, flags); | 346 | spin_unlock_irqrestore(&bitmap->lock, flags); |
344 | return 0; | 347 | return 0; |
345 | } | 348 | } |
346 | page_cache_get(bitmap->sb_page); | ||
347 | spin_unlock_irqrestore(&bitmap->lock, flags); | 349 | spin_unlock_irqrestore(&bitmap->lock, flags); |
348 | sb = (bitmap_super_t *)kmap(bitmap->sb_page); | 350 | sb = (bitmap_super_t *)kmap(bitmap->sb_page); |
349 | sb->events = cpu_to_le64(bitmap->mddev->events); | 351 | sb->events = cpu_to_le64(bitmap->mddev->events); |
350 | if (!bitmap->mddev->degraded) | 352 | if (!bitmap->mddev->degraded) |
351 | sb->events_cleared = cpu_to_le64(bitmap->mddev->events); | 353 | sb->events_cleared = cpu_to_le64(bitmap->mddev->events); |
352 | kunmap(bitmap->sb_page); | 354 | kunmap(bitmap->sb_page); |
353 | return write_page(bitmap->sb_page, 0); | 355 | return write_page(bitmap, bitmap->sb_page, 0); |
354 | } | 356 | } |
355 | 357 | ||
356 | /* print out the bitmap file superblock */ | 358 | /* print out the bitmap file superblock */ |
@@ -556,10 +558,10 @@ static void bitmap_file_unmap(struct bitmap *bitmap) | |||
556 | static void bitmap_stop_daemons(struct bitmap *bitmap); | 558 | static void bitmap_stop_daemons(struct bitmap *bitmap); |
557 | 559 | ||
558 | /* dequeue the next item in a page list -- don't call from irq context */ | 560 | /* dequeue the next item in a page list -- don't call from irq context */ |
559 | static struct page_list *dequeue_page(struct bitmap *bitmap, | 561 | static struct page_list *dequeue_page(struct bitmap *bitmap) |
560 | struct list_head *head) | ||
561 | { | 562 | { |
562 | struct page_list *item = NULL; | 563 | struct page_list *item = NULL; |
564 | struct list_head *head = &bitmap->complete_pages; | ||
563 | 565 | ||
564 | spin_lock(&bitmap->write_lock); | 566 | spin_lock(&bitmap->write_lock); |
565 | if (list_empty(head)) | 567 | if (list_empty(head)) |
@@ -573,23 +575,15 @@ out: | |||
573 | 575 | ||
574 | static void drain_write_queues(struct bitmap *bitmap) | 576 | static void drain_write_queues(struct bitmap *bitmap) |
575 | { | 577 | { |
576 | struct list_head *queues[] = { &bitmap->complete_pages, NULL }; | ||
577 | struct list_head *head; | ||
578 | struct page_list *item; | 578 | struct page_list *item; |
579 | int i; | ||
580 | 579 | ||
581 | for (i = 0; queues[i]; i++) { | 580 | while ((item = dequeue_page(bitmap))) { |
582 | head = queues[i]; | 581 | /* don't bother to wait */ |
583 | while ((item = dequeue_page(bitmap, head))) { | 582 | page_cache_release(item->page); |
584 | page_cache_release(item->page); | 583 | mempool_free(item, bitmap->write_pool); |
585 | mempool_free(item, bitmap->write_pool); | ||
586 | } | ||
587 | } | 584 | } |
588 | 585 | ||
589 | spin_lock(&bitmap->write_lock); | ||
590 | bitmap->writes_pending = 0; /* make sure waiters continue */ | ||
591 | wake_up(&bitmap->write_wait); | 586 | wake_up(&bitmap->write_wait); |
592 | spin_unlock(&bitmap->write_lock); | ||
593 | } | 587 | } |
594 | 588 | ||
595 | static void bitmap_file_put(struct bitmap *bitmap) | 589 | static void bitmap_file_put(struct bitmap *bitmap) |
@@ -734,13 +728,13 @@ int bitmap_unplug(struct bitmap *bitmap) | |||
734 | spin_unlock_irqrestore(&bitmap->lock, flags); | 728 | spin_unlock_irqrestore(&bitmap->lock, flags); |
735 | 729 | ||
736 | if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) | 730 | if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) |
737 | if (write_page(page, 0)) | 731 | if (write_page(bitmap, page, 0)) |
738 | return 1; | 732 | return 1; |
739 | } | 733 | } |
740 | if (wait) { /* if any writes were performed, we need to wait on them */ | 734 | if (wait) { /* if any writes were performed, we need to wait on them */ |
741 | spin_lock_irq(&bitmap->write_lock); | 735 | spin_lock_irq(&bitmap->write_lock); |
742 | wait_event_lock_irq(bitmap->write_wait, | 736 | wait_event_lock_irq(bitmap->write_wait, |
743 | bitmap->writes_pending == 0, bitmap->write_lock, | 737 | list_empty(&bitmap->complete_pages), bitmap->write_lock, |
744 | wake_up_process(bitmap->writeback_daemon->tsk)); | 738 | wake_up_process(bitmap->writeback_daemon->tsk)); |
745 | spin_unlock_irq(&bitmap->write_lock); | 739 | spin_unlock_irq(&bitmap->write_lock); |
746 | } | 740 | } |
@@ -841,7 +835,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync) | |||
841 | */ | 835 | */ |
842 | memset(page_address(page) + offset, 0xff, | 836 | memset(page_address(page) + offset, 0xff, |
843 | PAGE_SIZE - offset); | 837 | PAGE_SIZE - offset); |
844 | ret = write_page(page, 1); | 838 | ret = write_page(bitmap, page, 1); |
845 | if (ret) { | 839 | if (ret) { |
846 | kunmap(page); | 840 | kunmap(page); |
847 | /* release, page not in filemap yet */ | 841 | /* release, page not in filemap yet */ |
@@ -934,7 +928,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
934 | } | 928 | } |
935 | spin_unlock_irqrestore(&bitmap->lock, flags); | 929 | spin_unlock_irqrestore(&bitmap->lock, flags); |
936 | if (attr & BITMAP_PAGE_NEEDWRITE) { | 930 | if (attr & BITMAP_PAGE_NEEDWRITE) { |
937 | if (write_page(page, 0)) | 931 | if (write_page(bitmap, page, 0)) |
938 | bitmap_file_kick(bitmap); | 932 | bitmap_file_kick(bitmap); |
939 | page_cache_release(page); | 933 | page_cache_release(page); |
940 | } | 934 | } |
@@ -950,7 +944,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
950 | if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) { | 944 | if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) { |
951 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 945 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
952 | spin_unlock_irqrestore(&bitmap->lock, flags); | 946 | spin_unlock_irqrestore(&bitmap->lock, flags); |
953 | err = write_page(lastpage, 0); | 947 | err = write_page(bitmap, lastpage, 0); |
954 | } else { | 948 | } else { |
955 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 949 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
956 | spin_unlock_irqrestore(&bitmap->lock, flags); | 950 | spin_unlock_irqrestore(&bitmap->lock, flags); |
@@ -998,7 +992,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) | |||
998 | if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) { | 992 | if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) { |
999 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 993 | clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1000 | spin_unlock_irqrestore(&bitmap->lock, flags); | 994 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1001 | err = write_page(lastpage, 0); | 995 | err = write_page(bitmap, lastpage, 0); |
1002 | } else { | 996 | } else { |
1003 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); | 997 | set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); |
1004 | spin_unlock_irqrestore(&bitmap->lock, flags); | 998 | spin_unlock_irqrestore(&bitmap->lock, flags); |
@@ -1034,46 +1028,40 @@ static void bitmap_writeback_daemon(mddev_t *mddev) | |||
1034 | struct page_list *item; | 1028 | struct page_list *item; |
1035 | int err = 0; | 1029 | int err = 0; |
1036 | 1030 | ||
1037 | while (1) { | 1031 | if (signal_pending(current)) { |
1038 | PRINTK("%s: bitmap writeback daemon waiting...\n", bmname(bitmap)); | 1032 | printk(KERN_INFO |
1039 | down_interruptible(&bitmap->write_done); | 1033 | "%s: bitmap writeback daemon got signal, exiting...\n", |
1040 | if (signal_pending(current)) { | 1034 | bmname(bitmap)); |
1041 | printk(KERN_INFO | 1035 | err = -EINTR; |
1042 | "%s: bitmap writeback daemon got signal, exiting...\n", | 1036 | goto out; |
1043 | bmname(bitmap)); | 1037 | } |
1044 | break; | ||
1045 | } | ||
1046 | 1038 | ||
1047 | PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap)); | 1039 | PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap)); |
1048 | /* wait on bitmap page writebacks */ | 1040 | /* wait on bitmap page writebacks */ |
1049 | while ((item = dequeue_page(bitmap, &bitmap->complete_pages))) { | 1041 | while ((item = dequeue_page(bitmap))) { |
1050 | page = item->page; | 1042 | page = item->page; |
1051 | mempool_free(item, bitmap->write_pool); | 1043 | mempool_free(item, bitmap->write_pool); |
1052 | PRINTK("wait on page writeback: %p %lu\n", page, bitmap->writes_pending); | 1044 | PRINTK("wait on page writeback: %p\n", page); |
1053 | wait_on_page_writeback(page); | 1045 | wait_on_page_writeback(page); |
1054 | PRINTK("finished page writeback: %p %lu\n", page, bitmap->writes_pending); | 1046 | PRINTK("finished page writeback: %p\n", page); |
1055 | spin_lock(&bitmap->write_lock); | 1047 | |
1056 | if (!--bitmap->writes_pending) | 1048 | err = PageError(page); |
1057 | wake_up(&bitmap->write_wait); | 1049 | page_cache_release(page); |
1058 | spin_unlock(&bitmap->write_lock); | 1050 | if (err) { |
1059 | err = PageError(page); | 1051 | printk(KERN_WARNING "%s: bitmap file writeback " |
1060 | page_cache_release(page); | 1052 | "failed (page %lu): %d\n", |
1061 | if (err) { | 1053 | bmname(bitmap), page->index, err); |
1062 | printk(KERN_WARNING "%s: bitmap file writeback " | 1054 | bitmap_file_kick(bitmap); |
1063 | "failed (page %lu): %d\n", | 1055 | goto out; |
1064 | bmname(bitmap), page->index, err); | ||
1065 | bitmap_file_kick(bitmap); | ||
1066 | goto out; | ||
1067 | } | ||
1068 | } | 1056 | } |
1069 | } | 1057 | } |
1070 | out: | 1058 | out: |
1059 | wake_up(&bitmap->write_wait); | ||
1071 | if (err) { | 1060 | if (err) { |
1072 | printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n", | 1061 | printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n", |
1073 | bmname(bitmap), err); | 1062 | bmname(bitmap), err); |
1074 | daemon_exit(bitmap, &bitmap->writeback_daemon); | 1063 | daemon_exit(bitmap, &bitmap->writeback_daemon); |
1075 | } | 1064 | } |
1076 | return; | ||
1077 | } | 1065 | } |
1078 | 1066 | ||
1079 | static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr, | 1067 | static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr, |
@@ -1375,7 +1363,7 @@ int bitmap_setallbits(struct bitmap *bitmap) | |||
1375 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1363 | spin_unlock_irqrestore(&bitmap->lock, flags); |
1376 | memset(kmap(page), 0xff, PAGE_SIZE); | 1364 | memset(kmap(page), 0xff, PAGE_SIZE); |
1377 | kunmap(page); | 1365 | kunmap(page); |
1378 | if (write_page(page, 0)) | 1366 | if (write_page(bitmap, page, 0)) |
1379 | return 1; | 1367 | return 1; |
1380 | } | 1368 | } |
1381 | 1369 | ||
@@ -1443,7 +1431,6 @@ int bitmap_create(mddev_t *mddev) | |||
1443 | mddev->bitmap = bitmap; | 1431 | mddev->bitmap = bitmap; |
1444 | 1432 | ||
1445 | spin_lock_init(&bitmap->write_lock); | 1433 | spin_lock_init(&bitmap->write_lock); |
1446 | init_MUTEX_LOCKED(&bitmap->write_done); | ||
1447 | INIT_LIST_HEAD(&bitmap->complete_pages); | 1434 | INIT_LIST_HEAD(&bitmap->complete_pages); |
1448 | init_waitqueue_head(&bitmap->write_wait); | 1435 | init_waitqueue_head(&bitmap->write_wait); |
1449 | bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc, | 1436 | bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc, |