Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszer...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Oct 2016 00:23:33 +0000 (17:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Oct 2016 00:23:33 +0000 (17:23 -0700)
Pull overlayfs updates from Miklos Szeredi:
 "This update contains fixes to the "use mounter's permission to access
  underlying layers" area, and miscellaneous other fixes and cleanups.

  No new features this time"

* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: use vfs_get_link()
  vfs: add vfs_get_link() helper
  ovl: use generic_readlink
  ovl: explain error values when removing acl from workdir
  ovl: Fix info leak in ovl_lookup_temp()
  ovl: during copy up, switch to mounter's creds early
  ovl: lookup: do getxattr with mounter's permission
  ovl: copy_up_xattr(): use strnlen

1  2 
fs/namei.c
fs/overlayfs/copy_up.c
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/super.c
include/linux/fs.h

diff --combined fs/namei.c
@@@ -1015,7 -1015,7 +1015,7 @@@ const char *get_link(struct nameidata *
        if (!(nd->flags & LOOKUP_RCU)) {
                touch_atime(&last->link);
                cond_resched();
 -      } else if (atime_needs_update(&last->link, inode)) {
 +      } else if (atime_needs_update_rcu(&last->link, inode)) {
                if (unlikely(unlazy_walk(nd, NULL, 0)))
                        return ERR_PTR(-ECHILD);
                touch_atime(&last->link);
@@@ -4369,9 -4369,12 +4369,9 @@@ int vfs_rename(struct inode *old_dir, s
        if (error)
                return error;
  
 -      if (!old_dir->i_op->rename && !old_dir->i_op->rename2)
 +      if (!old_dir->i_op->rename)
                return -EPERM;
  
 -      if (flags && !old_dir->i_op->rename2)
 -              return -EINVAL;
 -
        /*
         * If we are going to change the parent - check write permissions,
         * we'll need to flip '..'.
                if (error)
                        goto out;
        }
 -      if (!old_dir->i_op->rename2) {
 -              error = old_dir->i_op->rename(old_dir, old_dentry,
 -                                            new_dir, new_dentry);
 -      } else {
 -              WARN_ON(old_dir->i_op->rename != NULL);
 -              error = old_dir->i_op->rename2(old_dir, old_dentry,
 -                                             new_dir, new_dentry, flags);
 -      }
 +      error = old_dir->i_op->rename(old_dir, old_dentry,
 +                                     new_dir, new_dentry, flags);
        if (error)
                goto out;
  
@@@ -4668,6 -4677,31 +4668,31 @@@ int generic_readlink(struct dentry *den
  }
  EXPORT_SYMBOL(generic_readlink);
  
+ /**
+  * vfs_get_link - get symlink body
+  * @dentry: dentry on which to get symbolic link
+  * @done: caller needs to free returned data with this
+  *
+  * Calls security hook and i_op->get_link() on the supplied inode.
+  *
+  * It does not touch atime.  That's up to the caller if necessary.
+  *
+  * Does not work on "special" symlinks like /proc/$$/fd/N
+  */
+ const char *vfs_get_link(struct dentry *dentry, struct delayed_call *done)
+ {
+       const char *res = ERR_PTR(-EINVAL);
+       struct inode *inode = d_inode(dentry);
+       if (d_is_symlink(dentry)) {
+               res = ERR_PTR(security_inode_readlink(dentry));
+               if (!res)
+                       res = inode->i_op->get_link(dentry, inode, done);
+       }
+       return res;
+ }
+ EXPORT_SYMBOL(vfs_get_link);
  /* get the link contents into pagecache */
  const char *page_get_link(struct dentry *dentry, struct inode *inode,
                          struct delayed_call *callback)
diff --combined fs/overlayfs/copy_up.c
@@@ -57,9 -57,10 +57,10 @@@ int ovl_copy_xattr(struct dentry *old, 
        ssize_t list_size, size, value_size = 0;
        char *buf, *name, *value = NULL;
        int uninitialized_var(error);
+       size_t slen;
  
 -      if (!old->d_inode->i_op->getxattr ||
 -          !new->d_inode->i_op->getxattr)
 +      if (!(old->d_inode->i_opflags & IOP_XATTR) ||
 +          !(new->d_inode->i_opflags & IOP_XATTR))
                return 0;
  
        list_size = vfs_listxattr(old, NULL, 0);
                goto out;
        }
  
-       for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
+       for (name = buf; list_size; name += slen) {
+               slen = strnlen(name, list_size) + 1;
+               /* underlying fs providing us with an broken xattr list? */
+               if (WARN_ON(slen > list_size)) {
+                       error = -EIO;
+                       break;
+               }
+               list_size -= slen;
                if (ovl_is_private_xattr(name))
                        continue;
  retry:
                        goto retry;
                }
  
 +              error = security_inode_copy_up_xattr(name);
 +              if (error < 0 && error != -EOPNOTSUPP)
 +                      break;
 +              if (error == 1) {
 +                      error = 0;
 +                      continue; /* Discard */
 +              }
                error = vfs_setxattr(new, name, value, size, 0);
                if (error)
                        break;
@@@ -174,40 -177,6 +184,6 @@@ out_fput
        return error;
  }
  
- static char *ovl_read_symlink(struct dentry *realdentry)
- {
-       int res;
-       char *buf;
-       struct inode *inode = realdentry->d_inode;
-       mm_segment_t old_fs;
-       res = -EINVAL;
-       if (!inode->i_op->readlink)
-               goto err;
-       res = -ENOMEM;
-       buf = (char *) __get_free_page(GFP_KERNEL);
-       if (!buf)
-               goto err;
-       old_fs = get_fs();
-       set_fs(get_ds());
-       /* The cast to a user pointer is valid due to the set_fs() */
-       res = inode->i_op->readlink(realdentry,
-                                   (char __user *)buf, PAGE_SIZE - 1);
-       set_fs(old_fs);
-       if (res < 0) {
-               free_page((unsigned long) buf);
-               goto err;
-       }
-       buf[res] = '\0';
-       return buf;
- err:
-       return ERR_PTR(res);
- }
  static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat)
  {
        struct iattr attr = {
@@@ -255,8 -224,6 +231,8 @@@ static int ovl_copy_up_locked(struct de
        struct dentry *upper = NULL;
        umode_t mode = stat->mode;
        int err;
 +      const struct cred *old_creds = NULL;
 +      struct cred *new_creds = NULL;
  
        newdentry = ovl_lookup_temp(workdir, dentry);
        err = PTR_ERR(newdentry);
        if (IS_ERR(upper))
                goto out1;
  
 +      err = security_inode_copy_up(dentry, &new_creds);
 +      if (err < 0)
 +              goto out2;
 +
 +      if (new_creds)
 +              old_creds = override_creds(new_creds);
 +
        /* Can't properly set mode on creation because of the umask */
        stat->mode &= S_IFMT;
        err = ovl_create_real(wdir, newdentry, stat, link, NULL, true);
        stat->mode = mode;
 +
 +      if (new_creds) {
 +              revert_creds(old_creds);
 +              put_cred(new_creds);
 +      }
 +
        if (err)
                goto out2;
  
@@@ -354,19 -308,20 +330,20 @@@ out_cleanup
  int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
                    struct path *lowerpath, struct kstat *stat)
  {
+       DEFINE_DELAYED_CALL(done);
        struct dentry *workdir = ovl_workdir(dentry);
        int err;
        struct kstat pstat;
        struct path parentpath;
+       struct dentry *lowerdentry = lowerpath->dentry;
        struct dentry *upperdir;
        struct dentry *upperdentry;
-       const struct cred *old_cred;
-       char *link = NULL;
+       const char *link = NULL;
  
        if (WARN_ON(!workdir))
                return -EROFS;
  
-       ovl_do_check_copy_up(lowerpath->dentry);
+       ovl_do_check_copy_up(lowerdentry);
  
        ovl_path_upper(parent, &parentpath);
        upperdir = parentpath.dentry;
                return err;
  
        if (S_ISLNK(stat->mode)) {
-               link = ovl_read_symlink(lowerpath->dentry);
+               link = vfs_get_link(lowerdentry, &done);
                if (IS_ERR(link))
                        return PTR_ERR(link);
        }
  
-       old_cred = ovl_override_creds(dentry->d_sb);
        err = -EIO;
        if (lock_rename(workdir, upperdir) != NULL) {
                pr_err("overlayfs: failed to lock workdir+upperdir\n");
        }
  out_unlock:
        unlock_rename(workdir, upperdir);
-       revert_creds(old_cred);
-       if (link)
-               free_page((unsigned long) link);
+       do_delayed_call(&done);
  
        return err;
  }
  
  int ovl_copy_up(struct dentry *dentry)
  {
-       int err;
+       int err = 0;
+       const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
  
-       err = 0;
        while (!err) {
                struct dentry *next;
                struct dentry *parent;
                dput(parent);
                dput(next);
        }
+       revert_creds(old_cred);
  
        return err;
  }
diff --combined fs/overlayfs/dir.c
@@@ -14,6 -14,7 +14,7 @@@
  #include <linux/cred.h>
  #include <linux/posix_acl.h>
  #include <linux/posix_acl_xattr.h>
+ #include <linux/atomic.h>
  #include "overlayfs.h"
  
  void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
@@@ -37,8 -38,10 +38,10 @@@ struct dentry *ovl_lookup_temp(struct d
  {
        struct dentry *temp;
        char name[20];
+       static atomic_t temp_id = ATOMIC_INIT(0);
  
-       snprintf(name, sizeof(name), "#%lx", (unsigned long) dentry);
+       /* counter is allowed to wrap, since temp dentries are ephemeral */
+       snprintf(name, sizeof(name), "#%x", atomic_inc_return(&temp_id));
  
        temp = lookup_one_len(name, workdir, strlen(name));
        if (!IS_ERR(temp) && temp->d_inode) {
@@@ -489,15 -492,6 +492,15 @@@ static int ovl_create_or_link(struct de
        if (override_cred) {
                override_cred->fsuid = inode->i_uid;
                override_cred->fsgid = inode->i_gid;
 +              if (!hardlink) {
 +                      err = security_dentry_create_files_as(dentry,
 +                                      stat->mode, &dentry->d_name, old_cred,
 +                                      override_cred);
 +                      if (err) {
 +                              put_cred(override_cred);
 +                              goto out_revert_creds;
 +                      }
 +              }
                put_cred(override_creds(override_cred));
                put_cred(override_cred);
  
                        err = ovl_create_over_whiteout(dentry, inode, stat,
                                                        link, hardlink);
        }
 +out_revert_creds:
        revert_creds(old_cred);
        if (!err) {
                struct inode *realinode = d_inode(ovl_dentry_upper(dentry));
@@@ -1006,14 -999,17 +1009,14 @@@ const struct inode_operations ovl_dir_i
        .symlink        = ovl_symlink,
        .unlink         = ovl_unlink,
        .rmdir          = ovl_rmdir,
 -      .rename2        = ovl_rename2,
 +      .rename         = ovl_rename2,
        .link           = ovl_link,
        .setattr        = ovl_setattr,
        .create         = ovl_create,
        .mknod          = ovl_mknod,
        .permission     = ovl_permission,
        .getattr        = ovl_dir_getattr,
 -      .setxattr       = generic_setxattr,
 -      .getxattr       = generic_getxattr,
        .listxattr      = ovl_listxattr,
 -      .removexattr    = generic_removexattr,
        .get_acl        = ovl_get_acl,
        .update_time    = ovl_update_time,
  };
diff --combined fs/overlayfs/inode.c
@@@ -19,6 -19,7 +19,7 @@@ static int ovl_copy_up_truncate(struct 
        struct dentry *parent;
        struct kstat stat;
        struct path lowerpath;
+       const struct cred *old_cred;
  
        parent = dget_parent(dentry);
        err = ovl_copy_up(parent);
                goto out_dput_parent;
  
        ovl_path_lower(dentry, &lowerpath);
-       err = vfs_getattr(&lowerpath, &stat);
-       if (err)
-               goto out_dput_parent;
  
-       stat.size = 0;
-       err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       err = vfs_getattr(&lowerpath, &stat);
+       if (!err) {
+               stat.size = 0;
+               err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
+       }
+       revert_creds(old_cred);
  
  out_dput_parent:
        dput(parent);
@@@ -53,7 -56,7 +56,7 @@@ int ovl_setattr(struct dentry *dentry, 
         * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
         * check for a swapfile (which this won't be anyway).
         */
 -      err = inode_change_ok(dentry->d_inode, attr);
 +      err = setattr_prepare(dentry, attr);
        if (err)
                return err;
  
@@@ -153,45 -156,18 +156,18 @@@ static const char *ovl_get_link(struct 
                                struct inode *inode,
                                struct delayed_call *done)
  {
-       struct dentry *realdentry;
-       struct inode *realinode;
        const struct cred *old_cred;
        const char *p;
  
        if (!dentry)
                return ERR_PTR(-ECHILD);
  
-       realdentry = ovl_dentry_real(dentry);
-       realinode = realdentry->d_inode;
-       if (WARN_ON(!realinode->i_op->get_link))
-               return ERR_PTR(-EPERM);
        old_cred = ovl_override_creds(dentry->d_sb);
-       p = realinode->i_op->get_link(realdentry, realinode, done);
+       p = vfs_get_link(ovl_dentry_real(dentry), done);
        revert_creds(old_cred);
        return p;
  }
  
- static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
- {
-       struct path realpath;
-       struct inode *realinode;
-       const struct cred *old_cred;
-       int err;
-       ovl_path_real(dentry, &realpath);
-       realinode = realpath.dentry->d_inode;
-       if (!realinode->i_op->readlink)
-               return -EINVAL;
-       old_cred = ovl_override_creds(dentry->d_sb);
-       err = realinode->i_op->readlink(realpath.dentry, buf, bufsiz);
-       revert_creds(old_cred);
-       return err;
- }
  bool ovl_is_private_xattr(const char *name)
  {
        return strncmp(name, OVL_XATTR_PREFIX,
@@@ -367,7 -343,10 +343,7 @@@ static const struct inode_operations ov
        .setattr        = ovl_setattr,
        .permission     = ovl_permission,
        .getattr        = ovl_getattr,
 -      .setxattr       = generic_setxattr,
 -      .getxattr       = generic_getxattr,
        .listxattr      = ovl_listxattr,
 -      .removexattr    = generic_removexattr,
        .get_acl        = ovl_get_acl,
        .update_time    = ovl_update_time,
  };
  static const struct inode_operations ovl_symlink_inode_operations = {
        .setattr        = ovl_setattr,
        .get_link       = ovl_get_link,
-       .readlink       = ovl_readlink,
+       .readlink       = generic_readlink,
        .getattr        = ovl_getattr,
 -      .setxattr       = generic_setxattr,
 -      .getxattr       = generic_getxattr,
        .listxattr      = ovl_listxattr,
 -      .removexattr    = generic_removexattr,
        .update_time    = ovl_update_time,
  };
  
diff --combined fs/overlayfs/super.c
@@@ -273,12 -273,11 +273,11 @@@ static bool ovl_is_opaquedir(struct den
  {
        int res;
        char val;
-       struct inode *inode = dentry->d_inode;
  
-       if (!S_ISDIR(inode->i_mode) || !(inode->i_opflags & IOP_XATTR))
+       if (!d_is_dir(dentry))
                return false;
  
-       res = __vfs_getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);
+       res = vfs_getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1);
        if (res == 1 && val == 'y')
                return true;
  
@@@ -419,16 -418,12 +418,12 @@@ static bool ovl_dentry_weird(struct den
                                  DCACHE_OP_COMPARE);
  }
  
- static inline struct dentry *ovl_lookup_real(struct super_block *ovl_sb,
-                                            struct dentry *dir,
+ static inline struct dentry *ovl_lookup_real(struct dentry *dir,
                                             const struct qstr *name)
  {
-       const struct cred *old_cred;
        struct dentry *dentry;
  
-       old_cred = ovl_override_creds(ovl_sb);
        dentry = lookup_one_len_unlocked(name->name, dir, name->len);
-       revert_creds(old_cred);
  
        if (IS_ERR(dentry)) {
                if (PTR_ERR(dentry) == -ENOENT)
@@@ -469,6 -464,7 +464,7 @@@ struct dentry *ovl_lookup(struct inode 
                          unsigned int flags)
  {
        struct ovl_entry *oe;
+       const struct cred *old_cred;
        struct ovl_entry *poe = dentry->d_parent->d_fsdata;
        struct path *stack = NULL;
        struct dentry *upperdir, *upperdentry = NULL;
        unsigned int i;
        int err;
  
+       old_cred = ovl_override_creds(dentry->d_sb);
        upperdir = ovl_upperdentry_dereference(poe);
        if (upperdir) {
-               this = ovl_lookup_real(dentry->d_sb, upperdir, &dentry->d_name);
+               this = ovl_lookup_real(upperdir, &dentry->d_name);
                err = PTR_ERR(this);
                if (IS_ERR(this))
                        goto out;
                bool opaque = false;
                struct path lowerpath = poe->lowerstack[i];
  
-               this = ovl_lookup_real(dentry->d_sb,
-                                      lowerpath.dentry, &dentry->d_name);
+               this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name);
                err = PTR_ERR(this);
                if (IS_ERR(this)) {
                        /*
                ovl_copyattr(realdentry->d_inode, inode);
        }
  
+       revert_creds(old_cred);
        oe->opaque = upperopaque;
        oe->__upperdentry = upperdentry;
        memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr);
@@@ -606,6 -603,7 +603,7 @@@ out_put
  out_put_upper:
        dput(upperdentry);
  out:
+       revert_creds(old_cred);
        return ERR_PTR(err);
  }
  
@@@ -834,6 -832,19 +832,19 @@@ retry
                if (err)
                        goto out_dput;
  
+               /*
+                * Try to remove POSIX ACL xattrs from workdir.  We are good if:
+                *
+                * a) success (there was a POSIX ACL xattr and was removed)
+                * b) -ENODATA (there was no POSIX ACL xattr)
+                * c) -EOPNOTSUPP (POSIX ACL xattrs are not supported)
+                *
+                * There are various other error values that could effectively
+                * mean that the xattr doesn't exist (e.g. -ERANGE is returned
+                * if the xattr name is too long), but the set of filesystems
+                * allowed as upper are limited to "normal" ones, where checking
+                * for the above two errors is sufficient.
+                */
                err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_DEFAULT);
                if (err && err != -ENODATA && err != -EOPNOTSUPP)
                        goto out_dput;
@@@ -1320,7 -1331,7 +1331,7 @@@ static int ovl_fill_super(struct super_
        sb->s_xattr = ovl_xattr_handlers;
        sb->s_root = root_dentry;
        sb->s_fs_info = ufs;
 -      sb->s_flags |= MS_POSIXACL;
 +      sb->s_flags |= MS_POSIXACL | MS_NOREMOTELOCK;
  
        return 0;
  
diff --combined include/linux/fs.h
@@@ -63,7 -63,7 +63,7 @@@ extern void __init files_maxfiles_init(
  
  extern struct files_stat_struct files_stat;
  extern unsigned long get_max_files(void);
 -extern int sysctl_nr_open;
 +extern unsigned int sysctl_nr_open;
  extern struct inodes_stat_t inodes_stat;
  extern int leases_enable, lease_break_time;
  extern int sysctl_protected_symlinks;
@@@ -224,7 -224,6 +224,7 @@@ typedef int (dio_iodone_t)(struct kioc
  #define ATTR_KILL_PRIV        (1 << 14)
  #define ATTR_OPEN     (1 << 15) /* Truncating from open(O_TRUNC) */
  #define ATTR_TIMES_SET        (1 << 16)
 +#define ATTR_TOUCH    (1 << 17)
  
  /*
   * Whiteout is represented by a char device.  The following constants define the
@@@ -440,9 -439,8 +440,9 @@@ struct address_space 
        unsigned long           nrexceptional;
        pgoff_t                 writeback_index;/* writeback starts here */
        const struct address_space_operations *a_ops;   /* methods */
 -      unsigned long           flags;          /* error bits/gfp mask */
 +      unsigned long           flags;          /* error bits */
        spinlock_t              private_lock;   /* for use by the address_space */
 +      gfp_t                   gfp_mask;       /* implicit gfp mask for allocations */
        struct list_head        private_list;   /* ditto */
        void                    *private_data;  /* ditto */
  } __attribute__((aligned(sizeof(long))));
@@@ -593,7 -591,6 +593,7 @@@ is_uncached_acl(struct posix_acl *acl
  #define IOP_FASTPERM  0x0001
  #define IOP_LOOKUP    0x0002
  #define IOP_NOFOLLOW  0x0004
 +#define IOP_XATTR     0x0008
  
  /*
   * Keep mostly read-only and often accessed (especially for
@@@ -1067,18 -1064,6 +1067,18 @@@ struct file_lock_context 
  
  extern void send_sigio(struct fown_struct *fown, int fd, int band);
  
 +/*
 + * Return the inode to use for locking
 + *
 + * For overlayfs this should be the overlay inode, not the real inode returned
 + * by file_inode().  For any other fs file_inode(filp) and locks_inode(filp) are
 + * equal.
 + */
 +static inline struct inode *locks_inode(const struct file *f)
 +{
 +      return f->f_path.dentry->d_inode;
 +}
 +
  #ifdef CONFIG_FILE_LOCKING
  extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *);
  extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
@@@ -1266,7 -1251,7 +1266,7 @@@ static inline struct dentry *file_dentr
  
  static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
  {
 -      return locks_lock_inode_wait(file_inode(filp), fl);
 +      return locks_lock_inode_wait(locks_inode(filp), fl);
  }
  
  struct fasync_struct {
@@@ -1474,7 -1459,6 +1474,7 @@@ static inline void i_gid_write(struct i
  }
  
  extern struct timespec current_fs_time(struct super_block *sb);
 +extern struct timespec current_time(struct inode *inode);
  
  /*
   * Snapshotting support.
@@@ -1749,10 -1733,17 +1749,10 @@@ struct inode_operations 
        int (*rmdir) (struct inode *,struct dentry *);
        int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
        int (*rename) (struct inode *, struct dentry *,
 -                      struct inode *, struct dentry *);
 -      int (*rename2) (struct inode *, struct dentry *,
                        struct inode *, struct dentry *, unsigned int);
        int (*setattr) (struct dentry *, struct iattr *);
        int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
 -      int (*setxattr) (struct dentry *, struct inode *,
 -                       const char *, const void *, size_t, int);
 -      ssize_t (*getxattr) (struct dentry *, struct inode *,
 -                           const char *, void *, size_t);
        ssize_t (*listxattr) (struct dentry *, char *, size_t);
 -      int (*removexattr) (struct dentry *, const char *);
        int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
                      u64 len);
        int (*update_time)(struct inode *, struct timespec *, int);
@@@ -2015,6 -2006,7 +2015,6 @@@ enum file_time_flags 
        S_VERSION = 8,
  };
  
 -extern bool atime_needs_update(const struct path *, struct inode *);
  extern void touch_atime(const struct path *);
  static inline void file_accessed(struct file *file)
  {
@@@ -2083,19 -2075,10 +2083,19 @@@ struct super_block *sget(struct file_sy
                        int (*test)(struct super_block *,void *),
                        int (*set)(struct super_block *,void *),
                        int flags, void *data);
 -extern struct dentry *mount_pseudo(struct file_system_type *, char *,
 -      const struct super_operations *ops,
 -      const struct dentry_operations *dops,
 -      unsigned long);
 +extern struct dentry *mount_pseudo_xattr(struct file_system_type *, char *,
 +                                       const struct super_operations *ops,
 +                                       const struct xattr_handler **xattr,
 +                                       const struct dentry_operations *dops,
 +                                       unsigned long);
 +
 +static inline struct dentry *
 +mount_pseudo(struct file_system_type *fs_type, char *name,
 +           const struct super_operations *ops,
 +           const struct dentry_operations *dops, unsigned long magic)
 +{
 +      return mount_pseudo_xattr(fs_type, name, ops, NULL, dops, magic);
 +}
  
  /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
  #define fops_get(fops) \
@@@ -2172,7 -2155,7 +2172,7 @@@ static inline int mandatory_lock(struc
  
  static inline int locks_verify_locked(struct file *file)
  {
 -      if (mandatory_lock(file_inode(file)))
 +      if (mandatory_lock(locks_inode(file)))
                return locks_mandatory_locked(file);
        return 0;
  }
@@@ -2811,6 -2794,8 +2811,6 @@@ extern void block_sync_page(struct pag
  /* fs/splice.c */
  extern ssize_t generic_file_splice_read(struct file *, loff_t *,
                struct pipe_inode_info *, size_t, unsigned int);
 -extern ssize_t default_file_splice_read(struct file *, loff_t *,
 -              struct pipe_inode_info *, size_t, unsigned int);
  extern ssize_t iter_file_splice_write(struct pipe_inode_info *,
                struct file *, loff_t *, size_t, unsigned int);
  extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
@@@ -2934,6 -2919,7 +2934,7 @@@ extern int vfs_stat(const char __user *
  extern int vfs_lstat(const char __user *, struct kstat *);
  extern int vfs_fstat(unsigned int, struct kstat *);
  extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
+ extern const char *vfs_get_link(struct dentry *, struct delayed_call *);
  
  extern int __generic_block_fiemap(struct inode *inode,
                                  struct fiemap_extent_info *fieinfo,
@@@ -2965,8 -2951,7 +2966,8 @@@ extern int simple_open(struct inode *in
  extern int simple_link(struct dentry *, struct inode *, struct dentry *);
  extern int simple_unlink(struct inode *, struct dentry *);
  extern int simple_rmdir(struct inode *, struct dentry *);
 -extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
 +extern int simple_rename(struct inode *, struct dentry *,
 +                       struct inode *, struct dentry *, unsigned int);
  extern int noop_fsync(struct file *, loff_t, loff_t, int);
  extern int simple_empty(struct dentry *);
  extern int simple_readpage(struct file *file, struct page *page);
@@@ -3011,7 -2996,7 +3012,7 @@@ extern int buffer_migrate_page(struct a
  #define buffer_migrate_page NULL
  #endif
  
 -extern int inode_change_ok(const struct inode *, struct iattr *);
 +extern int setattr_prepare(struct dentry *, struct iattr *);
  extern int inode_newsize_ok(const struct inode *, loff_t offset);
  extern void setattr_copy(struct inode *inode, const struct iattr *attr);