[libata] bump versions
[pandora-kernel.git] / mm / shmem.c
index 343b3c0..37eaf42 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/swapops.h>
 #include <linux/mempolicy.h>
 #include <linux/namei.h>
+#include <linux/ctype.h>
 #include <asm/uaccess.h>
 #include <asm/div64.h>
 #include <asm/pgtable.h>
@@ -874,6 +875,51 @@ redirty:
 }
 
 #ifdef CONFIG_NUMA
+static inline int shmem_parse_mpol(char *value, int *policy, nodemask_t *policy_nodes)
+{
+       char *nodelist = strchr(value, ':');
+       int err = 1;
+
+       if (nodelist) {
+               /* NUL-terminate policy string */
+               *nodelist++ = '\0';
+               if (nodelist_parse(nodelist, *policy_nodes))
+                       goto out;
+       }
+       if (!strcmp(value, "default")) {
+               *policy = MPOL_DEFAULT;
+               /* Don't allow a nodelist */
+               if (!nodelist)
+                       err = 0;
+       } else if (!strcmp(value, "prefer")) {
+               *policy = MPOL_PREFERRED;
+               /* Insist on a nodelist of one node only */
+               if (nodelist) {
+                       char *rest = nodelist;
+                       while (isdigit(*rest))
+                               rest++;
+                       if (!*rest)
+                               err = 0;
+               }
+       } else if (!strcmp(value, "bind")) {
+               *policy = MPOL_BIND;
+               /* Insist on a nodelist */
+               if (nodelist)
+                       err = 0;
+       } else if (!strcmp(value, "interleave")) {
+               *policy = MPOL_INTERLEAVE;
+               /* Default to nodes online if no nodelist */
+               if (!nodelist)
+                       *policy_nodes = node_online_map;
+               err = 0;
+       }
+out:
+       /* Restore string for error message */
+       if (nodelist)
+               *--nodelist = ':';
+       return err;
+}
+
 static struct page *shmem_swapin_async(struct shared_policy *p,
                                       swp_entry_t entry, unsigned long idx)
 {
@@ -926,6 +972,11 @@ shmem_alloc_page(gfp_t gfp, struct shmem_inode_info *info,
        return page;
 }
 #else
+static inline int shmem_parse_mpol(char *value, int *policy, nodemask_t *policy_nodes)
+{
+       return 1;
+}
+
 static inline struct page *
 shmem_swapin(struct shmem_inode_info *info,swp_entry_t entry,unsigned long idx)
 {
@@ -1028,6 +1079,14 @@ repeat:
                        page_cache_release(swappage);
                        goto repeat;
                }
+               if (!PageSwapCache(swappage)) {
+                       /* Page migration has occured */
+                       shmem_swp_unmap(entry);
+                       spin_unlock(&info->lock);
+                       unlock_page(swappage);
+                       page_cache_release(swappage);
+                       goto repeat;
+               }
                if (PageWriteback(swappage)) {
                        shmem_swp_unmap(entry);
                        spin_unlock(&info->lock);
@@ -1316,7 +1375,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
                case S_IFREG:
                        inode->i_op = &shmem_inode_operations;
                        inode->i_fop = &shmem_file_operations;
-                       mpol_shared_policy_init(&info->policy);
+                       mpol_shared_policy_init(&info->policy, sbinfo->policy,
+                                                       &sbinfo->policy_nodes);
                        break;
                case S_IFDIR:
                        inode->i_nlink++;
@@ -1330,7 +1390,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
                         * Must not load anything in the rbtree,
                         * mpol_free_shared_policy will not be called.
                         */
-                       mpol_shared_policy_init(&info->policy);
+                       mpol_shared_policy_init(&info->policy, MPOL_DEFAULT,
+                                               NULL);
                        break;
                }
        } else if (sbinfo->max_inodes) {
@@ -1843,11 +1904,29 @@ static struct inode_operations shmem_symlink_inode_operations = {
        .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)
+static int shmem_parse_options(char *options, int *mode, uid_t *uid,
+       gid_t *gid, unsigned long *blocks, unsigned long *inodes,
+       int *policy, nodemask_t *policy_nodes)
 {
        char *this_char, *value, *rest;
 
-       while ((this_char = strsep(&options, ",")) != NULL) {
+       while (options != NULL) {
+               this_char = options;
+               for (;;) {
+                       /*
+                        * NUL-terminate this option: unfortunately,
+                        * mount options form a comma-separated list,
+                        * but mpol's nodelist may also contain commas.
+                        */
+                       options = strchr(options, ',');
+                       if (options == NULL)
+                               break;
+                       options++;
+                       if (!isdigit(*options)) {
+                               options[-1] = '\0';
+                               break;
+                       }
+               }
                if (!*this_char)
                        continue;
                if ((value = strchr(this_char,'=')) != NULL) {
@@ -1897,6 +1976,9 @@ static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid,
                        *gid = simple_strtoul(value,&rest,0);
                        if (*rest)
                                goto bad_val;
+               } else if (!strcmp(this_char,"mpol")) {
+                       if (shmem_parse_mpol(value,policy,policy_nodes))
+                               goto bad_val;
                } else {
                        printk(KERN_ERR "tmpfs: Bad mount option %s\n",
                               this_char);
@@ -1917,12 +1999,14 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
        unsigned long max_blocks = sbinfo->max_blocks;
        unsigned long max_inodes = sbinfo->max_inodes;
+       int policy = sbinfo->policy;
+       nodemask_t policy_nodes = sbinfo->policy_nodes;
        unsigned long blocks;
        unsigned long inodes;
        int error = -EINVAL;
 
-       if (shmem_parse_options(data, NULL, NULL, NULL,
-                               &max_blocks, &max_inodes))
+       if (shmem_parse_options(data, NULL, NULL, NULL, &max_blocks,
+                               &max_inodes, &policy, &policy_nodes))
                return error;
 
        spin_lock(&sbinfo->stat_lock);
@@ -1948,6 +2032,8 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
        sbinfo->free_blocks = max_blocks - blocks;
        sbinfo->max_inodes  = max_inodes;
        sbinfo->free_inodes = max_inodes - inodes;
+       sbinfo->policy = policy;
+       sbinfo->policy_nodes = policy_nodes;
 out:
        spin_unlock(&sbinfo->stat_lock);
        return error;
@@ -1972,6 +2058,8 @@ static int shmem_fill_super(struct super_block *sb,
        struct shmem_sb_info *sbinfo;
        unsigned long blocks = 0;
        unsigned long inodes = 0;
+       int policy = MPOL_DEFAULT;
+       nodemask_t policy_nodes = node_online_map;
 
 #ifdef CONFIG_TMPFS
        /*
@@ -1984,8 +2072,8 @@ static int shmem_fill_super(struct super_block *sb,
                inodes = totalram_pages - totalhigh_pages;
                if (inodes > blocks)
                        inodes = blocks;
-               if (shmem_parse_options(data, &mode, &uid, &gid,
-                                       &blocks, &inodes))
+               if (shmem_parse_options(data, &mode, &uid, &gid, &blocks,
+                                       &inodes, &policy, &policy_nodes))
                        return -EINVAL;
        }
 #else
@@ -2003,6 +2091,8 @@ static int shmem_fill_super(struct super_block *sb,
        sbinfo->free_blocks = blocks;
        sbinfo->max_inodes = inodes;
        sbinfo->free_inodes = inodes;
+       sbinfo->policy = policy;
+       sbinfo->policy_nodes = policy_nodes;
 
        sb->s_fs_info = sbinfo;
        sb->s_maxbytes = SHMEM_MAX_BYTES;
@@ -2029,7 +2119,7 @@ failed:
        return err;
 }
 
-static kmem_cache_t *shmem_inode_cachep;
+static struct kmem_cache *shmem_inode_cachep;
 
 static struct inode *shmem_alloc_inode(struct super_block *sb)
 {
@@ -2049,7 +2139,8 @@ static void shmem_destroy_inode(struct inode *inode)
        kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
 }
 
-static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+static void init_once(void *foo, struct kmem_cache *cachep,
+                     unsigned long flags)
 {
        struct shmem_inode_info *p = (struct shmem_inode_info *) foo;