aboutsummaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2008-02-05 01:28:51 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:15 -0500
commita0ee5ec520ede1dc8e2194623bcebfd9fab408f2 (patch)
tree74a3668798213661a9e62a1b576f081f1ce44838 /mm/shmem.c
parentd9fe526a83b84edc9c5ff217a00c896bfc20b2ce (diff)
tmpfs: allocate on read when stacked
tmpfs is expected to limit the memory used (unless mounted with nr_blocks=0 or size=0). But if a stacked filesystem such as unionfs gets pages from a sparse tmpfs file by reading holes, and then writes to them, it can easily exceed any such limit at present. So suppress the SGP_READ "don't allocate page" ZERO_PAGE optimization when reading for the kernel (a KERNEL_DS check, ugh, sorry about that). Indeed, pessimistically mark such pages as dirty, so they cannot get reclaimed and unaccounted by mistake. The venerable shmem_recalc_inode code (originally to account for the reclaim of clean pages) suffices to get the accounting right when swappages are dropped in favour of more uptodate filepages. This also fixes the NULL shmem_swp_entry BUG or oops in shmem_writepage, caused by unionfs writing to a very sparse tmpfs file: to minimize memory allocation in swapout, tmpfs requires the swap vector be allocated upfront, which wasn't always happening in this stacked case. Signed-off-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index 4ae47f54c822..c919ed578f0a 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -80,6 +80,7 @@
80enum sgp_type { 80enum sgp_type {
81 SGP_READ, /* don't exceed i_size, don't allocate page */ 81 SGP_READ, /* don't exceed i_size, don't allocate page */
82 SGP_CACHE, /* don't exceed i_size, may allocate page */ 82 SGP_CACHE, /* don't exceed i_size, may allocate page */
83 SGP_DIRTY, /* like SGP_CACHE, but set new page dirty */
83 SGP_WRITE, /* may exceed i_size, may allocate page */ 84 SGP_WRITE, /* may exceed i_size, may allocate page */
84}; 85};
85 86
@@ -1333,6 +1334,8 @@ repeat:
1333 clear_highpage(filepage); 1334 clear_highpage(filepage);
1334 flush_dcache_page(filepage); 1335 flush_dcache_page(filepage);
1335 SetPageUptodate(filepage); 1336 SetPageUptodate(filepage);
1337 if (sgp == SGP_DIRTY)
1338 set_page_dirty(filepage);
1336 } 1339 }
1337done: 1340done:
1338 *pagep = filepage; 1341 *pagep = filepage;
@@ -1518,6 +1521,15 @@ static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_
1518 struct inode *inode = filp->f_path.dentry->d_inode; 1521 struct inode *inode = filp->f_path.dentry->d_inode;
1519 struct address_space *mapping = inode->i_mapping; 1522 struct address_space *mapping = inode->i_mapping;
1520 unsigned long index, offset; 1523 unsigned long index, offset;
1524 enum sgp_type sgp = SGP_READ;
1525
1526 /*
1527 * Might this read be for a stacking filesystem? Then when reading
1528 * holes of a sparse file, we actually need to allocate those pages,
1529 * and even mark them dirty, so it cannot exceed the max_blocks limit.
1530 */
1531 if (segment_eq(get_fs(), KERNEL_DS))
1532 sgp = SGP_DIRTY;
1521 1533
1522 index = *ppos >> PAGE_CACHE_SHIFT; 1534 index = *ppos >> PAGE_CACHE_SHIFT;
1523 offset = *ppos & ~PAGE_CACHE_MASK; 1535 offset = *ppos & ~PAGE_CACHE_MASK;
@@ -1536,7 +1548,7 @@ static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_
1536 break; 1548 break;
1537 } 1549 }
1538 1550
1539 desc->error = shmem_getpage(inode, index, &page, SGP_READ, NULL); 1551 desc->error = shmem_getpage(inode, index, &page, sgp, NULL);
1540 if (desc->error) { 1552 if (desc->error) {
1541 if (desc->error == -EINVAL) 1553 if (desc->error == -EINVAL)
1542 desc->error = 0; 1554 desc->error = 0;