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

IKEDA Munehiro m-ikeda at ds.jp.nec.com
Fri Jul 20 06:45:29 EDT 2007


By former implementation, compressed page 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.

PROBLEM IS STILL REMAINED.
When free swap-cache (which means compressed anon page),
corresponding zone->vm_stat[] must be updated by
__dec_zone_page_state().
But we can't do it because chunk_head->flags lost information
about zones and nodes.
First of all, what is zone/node of compressed page?


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

diff --git a/mm/ccache.c b/mm/ccache.c
index 790027a..22679cc 100644
--- a/mm/ccache.c
+++ b/mm/ccache.c
@@ -752,6 +752,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);
 
@@ -1062,6 +1065,32 @@ 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
+		 * but simply waste the page
+		 */
+		if (current->flags & PF_MEMALLOC) {
+			if (PageSwapCache(ch)) {
+				atomic_dec(&anon_cc_size);
+				total_swapcache_pages--;
+				/* how to do?
+				__dec_zone_page_state(ch, NR_FILE_PAGES);
+				*/
+			} else {
+				atomic_dec(&fs_backed_cc_size);
+				mapping->nrpages--;
+			}
+			__free_chunk_head(ch);
+			write_lock_irq(&mapping->tree_lock);
+			radix_tree_delete(&mapping->page_tree, ch->offset);
+			write_unlock_irq(&mapping->tree_lock);
+			bit_spin_unlock(PG_locked, &ch->flags);
+			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