Force page->private removal in btrfs_invalidatepage
btrfs_invalidatepage is not allowed to leave pages around on the lru.
Any such pages will trigger an oops later on because the VM will see
page->private and assume it is a buffer head.
This also forces extra flushes of the async work queues before
dropping all the pages on the btree inode during unmount. Left over
items on the work queues are one possible cause of busy state ranges
during truncate_inode_pages.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 9d648f2..b479cdf 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -533,6 +533,12 @@
tree = &BTRFS_I(page->mapping->host)->io_tree;
extent_invalidatepage(tree, page, offset);
btree_releasepage(page, GFP_NOFS);
+ if (PagePrivate(page)) {
+ printk("2invalidate page cleaning up after releasepage\n");
+ ClearPagePrivate(page);
+ set_page_private(page, 0);
+ page_cache_release(page);
+ }
}
#if 0
@@ -1484,6 +1490,8 @@
write_ctree_super(NULL, root);
mutex_unlock(&fs_info->fs_mutex);
+ btrfs_transaction_flush_work(root);
+
if (fs_info->delalloc_bytes) {
printk("btrfs: at unmount delalloc count %Lu\n",
fs_info->delalloc_bytes);
@@ -1514,7 +1522,11 @@
extent_io_tree_empty_lru(&fs_info->extent_ins);
extent_io_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->io_tree);
+ flush_workqueue(end_io_workqueue);
+ flush_workqueue(async_submit_workqueue);
+
truncate_inode_pages(fs_info->btree_inode->i_mapping, 0);
+
flush_workqueue(end_io_workqueue);
destroy_workqueue(end_io_workqueue);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 40f8da8..347cd85 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2524,6 +2524,12 @@
tree = &BTRFS_I(page->mapping->host)->io_tree;
extent_invalidatepage(tree, page, offset);
btrfs_releasepage(page, GFP_NOFS);
+ if (PagePrivate(page)) {
+ printk("invalidate page cleaning up after releasepage\n");
+ ClearPagePrivate(page);
+ set_page_private(page, 0);
+ page_cache_release(page);
+ }
}
/*