KVM: x86: Clear apic tsc-deadline after deadline
[sfrench/cifs-2.6.git] / mm / shmem.c
index 302d1cf7ad07c385ebfeb381dd42af542b4787a5..0e5fb225007c519a27b680673160011bd74dd445 100644 (file)
@@ -66,6 +66,9 @@ static struct vfsmount *shm_mnt;
 #include <linux/highmem.h>
 #include <linux/seq_file.h>
 #include <linux/magic.h>
+#include <linux/syscalls.h>
+#include <linux/fcntl.h>
+#include <uapi/linux/memfd.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -419,7 +422,6 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
                        pvec.pages, indices);
                if (!pvec.nr)
                        break;
-               mem_cgroup_uncharge_start();
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
 
@@ -447,7 +449,6 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
                }
                pagevec_remove_exceptionals(&pvec);
                pagevec_release(&pvec);
-               mem_cgroup_uncharge_end();
                cond_resched();
                index++;
        }
@@ -495,7 +496,6 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
                        index = start;
                        continue;
                }
-               mem_cgroup_uncharge_start();
                for (i = 0; i < pagevec_count(&pvec); i++) {
                        struct page *page = pvec.pages[i];
 
@@ -531,7 +531,6 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,
                }
                pagevec_remove_exceptionals(&pvec);
                pagevec_release(&pvec);
-               mem_cgroup_uncharge_end();
                index++;
        }
 
@@ -551,6 +550,7 @@ EXPORT_SYMBOL_GPL(shmem_truncate_range);
 static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
 {
        struct inode *inode = dentry->d_inode;
+       struct shmem_inode_info *info = SHMEM_I(inode);
        int error;
 
        error = inode_change_ok(inode, attr);
@@ -561,6 +561,11 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
                loff_t oldsize = inode->i_size;
                loff_t newsize = attr->ia_size;
 
+               /* protected by i_mutex */
+               if ((newsize < oldsize && (info->seals & F_SEAL_SHRINK)) ||
+                   (newsize > oldsize && (info->seals & F_SEAL_GROW)))
+                       return -EPERM;
+
                if (newsize != oldsize) {
                        error = shmem_reacct_size(SHMEM_I(inode)->flags,
                                        oldsize, newsize);
@@ -621,7 +626,7 @@ static int shmem_unuse_inode(struct shmem_inode_info *info,
        radswap = swp_to_radix_entry(swap);
        index = radix_tree_locate_item(&mapping->page_tree, radswap);
        if (index == -1)
-               return 0;
+               return -EAGAIN; /* tell shmem_unuse we found nothing */
 
        /*
         * Move _head_ to start search for next from here.
@@ -680,7 +685,6 @@ static int shmem_unuse_inode(struct shmem_inode_info *info,
                        spin_unlock(&info->lock);
                        swap_free(swap);
                }
-               error = 1;      /* not an error, but entry was found */
        }
        return error;
 }
@@ -692,7 +696,7 @@ int shmem_unuse(swp_entry_t swap, struct page *page)
 {
        struct list_head *this, *next;
        struct shmem_inode_info *info;
-       int found = 0;
+       struct mem_cgroup *memcg;
        int error = 0;
 
        /*
@@ -707,26 +711,32 @@ int shmem_unuse(swp_entry_t swap, struct page *page)
         * the shmem_swaplist_mutex which might hold up shmem_writepage().
         * Charged back to the user (not to caller) when swap account is used.
         */
-       error = mem_cgroup_charge_file(page, current->mm, GFP_KERNEL);
+       error = mem_cgroup_try_charge(page, current->mm, GFP_KERNEL, &memcg);
        if (error)
                goto out;
        /* No radix_tree_preload: swap entry keeps a place for page in tree */
+       error = -EAGAIN;
 
        mutex_lock(&shmem_swaplist_mutex);
        list_for_each_safe(this, next, &shmem_swaplist) {
                info = list_entry(this, struct shmem_inode_info, swaplist);
                if (info->swapped)
-                       found = shmem_unuse_inode(info, swap, &page);
+                       error = shmem_unuse_inode(info, swap, &page);
                else
                        list_del_init(&info->swaplist);
                cond_resched();
-               if (found)
+               if (error != -EAGAIN)
                        break;
+               /* found nothing in this: move on to search the next */
        }
        mutex_unlock(&shmem_swaplist_mutex);
 
-       if (found < 0)
-               error = found;
+       if (error) {
+               if (error != -ENOMEM)
+                       error = 0;
+               mem_cgroup_cancel_charge(page, memcg);
+       } else
+               mem_cgroup_commit_charge(page, memcg, true);
 out:
        unlock_page(page);
        page_cache_release(page);
@@ -830,7 +840,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
        }
 
        mutex_unlock(&shmem_swaplist_mutex);
-       swapcache_free(swap, NULL);
+       swapcache_free(swap);
 redirty:
        set_page_dirty(page);
        if (wbc->for_reclaim)
@@ -1003,7 +1013,7 @@ static int shmem_replace_page(struct page **pagep, gfp_t gfp,
                 */
                oldpage = newpage;
        } else {
-               mem_cgroup_replace_page_cache(oldpage, newpage);
+               mem_cgroup_migrate(oldpage, newpage, false);
                lru_cache_add_anon(newpage);
                *pagep = newpage;
        }
@@ -1030,6 +1040,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
        struct address_space *mapping = inode->i_mapping;
        struct shmem_inode_info *info;
        struct shmem_sb_info *sbinfo;
+       struct mem_cgroup *memcg;
        struct page *page;
        swp_entry_t swap;
        int error;
@@ -1108,8 +1119,7 @@ repeat:
                                goto failed;
                }
 
