VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / mm / shmem.c
index 5a6d56a..57f8617 100644 (file)
 #include <linux/security.h>
 #include <linux/swapops.h>
 #include <linux/mempolicy.h>
+#include <linux/namei.h>
 #include <asm/uaccess.h>
 #include <asm/div64.h>
 #include <asm/pgtable.h>
 
 /* This magic number is used in glibc for posix shared memory */
-#define TMPFS_MAGIC    0x01021994
 
 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
 #define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
@@ -103,23 +103,25 @@ static inline void shmem_dir_unmap(struct page **dir)
 }
 
 static swp_entry_t *shmem_swp_map(struct page *page)
+{
+       return (swp_entry_t *)kmap_atomic(page, KM_USER1);
+}
+
+static inline void shmem_swp_balance_unmap(void)
 {
        /*
-        * We have to avoid the unconditional inc_preempt_count()
-        * in kmap_atomic(), since shmem_swp_unmap() will also be
-        * applied to the low memory addresses within i_direct[].
-        * PageHighMem and high_memory tests are good for all arches
-        * and configs: highmem_start_page and FIXADDR_START are not.
+        * When passing a pointer to an i_direct entry, to code which
+        * also handles indirect entries and so will shmem_swp_unmap,
+        * we must arrange for the preempt count to remain in balance.
+        * What kmap_atomic of a lowmem page does depends on config
+        * and architecture, so pretend to kmap_atomic some lowmem page.
         */
-       return PageHighMem(page)?
-               (swp_entry_t *)kmap_atomic(page, KM_USER1):
-               (swp_entry_t *)page_address(page);
+       (void) kmap_atomic(ZERO_PAGE(0), KM_USER1);
 }
 
 static inline void shmem_swp_unmap(swp_entry_t *entry)
 {
-       if (entry >= (swp_entry_t *)high_memory)
-               kunmap_atomic(entry, KM_USER1);
+       kunmap_atomic(entry, KM_USER1);
 }
 
 static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb)
@@ -262,8 +264,10 @@ static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long
        struct page **dir;
        struct page *subdir;
 
-       if (index < SHMEM_NR_DIRECT)
+       if (index < SHMEM_NR_DIRECT) {
+               shmem_swp_balance_unmap();
                return info->i_direct+index;
+       }
        if (!info->i_indirect) {
                if (page) {
                        info->i_indirect = *page;
@@ -305,17 +309,7 @@ static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long
                *page = NULL;
        }
        shmem_dir_unmap(dir);
-
-       /*
-        * With apologies... caller shmem_swp_alloc passes non-NULL
-        * page (though perhaps NULL *page); and now we know that this
-        * indirect page has been allocated, we can shortcut the final
-        * kmap if we know it contains no swap entries, as is commonly
-        * the case: return pointer to a 0 which doesn't need kmapping.
-        */
-       return (page && !subdir->nr_swapped)?
-               (swp_entry_t *)&subdir->nr_swapped:
-               shmem_swp_map(subdir) + offset;
+       return shmem_swp_map(subdir) + offset;
 }
 
 static void shmem_swp_set(struct shmem_inode_info *info, swp_entry_t *entry, unsigned long value)
@@ -342,7 +336,6 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long
        struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
        struct page *page = NULL;
        swp_entry_t *entry;
-       static const swp_entry_t unswapped = { 0 };
 
        if (sgp != SGP_WRITE &&
            ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode))
@@ -350,7 +343,7 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long
 
        while (!(entry = shmem_swp_entry(info, index, &page))) {
                if (sgp == SGP_READ)
-                       return (swp_entry_t *) &unswapped;
+                       return shmem_swp_map(ZERO_PAGE(0));
                /*
                 * Test free_blocks against 1 not 0, since we have 1 data
                 * page (and perhaps indirect index pages) yet to allocate:
@@ -649,8 +642,10 @@ static int shmem_unuse_inode(struct shmem_inode_info *info, swp_entry_t entry, s
        if (size > SHMEM_NR_DIRECT)
                size = SHMEM_NR_DIRECT;
        offset = shmem_find_swp(entry, ptr, ptr+size);
-       if (offset >= 0)
+       if (offset >= 0) {
+               shmem_swp_balance_unmap();
                goto found;
+       }
        if (!info->i_indirect)
                goto lost2;
        /* we might be racing with shmem_truncate */
@@ -1125,15 +1120,9 @@ static int shmem_populate(struct vm_area_struct *vma,
                                return err;
                        }
                } else if (nonblock) {
-                       /*
-                        * If a nonlinear mapping then store the file page
-                        * offset in the pte.
-                        */
-                       if (pgoff != linear_page_index(vma, addr)) {
-                               err = install_file_pte(mm, vma, addr, pgoff, prot);
-                               if (err)
-                                       return err;
-                       }
+                       err = install_file_pte(mm, vma, addr, pgoff, prot);
+                       if (err)
+                               return err;
                }
 
                len -= PAGE_SIZE;
