summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2017-01-19 09:52:15 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2017-01-19 09:52:15 -0800
commitde95841ab08083acae49190b82c658fbe4338aa7 (patch)
tree03250e8fad0aa08ea52e5e9ae5446846189d234a
parentca292680f390abe2b82e2ea67177dadac0399fd3 (diff)
parenta5b88c7fda4e34bae7e63aa5929ce9fd62204c51 (diff)
Merge "fs: fuse: Workaround for CMA migration"
-rw-r--r--fs/fuse/file.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 338ae65a160f..5071d1039c26 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -900,6 +900,41 @@ static int fuse_readpages_fill(void *_data, struct page *page)
return -EIO;
}
+#ifdef CONFIG_CMA
+ if (is_cma_pageblock(page)) {
+ struct page *oldpage = page, *newpage;
+ int err;
+
+ /* make sure that old page is not free in-between the calls */
+ page_cache_get(oldpage);
+
+ newpage = alloc_page(GFP_HIGHUSER);
+ if (!newpage) {
+ page_cache_release(oldpage);
+ return -ENOMEM;
+ }
+
+ err = replace_page_cache_page(oldpage, newpage, GFP_KERNEL);
+ if (err) {
+ __free_page(newpage);
+ page_cache_release(oldpage);
+ return err;
+ }
+
+ /*
+ * Decrement the count on new page to make page cache the only
+ * owner of it
+ */
+ lock_page(newpage);
+ put_page(newpage);
+
+ /* finally release the old page and swap pointers */
+ unlock_page(oldpage);
+ page_cache_release(oldpage);
+ page = newpage;
+ }
+#endif
+
page_cache_get(page);
req->pages[req->num_pages] = page;
req->page_descs[req->num_pages].length = PAGE_SIZE;