Btrfs: complete page writeback before doing ordered extents

We can deadlock waiting for pages to end writeback because we are doing an
allocation while hold a tree lock since the ordered extent stuff will
require tree locks.  A quick easy way to fix this is to end page writeback
before we do our ordered io stuff, which works fine since we don't really
need the page for this to work.  Eventually we want to make this work happen
as soon as the io is completed and then push the ordered extent stuff off to
a worker thread, but at this stage we need this deadlock fixed with changing
as little as possible.  Thanks,

Signed-off-by: Josef Bacik <josef@redhat.com>
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index 86eff48..225f6e0 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -286,13 +286,12 @@
 	inode = cb->inode;
 	tree = &BTRFS_I(inode)->io_tree;
 	cb->compressed_pages[0]->mapping = cb->inode->i_mapping;
+	end_compressed_writeback(inode, cb->start, cb->len);
 	tree->ops->writepage_end_io_hook(cb->compressed_pages[0],
 					 cb->start,
 					 cb->start + cb->len - 1,
 					 NULL, 1);
 	cb->compressed_pages[0]->mapping = NULL;
-
-	end_compressed_writeback(inode, cb->start, cb->len);
 	/* note, our inode could be gone now */
 
 	/*
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index a128a8c..35ea6df 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1806,16 +1806,6 @@
 }
 
 /*
- * helper function to end page writeback if all the extents
- * in the tree for that page are done with writeback
- */
-static void check_page_writeback(struct extent_io_tree *tree,
-				 struct page *page)
-{
-	end_page_writeback(page);
-}
-
-/*
  * When IO fails, either with EIO or csum verification fails, we
  * try other mirrors that might have a good copy of the data.  This
  * io_failure_record is used to record state as we go through all the
@@ -2210,6 +2200,13 @@
 	struct extent_io_tree *tree;
 	int ret;
 
+	/*
+	 * Don't want the page disappearing out from under us after we clear
+	 * writeback.
+	 */
+	page_cache_get(page);
+	end_page_writeback(page);
+
 	tree = &BTRFS_I(page->mapping->host)->io_tree;
 
 	if (tree->ops && tree->ops->writepage_end_io_hook) {
@@ -2224,8 +2221,10 @@
 		ret = tree->ops->writepage_io_failed_hook(NULL, page,
 						 start, end, NULL);
 		/* Writeback already completed */
-		if (ret == 0)
+		if (ret == 0) {
+			page_cache_release(page);
 			return 1;
+		}
 	}
 
 	if (!uptodate) {
@@ -2233,6 +2232,7 @@
 		ClearPageUptodate(page);
 		SetPageError(page);
 	}
+	page_cache_release(page);
 	return 0;
 }
 
@@ -2271,11 +2271,6 @@
 
 		if (end_extent_writepage(page, err, start, end))
 			continue;
-
-		if (whole_page)
-			end_page_writeback(page);
-		else
-			check_page_writeback(tree, page);
 	} while (bvec >= bio->bi_io_vec);
 
 	bio_put(bio);
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 202008e..cecf8df 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -972,9 +972,7 @@
 		goto out;
 
 
-	ret = filemap_write_and_wait(inode->i_mapping);
-	if (ret)
-		goto out;
+	btrfs_wait_ordered_range(inode, 0, (u64)-1);
 
 	key.objectid = BTRFS_FREE_SPACE_OBJECTID;
 	key.offset = offset;
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index bbf6d0d..acfb360 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -196,7 +196,7 @@
 	entry->len = len;
 	entry->disk_len = disk_len;
 	entry->bytes_left = len;
-	entry->inode = inode;
+	entry->inode = igrab(inode);
 	entry->compress_type = compress_type;
 	if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE)
 		set_bit(type, &entry->flags);
@@ -399,6 +399,8 @@
 	trace_btrfs_ordered_extent_put(entry->inode, entry);
 
 	if (atomic_dec_and_test(&entry->refs)) {
+		if (entry->inode)
+			btrfs_add_delayed_iput(entry->inode);
 		while (!list_empty(&entry->list)) {
 			cur = entry->list.next;
 			sum = list_entry(cur, struct btrfs_ordered_sum, list);