@@ -1477,7 +1466,7 @@ static ssize_t shmem_file_read(struct file *filp, char __user *buf, size_t count
 
        desc.written = 0;
        desc.count = count;
-       desc.buf = buf;
+       desc.arg.buf = buf;
        desc.error = 0;
 
        do_shmem_file_read(filp, ppos, &desc, file_read_actor);
@@ -1487,7 +1476,7 @@ static ssize_t shmem_file_read(struct file *filp, char __user *buf, size_t count
 }
 
 static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos,
-                        size_t count, read_actor_t actor, void __user *target)
+                        size_t count, read_actor_t actor, void *target)
 {
        read_descriptor_t desc;
 
@@ -1496,7 +1485,7 @@ static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos,
 
        desc.written = 0;
        desc.count = count;
-       desc.buf = target;
+       desc.arg.data = target;
        desc.error = 0;
 
        do_shmem_file_read(in_file, ppos, &desc, actor);
@@ -1509,7 +1498,7 @@ static int shmem_statfs(struct super_block *sb, struct kstatfs *buf)
 {
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 
-       buf->f_type = TMPFS_MAGIC;
+       buf->f_type = TMPFS_SUPER_MAGIC;
        buf->f_bsize = PAGE_CACHE_SIZE;
        spin_lock(&sbinfo->stat_lock);
        buf->f_blocks = sbinfo->max_blocks;
@@ -1676,51 +1665,45 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
        return 0;
 }
 
-static int shmem_readlink_inline(struct dentry *dentry, char __user *buffer, int buflen)
-{
-       return vfs_readlink(dentry, buffer, buflen, (const char *)SHMEM_I(dentry->d_inode));
-}
-
 static int shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
 {
-       return vfs_follow_link(nd, (const char *)SHMEM_I(dentry->d_inode));
+       nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode));
+       return 0;
 }
 
-static int shmem_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct page *page = NULL;
        int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
-       if (res)
-               return res;
-       res = vfs_readlink(dentry, buffer, buflen, kmap(page));
-       kunmap(page);
-       mark_page_accessed(page);
-       page_cache_release(page);
-       return res;
+       nd_set_link(nd, res ? ERR_PTR(res) : kmap(page));
+       return 0;
 }
 
-static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void shmem_put_link(struct dentry *dentry, struct nameidata *nd)
 {
-       struct page *page = NULL;
-       int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
-       if (res)
-               return res;
-       res = vfs_follow_link(nd, kmap(page));
-       kunmap(page);
-       mark_page_accessed(page);
-       page_cache_release(page);
-       return res;
+       if (!IS_ERR(nd_get_link(nd))) {
+               struct page *page;
+
+               page = find_get_page(dentry->d_inode->i_mapping, 0);
+               if (!page)
+                       BUG();
+               kunmap(page);
+               mark_page_accessed(page);
+               page_cache_release(page);
+               page_cache_release(page);
+       }
 }
 
 static struct inode_operations shmem_symlink_inline_operations = {
-       .readlink       = shmem_readlink_inline,
+       .readlink       = generic_readlink,
        .follow_link    = shmem_follow_link_inline,
 };
 
 static struct inode_operations shmem_symlink_inode_operations = {
        .truncate       = shmem_truncate,
-       .readlink       = shmem_readlink,
+       .readlink       = generic_readlink,
        .follow_link    = shmem_follow_link,
+       .put_link       = shmem_put_link,
 };
 
 static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes)
@@ -1845,7 +1828,7 @@ static int shmem_fill_super(struct super_block *sb,
        sb->s_maxbytes = SHMEM_MAX_BYTES;
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-       sb->s_magic = TMPFS_MAGIC;
+       sb->s_magic = TMPFS_SUPER_MAGIC;
        sb->s_op = &shmem_ops;
        inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
        if (!inode)