]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - mm/shmem.c
x86/mm, mm/hwpoison: Clear PRESENT bit for kernel 1:1 mappings of poison pages
[mirror_ubuntu-artful-kernel.git] / mm / shmem.c
index b0aa6075d164df9ae4766876cc823394abaebc6d..859e4c224b80a94ea35a67704f29c6c03184cdc6 100644 (file)
@@ -110,9 +110,13 @@ static unsigned long shmem_default_max_blocks(void)
        return totalram_pages / 2;
 }
 
-static unsigned long shmem_default_max_inodes(void)
+static int shmem_default_max_inodes(void)
 {
-       return min(totalram_pages - totalhigh_pages, totalram_pages / 2);
+       unsigned long ul;
+
+       ul = INT_MAX;
+       ul = min3(ul, totalram_pages - totalhigh_pages, totalram_pages / 2);
+       return ul;
 }
 #endif
 
@@ -1022,7 +1026,11 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
                         */
                        if (IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE)) {
                                spin_lock(&sbinfo->shrinklist_lock);
-                               if (list_empty(&info->shrinklist)) {
+                               /*
+                                * _careful to defend against unlocked access to
+                                * ->shrink_list in shmem_unused_huge_shrink()
+                                */
+                               if (list_empty_careful(&info->shrinklist)) {
                                        list_add_tail(&info->shrinklist,
                                                        &sbinfo->shrinklist);
                                        sbinfo->shrinklist_len++;
@@ -1064,6 +1072,11 @@ static void shmem_evict_inode(struct inode *inode)
 
        simple_xattrs_free(&info->xattrs);
        WARN_ON(inode->i_blocks);
+       if (!sbinfo->idr_nouse && inode->i_ino) {
+               mutex_lock(&sbinfo->idr_lock);
+               idr_remove(&sbinfo->idr, inode->i_ino);
+               mutex_unlock(&sbinfo->idr_lock);
+       }
        shmem_free_inode(inode->i_sb);
        clear_inode(inode);
 }
@@ -1817,7 +1830,11 @@ alloc_nohuge:            page = shmem_alloc_and_acct_page(gfp, info, sbinfo,
                         * to shrink under memory pressure.
                         */
                        spin_lock(&sbinfo->shrinklist_lock);
-                       if (list_empty(&info->shrinklist)) {
+                       /*
+                        * _careful to defend against unlocked access to
+                        * ->shrink_list in shmem_unused_huge_shrink()
+                        */
+                       if (list_empty_careful(&info->shrinklist)) {
                                list_add_tail(&info->shrinklist,
                                                &sbinfo->shrinklist);
                                sbinfo->shrinklist_len++;
@@ -2140,13 +2157,13 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
        struct inode *inode;
        struct shmem_inode_info *info;
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+       int ino;
 
        if (shmem_reserve_inode(sb))
                return NULL;
 
        inode = new_inode(sb);
        if (inode) {
-               inode->i_ino = get_next_ino();
                inode_init_owner(inode, dir, mode);
                inode->i_blocks = 0;
                inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
@@ -2188,6 +2205,25 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
                        mpol_shared_policy_init(&info->policy, NULL);
                        break;
                }
+
+               if (!sbinfo->idr_nouse) {
+                       /* inum 0 and 1 are unused */
+                       mutex_lock(&sbinfo->idr_lock);
+                       ino = idr_alloc(&sbinfo->idr, inode, 2, INT_MAX,
+                                       GFP_NOFS);
+                       if (ino > 0) {
+                               inode->i_ino = ino;
+                               mutex_unlock(&sbinfo->idr_lock);
+                               __insert_inode_hash(inode, inode->i_ino);
+                       } else {
+                               inode->i_ino = 0;
+                               mutex_unlock(&sbinfo->idr_lock);
+                               iput(inode);
+                               /* shmem_free_inode() will be called */
+                               inode = NULL;
+                       }
+               } else
+                       inode->i_ino = get_next_ino();
        } else
                shmem_free_inode(sb);
        return inode;
@@ -3373,8 +3409,7 @@ static struct dentry *shmem_get_parent(struct dentry *child)
 static int shmem_match(struct inode *ino, void *vfh)
 {
        __u32 *fh = vfh;
-       __u64 inum = fh[2];
-       inum = (inum << 32) | fh[1];
+       __u64 inum = fh[1];
        return ino->i_ino == inum && fh[0] == ino->i_generation;
 }
 
@@ -3385,14 +3420,11 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
        struct dentry *dentry = NULL;
        u64 inum;
 
-       if (fh_len < 3)
+       if (fh_len < 2)
                return NULL;
 
-       inum = fid->raw[2];
-       inum = (inum << 32) | fid->raw[1];
-
-       inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]),
-                       shmem_match, fid->raw);
+       inum = fid->raw[1];
+       inode = ilookup5(sb, inum, shmem_match, fid->raw);
        if (inode) {
                dentry = d_find_alias(inode);
                iput(inode);
@@ -3404,30 +3436,15 @@ static struct dentry *shmem_fh_to_dentry(struct super_block *sb,
 static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len,
                                struct inode *parent)
 {
-       if (*len < 3) {
-               *len = 3;
+       if (*len < 2) {
+               *len = 2;
                return FILEID_INVALID;
        }
 
-       if (inode_unhashed(inode)) {
-               /* Unfortunately insert_inode_hash is not idempotent,
-                * so as we hash inodes here rather than at creation
-                * time, we need a lock to ensure we only try
-                * to do it once
-                */
-               static DEFINE_SPINLOCK(lock);
-               spin_lock(&lock);
-               if (inode_unhashed(inode))
-                       __insert_inode_hash(inode,
-                                           inode->i_ino + inode->i_generation);
-               spin_unlock(&lock);
-       }
-
        fh[0] = inode->i_generation;
        fh[1] = inode->i_ino;
-       fh[2] = ((__u64)inode->i_ino) >> 32;
 
-       *len = 3;
+       *len = 2;
        return 1;
 }
 
@@ -3491,7 +3508,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
                                goto bad_val;
                } else if (!strcmp(this_char,"nr_inodes")) {
                        sbinfo->max_inodes = memparse(value, &rest);
-                       if (*rest)
+                       if (*rest || sbinfo->max_inodes < 2)
                                goto bad_val;
                } else if (!strcmp(this_char,"mode")) {
                        if (remount)
@@ -3556,7 +3573,7 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
 {
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
        struct shmem_sb_info config = *sbinfo;
-       unsigned long inodes;
+       int inodes;
        int error = -EINVAL;
 
        config.mpol = NULL;
@@ -3605,7 +3622,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root)
                seq_printf(seq, ",size=%luk",
                        sbinfo->max_blocks << (PAGE_SHIFT - 10));
        if (sbinfo->max_inodes != shmem_default_max_inodes())
-               seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
+               seq_printf(seq, ",nr_inodes=%d", sbinfo->max_inodes);
        if (sbinfo->mode != (S_IRWXUGO | S_ISVTX))
                seq_printf(seq, ",mode=%03ho", sbinfo->mode);
        if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
@@ -3699,6 +3716,8 @@ static void shmem_put_super(struct super_block *sb)
 {
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 
+       if (!sbinfo->idr_nouse)
+               idr_destroy(&sbinfo->idr);
        percpu_counter_destroy(&sbinfo->used_blocks);
        mpol_put(sbinfo->mpol);
        kfree(sbinfo);
@@ -3717,6 +3736,8 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
        if (!sbinfo)
                return -ENOMEM;
 
+       mutex_init(&sbinfo->idr_lock);
+       idr_init(&sbinfo->idr);
        sbinfo->mode = S_IRWXUGO | S_ISVTX;
        sbinfo->uid = current_fsuid();
        sbinfo->gid = current_fsgid();
@@ -3825,6 +3846,15 @@ static void shmem_destroy_inodecache(void)
        kmem_cache_destroy(shmem_inode_cachep);
 }
 
+static __init void shmem_no_idr(struct super_block *sb)
+{
+       struct shmem_sb_info *sbinfo;
+
+       sbinfo = SHMEM_SB(sb);
+       sbinfo->idr_nouse = true;
+       idr_destroy(&sbinfo->idr);
+}
+
 static const struct address_space_operations shmem_aops = {
        .writepage      = shmem_writepage,
        .set_page_dirty = __set_page_dirty_no_writeback,
@@ -3957,9 +3987,10 @@ int __init shmem_init(void)
                pr_err("Could not kern_mount tmpfs\n");
                goto out1;
        }
+       shmem_no_idr(shm_mnt->mnt_sb);
 
 #ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
-       if (has_transparent_hugepage() && shmem_huge < SHMEM_HUGE_DENY)
+       if (has_transparent_hugepage() && shmem_huge > SHMEM_HUGE_DENY)
                SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge;
        else
                shmem_huge = 0; /* just in case it was patched */
@@ -4020,7 +4051,7 @@ static ssize_t shmem_enabled_store(struct kobject *kobj,
                return -EINVAL;
 
        shmem_huge = huge;
-       if (shmem_huge < SHMEM_HUGE_DENY)
+       if (shmem_huge > SHMEM_HUGE_DENY)
                SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge;
        return count;
 }