x86: add tizen_qemu_x86_defconfig & tizen_qemu_x86_64_defconfig
[platform/kernel/linux-rpi.git] / mm / secretmem.c
index 1fea68b..d1986ce 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/secretmem.h>
 #include <linux/set_memory.h>
 #include <linux/sched/signal.h>
-#include <linux/refcount.h>
 
 #include <uapi/linux/magic.h>
 
@@ -41,11 +40,11 @@ module_param_named(enable, secretmem_enable, bool, 0400);
 MODULE_PARM_DESC(secretmem_enable,
                 "Enable secretmem and memfd_secret(2) system call");
 
-static refcount_t secretmem_users;
+static atomic_t secretmem_users;
 
 bool secretmem_active(void)
 {
-       return !!refcount_read(&secretmem_users);
+       return !!atomic_read(&secretmem_users);
 }
 
 static vm_fault_t secretmem_fault(struct vm_fault *vmf)
@@ -56,22 +55,28 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf)
        gfp_t gfp = vmf->gfp_mask;
        unsigned long addr;
        struct page *page;
+       vm_fault_t ret;
        int err;
 
        if (((loff_t)vmf->pgoff << PAGE_SHIFT) >= i_size_read(inode))
                return vmf_error(-EINVAL);
 
+       filemap_invalidate_lock_shared(mapping);
+
 retry:
        page = find_lock_page(mapping, offset);
        if (!page) {
                page = alloc_page(gfp | __GFP_ZERO);
-               if (!page)
-                       return VM_FAULT_OOM;
+               if (!page) {
+                       ret = VM_FAULT_OOM;
+                       goto out;
+               }
 
                err = set_direct_map_invalid_noflush(page);
                if (err) {
                        put_page(page);
-                       return vmf_error(err);
+                       ret = vmf_error(err);
+                       goto out;
                }
 
                __SetPageUptodate(page);
@@ -87,7 +92,8 @@ retry:
                        if (err == -EEXIST)
                                goto retry;
 
-                       return vmf_error(err);
+                       ret = vmf_error(err);
+                       goto out;
                }
 
                addr = (unsigned long)page_address(page);
@@ -95,7 +101,11 @@ retry:
        }
 
        vmf->page = page;
-       return VM_FAULT_LOCKED;
+       ret = VM_FAULT_LOCKED;
+
+out:
+       filemap_invalidate_unlock_shared(mapping);
+       return ret;
 }
 
 static const struct vm_operations_struct secretmem_vm_ops = {
@@ -104,7 +114,7 @@ static const struct vm_operations_struct secretmem_vm_ops = {
 
 static int secretmem_release(struct inode *inode, struct file *file)
 {
-       refcount_dec(&secretmem_users);
+       atomic_dec(&secretmem_users);
        return 0;
 }
 
@@ -159,6 +169,30 @@ const struct address_space_operations secretmem_aops = {
        .isolate_page   = secretmem_isolate_page,
 };
 
+static int secretmem_setattr(struct user_namespace *mnt_userns,
+                            struct dentry *dentry, struct iattr *iattr)
+{
+       struct inode *inode = d_inode(dentry);
+       struct address_space *mapping = inode->i_mapping;
+       unsigned int ia_valid = iattr->ia_valid;
+       int ret;
+
+       filemap_invalidate_lock(mapping);
+
+       if ((ia_valid & ATTR_SIZE) && inode->i_size)
+               ret = -EINVAL;
+       else
+               ret = simple_setattr(mnt_userns, dentry, iattr);
+
+       filemap_invalidate_unlock(mapping);
+
+       return ret;
+}
+
+static const struct inode_operations secretmem_iops = {
+       .setattr = secretmem_setattr,
+};
+
 static struct vfsmount *secretmem_mnt;
 
 static struct file *secretmem_file_create(unsigned long flags)
@@ -178,6 +212,7 @@ static struct file *secretmem_file_create(unsigned long flags)
        mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
        mapping_set_unevictable(inode->i_mapping);
 
+       inode->i_op = &secretmem_iops;
        inode->i_mapping->a_ops = &secretmem_aops;
 
        /* pretend we are a normal file with zero size */
@@ -204,6 +239,8 @@ SYSCALL_DEFINE1(memfd_secret, unsigned int, flags)
 
        if (flags & ~(SECRETMEM_FLAGS_MASK | O_CLOEXEC))
                return -EINVAL;
+       if (atomic_read(&secretmem_users) < 0)
+               return -ENFILE;
 
        fd = get_unused_fd_flags(flags & O_CLOEXEC);
        if (fd < 0)
@@ -217,8 +254,8 @@ SYSCALL_DEFINE1(memfd_secret, unsigned int, flags)
 
        file->f_flags |= O_LARGEFILE;
 
+       atomic_inc(&secretmem_users);
        fd_install(fd, file);
-       refcount_inc(&secretmem_users);
        return fd;
 
 err_put_fd:
@@ -246,7 +283,7 @@ static int secretmem_init(void)
 
        secretmem_mnt = kern_mount(&secretmem_fs);
        if (IS_ERR(secretmem_mnt))
-               ret = PTR_ERR(secretmem_mnt);
+               return PTR_ERR(secretmem_mnt);
 
        /* prevent secretmem mappings from ever getting PROT_EXEC */
        secretmem_mnt->mnt_flags |= MNT_NOEXEC;