Merge remote-tracking branch 'ovl/for-viro' into for-linus
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 2 Mar 2017 11:41:22 +0000 (06:41 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 2 Mar 2017 11:41:22 +0000 (06:41 -0500)
Overlayfs-related series from Miklos and Amir

1  2 
drivers/block/loop.c
drivers/gpu/drm/i915/i915_gem_dmabuf.c
fs/aio.c
fs/namei.c
fs/splice.c
include/linux/fs.h
mm/mmap.c
mm/nommu.c

diff --combined drivers/block/loop.c
@@@ -501,9 -501,9 +501,9 @@@ static int lo_rw_aio(struct loop_devic
        cmd->iocb.ki_flags = IOCB_DIRECT;
  
        if (rw == WRITE)
-               ret = file->f_op->write_iter(&cmd->iocb, &iter);
+               ret = call_write_iter(file, &cmd->iocb, &iter);
        else
-               ret = file->f_op->read_iter(&cmd->iocb, &iter);
+               ret = call_read_iter(file, &cmd->iocb, &iter);
  
        if (ret != -EIOCBQUEUED)
                cmd->iocb.ki_complete(&cmd->iocb, ret, 0);
@@@ -1097,12 -1097,9 +1097,12 @@@ loop_set_status(struct loop_device *lo
        if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
                return -EINVAL;
  
 +      /* I/O need to be drained during transfer transition */
 +      blk_mq_freeze_queue(lo->lo_queue);
 +
        err = loop_release_xfer(lo);
        if (err)
 -              return err;
 +              goto exit;
  
        if (info->lo_encrypt_type) {
                unsigned int type = info->lo_encrypt_type;
  
        err = loop_init_xfer(lo, xfer, info);
        if (err)
 -              return err;
 +              goto exit;
  
        if (lo->lo_offset != info->lo_offset ||
            lo->lo_sizelimit != info->lo_sizelimit)
 -              if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit))
 -                      return -EFBIG;
 +              if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) {
 +                      err = -EFBIG;
 +                      goto exit;
 +              }
  
        loop_config_discard(lo);
  
        /* update dio if lo_offset or transfer is changed */
        __loop_update_dio(lo, lo->use_dio);
  
 -      return 0;
 + exit:
 +      blk_mq_unfreeze_queue(lo->lo_queue);
 +      return err;
  }
  
  static int
