Commit 77ad4bc7 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[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: default avatarNeil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent bfb39fba
...@@ -261,30 +261,33 @@ char *file_path(struct file *file, char *buf, int count) ...@@ -261,30 +261,33 @@ char *file_path(struct file *file, char *buf, int count)
/* /*
* write out a page * write out a page
*/ */
static int write_page(struct page *page, int wait) static int write_page(struct bitmap *bitmap, struct page *page, int wait)
{ {
int ret = -ENOMEM; int ret = -ENOMEM;
lock_page(page); lock_page(page);
if (page->mapping == NULL)
goto unlock_out;
else if (i_size_read(page->mapping->host) < page->index << PAGE_SHIFT) {
ret = -ENOENT;
goto unlock_out;
}
ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE); ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE);
if (!ret) if (!ret)
ret = page->mapping->a_ops->commit_write(NULL, page, 0, ret = page->mapping->a_ops->commit_write(NULL, page, 0,
PAGE_SIZE); PAGE_SIZE);
if (ret) { if (ret) {
unlock_out:
unlock_page(page); unlock_page(page);
return ret; return ret;
} }
set_page_dirty(page); /* force it to be written out */ set_page_dirty(page); /* force it to be written out */
if (!wait) {
/* add to list to be waited for by daemon */
struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO);
item->page = page;
page_cache_get(page);
spin_lock(&bitmap->write_lock);
list_add(&item->list, &bitmap->complete_pages);
spin_unlock(&bitmap->write_lock);
md_wakeup_thread(bitmap->writeback_daemon);
}
return write_one_page(page, wait); return write_one_page(page, wait);
} }
...@@ -343,14 +346,13 @@ int bitmap_update_sb(struct bitmap *bitmap) ...@@ -343,14 +346,13 @@ int bitmap_update_sb(struct bitmap *bitmap)
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
return 0; return 0;
} }
page_cache_get(bitmap->sb_page);
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
sb = (bitmap_super_t *)kmap(bitmap->sb_page); sb = (bitmap_super_t *)kmap(bitmap->sb_page);
sb->events = cpu_to_le64(bitmap->mddev->events); sb->events = cpu_to_le64(bitmap->mddev->events);
if (!bitmap->mddev->degraded) if (!bitmap->mddev->degraded)
sb->events_cleared = cpu_to_le64(bitmap->mddev->events); sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
kunmap(bitmap->sb_page); kunmap(bitmap->sb_page);
return write_page(bitmap->sb_page, 0); return write_page(bitmap, bitmap->sb_page, 0);
} }
/* print out the bitmap file superblock */ /* print out the bitmap file superblock */
...@@ -556,10 +558,10 @@ static void bitmap_file_unmap(struct bitmap *bitmap) ...@@ -556,10 +558,10 @@ static void bitmap_file_unmap(struct bitmap *bitmap)
static void bitmap_stop_daemons(struct bitmap *bitmap); static void bitmap_stop_daemons(struct bitmap *bitmap);
/* dequeue the next item in a page list -- don't call from irq context */ /* dequeue the next item in a page list -- don't call from irq context */
static struct page_list *dequeue_page(struct bitmap *bitmap, static struct page_list *dequeue_page(struct bitmap *bitmap)
struct list_head *head)
{ {
struct page_list *item = NULL; struct page_list *item = NULL;
struct list_head *head = &bitmap->complete_pages;
spin_lock(&bitmap->write_lock); spin_lock(&bitmap->write_lock);
if (list_empty(head)) if (list_empty(head))
...@@ -573,23 +575,15 @@ static struct page_list *dequeue_page(struct bitmap *bitmap, ...@@ -573,23 +575,15 @@ static struct page_list *dequeue_page(struct bitmap *bitmap,
static void drain_write_queues(struct bitmap *bitmap) static void drain_write_queues(struct bitmap *bitmap)
{ {
struct list_head *queues[] = { &bitmap->complete_pages, NULL };
struct list_head *head;
struct page_list *item; struct page_list *item;
int i;
for (i = 0; queues[i]; i++) { while ((item = dequeue_page(bitmap))) {
head = queues[i]; /* don't bother to wait */
while ((item = dequeue_page(bitmap, head))) {
page_cache_release(item->page); page_cache_release(item->page);
mempool_free(item, bitmap->write_pool); mempool_free(item, bitmap->write_pool);
} }
}
spin_lock(&bitmap->write_lock);
bitmap->writes_pending = 0; /* make sure waiters continue */
wake_up(&bitmap->write_wait); wake_up(&bitmap->write_wait);
spin_unlock(&bitmap->write_lock);
} }
static void bitmap_file_put(struct bitmap *bitmap) static void bitmap_file_put(struct bitmap *bitmap)
...@@ -734,13 +728,13 @@ int bitmap_unplug(struct bitmap *bitmap) ...@@ -734,13 +728,13 @@ int bitmap_unplug(struct bitmap *bitmap)
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE))
if (write_page(page, 0)) if (write_page(bitmap, page, 0))
return 1; return 1;
} }
if (wait) { /* if any writes were performed, we need to wait on them */ if (wait) { /* if any writes were performed, we need to wait on them */
spin_lock_irq(&bitmap->write_lock); spin_lock_irq(&bitmap->write_lock);
wait_event_lock_irq(bitmap->write_wait, wait_event_lock_irq(bitmap->write_wait,
bitmap->writes_pending == 0, bitmap->write_lock, list_empty(&bitmap->complete_pages), bitmap->write_lock,
wake_up_process(bitmap->writeback_daemon->tsk)); wake_up_process(bitmap->writeback_daemon->tsk));
spin_unlock_irq(&bitmap->write_lock); spin_unlock_irq(&bitmap->write_lock);
} }
...@@ -841,7 +835,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync) ...@@ -841,7 +835,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, int in_sync)
*/ */
memset(page_address(page) + offset, 0xff, memset(page_address(page) + offset, 0xff,
PAGE_SIZE - offset); PAGE_SIZE - offset);
ret = write_page(page, 1); ret = write_page(bitmap, page, 1);
if (ret) { if (ret) {
kunmap(page); kunmap(page);
/* release, page not in filemap yet */ /* release, page not in filemap yet */
...@@ -934,7 +928,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) ...@@ -934,7 +928,7 @@ int bitmap_daemon_work(struct bitmap *bitmap)
} }
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
if (attr & BITMAP_PAGE_NEEDWRITE) { if (attr & BITMAP_PAGE_NEEDWRITE) {
if (write_page(page, 0)) if (write_page(bitmap, page, 0))
bitmap_file_kick(bitmap); bitmap_file_kick(bitmap);
page_cache_release(page); page_cache_release(page);
} }
...@@ -950,7 +944,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) ...@@ -950,7 +944,7 @@ int bitmap_daemon_work(struct bitmap *bitmap)
if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) { if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) {
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
err = write_page(lastpage, 0); err = write_page(bitmap, lastpage, 0);
} else { } else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
...@@ -998,7 +992,7 @@ int bitmap_daemon_work(struct bitmap *bitmap) ...@@ -998,7 +992,7 @@ int bitmap_daemon_work(struct bitmap *bitmap)
if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) { if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) {
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
err = write_page(lastpage, 0); err = write_page(bitmap, lastpage, 0);
} else { } else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE); set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
...@@ -1034,28 +1028,23 @@ static void bitmap_writeback_daemon(mddev_t *mddev) ...@@ -1034,28 +1028,23 @@ static void bitmap_writeback_daemon(mddev_t *mddev)
struct page_list *item; struct page_list *item;
int err = 0; int err = 0;
while (1) {
PRINTK("%s: bitmap writeback daemon waiting...\n", bmname(bitmap));
down_interruptible(&bitmap->write_done);
if (signal_pending(current)) { if (signal_pending(current)) {
printk(KERN_INFO printk(KERN_INFO
"%s: bitmap writeback daemon got signal, exiting...\n", "%s: bitmap writeback daemon got signal, exiting...\n",
bmname(bitmap)); bmname(bitmap));
break; err = -EINTR;
goto out;
} }
PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap)); PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap));
/* wait on bitmap page writebacks */ /* wait on bitmap page writebacks */
while ((item = dequeue_page(bitmap, &bitmap->complete_pages))) { while ((item = dequeue_page(bitmap))) {
page = item->page; page = item->page;
mempool_free(item, bitmap->write_pool); mempool_free(item, bitmap->write_pool);
PRINTK("wait on page writeback: %p %lu\n", page, bitmap->writes_pending); PRINTK("wait on page writeback: %p\n", page);
wait_on_page_writeback(page); wait_on_page_writeback(page);
PRINTK("finished page writeback: %p %lu\n", page, bitmap->writes_pending); PRINTK("finished page writeback: %p\n", page);
spin_lock(&bitmap->write_lock);
if (!--bitmap->writes_pending)
wake_up(&bitmap->write_wait);
spin_unlock(&bitmap->write_lock);
err = PageError(page); err = PageError(page);
page_cache_release(page); page_cache_release(page);
if (err) { if (err) {
...@@ -1066,14 +1055,13 @@ static void bitmap_writeback_daemon(mddev_t *mddev) ...@@ -1066,14 +1055,13 @@ static void bitmap_writeback_daemon(mddev_t *mddev)
goto out; goto out;
} }
} }
} out:
out: wake_up(&bitmap->write_wait);
if (err) { if (err) {
printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n", printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n",
bmname(bitmap), err); bmname(bitmap), err);
daemon_exit(bitmap, &bitmap->writeback_daemon); daemon_exit(bitmap, &bitmap->writeback_daemon);
} }
return;
} }
static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr, static int bitmap_start_daemon(struct bitmap *bitmap, mdk_thread_t **ptr,
...@@ -1375,7 +1363,7 @@ int bitmap_setallbits(struct bitmap *bitmap) ...@@ -1375,7 +1363,7 @@ int bitmap_setallbits(struct bitmap *bitmap)
spin_unlock_irqrestore(&bitmap->lock, flags); spin_unlock_irqrestore(&bitmap->lock, flags);
memset(kmap(page), 0xff, PAGE_SIZE); memset(kmap(page), 0xff, PAGE_SIZE);
kunmap(page); kunmap(page);
if (write_page(page, 0)) if (write_page(bitmap, page, 0))
return 1; return 1;
} }
...@@ -1443,7 +1431,6 @@ int bitmap_create(mddev_t *mddev) ...@@ -1443,7 +1431,6 @@ int bitmap_create(mddev_t *mddev)
mddev->bitmap = bitmap; mddev->bitmap = bitmap;
spin_lock_init(&bitmap->write_lock); spin_lock_init(&bitmap->write_lock);
init_MUTEX_LOCKED(&bitmap->write_done);
INIT_LIST_HEAD(&bitmap->complete_pages); INIT_LIST_HEAD(&bitmap->complete_pages);
init_waitqueue_head(&bitmap->write_wait); init_waitqueue_head(&bitmap->write_wait);
bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc, bitmap->write_pool = mempool_create(WRITE_POOL_SIZE, write_pool_alloc,
......
...@@ -233,21 +233,12 @@ struct bitmap { ...@@ -233,21 +233,12 @@ struct bitmap {
unsigned long daemon_sleep; /* how many seconds between updates? */ unsigned long daemon_sleep; /* how many seconds between updates? */
/* /*
* bitmap write daemon - this daemon performs writes to the bitmap file * bitmap_writeback_daemon waits for file-pages that have been written,
* this thread is only needed because of a limitation in ext3 (jbd) * as there is no way to get a call-back when a page write completes.
* that does not allow a task to have two journal transactions ongoing
* simultaneously (even if the transactions are for two different
* filesystems) -- in the case of bitmap, that would be the filesystem
* that the bitmap file resides on and the filesystem that is mounted
* on the md device -- see current->journal_info in jbd/transaction.c
*/ */
mdk_thread_t *writeback_daemon; mdk_thread_t *writeback_daemon;
spinlock_t write_lock; spinlock_t write_lock;
struct semaphore write_ready;
struct semaphore write_done;
unsigned long writes_pending;
wait_queue_head_t write_wait; wait_queue_head_t write_wait;
struct list_head write_pages;
struct list_head complete_pages; struct list_head complete_pages;
mempool_t *write_pool; mempool_t *write_pool;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment