Commit 70fa2a42 authored by Andrew Morton's avatar Andrew Morton Committed by Dave Jones

[PATCH] handle oom in tmpfs

From: Hugh Dickins <hugh@veritas.com>

move_from_swap_cache and add_to_page_cache_lru are using GFP_ATOMIC,
which can easily fail in an intermittent way.  Rude if shmem_getpage
then fails with -ENOMEM: use blk_congestion_wait() to let kswapd in,
and repeat.
parent 65ce13e2
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/blkdev.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/* This magic number is used in glibc for posix shared memory */ /* This magic number is used in glibc for posix shared memory */
...@@ -838,8 +839,7 @@ static int shmem_getpage(struct inode *inode, unsigned long idx, struct page **p ...@@ -838,8 +839,7 @@ static int shmem_getpage(struct inode *inode, unsigned long idx, struct page **p
SetPageUptodate(filepage); SetPageUptodate(filepage);
set_page_dirty(filepage); set_page_dirty(filepage);
swap_free(swap); swap_free(swap);
} else if (!(error = move_from_swap_cache( } else if (move_from_swap_cache(swappage, idx, mapping) == 0) {
swappage, idx, mapping))) {
shmem_swp_set(info, entry, 0); shmem_swp_set(info, entry, 0);
shmem_swp_unmap(entry); shmem_swp_unmap(entry);
spin_unlock(&info->lock); spin_unlock(&info->lock);
...@@ -850,8 +850,8 @@ static int shmem_getpage(struct inode *inode, unsigned long idx, struct page **p ...@@ -850,8 +850,8 @@ static int shmem_getpage(struct inode *inode, unsigned long idx, struct page **p
spin_unlock(&info->lock); spin_unlock(&info->lock);
unlock_page(swappage); unlock_page(swappage);
page_cache_release(swappage); page_cache_release(swappage);
if (error != -EEXIST) /* let kswapd refresh zone for GFP_ATOMICs */
goto failed; blk_congestion_wait(WRITE, HZ/50);
goto repeat; goto repeat;
} }
} else if (sgp == SGP_READ && !filepage) { } else if (sgp == SGP_READ && !filepage) {
...@@ -897,15 +897,16 @@ static int shmem_getpage(struct inode *inode, unsigned long idx, struct page **p ...@@ -897,15 +897,16 @@ static int shmem_getpage(struct inode *inode, unsigned long idx, struct page **p
swap = *entry; swap = *entry;
shmem_swp_unmap(entry); shmem_swp_unmap(entry);
} }
if (error || swap.val || if (error || swap.val || 0 != add_to_page_cache_lru(
(error = add_to_page_cache_lru( filepage, mapping, idx, GFP_ATOMIC)) {
filepage, mapping, idx, GFP_ATOMIC))) {
spin_unlock(&info->lock); spin_unlock(&info->lock);
page_cache_release(filepage); page_cache_release(filepage);
shmem_free_block(inode); shmem_free_block(inode);
filepage = NULL; filepage = NULL;
if (error != -EEXIST) if (error)
goto failed; goto failed;
/* let kswapd refresh zone for GFP_ATOMICs */
blk_congestion_wait(WRITE, HZ / 50);
goto repeat; goto repeat;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment