OSDN Git Service

fs: fuse: Workaround for CMA migration
authorLaura Abbott <lauraa@codeaurora.org>
Tue, 4 Dec 2012 01:50:34 +0000 (17:50 -0800)
committerLiam Mark <lmark@codeaurora.org>
Thu, 19 Jan 2017 00:18:26 +0000 (16:18 -0800)
The FUSE file system may hold references to pages for long
periods of time, preventing migration from occurring. If a CMA
page is used here, CMA allocations may fail. Work around this
by swapping out a CMA page for a non-CMA page when working with
the FUSE file system.

Change-Id: Id763ea833ee125c8732ae3759ec9e20d94aa8424
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
Signed-off-by: Prasad Sodagudi <psodagud@codeaurora.org>
fs/fuse/file.c

index 338ae65..5071d10 100644 (file)
@@ -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;