Merge remote-tracking branch 'asoc/fix/spear' into asoc-next
[cascardo/linux.git] / mm / shmem.c
index 5dd56f6..1c44af7 100644 (file)
@@ -335,19 +335,19 @@ static unsigned shmem_find_get_pages_and_swap(struct address_space *mapping,
                                        pgoff_t start, unsigned int nr_pages,
                                        struct page **pages, pgoff_t *indices)
 {
-       unsigned int i;
-       unsigned int ret;
-       unsigned int nr_found;
+       void **slot;
+       unsigned int ret = 0;
+       struct radix_tree_iter iter;
+
+       if (!nr_pages)
+               return 0;
 
        rcu_read_lock();
 restart:
-       nr_found = radix_tree_gang_lookup_slot(&mapping->page_tree,
-                               (void ***)pages, indices, start, nr_pages);
-       ret = 0;
-       for (i = 0; i < nr_found; i++) {
+       radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
                struct page *page;
 repeat:
-               page = radix_tree_deref_slot((void **)pages[i]);
+               page = radix_tree_deref_slot(slot);
                if (unlikely(!page))
                        continue;
                if (radix_tree_exception(page)) {
@@ -364,17 +364,16 @@ repeat:
                        goto repeat;
 
                /* Has the page moved? */
-               if (unlikely(page != *((void **)pages[i]))) {
+               if (unlikely(page != *slot)) {
                        page_cache_release(page);
                        goto repeat;
                }
 export:
-               indices[ret] = indices[i];
+               indices[ret] = iter.index;
                pages[ret] = page;
-               ret++;
+               if (++ret == nr_pages)
+                       break;
        }
-       if (unlikely(!ret && nr_found))
-               goto restart;
        rcu_read_unlock();
        return ret;
 }
@@ -1295,7 +1294,7 @@ unlock:
 
 static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
-       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(vma->vm_file);
        int error;
        int ret = VM_FAULT_LOCKED;
 
@@ -1313,14 +1312,14 @@ static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 #ifdef CONFIG_NUMA
 static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol)
 {
-       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(vma->vm_file);
        return mpol_set_shared_policy(&SHMEM_I(inode)->policy, vma, mpol);
 }
 
 static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
                                          unsigned long addr)
 {
-       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(vma->vm_file);
        pgoff_t index;
 
        index = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
@@ -1330,7 +1329,7 @@ static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
 
 int shmem_lock(struct file *file, int lock, struct user_struct *user)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(file);
        struct shmem_inode_info *info = SHMEM_I(inode);
        int retval = -ENOMEM;
 
@@ -1465,7 +1464,7 @@ shmem_write_end(struct file *file, struct address_space *mapping,
 
 static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_t *desc, read_actor_t actor)
 {
-       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(filp);
        struct address_space *mapping = inode->i_mapping;
        pgoff_t index;
        unsigned long offset;
@@ -1808,7 +1807,7 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
 static long shmem_fallocate(struct file *file, int mode, loff_t offset,
                                                         loff_t len)
 {
-       struct inode *inode = file->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(file);
        struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
        struct shmem_falloc shmem_falloc;
        pgoff_t start, index, end;
@@ -2351,7 +2350,7 @@ static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len,
 {
        if (*len < 3) {
                *len = 3;
-               return 255;
+               return FILEID_INVALID;
        }
 
        if (inode_unhashed(inode)) {
@@ -2386,6 +2385,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
                               bool remount)
 {
        char *this_char, *value, *rest;
+       struct mempolicy *mpol = NULL;
        uid_t uid;
        gid_t gid;
 
@@ -2414,7 +2414,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
                        printk(KERN_ERR
                            "tmpfs: No value for mount option '%s'\n",
                            this_char);
-                       return 1;
+                       goto error;
                }
 
                if (!strcmp(this_char,"size")) {
@@ -2463,19 +2463,24 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
                        if (!gid_valid(sbinfo->gid))
                                goto bad_val;
                } else if (!strcmp(this_char,"mpol")) {
-                       if (mpol_parse_str(value, &sbinfo->mpol))
+                       mpol_put(mpol);
+                       mpol = NULL;
+                       if (mpol_parse_str(value, &mpol))
                                goto bad_val;
                } else {
                        printk(KERN_ERR "tmpfs: Bad mount option %s\n",
                               this_char);
-                       return 1;
+                       goto error;
                }
        }
+       sbinfo->mpol = mpol;
        return 0;
 
 bad_val:
        printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n",
               value, this_char);
+error:
+       mpol_put(mpol);
        return 1;
 
 }
@@ -2487,6 +2492,7 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
        unsigned long inodes;
        int error = -EINVAL;
 
+       config.mpol = NULL;
        if (shmem_parse_options(data, &config, true))
                return error;
 
@@ -2511,8 +2517,13 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
        sbinfo->max_inodes  = config.max_inodes;
        sbinfo->free_inodes = config.max_inodes - inodes;
 
-       mpol_put(sbinfo->mpol);
-       sbinfo->mpol        = config.mpol;      /* transfers initial ref */
+       /*
+        * Preserve previous mempolicy unless mpol remount option was specified.
+        */
+       if (config.mpol) {
+               mpol_put(sbinfo->mpol);
+               sbinfo->mpol = config.mpol;     /* transfers initial ref */
+       }
 out:
        spin_unlock(&sbinfo->stat_lock);
        return error;
@@ -2545,6 +2556,7 @@ static void shmem_put_super(struct super_block *sb)
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 
        percpu_counter_destroy(&sbinfo->used_blocks);
+       mpol_put(sbinfo->mpol);
        kfree(sbinfo);
        sb->s_fs_info = NULL;
 }
