Commit 247e743c authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Use async helpers to deal with pages that have been improperly dirtied



Higher layers sometimes call set_page_dirty without asking the filesystem
to help.  This causes many problems for the data=ordered and cow code.
This commit detects pages that haven't been properly setup for IO and
kicks off an async helper to deal with them.

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent e6dcd2dc
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -546,6 +546,12 @@ struct btrfs_fs_info {
	struct btrfs_workers endio_workers;
	struct btrfs_workers endio_write_workers;
	struct btrfs_workers submit_workers;
	/*
	 * fixup workers take dirty pages that didn't properly go through
	 * the cow mechanism and make them safe to write.  It happens
	 * for the sys_munmap function call path
	 */
	struct btrfs_workers fixup_workers;
	struct task_struct *transaction_kthread;
	struct task_struct *cleaner_kthread;
	int thread_pool_size;
+4 −0
Original line number Diff line number Diff line
@@ -1329,11 +1329,13 @@ struct btrfs_root *open_ctree(struct super_block *sb,
	 */
	btrfs_init_workers(&fs_info->workers, fs_info->thread_pool_size);
	btrfs_init_workers(&fs_info->submit_workers, fs_info->thread_pool_size);
	btrfs_init_workers(&fs_info->fixup_workers, 1);
	btrfs_init_workers(&fs_info->endio_workers, fs_info->thread_pool_size);
	btrfs_init_workers(&fs_info->endio_write_workers,
			   fs_info->thread_pool_size);
	btrfs_start_workers(&fs_info->workers, 1);
	btrfs_start_workers(&fs_info->submit_workers, 1);
	btrfs_start_workers(&fs_info->fixup_workers, 1);
	btrfs_start_workers(&fs_info->endio_workers, fs_info->thread_pool_size);
	btrfs_start_workers(&fs_info->endio_write_workers,
			    fs_info->thread_pool_size);
@@ -1454,6 +1456,7 @@ fail_tree_root:
fail_sys_array:
fail_sb_buffer:
	extent_io_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->io_tree);
	btrfs_stop_workers(&fs_info->fixup_workers);
	btrfs_stop_workers(&fs_info->workers);
	btrfs_stop_workers(&fs_info->endio_workers);
	btrfs_stop_workers(&fs_info->endio_write_workers);
@@ -1710,6 +1713,7 @@ int close_ctree(struct btrfs_root *root)

	truncate_inode_pages(fs_info->btree_inode->i_mapping, 0);

	btrfs_stop_workers(&fs_info->fixup_workers);
	btrfs_stop_workers(&fs_info->workers);
	btrfs_stop_workers(&fs_info->endio_workers);
	btrfs_stop_workers(&fs_info->endio_write_workers);
+10 −0
Original line number Diff line number Diff line
@@ -2050,6 +2050,16 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
	lock_extent(tree, start, page_end, GFP_NOFS);
	unlock_start = start;

	if (tree->ops && tree->ops->writepage_start_hook) {
		ret = tree->ops->writepage_start_hook(page, start, page_end);
		if (ret == -EAGAIN) {
			unlock_extent(tree, start, page_end, GFP_NOFS);
			redirty_page_for_writepage(wbc, page);
			unlock_page(page);
			return 0;
		}
	}

	end = page_end;
	if (test_range_bit(tree, start, page_end, EXTENT_DELALLOC, 0)) {
		printk("found delalloc bits after lock_extent\n");
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ typedef int (extent_submit_bio_hook_t)(struct inode *inode, int rw,
				       struct bio *bio, int mirror_num);
struct extent_io_ops {
	int (*fill_delalloc)(struct inode *inode, u64 start, u64 end);
	int (*writepage_start_hook)(struct page *page, u64 start, u64 end);
	int (*writepage_io_hook)(struct page *page, u64 start, u64 end);
	extent_submit_bio_hook_t *submit_bio_hook;
	int (*merge_bio_hook)(struct page *page, unsigned long offset,
+1 −0
Original line number Diff line number Diff line
@@ -313,6 +313,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
		for (i = 0; i < num_pages; i++) {
			struct page *p = pages[i];
			SetPageUptodate(p);
			ClearPageChecked(p);
			set_page_dirty(p);
		}
	} else {
Loading