[linux-mm-cc] [PATCH 10/12] avoid OOM : avoid decompression by memory reclaiming context

IKEDA Munehiro m-ikeda at ds.jp.nec.com
Mon Jul 23 06:09:51 EDT 2007


By former implementation, compressed page-cache was freed after
beeing decompressed once even if the context was memory reclaimer.
The memory reclaimer runs under memory pressure. So this
behavior increases memory pressure and shall cause OOM-Killer.
This patch simply frees corresponding chunks and chunk_head
without decompression.

Code in v1 was confused memory reclaimer(PF_MEMALLOC) and
process exiting(PF_EXITING).  In former case compressed
page-cache can be simply freed, and in later case compressed
anon memory can be simply freed.
V1 tried to free both of them in the former case, so
this patch corrects it.
This patch frees a compressed page-cache when PF_MEMALLOC
same as v1, but doesn't free compressed anon memory.
When PF_EXITING, the compressed anon page will be decompressed as
usual access.  This should be avoided but is remained as
"future work".

Signed-off-by: IKEDA, Munehiro <m-ikeda at ds.jp.nec.com>
---
 mm/ccache.c  |   21 +++++++++++++++++++++
 mm/filemap.c |   10 ++++++----
 2 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/mm/ccache.c b/mm/ccache.c
index 3f5a7d3..3010ab8 100644
--- a/mm/ccache.c
+++ b/mm/ccache.c
@@ -753,6 +753,9 @@ static struct page *alloc_or_eat_ccache_lock(gfp_t gfp_mask,
 	struct page *page;
 	gfp_t mask;
 
+	/* reclaiming path shouldn't call this function */
+	BUG_ON(current->flags & PF_MEMALLOC);
+
 	/* __GFP_NOFAIL is handled in this function */
 	mask = (gfp_mask & ~__GFP_NOFAIL)| (GFP_NOWAIT|__GFP_NOWARN);
 
@@ -1063,6 +1066,24 @@ struct page *handle_ccache_fault(struct chunk_head *ch,
 			return cleanup_dup_fault(ch, mapping);
 		}
 
+		/*
+		 * Is this reclaim path?
+		 * If so, shouldn't decompress the page-cache page
+		 * but simply waste it.
+		 */
+		if (!PageSwapCache(ch) && (current->flags & PF_MEMALLOC)) {
+			write_lock_irq(&mapping->tree_lock);
+			radix_tree_delete(&mapping->page_tree, ch->offset);
+			mapping->nrpages--;
+			write_unlock_irq(&mapping->tree_lock);
+			__free_chunk_head(ch);
+			bit_spin_unlock(PG_locked, &ch->flags);
+			atomic_dec(&fs_backed_cc_size);
+			release_chunk_head(ch);	/* page/swap cache */
+			release_chunk_head(ch);	/* ccache */
+			return NULL;
+		}
+
 		/* Decompress page and return it */
 		page = cc_readpage(ch);
 		CC_DEBUG2("after cc_readpage");
diff --git a/mm/filemap.c b/mm/filemap.c
index 75c1b73..7c5f6e4 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -734,8 +734,8 @@ static unsigned int decomp_ccache_pages(struct page **pages,
 			page = handle_ccache_fault
 				((struct chunk_head *)pages[i], mapping);
 
-			if (!page) {
-				CC_INFO("HCF returned null");
+			if (!page && !(current->flags & PF_MEMALLOC)) {
+				CC_INFO("HCF returned null in regular path");
 				release_chunk_heads_or_pages(pages,
 							     i + 1, nr_pages);
 				CC_INFO("done release ch_or_pages: ret=%d", i);
@@ -816,8 +816,10 @@ static unsigned int decomp_ccache_pages_contig(struct page **pages,
 
 		/* Here, pages[i] == NULL */
 		release_chunk_heads_or_pages(pages, i + 1, nr_pages);
-		CC_INFO("HCF returned null");
-		CC_INFO("done release ch_or_pages: ret=%d", i);
+		if (!(current->flags & PF_MEMALLOC)) {
+			CC_INFO("HCF returned null in regular path");
+			CC_INFO("done release ch_or_pages: ret=%d", i);
+		}
 		break;
 	}
 	return i;
-- 
1.4.4.4



More information about the linux-mm-cc mailing list