@@ -2766,6 +2778,7 @@ static struct file_system_type shmem_fs_type = {
        .name           = "tmpfs",
        .mount          = shmem_mount,
        .kill_sb        = kill_litter_super,
+       .fs_flags       = FS_USERNS_MOUNT,
 };
 
 int __init shmem_init(void)
@@ -2823,6 +2836,7 @@ static struct file_system_type shmem_fs_type = {
        .name           = "tmpfs",
        .mount          = ramfs_mount,
        .kill_sb        = kill_litter_super,
+       .fs_flags       = FS_USERNS_MOUNT,
 };
 
 int __init shmem_init(void)
@@ -2865,6 +2879,16 @@ EXPORT_SYMBOL_GPL(shmem_truncate_range);
 
 /* common code */
 
+static char *shmem_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+       return dynamic_dname(dentry, buffer, buflen, "/%s (deleted)",
+                               dentry->d_name.name);
+}
+
+static struct dentry_operations anon_ops = {
+       .d_dname = shmem_dname
+};
+
 /**
  * shmem_file_setup - get an unlinked file living in tmpfs
  * @name: name for dentry (to be seen in /proc/<pid>/maps
@@ -2873,15 +2897,14 @@ EXPORT_SYMBOL_GPL(shmem_truncate_range);
  */
 struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
 {
-       int error;
-       struct file *file;
+       struct file *res;
        struct inode *inode;
        struct path path;
-       struct dentry *root;
+       struct super_block *sb;
        struct qstr this;
 
        if (IS_ERR(shm_mnt))
-               return (void *)shm_mnt;
+               return ERR_CAST(shm_mnt);
 
        if (size < 0 || size > MAX_LFS_FILESIZE)
                return ERR_PTR(-EINVAL);
@@ -2889,18 +2912,19 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
        if (shmem_acct_size(flags, size))
                return ERR_PTR(-ENOMEM);
 
-       error = -ENOMEM;
+       res = ERR_PTR(-ENOMEM);
        this.name = name;
        this.len = strlen(name);
        this.hash = 0; /* will go */
-       root = shm_mnt->mnt_root;
-       path.dentry = d_alloc(root, &this);
+       sb = shm_mnt->mnt_sb;
+       path.dentry = d_alloc_pseudo(sb, &this);
        if (!path.dentry)
                goto put_memory;
+       d_set_d_op(path.dentry, &anon_ops);
        path.mnt = mntget(shm_mnt);
 
-       error = -ENOSPC;
-       inode = shmem_get_inode(root->d_sb, NULL, S_IFREG | S_IRWXUGO, 0, flags);
+       res = ERR_PTR(-ENOSPC);
+       inode = shmem_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0, flags);
        if (!inode)
                goto put_dentry;
 
@@ -2908,24 +2932,23 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
        inode->i_size = size;
        clear_nlink(inode);     /* It is unlinked */
 #ifndef CONFIG_MMU
-       error = ramfs_nommu_expand_for_mapping(inode, size);
-       if (error)
+       res = ERR_PTR(ramfs_nommu_expand_for_mapping(inode, size));
+       if (IS_ERR(res))
                goto put_dentry;
 #endif
 
-       error = -ENFILE;
-       file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
+       res = alloc_file(&path, FMODE_WRITE | FMODE_READ,
                  &shmem_file_operations);
-       if (!file)
+       if (IS_ERR(res))
                goto put_dentry;
 
-       return file;
+       return res;
 
 put_dentry:
        path_put(&path);
 put_memory:
        shmem_unacct_size(flags, size);
-       return ERR_PTR(error);
+       return res;
 }
 EXPORT_SYMBOL_GPL(shmem_file_setup);