-               error = mem_cgroup_charge_file(page, current->mm,
-                                               gfp & GFP_RECLAIM_MASK);
+               error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg);
                if (!error) {
                        error = shmem_add_to_page_cache(page, mapping, index,
                                                swp_to_radix_entry(swap));
@@ -1125,12 +1135,16 @@ repeat:
                         * Reset swap.val? No, leave it so "failed" goes back to
                         * "repeat": reading a hole and writing should succeed.
                         */
-                       if (error)
+                       if (error) {
+                               mem_cgroup_cancel_charge(page, memcg);
                                delete_from_swap_cache(page);
+                       }
                }
                if (error)
                        goto failed;
 
+               mem_cgroup_commit_charge(page, memcg, true);
+
                spin_lock(&info->lock);
                info->swapped--;
                shmem_recalc_inode(inode);
@@ -1168,8 +1182,7 @@ repeat:
                if (sgp == SGP_WRITE)
                        __SetPageReferenced(page);
 
-               error = mem_cgroup_charge_file(page, current->mm,
-                                               gfp & GFP_RECLAIM_MASK);
+               error = mem_cgroup_try_charge(page, current->mm, gfp, &memcg);
                if (error)
                        goto decused;
                error = radix_tree_maybe_preload(gfp & GFP_RECLAIM_MASK);
@@ -1179,9 +1192,10 @@ repeat:
                        radix_tree_preload_end();
                }
                if (error) {
-                       mem_cgroup_uncharge_cache_page(page);
+                       mem_cgroup_cancel_charge(page, memcg);
                        goto decused;
                }
+               mem_cgroup_commit_charge(page, memcg, false);
                lru_cache_add_anon(page);
 
                spin_lock(&info->lock);
@@ -1407,6 +1421,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
                info = SHMEM_I(inode);
                memset(info, 0, (char *)inode - (char *)info);
                spin_lock_init(&info->lock);
+               info->seals = F_SEAL_SEAL;
                info->flags = flags & VM_NORESERVE;
                INIT_LIST_HEAD(&info->swaplist);
                simple_xattrs_init(&info->xattrs);
@@ -1465,7 +1480,17 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
                        struct page **pagep, void **fsdata)
 {
        struct inode *inode = mapping->host;
+       struct shmem_inode_info *info = SHMEM_I(inode);
        pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+
+       /* i_mutex is held by caller */
+       if (unlikely(info->seals)) {
+               if (info->seals & F_SEAL_WRITE)
+                       return -EPERM;
+               if ((info->seals & F_SEAL_GROW) && pos + len > inode->i_size)
+                       return -EPERM;
+       }
+
        return shmem_getpage(inode, index, pagep, SGP_WRITE, NULL);
 }
 
@@ -1803,11 +1828,233 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
        return offset;
 }
 
