Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a5e9cf1 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds
Browse files

[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: 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 39730960
Loading
Loading
Loading
Loading
+38 −30
Original line number Diff line number Diff line
@@ -313,7 +313,16 @@ static int write_page(struct bitmap *bitmap, struct page *page, int wait)
	if (bitmap->file == NULL)
		return write_sb_page(bitmap->mddev, bitmap->offset, page, wait);

	if (wait)
		lock_page(page);
	else {
		if (TestSetPageLocked(page))
			return -EAGAIN; /* already locked */
		if (PageWriteback(page)) {
			unlock_page(page);
			return -EAGAIN;
		}
	}

	ret = page->mapping->a_ops->prepare_write(NULL, page, 0, PAGE_SIZE);
	if (!ret)
@@ -400,7 +409,7 @@ int bitmap_update_sb(struct bitmap *bitmap)
	if (!bitmap->mddev->degraded)
		sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
	kunmap(bitmap->sb_page);
	return write_page(bitmap, bitmap->sb_page, 0);
	return write_page(bitmap, bitmap->sb_page, 1);
}

/* print out the bitmap file superblock */
@@ -762,6 +771,7 @@ int bitmap_unplug(struct bitmap *bitmap)
	unsigned long i, attr, flags;
	struct page *page;
	int wait = 0;
	int err;

	if (!bitmap)
		return 0;
@@ -782,10 +792,18 @@ int bitmap_unplug(struct bitmap *bitmap)
			wait = 1;
		spin_unlock_irqrestore(&bitmap->lock, flags);

		if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE))
			if (write_page(bitmap, page, 0))
		if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) {
			err = write_page(bitmap, page, 0);
			if (err == -EAGAIN) {
				if (attr & BITMAP_PAGE_DIRTY)
					err = write_page(bitmap, page, 1);
				else
					err = 0;
			}
			if (err)
				return 1;
		}
	}
	if (wait) { /* if any writes were performed, we need to wait on them */
		if (bitmap->file) {
			spin_lock_irq(&bitmap->write_lock);
@@ -1006,8 +1024,15 @@ int bitmap_daemon_work(struct bitmap *bitmap)
				}
				spin_unlock_irqrestore(&bitmap->lock, flags);
				if (attr & BITMAP_PAGE_NEEDWRITE) {
					if (write_page(bitmap, page, 0))
					switch (write_page(bitmap, page, 0)) {
					case -EAGAIN:
						set_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
						break;
					case 0:
						break;
					default:
						bitmap_file_kick(bitmap);
					}
					page_cache_release(page);
				}
				continue;
@@ -1020,6 +1045,10 @@ int bitmap_daemon_work(struct bitmap *bitmap)
					clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
					spin_unlock_irqrestore(&bitmap->lock, flags);
					err = write_page(bitmap, lastpage, 0);
					if (err == -EAGAIN) {
						err = 0;
						set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
					}
				} else {
					set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
					spin_unlock_irqrestore(&bitmap->lock, flags);
@@ -1068,6 +1097,10 @@ int bitmap_daemon_work(struct bitmap *bitmap)
			clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
			spin_unlock_irqrestore(&bitmap->lock, flags);
			err = write_page(bitmap, lastpage, 0);
			if (err == -EAGAIN) {
				set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
				err = 0;
			}
		} else {
			set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
			spin_unlock_irqrestore(&bitmap->lock, flags);
@@ -1421,31 +1454,6 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset,
	}
}

/* dirty the entire bitmap */
int bitmap_setallbits(struct bitmap *bitmap)
{
	unsigned long flags;
	unsigned long j;

	/* dirty the in-memory bitmap */
	bitmap_set_memory_bits(bitmap, 0, bitmap->chunks << CHUNK_BLOCK_SHIFT(bitmap), 1);

	/* dirty the bitmap file */
	for (j = 0; j < bitmap->file_pages; j++) {
		struct page *page = bitmap->filemap[j];

		spin_lock_irqsave(&bitmap->lock, flags);
		page_cache_get(page);
		spin_unlock_irqrestore(&bitmap->lock, flags);
		memset(kmap(page), 0xff, PAGE_SIZE);
		kunmap(page);
		if (write_page(bitmap, page, 0))
			return 1;
	}

	return 0;
}

/*
 * free memory that was allocated
 */