@@@ -141,7 -141,7 +141,7 @@@ static int i915_gem_dmabuf_mmap(struct 
        if (!obj->base.filp)
                return -ENODEV;
  
-       ret = obj->base.filp->f_op->mmap(obj->base.filp, vma);
+       ret = call_mmap(obj->base.filp, vma);
        if (ret)
                return ret;
  
@@@ -278,7 -278,7 +278,7 @@@ struct drm_gem_object *i915_gem_prime_i
  
        get_dma_buf(dma_buf);
  
 -      obj = i915_gem_object_alloc(dev);
 +      obj = i915_gem_object_alloc(to_i915(dev));
        if (obj == NULL) {
                ret = -ENOMEM;
                goto fail_detach;
diff --combined fs/aio.c
+++ b/fs/aio.c
@@@ -1085,8 -1085,7 +1085,8 @@@ static void aio_complete(struct kiocb *
                 * Tell lockdep we inherited freeze protection from submission
                 * thread.
                 */
 -              __sb_writers_acquired(file_inode(file)->i_sb, SB_FREEZE_WRITE);
 +              if (S_ISREG(file_inode(file)->i_mode))
 +                      __sb_writers_acquired(file_inode(file)->i_sb, SB_FREEZE_WRITE);
                file_end_write(file);
        }
  
@@@ -1495,7 -1494,7 +1495,7 @@@ static ssize_t aio_read(struct kiocb *r
                return ret;
        ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
        if (!ret)
-               ret = aio_ret(req, file->f_op->read_iter(req, &iter));
+               ret = aio_ret(req, call_read_iter(file, req, &iter));
        kfree(iovec);
        return ret;
  }
@@@ -1520,14 -1519,13 +1520,14 @@@ static ssize_t aio_write(struct kiocb *
        if (!ret) {
                req->ki_flags |= IOCB_WRITE;
                file_start_write(file);
-               ret = aio_ret(req, file->f_op->write_iter(req, &iter));
+               ret = aio_ret(req, call_write_iter(file, req, &iter));
                /*
                 * We release freeze protection in aio_complete().  Fool lockdep
                 * by telling it the lock got released so that it doesn't
                 * complain about held lock when we return to userspace.
                 */
 -              __sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
 +              if (S_ISREG(file_inode(file)->i_mode))
 +                      __sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
        }
        kfree(iovec);
        return ret;
diff --combined fs/namei.c
@@@ -672,15 -672,17 +672,15 @@@ static bool legitimize_links(struct nam
  /**
   * unlazy_walk - try to switch to ref-walk mode.
   * @nd: nameidata pathwalk data
 - * @dentry: child of nd->path.dentry or NULL
 - * @seq: seq number to check dentry against
   * Returns: 0 on success, -ECHILD on failure
   *
 - * unlazy_walk attempts to legitimize the current nd->path, nd->root and dentry
 - * for ref-walk mode.  @dentry must be a path found by a do_lookup call on
 - * @nd or NULL.  Must be called from rcu-walk context.
 + * unlazy_walk attempts to legitimize the current nd->path and nd->root
 + * for ref-walk mode.
 + * Must be called from rcu-walk context.
   * Nothing should touch nameidata between unlazy_walk() failure and
   * terminate_walk().
   */
 -static int unlazy_walk(struct nameidata *nd, struct dentry *dentry, unsigned seq)
 +static int unlazy_walk(struct nameidata *nd)
  {
        struct dentry *parent = nd->path.dentry;
  
        nd->flags &= ~LOOKUP_RCU;
        if (unlikely(!legitimize_links(nd)))
                goto out2;
 +      if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
 +              goto out1;
 +      if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
 +              if (unlikely(!legitimize_path(nd, &nd->root, nd->root_seq)))
 +                      goto out;
 +      }
 +      rcu_read_unlock();
 +      BUG_ON(nd->inode != parent->d_inode);
 +      return 0;
 +
 +out2:
 +      nd->path.mnt = NULL;
 +      nd->path.dentry = NULL;
 +out1:
 +      if (!(nd->flags & LOOKUP_ROOT))
 +              nd->root.mnt = NULL;
 +out:
 +      rcu_read_unlock();
 +      return -ECHILD;
 +}
 +
 +/**
 + * unlazy_child - try to switch to ref-walk mode.
 + * @nd: nameidata pathwalk data
 + * @dentry: child of nd->path.dentry
 + * @seq: seq number to check dentry against
 + * Returns: 0 on success, -ECHILD on failure
 + *
 + * unlazy_child attempts to legitimize the current nd->path, nd->root and dentry
 + * for ref-walk mode.  @dentry must be a path found by a do_lookup call on
 + * @nd.  Must be called from rcu-walk context.
 + * Nothing should touch nameidata between unlazy_child() failure and
 + * terminate_walk().
 + */
 +static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned seq)
 +{
 +      BUG_ON(!(nd->flags & LOOKUP_RCU));
 +
 +      nd->flags &= ~LOOKUP_RCU;
 +      if (unlikely(!legitimize_links(nd)))
 +              goto out2;
        if (unlikely(!legitimize_mnt(nd->path.mnt, nd->m_seq)))
                goto out2;
 -      if (unlikely(!lockref_get_not_dead(&parent->d_lockref)))
 +      if (unlikely(!lockref_get_not_dead(&nd->path.dentry->d_lockref)))
                goto out1;
  
        /*
 -       * For a negative lookup, the lookup sequence point is the parents
 -       * sequence point, and it only needs to revalidate the parent dentry.
 -       *
 -       * For a positive lookup, we need to move both the parent and the
 -       * dentry from the RCU domain to be properly refcounted. And the
 -       * sequence number in the dentry validates *both* dentry counters,
 -       * since we checked the sequence number of the parent after we got
 -       * the child sequence number. So we know the parent must still
 -       * be valid if the child sequence number is still valid.
 +       * We need to move both the parent and the dentry from the RCU domain
 +       * to be properly refcounted. And the sequence number in the dentry
 +       * validates *both* dentry counters, since we checked the sequence
 +       * number of the parent after we got the child sequence number. So we
 +       * know the parent must still be valid if the child sequence number is
         */
 -      if (!dentry) {
 -              if (read_seqcount_retry(&parent->d_seq, nd->seq))
 -                      goto out;
 -              BUG_ON(nd->inode != parent->d_inode);
 -      } else {
 -              if (!lockref_get_not_dead(&dentry->d_lockref))
 -                      goto out;
 -              if (read_seqcount_retry(&dentry->d_seq, seq))
 -                      goto drop_dentry;
 +      if (unlikely(!lockref_get_not_dead(&dentry->d_lockref)))
 +              goto out;
 +      if (unlikely(read_seqcount_retry(&dentry->d_seq, seq))) {
 +              rcu_read_unlock();
 +              dput(dentry);
 +              goto drop_root_mnt;
        }
 -
        /*
         * Sequence counts matched. Now make sure that the root is
         * still valid and get it if required.
        rcu_read_unlock();
        return 0;
  
 -drop_dentry:
 -      rcu_read_unlock();
 -      dput(dentry);
 -      goto drop_root_mnt;
  out2:
        nd->path.mnt = NULL;
  out1:
@@@ -776,12 -749,27 +776,12 @@@ drop_root_mnt
        return -ECHILD;
  }
  
 -static int unlazy_link(struct nameidata *nd, struct path *link, unsigned seq)
 -{
 -      if (unlikely(!legitimize_path(nd, link, seq))) {
 -              drop_links(nd);
 -              nd->depth = 0;
 -              nd->flags &= ~LOOKUP_RCU;
 -              nd->path.mnt = NULL;
 -              nd->path.dentry = NULL;
 -              if (!(nd->flags & LOOKUP_ROOT))
 -                      nd->root.mnt = NULL;
 -              rcu_read_unlock();
 -      } else if (likely(unlazy_walk(nd, NULL, 0)) == 0) {
 -              return 0;
 -      }
 -      path_put(link);
 -      return -ECHILD;
 -}
 -
  static inline int d_revalidate(struct dentry *dentry, unsigned int flags)
  {
 -      return dentry->d_op->d_revalidate(dentry, flags);
 +      if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE))
 +              return dentry->d_op->d_revalidate(dentry, flags);
 +      else
 +              return 1;
  }
  
  /**
@@@ -802,7 -790,7 +802,7 @@@ static int complete_walk(struct nameida
        if (nd->flags & LOOKUP_RCU) {
                if (!(nd->flags & LOOKUP_ROOT))
                        nd->root.mnt = NULL;
 -              if (unlikely(unlazy_walk(nd, NULL, 0)))
 +              if (unlikely(unlazy_walk(nd)))
                        return -ECHILD;
        }
  
@@@ -1028,7 -1016,7 +1028,7 @@@ const char *get_link(struct nameidata *
                touch_atime(&last->link);
                cond_resched();
        } else if (atime_needs_update_rcu(&last->link, inode)) {
 -              if (unlikely(unlazy_walk(nd, NULL, 0)))
 +              if (unlikely(unlazy_walk(nd)))
                        return ERR_PTR(-ECHILD);
                touch_atime(&last->link);
        }
                if (nd->flags & LOOKUP_RCU) {
                        res = get(NULL, inode, &last->done);
                        if (res == ERR_PTR(-ECHILD)) {
 -                              if (unlikely(unlazy_walk(nd, NULL, 0)))
 +                              if (unlikely(unlazy_walk(nd)))
                                        return ERR_PTR(-ECHILD);
                                res = get(dentry, inode, &last->done);
                        }
@@@ -1112,6 -1100,7 +1112,6 @@@ static int follow_automount(struct pat
                            bool *need_mntput)
  {
        struct vfsmount *mnt;
 -      const struct cred *old_cred;
        int err;
  
        if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
        if (nd->total_link_count >= 40)
                return -ELOOP;
  
 -      old_cred = override_creds(&init_cred);
        mnt = path->dentry->d_op->d_automount(path);
 -      revert_creds(old_cred);
        if (IS_ERR(mnt)) {
                /*
                 * The filesystem is allowed to return -EISDIR here to indicate
@@@ -1481,14 -1472,19 +1481,14 @@@ static struct dentry *lookup_dcache(con
                                    struct dentry *dir,
                                    unsigned int flags)
  {
 -      struct dentry *dentry;
 -      int error;
 -
 -      dentry = d_lookup(dir, name);
 +      struct dentry *dentry = d_lookup(dir, name);
        if (dentry) {
 -              if (dentry->d_flags & DCACHE_OP_REVALIDATE) {
 -                      error = d_revalidate(dentry, flags);
 -                      if (unlikely(error <= 0)) {
 -                              if (!error)
 -                                      d_invalidate(dentry);
 -                              dput(dentry);
 -                              return ERR_PTR(error);
 -                      }
 +              int error = d_revalidate(dentry, flags);
 +              if (unlikely(error <= 0)) {
 +                      if (!error)
 +                              d_invalidate(dentry);
 +                      dput(dentry);
 +                      return ERR_PTR(error);
                }
        }
        return dentry;
@@@ -1553,7 -1549,7 +1553,7 @@@ static int lookup_fast(struct nameidat
                bool negative;
                dentry = __d_lookup_rcu(parent, &nd->last, &seq);
                if (unlikely(!dentry)) {
 -                      if (unlazy_walk(nd, NULL, 0))
 +                      if (unlazy_walk(nd))
                                return -ECHILD;
                        return 0;
                }
                        return -ECHILD;
  
                *seqp = seq;
 -              if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE))
 -                      status = d_revalidate(dentry, nd->flags);
 -              if (unlikely(status <= 0)) {
 -                      if (unlazy_walk(nd, dentry, seq))
 -                              return -ECHILD;
 -                      if (status == -ECHILD)
 -                              status = d_revalidate(dentry, nd->flags);
 -              } else {
 +              status = d_revalidate(dentry, nd->flags);
 +              if (likely(status > 0)) {
                        /*
                         * Note: do negative dentry check after revalidation in
                         * case that drops it.
                        path->dentry = dentry;
                        if (likely(__follow_mount_rcu(nd, path, inode, seqp)))
                                return 1;
 -                      if (unlazy_walk(nd, dentry, seq))
 -                              return -ECHILD;
                }
 +              if (unlazy_child(nd, dentry, seq))
 +                      return -ECHILD;
 +              if (unlikely(status == -ECHILD))
 +                      /* we'd been told to redo it in non-rcu mode */
 +                      status = d_revalidate(dentry, nd->flags);
        } else {
                dentry = __d_lookup(parent, &nd->last);
                if (unlikely(!dentry))
                        return 0;
 -              if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE))
 -                      status = d_revalidate(dentry, nd->flags);
 +              status = d_revalidate(dentry, nd->flags);
        }
        if (unlikely(status <= 0)) {
                if (!status)
@@@ -1639,7 -1639,8 +1639,7 @@@ again
        if (IS_ERR(dentry))
                goto out;
        if (unlikely(!d_in_lookup(dentry))) {
 -              if ((dentry->d_flags & DCACHE_OP_REVALIDATE) &&
 -                  !(flags & LOOKUP_NO_REVAL)) {
 +              if (!(flags & LOOKUP_NO_REVAL)) {
                        int error = d_revalidate(dentry, flags);
                        if (unlikely(error <= 0)) {
                                if (!error) {
@@@ -1670,7 -1671,7 +1670,7 @@@ static inline int may_lookup(struct nam
                int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
                if (err != -ECHILD)
                        return err;
 -              if (unlazy_walk(nd, NULL, 0))
 +              if (unlazy_walk(nd))
                        return -ECHILD;
        }
        return inode_permission(nd->inode, MAY_EXEC);
@@@ -1705,17 -1706,9 +1705,17 @@@ static int pick_link(struct nameidata *
        error = nd_alloc_stack(nd);
        if (unlikely(error)) {
                if (error == -ECHILD) {
 -                      if (unlikely(unlazy_link(nd, link, seq)))
 -                              return -ECHILD;
 -                      error = nd_alloc_stack(nd);
 +                      if (unlikely(!legitimize_path(nd, link, seq))) {
 +                              drop_links(nd);
 +                              nd->depth = 0;
 +                              nd->flags &= ~LOOKUP_RCU;
 +                              nd->path.mnt = NULL;
 +                              nd->path.dentry = NULL;
 +                              if (!(nd->flags & LOOKUP_ROOT))
 +                                      nd->root.mnt = NULL;
 +                              rcu_read_unlock();
 +                      } else if (likely(unlazy_walk(nd)) == 0)
 +                              error = nd_alloc_stack(nd);
                }
                if (error) {
                        path_put(link);
@@@ -2132,7 -2125,7 +2132,7 @@@ OK
                }
                if (unlikely(!d_can_lookup(nd->path.dentry))) {
                        if (nd->flags & LOOKUP_RCU) {
 -                              if (unlazy_walk(nd, NULL, 0))
 +                              if (unlazy_walk(nd))
                                        return -ECHILD;
                        }
                        return -ENOTDIR;
@@@ -2589,7 -2582,7 +2589,7 @@@ mountpoint_last(struct nameidata *nd
  
        /* If we're in rcuwalk, drop out of it to handle last component */
        if (nd->flags & LOOKUP_RCU) {
 -              if (unlazy_walk(nd, NULL, 0))
 +              if (unlazy_walk(nd))
                        return -ECHILD;
        }
  
@@@ -2948,16 -2941,10 +2948,16 @@@ static inline int open_to_namei_flags(i
  
  static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t mode)
  {
 +      struct user_namespace *s_user_ns;
        int error = security_path_mknod(dir, dentry, mode, 0);
        if (error)
                return error;
  
 +      s_user_ns = dir->dentry->d_sb->s_user_ns;
 +      if (!kuid_has_mapping(s_user_ns, current_fsuid()) ||
 +          !kgid_has_mapping(s_user_ns, current_fsgid()))
 +              return -EOVERFLOW;
 +
        error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
        if (error)
                return error;
@@@ -3082,6 -3069,9 +3082,6 @@@ static int lookup_open(struct nameidat
                if (d_in_lookup(dentry))
                        break;
  
 -              if (!(dentry->d_flags & DCACHE_OP_REVALIDATE))
 -                      break;
 -
                error = d_revalidate(dentry, nd->flags);
                if (likely(error > 0))
                        break;
        return error;
  }
  
+ struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag)
+ {
+       static const struct qstr name = QSTR_INIT("/", 1);
+       struct dentry *child = NULL;
+       struct inode *dir = dentry->d_inode;
+       struct inode *inode;
+       int error;
+       /* we want directory to be writable */
+       error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+       if (error)
+               goto out_err;
+       error = -EOPNOTSUPP;
+       if (!dir->i_op->tmpfile)
+               goto out_err;
+       error = -ENOMEM;
+       child = d_alloc(dentry, &name);
+       if (unlikely(!child))
+               goto out_err;
+       error = dir->i_op->tmpfile(dir, child, mode);
+       if (error)
+               goto out_err;
+       error = -ENOENT;
+       inode = child->d_inode;
+       if (unlikely(!inode))
+               goto out_err;
+       if (!(open_flag & O_EXCL)) {
+               spin_lock(&inode->i_lock);
+               inode->i_state |= I_LINKABLE;
+               spin_unlock(&inode->i_lock);
+       }
+       return child;
+ out_err:
+       dput(child);
+       return ERR_PTR(error);
+ }
+ EXPORT_SYMBOL(vfs_tmpfile);
  static int do_tmpfile(struct nameidata *nd, unsigned flags,
                const struct open_flags *op,
                struct file *file, int *opened)
  {
-       static const struct qstr name = QSTR_INIT("/", 1);
        struct dentry *child;
-       struct inode *dir;
        struct path path;
        int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path);
        if (unlikely(error))
        error = mnt_want_write(path.mnt);
        if (unlikely(error))
                goto out;
-       dir = path.dentry->d_inode;
-       /* we want directory to be writable */
-       error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
-       if (error)
+       child = vfs_tmpfile(path.dentry, op->mode, op->open_flag);
+       error = PTR_ERR(child);
+       if (unlikely(IS_ERR(child)))
                goto out2;
-       if (!dir->i_op->tmpfile) {
-               error = -EOPNOTSUPP;
-               goto out2;
-       }
-       child = d_alloc(path.dentry, &name);
-       if (unlikely(!child)) {
-               error = -ENOMEM;
-               goto out2;
-       }
        dput(path.dentry);
        path.dentry = child;
-       error = dir->i_op->tmpfile(dir, child, op->mode);
-       if (error)
-               goto out2;
        audit_inode(nd->name, child, 0);
        /* Don't check for other permissions, the inode was just created */
        error = may_open(&path, 0, op->open_flag);
        if (error)
                goto out2;
        error = open_check_o_direct(file);
-       if (error) {
+       if (error)
                fput(file);
-       } else if (!(op->open_flag & O_EXCL)) {
-               struct inode *inode = file_inode(file);
-               spin_lock(&inode->i_lock);
-               inode->i_state |= I_LINKABLE;
-               spin_unlock(&inode->i_lock);
-       }
  out2:
        mnt_drop_write(path.mnt);
  out:
diff --combined fs/splice.c
@@@ -204,7 -204,6 +204,7 @@@ ssize_t splice_to_pipe(struct pipe_inod
                buf->len = spd->partial[page_nr].len;
                buf->private = spd->partial[page_nr].private;
                buf->ops = spd->ops;
 +              buf->flags = 0;
  
                pipe->nrbufs++;
                page_nr++;
@@@ -307,7 -306,7 +307,7 @@@ ssize_t generic_file_splice_read(struc
        idx = to.idx;
        init_sync_kiocb(&kiocb, in);
        kiocb.ki_pos = *ppos;
-       ret = in->f_op->read_iter(&kiocb, &to);
+       ret = call_read_iter(in, &kiocb, &to);
        if (ret > 0) {
                *ppos = kiocb.ki_pos;
                file_accessed(in);
diff --combined include/linux/fs.h
@@@ -423,7 -423,6 +423,7 @@@ struct block_device 
        int                     bd_invalidated;
        struct gendisk *        bd_disk;
        struct request_queue *  bd_queue;
 +      struct backing_dev_info *bd_bdi;
        struct list_head        bd_list;
        /*
         * Private data.  You must have bd_claim'ed the block_device
@@@ -1562,6 -1561,9 +1562,9 @@@ extern int vfs_unlink(struct inode *, s
  extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);
  extern int vfs_whiteout(struct inode *, struct dentry *);
  
+ extern struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode,
+                                 int open_flag);
  /*
   * VFS file helper functions.
   */
@@@ -1713,6 -1715,29 +1716,29 @@@ struct inode_operations 
        int (*set_acl)(struct inode *, struct posix_acl *, int);
  } ____cacheline_aligned;
  
+ static inline ssize_t call_read_iter(struct file *file, struct kiocb *kio,
+                                    struct iov_iter *iter)
+ {
+       return file->f_op->read_iter(kio, iter);
+ }
+ static inline ssize_t call_write_iter(struct file *file, struct kiocb *kio,
+                                     struct iov_iter *iter)
+ {
+       return file->f_op->write_iter(kio, iter);
+ }
+ static inline int call_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+       return file->f_op->mmap(file, vma);
+ }
+ static inline int call_fsync(struct file *file, loff_t start, loff_t end,
+                            int datasync)
+ {
+       return file->f_op->fsync(file, start, end, datasync);
+ }
  ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
                              unsigned long nr_segs, unsigned long fast_segs,
                              struct iovec *fast_pointer,
@@@ -1739,19 -1764,6 +1765,6 @@@ extern int vfs_dedupe_file_range_compar
  extern int vfs_dedupe_file_range(struct file *file,
                                 struct file_dedupe_range *same);
  
- static inline int do_clone_file_range(struct file *file_in, loff_t pos_in,
-                                     struct file *file_out, loff_t pos_out,
-                                     u64 len)
- {
-       int ret;
-       sb_start_write(file_inode(file_out)->i_sb);
-       ret = vfs_clone_file_range(file_in, pos_in, file_out, pos_out, len);
-       sb_end_write(file_inode(file_out)->i_sb);
-       return ret;
- }
  struct super_operations {
        struct inode *(*alloc_inode)(struct super_block *sb);
        void (*destroy_inode)(struct inode *);
@@@ -2343,7 -2355,6 +2356,7 @@@ extern struct kmem_cache *names_cachep
  #ifdef CONFIG_BLOCK
  extern int register_blkdev(unsigned int, const char *);
  extern void unregister_blkdev(unsigned int, const char *);
 +extern void bdev_unhash_inode(dev_t dev);
  extern struct block_device *bdget(dev_t);
  extern struct block_device *bdgrab(struct block_device *bdev);
  extern void bd_set_size(struct block_device *, loff_t size);
@@@ -2563,6 -2574,19 +2576,19 @@@ static inline void file_end_write(struc
        __sb_end_write(file_inode(file)->i_sb, SB_FREEZE_WRITE);
  }
  
+ static inline int do_clone_file_range(struct file *file_in, loff_t pos_in,
+                                     struct file *file_out, loff_t pos_out,
+                                     u64 len)
+ {
+       int ret;
+       file_start_write(file_out);
+       ret = vfs_clone_file_range(file_in, pos_in, file_out, pos_out, len);
+       file_end_write(file_out);
+       return ret;
+ }
  /*
   * get_write_access() gets write permission for a file.
   * put_write_access() releases this write permission.
diff --combined mm/mmap.c
+++ b/mm/mmap.c
@@@ -1668,7 -1668,7 +1668,7 @@@ unsigned long mmap_region(struct file *
                 * new file must not have been exposed to user-space, yet.
                 */
                vma->vm_file = get_file(file);
-               error = file->f_op->mmap(file, vma);
+               error = call_mmap(file, vma);
                if (error)
                        goto unmap_and_free_vma;
  
@@@ -2806,11 -2806,11 +2806,11 @@@ static inline void verify_mm_writelocke
   *  anonymous maps.  eventually we may be able to do some
   *  brk-specific accounting here.
   */
 -static int do_brk(unsigned long addr, unsigned long request)
 +static int do_brk_flags(unsigned long addr, unsigned long request, unsigned long flags)
  {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma, *prev;
 -      unsigned long flags, len;
 +      unsigned long len;
        struct rb_node **rb_link, *rb_parent;
        pgoff_t pgoff = addr >> PAGE_SHIFT;
        int error;
        if (!len)
                return 0;
  
 -      flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
 +      /* Until we need other flags, refuse anything except VM_EXEC. */
 +      if ((flags & (~VM_EXEC)) != 0)
 +              return -EINVAL;
 +      flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;
  
        error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
        if (offset_in_page(error))
        return 0;
  }
  
 -int vm_brk(unsigned long addr, unsigned long len)
 +static int do_brk(unsigned long addr, unsigned long len)
 +{
 +      return do_brk_flags(addr, len, 0);
 +}
 +
 +int vm_brk_flags(unsigned long addr, unsigned long len, unsigned long flags)
  {
        struct mm_struct *mm = current->mm;
        int ret;
        if (down_write_killable(&mm->mmap_sem))
                return -EINTR;
  
 -      ret = do_brk(addr, len);
 +      ret = do_brk_flags(addr, len, flags);
        populate = ((mm->def_flags & VM_LOCKED) != 0);
        up_write(&mm->mmap_sem);
        if (populate && !ret)
                mm_populate(addr, len);
        return ret;
  }
 +EXPORT_SYMBOL(vm_brk_flags);
 +
 +int vm_brk(unsigned long addr, unsigned long len)
 +{
 +      return vm_brk_flags(addr, len, 0);
 +}
  EXPORT_SYMBOL(vm_brk);
  
  /* Release all mmaps. */
diff --combined mm/nommu.c
@@@ -1084,7 -1084,7 +1084,7 @@@ static int do_mmap_shared_file(struct v
  {
        int ret;
  
-       ret = vma->vm_file->f_op->mmap(vma->vm_file, vma);
+       ret = call_mmap(vma->vm_file, vma);
        if (ret == 0) {
                vma->vm_region->vm_top = vma->vm_region->vm_end;
                return 0;
@@@ -1115,7 -1115,7 +1115,7 @@@ static int do_mmap_private(struct vm_ar
         * - VM_MAYSHARE will be set if it may attempt to share
         */
        if (capabilities & NOMMU_MAP_DIRECT) {
-               ret = vma->vm_file->f_op->mmap(vma->vm_file, vma);
+               ret = call_mmap(vma->vm_file, vma);
                if (ret == 0) {
                        /* shouldn't return success if we're not sharing */
                        BUG_ON(!(vma->vm_flags & VM_MAYSHARE));
@@@ -1191,7 -1191,7 +1191,7 @@@ error_free
  enomem:
        pr_err("Allocation of length %lu from process %d (%s) failed\n",
               len, current->pid, current->comm);
 -      show_free_areas(0);
 +      show_free_areas(0, NULL);
        return -ENOMEM;
  }
  
@@@ -1412,13 -1412,13 +1412,13 @@@ error_getting_vma
        kmem_cache_free(vm_region_jar, region);
        pr_warn("Allocation of vma for %lu byte allocation from process %d failed\n",
                        len, current->pid);
 -      show_free_areas(0);
 +      show_free_areas(0, NULL);
        return -ENOMEM;
  
  error_getting_region:
        pr_warn("Allocation of vm region for %lu byte allocation from process %d failed\n",
                        len, current->pid);
 -      show_free_areas(0);
 +      show_free_areas(0, NULL);
        return -ENOMEM;
  }