+/*
+ * We need a tag: a new tag would expand every radix_tree_node by 8 bytes,
+ * so reuse a tag which we firmly believe is never set or cleared on shmem.
+ */
+#define SHMEM_TAG_PINNED        PAGECACHE_TAG_TOWRITE
+#define LAST_SCAN               4       /* about 150ms max */
+
+static void shmem_tag_pins(struct address_space *mapping)
+{
+       struct radix_tree_iter iter;
+       void **slot;
+       pgoff_t start;
+       struct page *page;
+
+       lru_add_drain();
+       start = 0;
+       rcu_read_lock();
+
+restart:
+       radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
+               page = radix_tree_deref_slot(slot);
+               if (!page || radix_tree_exception(page)) {
+                       if (radix_tree_deref_retry(page))
+                               goto restart;
+               } else if (page_count(page) - page_mapcount(page) > 1) {
+                       spin_lock_irq(&mapping->tree_lock);
+                       radix_tree_tag_set(&mapping->page_tree, iter.index,
+                                          SHMEM_TAG_PINNED);
+                       spin_unlock_irq(&mapping->tree_lock);
+               }
+
+               if (need_resched()) {
+                       cond_resched_rcu();
+                       start = iter.index + 1;
+                       goto restart;
+               }
+       }
+       rcu_read_unlock();
+}
+
+/*
+ * Setting SEAL_WRITE requires us to verify there's no pending writer. However,
+ * via get_user_pages(), drivers might have some pending I/O without any active
+ * user-space mappings (eg., direct-IO, AIO). Therefore, we look at all pages
+ * and see whether it has an elevated ref-count. If so, we tag them and wait for
+ * them to be dropped.
+ * The caller must guarantee that no new user will acquire writable references
+ * to those pages to avoid races.
+ */
+static int shmem_wait_for_pins(struct address_space *mapping)
+{
+       struct radix_tree_iter iter;
+       void **slot;
+       pgoff_t start;
+       struct page *page;
+       int error, scan;
+
+       shmem_tag_pins(mapping);
+
+       error = 0;
+       for (scan = 0; scan <= LAST_SCAN; scan++) {
+               if (!radix_tree_tagged(&mapping->page_tree, SHMEM_TAG_PINNED))
+                       break;
+
+               if (!scan)
+                       lru_add_drain_all();
+               else if (schedule_timeout_killable((HZ << scan) / 200))
+                       scan = LAST_SCAN;
+
+               start = 0;
+               rcu_read_lock();
+restart:
+               radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter,
+                                          start, SHMEM_TAG_PINNED) {
+
+                       page = radix_tree_deref_slot(slot);
+                       if (radix_tree_exception(page)) {
+                               if (radix_tree_deref_retry(page))
+                                       goto restart;
+
+                               page = NULL;
+                       }
+
+                       if (page &&
+                           page_count(page) - page_mapcount(page) != 1) {
+                               if (scan < LAST_SCAN)
+                                       goto continue_resched;
+
+                               /*
+                                * On the last scan, we clean up all those tags
+                                * we inserted; but make a note that we still
+                                * found pages pinned.
+                                */
+                               error = -EBUSY;
+                       }
+
+                       spin_lock_irq(&mapping->tree_lock);
+                       radix_tree_tag_clear(&mapping->page_tree,
+                                            iter.index, SHMEM_TAG_PINNED);
+                       spin_unlock_irq(&mapping->tree_lock);
+continue_resched:
+                       if (need_resched()) {
+                               cond_resched_rcu();
+                               start = iter.index + 1;
+                               goto restart;
+                       }
+               }
+               rcu_read_unlock();
+       }
+
+       return error;
+}
+
+#define F_ALL_SEALS (F_SEAL_SEAL | \
+                    F_SEAL_SHRINK | \
+                    F_SEAL_GROW | \
+                    F_SEAL_WRITE)
+
+int shmem_add_seals(struct file *file, unsigned int seals)
+{
+       struct inode *inode = file_inode(file);
+       struct shmem_inode_info *info = SHMEM_I(inode);
+       int error;
+
+       /*
+        * SEALING
+        * Sealing allows multiple parties to share a shmem-file but restrict
+        * access to a specific subset of file operations. Seals can only be
+        * added, but never removed. This way, mutually untrusted parties can
+        * share common memory regions with a well-defined policy. A malicious
+        * peer can thus never perform unwanted operations on a shared object.
+        *
+        * Seals are only supported on special shmem-files and always affect
+        * the whole underlying inode. Once a seal is set, it may prevent some
+        * kinds of access to the file. Currently, the following seals are
+        * defined:
+        *   SEAL_SEAL: Prevent further seals from being set on this file
+        *   SEAL_SHRINK: Prevent the file from shrinking
+        *   SEAL_GROW: Prevent the file from growing
+        *   SEAL_WRITE: Prevent write access to the file
+        *
+        * As we don't require any trust relationship between two parties, we
+        * must prevent seals from being removed. Therefore, sealing a file
+        * only adds a given set of seals to the file, it never touches
+        * existing seals. Furthermore, the "setting seals"-operation can be
+        * sealed itself, which basically prevents any further seal from being
+        * added.
+        *
+        * Semantics of sealing are only defined on volatile files. Only
+        * anonymous shmem files support sealing. More importantly, seals are
+        * never written to disk. Therefore, there's no plan to support it on
+        * other file types.
+        */
+
+       if (file->f_op != &shmem_file_operations)
+               return -EINVAL;
+       if (!(file->f_mode & FMODE_WRITE))
+               return -EPERM;
+       if (seals & ~(unsigned int)F_ALL_SEALS)
+               return -EINVAL;
+
+       mutex_lock(&inode->i_mutex);
+
+       if (info->seals & F_SEAL_SEAL) {
+               error = -EPERM;
+               goto unlock;
+       }
+
+       if ((seals & F_SEAL_WRITE) && !(info->seals & F_SEAL_WRITE)) {
+               error = mapping_deny_writable(file->f_mapping);
+               if (error)
+                       goto unlock;
+
+               error = shmem_wait_for_pins(file->f_mapping);
+               if (error) {
+                       mapping_allow_writable(file->f_mapping);
+                       goto unlock;
+               }
+       }
+
+       info->seals |= seals;
+       error = 0;
+
+unlock:
+       mutex_unlock(&inode->i_mutex);
+       return error;
+}
+EXPORT_SYMBOL_GPL(shmem_add_seals);
+
+int shmem_get_seals(struct file *file)
+{
+       if (file->f_op != &shmem_file_operations)
+               return -EINVAL;
+
+       return SHMEM_I(file_inode(file))->seals;
+}
+EXPORT_SYMBOL_GPL(shmem_get_seals);
+
+long shmem_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       long error;
+
+       switch (cmd) {
+       case F_ADD_SEALS:
+               /* disallow upper 32bit */
+               if (arg > UINT_MAX)
+                       return -EINVAL;
+
+               error = shmem_add_seals(file, arg);
+               break;
+       case F_GET_SEALS:
+               error = shmem_get_seals(file);
+               break;
+       default:
+               error = -EINVAL;
+               break;
+       }
+
+       return error;
+}
+
 static long shmem_fallocate(struct file *file, int mode, loff_t offset,
                                                         loff_t len)
 {
        struct inode *inode = file_inode(file);
        struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+       struct shmem_inode_info *info = SHMEM_I(inode);
        struct shmem_falloc shmem_falloc;
        pgoff_t start, index, end;
        int error;
@@ -1823,6 +2070,12 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
                loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1;
                DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq);
 
