Commit 85c9ccd4 authored by NeilBrown's avatar NeilBrown Committed by Shaohua Li

md/bitmap: Don't write bitmap while earlier writes might be in-flight

As we don't wait for writes to complete in bitmap_daemon_work, they
could still be in-flight when bitmap_unplug writes again.  Or when
bitmap_daemon_work tries to write again.
This can be confusing and could risk the wrong data being written last.

So make sure we wait for old writes to complete before new writes start.
Signed-off-by: default avatarNeilBrown <neilb@suse.com>
Signed-off-by: default avatarShaohua Li <shli@fb.com>
parent a9ae93c8
...@@ -416,6 +416,21 @@ static int read_page(struct file *file, unsigned long index, ...@@ -416,6 +416,21 @@ static int read_page(struct file *file, unsigned long index,
* bitmap file superblock operations * bitmap file superblock operations
*/ */
/*
* bitmap_wait_writes() should be called before writing any bitmap
* blocks, to ensure previous writes, particularly from
* bitmap_daemon_work(), have completed.
*/
static void bitmap_wait_writes(struct bitmap *bitmap)
{
if (bitmap->storage.file)
wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0);
else
md_super_wait(bitmap->mddev);
}
/* update the event counter and sync the superblock to disk */ /* update the event counter and sync the superblock to disk */
void bitmap_update_sb(struct bitmap *bitmap) void bitmap_update_sb(struct bitmap *bitmap)
{ {
...@@ -978,6 +993,7 @@ void bitmap_unplug(struct bitmap *bitmap) ...@@ -978,6 +993,7 @@ void bitmap_unplug(struct bitmap *bitmap)
{ {
unsigned long i; unsigned long i;
int dirty, need_write; int dirty, need_write;
int writing = 0;
if (!bitmap || !bitmap->storage.filemap || if (!bitmap || !bitmap->storage.filemap ||
test_bit(BITMAP_STALE, &bitmap->flags)) test_bit(BITMAP_STALE, &bitmap->flags))
...@@ -992,15 +1008,15 @@ void bitmap_unplug(struct bitmap *bitmap) ...@@ -992,15 +1008,15 @@ void bitmap_unplug(struct bitmap *bitmap)
need_write = test_and_clear_page_attr(bitmap, i, need_write = test_and_clear_page_attr(bitmap, i,
BITMAP_PAGE_NEEDWRITE); BITMAP_PAGE_NEEDWRITE);
if (dirty || need_write) { if (dirty || need_write) {
if (!writing)
bitmap_wait_writes(bitmap);
clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING); clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING);
write_page(bitmap, bitmap->storage.filemap[i], 0); write_page(bitmap, bitmap->storage.filemap[i], 0);
writing = 1;
} }
} }
if (bitmap->storage.file) if (writing)
wait_event(bitmap->write_wait, bitmap_wait_writes(bitmap);
atomic_read(&bitmap->pending_writes)==0);
else
md_super_wait(bitmap->mddev);
if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags)) if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
bitmap_file_kick(bitmap); bitmap_file_kick(bitmap);
...@@ -1282,6 +1298,7 @@ void bitmap_daemon_work(struct mddev *mddev) ...@@ -1282,6 +1298,7 @@ void bitmap_daemon_work(struct mddev *mddev)
} }
spin_unlock_irq(&counts->lock); spin_unlock_irq(&counts->lock);
bitmap_wait_writes(bitmap);
/* Now start writeout on any page in NEEDWRITE that isn't DIRTY. /* Now start writeout on any page in NEEDWRITE that isn't DIRTY.
* DIRTY pages need to be written by bitmap_unplug so it can wait * DIRTY pages need to be written by bitmap_unplug so it can wait
* for them. * for them.
......
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