Commit:     a0ee5ec520ede1dc8e2194623bcebfd9fab408f2
Parent:     d9fe526a83b84edc9c5ff217a00c896bfc20b2ce
Author:     Hugh Dickins <[EMAIL PROTECTED]>
AuthorDate: Mon Feb 4 22:28:51 2008 -0800
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Tue Feb 5 09:44:15 2008 -0800

    tmpfs: allocate on read when stacked
    tmpfs is expected to limit the memory used (unless mounted with nr_blocks=0 
    size=0).  But if a stacked filesystem such as unionfs gets pages from a 
    tmpfs file by reading holes, and then writes to them, it can easily exceed 
    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 
    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 <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
 mm/shmem.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/mm/shmem.c b/mm/shmem.c
index 4ae47f5..c919ed5 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -80,6 +80,7 @@
 enum sgp_type {
        SGP_READ,       /* don't exceed i_size, don't allocate page */
        SGP_CACHE,      /* don't exceed i_size, may allocate page */
+       SGP_DIRTY,      /* like SGP_CACHE, but set new page dirty */
        SGP_WRITE,      /* may exceed i_size, may allocate page */
@@ -1333,6 +1334,8 @@ repeat:
+               if (sgp == SGP_DIRTY)
+                       set_page_dirty(filepage);
        *pagep = filepage;
@@ -1518,6 +1521,15 @@ static void do_shmem_file_read(struct file *filp, loff_t 
*ppos, read_descriptor_
        struct inode *inode = filp->f_path.dentry->d_inode;
        struct address_space *mapping = inode->i_mapping;
        unsigned long index, offset;
+       enum sgp_type sgp = SGP_READ;
+       /*
+        * Might this read be for a stacking filesystem?  Then when reading
+        * holes of a sparse file, we actually need to allocate those pages,
+        * and even mark them dirty, so it cannot exceed the max_blocks limit.
+        */
+       if (segment_eq(get_fs(), KERNEL_DS))
+               sgp = SGP_DIRTY;
        index = *ppos >> PAGE_CACHE_SHIFT;
        offset = *ppos & ~PAGE_CACHE_MASK;
@@ -1536,7 +1548,7 @@ static void do_shmem_file_read(struct file *filp, loff_t 
*ppos, read_descriptor_
-               desc->error = shmem_getpage(inode, index, &page, SGP_READ, 
+               desc->error = shmem_getpage(inode, index, &page, sgp, NULL);
                if (desc->error) {
                        if (desc->error == -EINVAL)
                                desc->error = 0;
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at

Reply via email to