+               /* protected by i_mutex */
+               if (info->seals & F_SEAL_WRITE) {
+                       error = -EPERM;
+                       goto out;
+               }
+
                shmem_falloc.waitq = &shmem_falloc_waitq;
                shmem_falloc.start = unmap_start >> PAGE_SHIFT;
                shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT;
@@ -1849,6 +2102,11 @@ static long shmem_fallocate(struct file *file, int mode, loff_t offset,
        if (error)
                goto out;
 
+       if ((info->seals & F_SEAL_GROW) && offset + len > inode->i_size) {
+               error = -EPERM;
+               goto out;
+       }
+
        start = offset >> PAGE_CACHE_SHIFT;
        end = (offset + len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
        /* Try to avoid a swapstorm if len is impossible to satisfy */
@@ -2065,17 +2323,45 @@ static int shmem_rmdir(struct inode *dir, struct dentry *dentry)
        return shmem_unlink(dir, dentry);
 }
 
+static int shmem_exchange(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
+{
+       bool old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
+       bool new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
+
+       if (old_dir != new_dir && old_is_dir != new_is_dir) {
+               if (old_is_dir) {
+                       drop_nlink(old_dir);
+                       inc_nlink(new_dir);
+               } else {
+                       drop_nlink(new_dir);
+                       inc_nlink(old_dir);
+               }
+       }
+       old_dir->i_ctime = old_dir->i_mtime =
+       new_dir->i_ctime = new_dir->i_mtime =
+       old_dentry->d_inode->i_ctime =
+       new_dentry->d_inode->i_ctime = CURRENT_TIME;
+
+       return 0;
+}
+
 /*
  * The VFS layer already does all the dentry stuff for rename,
  * we just have to decrement the usage count for the target if
  * it exists so that the VFS layer correctly free's it when it
  * gets overwritten.
  */
-static int shmem_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
+static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags)
 {
        struct inode *inode = old_dentry->d_inode;
        int they_are_dirs = S_ISDIR(inode->i_mode);
 
+       if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
+               return -EINVAL;
+
+       if (flags & RENAME_EXCHANGE)
+               return shmem_exchange(old_dir, old_dentry, new_dir, new_dentry);
+
        if (!simple_empty(new_dentry))
                return -ENOTEMPTY;
 
@@ -2584,6 +2870,77 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root)
        shmem_show_mpol(seq, sbinfo->mpol);
        return 0;
 }
+
+#define MFD_NAME_PREFIX "memfd:"
+#define MFD_NAME_PREFIX_LEN (sizeof(MFD_NAME_PREFIX) - 1)
+#define MFD_NAME_MAX_LEN (NAME_MAX - MFD_NAME_PREFIX_LEN)
+
+#define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING)
+
+SYSCALL_DEFINE2(memfd_create,
+               const char __user *, uname,
+               unsigned int, flags)
+{
+       struct shmem_inode_info *info;
+       struct file *file;
+       int fd, error;
+       char *name;
+       long len;
+
+       if (flags & ~(unsigned int)MFD_ALL_FLAGS)
+               return -EINVAL;
+
+       /* length includes terminating zero */
+       len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1);
+       if (len <= 0)
+               return -EFAULT;
+       if (len > MFD_NAME_MAX_LEN + 1)
+               return -EINVAL;
+
+       name = kmalloc(len + MFD_NAME_PREFIX_LEN, GFP_TEMPORARY);
+       if (!name)
+               return -ENOMEM;
+
+       strcpy(name, MFD_NAME_PREFIX);
+       if (copy_from_user(&name[MFD_NAME_PREFIX_LEN], uname, len)) {
+               error = -EFAULT;
+               goto err_name;
+       }
+
+       /* terminating-zero may have changed after strnlen_user() returned */
+       if (name[len + MFD_NAME_PREFIX_LEN - 1]) {
+               error = -EFAULT;
+               goto err_name;
+       }
+
+       fd = get_unused_fd_flags((flags & MFD_CLOEXEC) ? O_CLOEXEC : 0);
+       if (fd < 0) {
+               error = fd;
+               goto err_name;
+       }
+
+       file = shmem_file_setup(name, 0, VM_NORESERVE);
+       if (IS_ERR(file)) {
+               error = PTR_ERR(file);
+               goto err_fd;
+       }
+       info = SHMEM_I(file_inode(file));
+       file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
+       file->f_flags |= O_RDWR | O_LARGEFILE;
+       if (flags & MFD_ALLOW_SEALING)
+               info->seals &= ~F_SEAL_SEAL;
+
+       fd_install(fd, file);
+       kfree(name);
+       return fd;
+
+err_fd:
+       put_unused_fd(fd);
+err_name:
+       kfree(name);
+       return error;
+}
+
 #endif /* CONFIG_TMPFS */
 
 static void shmem_put_super(struct super_block *sb)
@@ -2758,7 +3115,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
        .mkdir          = shmem_mkdir,
        .rmdir          = shmem_rmdir,
        .mknod          = shmem_mknod,
-       .rename         = shmem_rename,
+       .rename2        = shmem_rename2,
        .tmpfile        = shmem_tmpfile,
 #endif
 #ifdef CONFIG_TMPFS_XATTR