]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge branch 'work.const-path' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 May 2016 21:41:03 +0000 (14:41 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 May 2016 21:41:03 +0000 (14:41 -0700)
Pull 'struct path' constification update from Al Viro:
 "'struct path' is passed by reference to a bunch of Linux security
  methods; in theory, there's nothing to stop them from modifying the
  damn thing and LSM community being what it is, sooner or later some
  enterprising soul is going to decide that it's a good idea.

  Let's remove the temptation and constify all of those..."

* 'work.const-path' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  constify ima_d_path()
  constify security_sb_pivotroot()
  constify security_path_chroot()
  constify security_path_{link,rename}
  apparmor: remove useless checks for NULL ->mnt
  constify security_path_{mkdir,mknod,symlink}
  constify security_path_{unlink,rmdir}
  apparmor: constify common_perm_...()
  apparmor: constify aa_path_link()
  apparmor: new helper - common_path_perm()
  constify chmod_common/security_path_chmod
  constify security_sb_mount()
  constify chown_common/security_path_chown
  tomoyo: constify assorted struct path *
  apparmor_path_truncate(): path->mnt is never NULL
  constify vfs_truncate()
  constify security_path_truncate()
  [apparmor] constify struct path * in a bunch of helpers

1  2 
fs/namei.c
fs/open.c
include/linux/fs.h
include/linux/lsm_hooks.h
include/linux/security.h
security/security.c
security/selinux/hooks.c

diff --combined fs/namei.c
index 11f3a18d9d2d67a8ed51c9b159749347f231761c,8c97544d68833ba5250888ab833940b4fc24d6eb..9d193d336c9f5e8c9c11f6a76c9f68fc63e076c3
@@@ -265,7 -265,7 +265,7 @@@ static int check_acl(struct inode *inod
                if (!acl)
                        return -EAGAIN;
                /* no ->get_acl() calls in RCU mode... */
 -              if (acl == ACL_NOT_CACHED)
 +              if (is_uncached_acl(acl))
                        return -ECHILD;
                return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);
        }
@@@ -1603,42 -1603,32 +1603,42 @@@ static struct dentry *lookup_slow(cons
                                  struct dentry *dir,
                                  unsigned int flags)
  {
 -      struct dentry *dentry;
 -      inode_lock(dir->d_inode);
 -      dentry = d_lookup(dir, name);
 -      if (unlikely(dentry)) {
 +      struct dentry *dentry = ERR_PTR(-ENOENT), *old;
 +      struct inode *inode = dir->d_inode;
 +      DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
 +
 +      inode_lock_shared(inode);
 +      /* Don't go there if it's already dead */
 +      if (unlikely(IS_DEADDIR(inode)))
 +              goto out;
 +again:
 +      dentry = d_alloc_parallel(dir, name, &wq);
 +      if (IS_ERR(dentry))
 +              goto out;
 +      if (unlikely(!d_in_lookup(dentry))) {
                if ((dentry->d_flags & DCACHE_OP_REVALIDATE) &&
                    !(flags & LOOKUP_NO_REVAL)) {
                        int error = d_revalidate(dentry, flags);
                        if (unlikely(error <= 0)) {
 -                              if (!error)
 +                              if (!error) {
                                        d_invalidate(dentry);
 +                                      dput(dentry);
 +                                      goto again;
 +                              }
                                dput(dentry);
                                dentry = ERR_PTR(error);
                        }
                }
 -              if (dentry) {
 -                      inode_unlock(dir->d_inode);
 -                      return dentry;
 +      } else {
 +              old = inode->i_op->lookup(inode, dentry, flags);
 +              d_lookup_done(dentry);
 +              if (unlikely(old)) {
 +                      dput(dentry);
 +                      dentry = old;
                }
        }
 -      dentry = d_alloc(dir, name);
 -      if (unlikely(!dentry)) {
 -              inode_unlock(dir->d_inode);
 -              return ERR_PTR(-ENOMEM);
 -      }
 -      dentry = lookup_real(dir->d_inode, dentry, flags);
 -      inode_unlock(dir->d_inode);
 +out:
 +      inode_unlock_shared(inode);
        return dentry;
  }
  
@@@ -1750,17 -1740,15 +1750,17 @@@ static int walk_component(struct nameid
                                          nd->flags);
                if (IS_ERR(path.dentry))
                        return PTR_ERR(path.dentry);
 -              if (unlikely(d_is_negative(path.dentry))) {
 -                      dput(path.dentry);
 -                      return -ENOENT;
 -              }
 +
                path.mnt = nd->path.mnt;
                err = follow_managed(&path, nd);
                if (unlikely(err < 0))
                        return err;
  
 +              if (unlikely(d_is_negative(path.dentry))) {
 +                      path_to_nameidata(&path, nd);
 +                      return -ENOENT;
 +              }
 +
                seq = 0;        /* we are already out of RCU mode */
                inode = d_backing_inode(path.dentry);
        }
@@@ -1804,49 -1792,30 +1804,49 @@@ static inline unsigned int fold_hash(un
        return hash_64(hash, 32);
  }
  
 +/*
 + * This is George Marsaglia's XORSHIFT generator.
 + * It implements a maximum-period LFSR in only a few
 + * instructions.  It also has the property (required
 + * by hash_name()) that mix_hash(0) = 0.
 + */
 +static inline unsigned long mix_hash(unsigned long hash)
 +{
 +      hash ^= hash << 13;
 +      hash ^= hash >> 7;
 +      hash ^= hash << 17;
 +      return hash;
 +}
 +
  #else /* 32-bit case */
  
  #define fold_hash(x) (x)
  
 +static inline unsigned long mix_hash(unsigned long hash)
 +{
 +      hash ^= hash << 13;
 +      hash ^= hash >> 17;
 +      hash ^= hash << 5;
 +      return hash;
 +}
 +
  #endif
  
  unsigned int full_name_hash(const unsigned char *name, unsigned int len)
  {
 -      unsigned long a, mask;
 -      unsigned long hash = 0;
 +      unsigned long a, hash = 0;
  
        for (;;) {
                a = load_unaligned_zeropad(name);
                if (len < sizeof(unsigned long))
                        break;
 -              hash += a;
 -              hash *= 9;
 +              hash = mix_hash(hash + a);
                name += sizeof(unsigned long);
                len -= sizeof(unsigned long);
                if (!len)
                        goto done;
        }
 -      mask = bytemask_from_count(len);
 -      hash += mask & a;
 +      hash += a & bytemask_from_count(len);
  done:
        return fold_hash(hash);
  }
@@@ -1864,7 -1833,7 +1864,7 @@@ static inline u64 hash_name(const char 
        hash = a = 0;
        len = -sizeof(unsigned long);
        do {
 -              hash = (hash + a) * 9;
 +              hash = mix_hash(hash + a);
                len += sizeof(unsigned long);
                a = load_unaligned_zeropad(name+len);
                b = a ^ REPEAT_BYTE('/');
@@@ -2295,33 -2264,6 +2295,33 @@@ int vfs_path_lookup(struct dentry *dent
  }
  EXPORT_SYMBOL(vfs_path_lookup);
  
 +/**
 + * lookup_hash - lookup single pathname component on already hashed name
 + * @name:     name and hash to lookup
 + * @base:     base directory to lookup from
 + *
 + * The name must have been verified and hashed (see lookup_one_len()).  Using
 + * this after just full_name_hash() is unsafe.
 + *
 + * This function also doesn't check for search permission on base directory.
 + *
 + * Use lookup_one_len_unlocked() instead, unless you really know what you are
 + * doing.
 + *
 + * Do not hold i_mutex; this helper takes i_mutex if necessary.
 + */
 +struct dentry *lookup_hash(const struct qstr *name, struct dentry *base)
 +{
 +      struct dentry *ret;
 +
 +      ret = lookup_dcache(name, base, 0);
 +      if (!ret)
 +              ret = lookup_slow(name, base, 0);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL(lookup_hash);
 +
  /**
   * lookup_one_len - filesystem helper to lookup single pathname component
   * @name:     pathname component to lookup
@@@ -2393,6 -2335,7 +2393,6 @@@ struct dentry *lookup_one_len_unlocked(
        struct qstr this;
        unsigned int c;
        int err;
 -      struct dentry *ret;
  
        this.name = name;
        this.len = len;
        if (err)
                return ERR_PTR(err);
  
 -      ret = lookup_dcache(&this, base, 0);
 -      if (!ret)
 -              ret = lookup_slow(&this, base, 0);
 -      return ret;
 +      return lookup_hash(&this, base);
  }
  EXPORT_SYMBOL(lookup_one_len_unlocked);
  
@@@ -2707,7 -2653,7 +2707,7 @@@ struct dentry *lock_rename(struct dentr
                return NULL;
        }
  
 -      mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
 +      mutex_lock(&p1->d_sb->s_vfs_rename_mutex);
  
        p = d_ancestor(p2, p1);
        if (p) {
@@@ -2734,7 -2680,7 +2734,7 @@@ void unlock_rename(struct dentry *p1, s
        inode_unlock(p1->d_inode);
        if (p1 != p2) {
                inode_unlock(p2->d_inode);
 -              mutex_unlock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
 +              mutex_unlock(&p1->d_sb->s_vfs_rename_mutex);
        }
  }
  EXPORT_SYMBOL(unlock_rename);
@@@ -2837,7 -2783,7 +2837,7 @@@ static inline int open_to_namei_flags(i
        return flag;
  }
  
- static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
+ static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t mode)
  {
        int error = security_path_mknod(dir, dentry, mode, 0);
        if (error)
  static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                        struct path *path, struct file *file,
                        const struct open_flags *op,
 -                      bool got_write, bool need_lookup,
 +                      int open_flag, umode_t mode,
                        int *opened)
  {
 +      struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
        struct inode *dir =  nd->path.dentry->d_inode;
 -      unsigned open_flag = open_to_namei_flags(op->open_flag);
 -      umode_t mode;
        int error;
 -      int acc_mode;
 -      int create_error = 0;
 -      struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
 -      bool excl;
 -
 -      BUG_ON(dentry->d_inode);
 -
 -      /* Don't create child dentry for a dead directory. */
 -      if (unlikely(IS_DEADDIR(dir))) {
 -              error = -ENOENT;
 -              goto out;
 -      }
 -
 -      mode = op->mode;
 -      if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
 -              mode &= ~current_umask();
  
 -      excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT);
 -      if (excl)
 +      if (!(~open_flag & (O_EXCL | O_CREAT))) /* both O_EXCL and O_CREAT */
                open_flag &= ~O_TRUNC;
  
 -      /*
 -       * Checking write permission is tricky, bacuse we don't know if we are
 -       * going to actually need it: O_CREAT opens should work as long as the
 -       * file exists.  But checking existence breaks atomicity.  The trick is
 -       * to check access and if not granted clear O_CREAT from the flags.
 -       *
 -       * Another problem is returing the "right" error value (e.g. for an
 -       * O_EXCL open we want to return EEXIST not EROFS).
 -       */
 -      if (((open_flag & (O_CREAT | O_TRUNC)) ||
 -          (open_flag & O_ACCMODE) != O_RDONLY) && unlikely(!got_write)) {
 -              if (!(open_flag & O_CREAT)) {
 -                      /*
 -                       * No O_CREATE -> atomicity not a requirement -> fall
 -                       * back to lookup + open
 -                       */
 -                      goto no_open;
 -              } else if (open_flag & (O_EXCL | O_TRUNC)) {
 -                      /* Fall back and fail with the right error */
 -                      create_error = -EROFS;
 -                      goto no_open;
 -              } else {
 -                      /* No side effects, safe to clear O_CREAT */
 -                      create_error = -EROFS;
 -                      open_flag &= ~O_CREAT;
 -              }
 -      }
 -
 -      if (open_flag & O_CREAT) {
 -              error = may_o_create(&nd->path, dentry, mode);
 -              if (error) {
 -                      create_error = error;
 -                      if (open_flag & O_EXCL)
 -                              goto no_open;
 -                      open_flag &= ~O_CREAT;
 -              }
 -      }
 -
        if (nd->flags & LOOKUP_DIRECTORY)
                open_flag |= O_DIRECTORY;
  
        file->f_path.dentry = DENTRY_NOT_SET;
        file->f_path.mnt = nd->path.mnt;
 -      error = dir->i_op->atomic_open(dir, dentry, file, open_flag, mode,
 -                                    opened);
 -      if (error < 0) {
 -              if (create_error && error == -ENOENT)
 -                      error = create_error;
 -              goto out;
 -      }
 -
 -      if (error) {    /* returned 1, that is */
 +      error = dir->i_op->atomic_open(dir, dentry, file,
 +                                     open_to_namei_flags(open_flag),
 +                                     mode, opened);
 +      d_lookup_done(dentry);
 +      if (!error) {
 +              /*
 +               * We didn't have the inode before the open, so check open
 +               * permission here.
 +               */
 +              int acc_mode = op->acc_mode;
 +              if (*opened & FILE_CREATED) {
 +                      WARN_ON(!(open_flag & O_CREAT));
 +                      fsnotify_create(dir, dentry);
 +                      acc_mode = 0;
 +              }
 +              error = may_open(&file->f_path, acc_mode, open_flag);
 +              if (WARN_ON(error > 0))
 +                      error = -EINVAL;
 +      } else if (error > 0) {
                if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
                        error = -EIO;
 -                      goto out;
 -              }
 -              if (file->f_path.dentry) {
 -                      dput(dentry);
 -                      dentry = file->f_path.dentry;
 -              }
 -              if (*opened & FILE_CREATED)
 -                      fsnotify_create(dir, dentry);
 -              if (!dentry->d_inode) {
 -                      WARN_ON(*opened & FILE_CREATED);
 -                      if (create_error) {
 -                              error = create_error;
 -                              goto out;
 -                      }
                } else {
 -                      if (excl && !(*opened & FILE_CREATED)) {
 -                              error = -EEXIST;
 -                              goto out;
 +                      if (file->f_path.dentry) {
 +                              dput(dentry);
 +                              dentry = file->f_path.dentry;
                        }
 +                      if (*opened & FILE_CREATED)
 +                              fsnotify_create(dir, dentry);
 +                      path->dentry = dentry;
 +                      path->mnt = nd->path.mnt;
 +                      return 1;
                }
 -              goto looked_up;
 -      }
 -
 -      /*
 -       * We didn't have the inode before the open, so check open permission
 -       * here.
 -       */
 -      acc_mode = op->acc_mode;
 -      if (*opened & FILE_CREATED) {
 -              WARN_ON(!(open_flag & O_CREAT));
 -              fsnotify_create(dir, dentry);
 -              acc_mode = 0;
        }
 -      error = may_open(&file->f_path, acc_mode, open_flag);
 -      if (error)
 -              fput(file);
 -
 -out:
        dput(dentry);
        return error;
 -
 -no_open:
 -      if (need_lookup) {
 -              dentry = lookup_real(dir, dentry, nd->flags);
 -              if (IS_ERR(dentry))
 -                      return PTR_ERR(dentry);
 -
 -              if (create_error) {
 -                      int open_flag = op->open_flag;
 -
 -                      error = create_error;
 -                      if ((open_flag & O_EXCL)) {
 -                              if (!dentry->d_inode)
 -                                      goto out;
 -                      } else if (!dentry->d_inode) {
 -                              goto out;
 -                      } else if ((open_flag & O_TRUNC) &&
 -                                 d_is_reg(dentry)) {
 -                              goto out;
 -                      }
 -                      /* will fail later, go on to get the right error */
 -              }
 -      }
 -looked_up:
 -      path->dentry = dentry;
 -      path->mnt = nd->path.mnt;
 -      return 1;
  }
  
  /*
@@@ -2943,118 -2988,62 +2943,118 @@@ static int lookup_open(struct nameidat
  {
        struct dentry *dir = nd->path.dentry;
        struct inode *dir_inode = dir->d_inode;
 +      int open_flag = op->open_flag;
        struct dentry *dentry;
 -      int error;
 -      bool need_lookup = false;
 +      int error, create_error = 0;
 +      umode_t mode = op->mode;
 +      DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
 +
 +      if (unlikely(IS_DEADDIR(dir_inode)))
 +              return -ENOENT;
  
        *opened &= ~FILE_CREATED;
 -      dentry = lookup_dcache(&nd->last, dir, nd->flags);
 -      if (IS_ERR(dentry))
 -              return PTR_ERR(dentry);
 +      dentry = d_lookup(dir, &nd->last);
 +      for (;;) {
 +              if (!dentry) {
 +                      dentry = d_alloc_parallel(dir, &nd->last, &wq);
 +                      if (IS_ERR(dentry))
 +                              return PTR_ERR(dentry);
 +              }
 +              if (d_in_lookup(dentry))
 +                      break;
  
 -      if (!dentry) {
 -              dentry = d_alloc(dir, &nd->last);
 -              if (unlikely(!dentry))
 -                      return -ENOMEM;
 -              need_lookup = true;
 -      } else if (dentry->d_inode) {
 +              if (!(dentry->d_flags & DCACHE_OP_REVALIDATE))
 +                      break;
 +
 +              error = d_revalidate(dentry, nd->flags);
 +              if (likely(error > 0))
 +                      break;
 +              if (error)
 +                      goto out_dput;
 +              d_invalidate(dentry);
 +              dput(dentry);
 +              dentry = NULL;
 +      }
 +      if (dentry->d_inode) {
                /* Cached positive dentry: will open in f_op->open */
                goto out_no_open;
        }
  
 -      if ((nd->flags & LOOKUP_OPEN) && dir_inode->i_op->atomic_open) {
 -              return atomic_open(nd, dentry, path, file, op, got_write,
 -                                 need_lookup, opened);
 +      /*
 +       * Checking write permission is tricky, bacuse we don't know if we are
 +       * going to actually need it: O_CREAT opens should work as long as the
 +       * file exists.  But checking existence breaks atomicity.  The trick is
 +       * to check access and if not granted clear O_CREAT from the flags.
 +       *
 +       * Another problem is returing the "right" error value (e.g. for an
 +       * O_EXCL open we want to return EEXIST not EROFS).
 +       */
 +      if (open_flag & O_CREAT) {
 +              if (!IS_POSIXACL(dir->d_inode))
 +                      mode &= ~current_umask();
 +              if (unlikely(!got_write)) {
 +                      create_error = -EROFS;
 +                      open_flag &= ~O_CREAT;
 +                      if (open_flag & (O_EXCL | O_TRUNC))
 +                              goto no_open;
 +                      /* No side effects, safe to clear O_CREAT */
 +              } else {
 +                      create_error = may_o_create(&nd->path, dentry, mode);
 +                      if (create_error) {
 +                              open_flag &= ~O_CREAT;
 +                              if (open_flag & O_EXCL)
 +                                      goto no_open;
 +                      }
 +              }
 +      } else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) &&
 +                 unlikely(!got_write)) {
 +              /*
 +               * No O_CREATE -> atomicity not a requirement -> fall
 +               * back to lookup + open
 +               */
 +              goto no_open;
        }
  
 -      if (need_lookup) {
 -              BUG_ON(dentry->d_inode);
 +      if (dir_inode->i_op->atomic_open) {
 +              error = atomic_open(nd, dentry, path, file, op, open_flag,
 +                                  mode, opened);
 +              if (unlikely(error == -ENOENT) && create_error)
 +                      error = create_error;
 +              return error;
 +      }
  
 -              dentry = lookup_real(dir_inode, dentry, nd->flags);
 -              if (IS_ERR(dentry))
 -                      return PTR_ERR(dentry);
 +no_open:
 +      if (d_in_lookup(dentry)) {
 +              struct dentry *res = dir_inode->i_op->lookup(dir_inode, dentry,
 +                                                           nd->flags);
 +              d_lookup_done(dentry);
 +              if (unlikely(res)) {
 +                      if (IS_ERR(res)) {
 +                              error = PTR_ERR(res);
 +                              goto out_dput;
 +                      }
 +                      dput(dentry);
 +                      dentry = res;
 +              }
        }
  
        /* Negative dentry, just create the file */
 -      if (!dentry->d_inode && (op->open_flag & O_CREAT)) {
 -              umode_t mode = op->mode;
 -              if (!IS_POSIXACL(dir->d_inode))
 -                      mode &= ~current_umask();
 -              /*
 -               * This write is needed to ensure that a
 -               * rw->ro transition does not occur between
 -               * the time when the file is created and when
 -               * a permanent write count is taken through
 -               * the 'struct file' in finish_open().
 -               */
 -              if (!got_write) {
 -                      error = -EROFS;
 -                      goto out_dput;
 -              }
 +      if (!dentry->d_inode && (open_flag & O_CREAT)) {
                *opened |= FILE_CREATED;
 -              error = security_path_mknod(&nd->path, dentry, mode, 0);
 -              if (error)
 +              audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE);
 +              if (!dir_inode->i_op->create) {
 +                      error = -EACCES;
                        goto out_dput;
 -              error = vfs_create(dir->d_inode, dentry, mode,
 -                                 nd->flags & LOOKUP_EXCL);
 +              }
 +              error = dir_inode->i_op->create(dir_inode, dentry, mode,
 +                                              open_flag & O_EXCL);
                if (error)
                        goto out_dput;
 +              fsnotify_create(dir_inode, dentry);
 +      }
 +      if (unlikely(create_error) && !dentry->d_inode) {
 +              error = create_error;
 +              goto out_dput;
        }
  out_no_open:
        path->dentry = dentry;
@@@ -3126,7 -3115,7 +3126,7 @@@ static int do_last(struct nameidata *nd
        }
  
  retry_lookup:
 -      if (op->open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
 +      if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
                error = mnt_want_write(nd->path.mnt);
                if (!error)
                        got_write = true;
                 * dropping this one anyway.
                 */
        }
 -      inode_lock(dir->d_inode);
 +      if (open_flag & O_CREAT)
 +              inode_lock(dir->d_inode);
 +      else
 +              inode_lock_shared(dir->d_inode);
        error = lookup_open(nd, &path, file, op, got_write, opened);
 -      inode_unlock(dir->d_inode);
 +      if (open_flag & O_CREAT)
 +              inode_unlock(dir->d_inode);
 +      else
 +              inode_unlock_shared(dir->d_inode);
  
        if (error <= 0) {
                if (error)
@@@ -3224,6 -3207,10 +3224,6 @@@ finish_open
                return error;
        }
        audit_inode(nd->name, nd->path.dentry, 0);
 -      if (unlikely(d_is_symlink(nd->path.dentry)) && !(open_flag & O_PATH)) {
 -              error = -ELOOP;
 -              goto out;
 -      }
        error = -EISDIR;
        if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
                goto out;
                got_write = true;
        }
  finish_open_created:
 -      if (likely(!(open_flag & O_PATH))) {
 -              error = may_open(&nd->path, acc_mode, open_flag);
 -              if (error)
 -                      goto out;
 -      }
 +      error = may_open(&nd->path, acc_mode, open_flag);
 +      if (error)
 +              goto out;
        BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
        error = vfs_open(&nd->path, file, current_cred());
        if (!error) {
        }
  opened:
        error = open_check_o_direct(file);
 -      if (error)
 -              goto exit_fput;
 -      error = ima_file_check(file, op->acc_mode, *opened);
 -      if (error)
 -              goto exit_fput;
 -
 -      if (will_truncate) {
 +      if (!error)
 +              error = ima_file_check(file, op->acc_mode, *opened);
 +      if (!error && will_truncate)
                error = handle_truncate(file);
 -              if (error)
 -                      goto exit_fput;
 -      }
  out:
 +      if (unlikely(error) && (*opened & FILE_OPENED))
 +              fput(file);
        if (unlikely(error > 0)) {
                WARN_ON(1);
                error = -EINVAL;
        path_put(&save_parent);
        return error;
  
 -exit_fput:
 -      fput(file);
 -      goto out;
 -
  stale_open:
        /* If no saved parent or already retried then can't retry */
        if (!save_parent.dentry || retried)
        return error;
  }
  
 +static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file)
 +{
 +      struct path path;
 +      int error = path_lookupat(nd, flags, &path);
 +      if (!error) {
 +              audit_inode(nd->name, path.dentry, 0);
 +              error = vfs_open(&path, file, current_cred());
 +              path_put(&path);
 +      }
 +      return error;
 +}
 +
  static struct file *path_openat(struct nameidata *nd,
                        const struct open_flags *op, unsigned flags)
  {
                goto out2;
        }
  
 +      if (unlikely(file->f_flags & O_PATH)) {
 +              error = do_o_path(nd, flags, file);
 +              if (!error)
 +                      opened |= FILE_OPENED;
 +              goto out2;
 +      }
 +
        s = path_init(nd, flags);
        if (IS_ERR(s)) {
                put_filp(file);
@@@ -4232,11 -4211,7 +4232,11 @@@ int vfs_rename(struct inode *old_dir, s
        bool new_is_dir = false;
        unsigned max_links = new_dir->i_sb->s_max_links;
  
 -      if (source == target)
 +      /*
 +       * Check source == target.
 +       * On overlayfs need to look at underlying inodes.
 +       */
 +      if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0))
                return 0;
  
        error = may_delete(old_dir, old_dentry, is_dir);
diff --combined fs/open.c
index 8701d2e2961fdcdbe99fc4420c718268c14e0618,cfdf71a6704e4a13e42574030bd9aa0dc06251e6..93ae3cdee4ab093c8a23c0505a45d5673ccbc6b6
+++ b/fs/open.c
@@@ -65,7 -65,7 +65,7 @@@ int do_truncate(struct dentry *dentry, 
        return ret;
  }
  
- long vfs_truncate(struct path *path, loff_t length)
+ long vfs_truncate(const struct path *path, loff_t length)
  {
        struct inode *inode;
        long error;
@@@ -499,7 -499,7 +499,7 @@@ out
        return error;
  }
  
- static int chmod_common(struct path *path, umode_t mode)
+ static int chmod_common(const struct path *path, umode_t mode)
  {
        struct inode *inode = path->dentry->d_inode;
        struct inode *delegated_inode = NULL;
@@@ -564,7 -564,7 +564,7 @@@ SYSCALL_DEFINE2(chmod, const char __use
        return sys_fchmodat(AT_FDCWD, filename, mode);
  }
  
- static int chown_common(struct path *path, uid_t user, gid_t group)
+ static int chown_common(const struct path *path, uid_t user, gid_t group)
  {
        struct inode *inode = path->dentry->d_inode;
        struct inode *delegated_inode = NULL;
@@@ -713,7 -713,7 +713,7 @@@ static int do_dentry_open(struct file *
        }
  
        /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
 -      if (S_ISREG(inode->i_mode))
 +      if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))
                f->f_mode |= FMODE_ATOMIC_POS;
  
        f->f_op = fops_get(inode->i_fop);
@@@ -840,12 -840,16 +840,12 @@@ EXPORT_SYMBOL(file_path)
  int vfs_open(const struct path *path, struct file *file,
             const struct cred *cred)
  {
 -      struct dentry *dentry = path->dentry;
 -      struct inode *inode = dentry->d_inode;
 +      struct inode *inode = vfs_select_inode(path->dentry, file->f_flags);
  
 -      file->f_path = *path;
 -      if (dentry->d_flags & DCACHE_OP_SELECT_INODE) {
 -              inode = dentry->d_op->d_select_inode(dentry, file->f_flags);
 -              if (IS_ERR(inode))
 -                      return PTR_ERR(inode);
 -      }
 +      if (IS_ERR(inode))
 +              return PTR_ERR(inode);
  
 +      file->f_path = *path;
        return do_dentry_open(file, inode, NULL, cred);
  }
  
diff --combined include/linux/fs.h
index e87245ac6941a5e796b3d4a410e230ec135433b7,09a68517e952a5d64eba7007060f7a03a3e5f786..98a18ccf3fc059c5bf24aa98de6df6872e119f98
@@@ -577,18 -577,6 +577,18 @@@ static inline void mapping_allow_writab
  struct posix_acl;
  #define ACL_NOT_CACHED ((void *)(-1))
  
 +static inline struct posix_acl *
 +uncached_acl_sentinel(struct task_struct *task)
 +{
 +      return (void *)task + 1;
 +}
 +
 +static inline bool
 +is_uncached_acl(struct posix_acl *acl)
 +{
 +      return (long)acl & 1;
 +}
 +
  #define IOP_FASTPERM  0x0001
  #define IOP_LOOKUP    0x0002
  #define IOP_NOFOLLOW  0x0004
@@@ -647,7 -635,7 +647,7 @@@ struct inode 
  
        /* Misc */
        unsigned long           i_state;
 -      struct mutex            i_mutex;
 +      struct rw_semaphore     i_rwsem;
  
        unsigned long           dirtied_when;   /* jiffies of first dirtying */
        unsigned long           dirtied_time_when;
                struct block_device     *i_bdev;
                struct cdev             *i_cdev;
                char                    *i_link;
 +              unsigned                i_dir_seq;
        };
  
        __u32                   i_generation;
@@@ -734,42 -721,27 +734,42 @@@ enum inode_i_mutex_lock_clas
  
  static inline void inode_lock(struct inode *inode)
  {
 -      mutex_lock(&inode->i_mutex);
 +      down_write(&inode->i_rwsem);
  }
  
  static inline void inode_unlock(struct inode *inode)
  {
 -      mutex_unlock(&inode->i_mutex);
 +      up_write(&inode->i_rwsem);
 +}
 +
 +static inline void inode_lock_shared(struct inode *inode)
 +{
 +      down_read(&inode->i_rwsem);
 +}
 +
 +static inline void inode_unlock_shared(struct inode *inode)
 +{
 +      up_read(&inode->i_rwsem);
  }
  
  static inline int inode_trylock(struct inode *inode)
  {
 -      return mutex_trylock(&inode->i_mutex);
 +      return down_write_trylock(&inode->i_rwsem);
 +}
 +
 +static inline int inode_trylock_shared(struct inode *inode)
 +{
 +      return down_read_trylock(&inode->i_rwsem);
  }
  
  static inline int inode_is_locked(struct inode *inode)
  {
 -      return mutex_is_locked(&inode->i_mutex);
 +      return rwsem_is_locked(&inode->i_rwsem);
  }
  
  static inline void inode_lock_nested(struct inode *inode, unsigned subclass)
  {
 -      mutex_lock_nested(&inode->i_mutex, subclass);
 +      down_write_nested(&inode->i_rwsem, subclass);
  }
  
  void lock_two_nondirectories(struct inode *, struct inode*);
@@@ -957,7 -929,7 +957,7 @@@ static inline struct file *get_file(str
  /* Page cache limit. The filesystems should put that into their s_maxbytes 
     limits, otherwise bad things can happen in VM. */ 
  #if BITS_PER_LONG==32
 -#define MAX_LFS_FILESIZE      (((loff_t)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) 
 +#define MAX_LFS_FILESIZE      (((loff_t)PAGE_SIZE << (BITS_PER_LONG-1))-1)
  #elif BITS_PER_LONG==64
  #define MAX_LFS_FILESIZE      ((loff_t)0x7fffffffffffffffLL)
  #endif
@@@ -1269,16 -1241,6 +1269,16 @@@ static inline struct inode *file_inode(
        return f->f_inode;
  }
  
 +static inline struct dentry *file_dentry(const struct file *file)
 +{
 +      struct dentry *dentry = file->f_path.dentry;
 +
 +      if (unlikely(dentry->d_flags & DCACHE_OP_REAL))
 +              return dentry->d_op->d_real(dentry, file_inode(file));
 +      else
 +              return dentry;
 +}
 +
  static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl)
  {
        return locks_lock_inode_wait(file_inode(filp), fl);
@@@ -1674,7 -1636,6 +1674,7 @@@ struct file_operations 
        ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
        ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
        int (*iterate) (struct file *, struct dir_context *);
 +      int (*iterate_shared) (struct file *, struct dir_context *);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
@@@ -1729,8 -1690,7 +1729,8 @@@ struct inode_operations 
        int (*setattr) (struct dentry *, struct iattr *);
        int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
        int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
 -      ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
 +      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,
@@@ -2107,7 -2067,7 +2107,7 @@@ extern int generic_update_time(struct i
  /* /sys/fs */
  extern struct kobject *fs_kobj;
  
 -#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
 +#define MAX_RW_COUNT (INT_MAX & PAGE_MASK)
  
  #ifdef CONFIG_MANDATORY_FILE_LOCKING
  extern int locks_mandatory_locked(struct file *);
@@@ -2293,7 -2253,7 +2293,7 @@@ struct filename 
        const char              iname[];
  };
  
- extern long vfs_truncate(struct path *, loff_t);
+ extern long vfs_truncate(const struct path *, loff_t);
  extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
                       struct file *filp);
  extern int vfs_fallocate(struct file *file, int mode, loff_t offset,
@@@ -3134,13 -3094,6 +3134,13 @@@ static inline bool dir_relax(struct ino
        return !IS_DEADDIR(inode);
  }
  
 +static inline bool dir_relax_shared(struct inode *inode)
 +{
 +      inode_unlock_shared(inode);
 +      inode_lock_shared(inode);
 +      return !IS_DEADDIR(inode);
 +}
 +
  extern bool path_noexec(const struct path *path);
  extern void inode_nohighmem(struct inode *inode);
  
index 41ab4662f95c715db44593effba2db0f0022f052,41c0aa6d39ea51bce714a9446ffe93780ad4d17f..512fd000562b1d03788f26ad15b16ae377bf16d1
   *    Return 0 if permission is granted.
   * @settime:
   *    Check permission to change the system time.
 - *    struct timespec and timezone are defined in include/linux/time.h
 + *    struct timespec64 is defined in include/linux/time64.h and timezone
 + *    is defined in include/linux/time.h
   *    @ts contains new time
   *    @tz contains new timezone
   *    Return 0 if permission is granted.
@@@ -1328,7 -1327,7 +1328,7 @@@ union security_list_options 
        int (*quotactl)(int cmds, int type, int id, struct super_block *sb);
        int (*quota_on)(struct dentry *dentry);
        int (*syslog)(int type);
 -      int (*settime)(const struct timespec *ts, const struct timezone *tz);
 +      int (*settime)(const struct timespec64 *ts, const struct timezone *tz);
        int (*vm_enough_memory)(struct mm_struct *mm, long pages);
  
        int (*bprm_set_creds)(struct linux_binprm *bprm);
        int (*sb_kern_mount)(struct super_block *sb, int flags, void *data);
        int (*sb_show_options)(struct seq_file *m, struct super_block *sb);
        int (*sb_statfs)(struct dentry *dentry);
-       int (*sb_mount)(const char *dev_name, struct path *path,
+       int (*sb_mount)(const char *dev_name, const struct path *path,
                        const char *type, unsigned long flags, void *data);
        int (*sb_umount)(struct vfsmount *mnt, int flags);
-       int (*sb_pivotroot)(struct path *old_path, struct path *new_path);
+       int (*sb_pivotroot)(const struct path *old_path, const struct path *new_path);
        int (*sb_set_mnt_opts)(struct super_block *sb,
                                struct security_mnt_opts *opts,
                                unsigned long kern_flags,
  
  
  #ifdef CONFIG_SECURITY_PATH
-       int (*path_unlink)(struct path *dir, struct dentry *dentry);
-       int (*path_mkdir)(struct path *dir, struct dentry *dentry,
+       int (*path_unlink)(const struct path *dir, struct dentry *dentry);
+       int (*path_mkdir)(const struct path *dir, struct dentry *dentry,
                                umode_t mode);
-       int (*path_rmdir)(struct path *dir, struct dentry *dentry);
-       int (*path_mknod)(struct path *dir, struct dentry *dentry,
+       int (*path_rmdir)(const struct path *dir, struct dentry *dentry);
+       int (*path_mknod)(const struct path *dir, struct dentry *dentry,
                                umode_t mode, unsigned int dev);
-       int (*path_truncate)(struct path *path);
-       int (*path_symlink)(struct path *dir, struct dentry *dentry,
+       int (*path_truncate)(const struct path *path);
+       int (*path_symlink)(const struct path *dir, struct dentry *dentry,
                                const char *old_name);
-       int (*path_link)(struct dentry *old_dentry, struct path *new_dir,
+       int (*path_link)(struct dentry *old_dentry, const struct path *new_dir,
                                struct dentry *new_dentry);
-       int (*path_rename)(struct path *old_dir, struct dentry *old_dentry,
-                               struct path *new_dir,
+       int (*path_rename)(const struct path *old_dir, struct dentry *old_dentry,
+                               const struct path *new_dir,
                                struct dentry *new_dentry);
-       int (*path_chmod)(struct path *path, umode_t mode);
-       int (*path_chown)(struct path *path, kuid_t uid, kgid_t gid);
-       int (*path_chroot)(struct path *path);
+       int (*path_chmod)(const struct path *path, umode_t mode);
+       int (*path_chown)(const struct path *path, kuid_t uid, kgid_t gid);
+       int (*path_chroot)(const struct path *path);
  #endif
  
        int (*inode_alloc_security)(struct inode *inode);
diff --combined include/linux/security.h
index 35ac8d9d4739d9eee29efd17c3b98d0977cb55a9,fcfa211c694f03b97aadf9cdecc62029a93e755e..14df373ff2caf4b3cdb36f8141b27b2892aa466b
@@@ -71,7 -71,7 +71,7 @@@ struct timezone
  /* These functions are in security/commoncap.c */
  extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
                       int cap, int audit);
 -extern int cap_settime(const struct timespec *ts, const struct timezone *tz);
 +extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz);
  extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
  extern int cap_ptrace_traceme(struct task_struct *parent);
  extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
@@@ -208,13 -208,7 +208,13 @@@ int security_capable_noaudit(const stru
  int security_quotactl(int cmds, int type, int id, struct super_block *sb);
  int security_quota_on(struct dentry *dentry);
  int security_syslog(int type);
 -int security_settime(const struct timespec *ts, const struct timezone *tz);
 +int security_settime64(const struct timespec64 *ts, const struct timezone *tz);
 +static inline int security_settime(const struct timespec *ts, const struct timezone *tz)
 +{
 +      struct timespec64 ts64 = timespec_to_timespec64(*ts);
 +
 +      return security_settime64(&ts64, tz);
 +}
  int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
  int security_bprm_set_creds(struct linux_binprm *bprm);
  int security_bprm_check(struct linux_binprm *bprm);
@@@ -228,10 -222,10 +228,10 @@@ int security_sb_remount(struct super_bl
  int security_sb_kern_mount(struct super_block *sb, int flags, void *data);
  int security_sb_show_options(struct seq_file *m, struct super_block *sb);
  int security_sb_statfs(struct dentry *dentry);
- int security_sb_mount(const char *dev_name, struct path *path,
+ int security_sb_mount(const char *dev_name, const struct path *path,
                      const char *type, unsigned long flags, void *data);
  int security_sb_umount(struct vfsmount *mnt, int flags);
- int security_sb_pivotroot(struct path *old_path, struct path *new_path);
+ int security_sb_pivotroot(const struct path *old_path, const struct path *new_path);
  int security_sb_set_mnt_opts(struct super_block *sb,
                                struct security_mnt_opts *opts,
                                unsigned long kern_flags,
@@@ -468,18 -462,10 +468,18 @@@ static inline int security_syslog(int t
        return 0;
  }
  
 +static inline int security_settime64(const struct timespec64 *ts,
 +                                   const struct timezone *tz)
 +{
 +      return cap_settime(ts, tz);
 +}
 +
  static inline int security_settime(const struct timespec *ts,
                                   const struct timezone *tz)
  {
 -      return cap_settime(ts, tz);
 +      struct timespec64 ts64 = timespec_to_timespec64(*ts);
 +
 +      return cap_settime(&ts64, tz);
  }
  
  static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
@@@ -544,7 -530,7 +544,7 @@@ static inline int security_sb_statfs(st
        return 0;
  }
  
- static inline int security_sb_mount(const char *dev_name, struct path *path,
+ static inline int security_sb_mount(const char *dev_name, const struct path *path,
                                    const char *type, unsigned long flags,
                                    void *data)
  {
@@@ -556,8 -542,8 +556,8 @@@ static inline int security_sb_umount(st
        return 0;
  }
  
- static inline int security_sb_pivotroot(struct path *old_path,
-                                       struct path *new_path)
+ static inline int security_sb_pivotroot(const struct path *old_path,
+                                       const struct path *new_path)
  {
        return 0;
  }
@@@ -1456,83 -1442,83 +1456,83 @@@ static inline void security_skb_classif
  #endif        /* CONFIG_SECURITY_NETWORK_XFRM */
  
  #ifdef CONFIG_SECURITY_PATH
- int security_path_unlink(struct path *dir, struct dentry *dentry);
- int security_path_mkdir(struct path *dir, struct dentry *dentry, umode_t mode);
- int security_path_rmdir(struct path *dir, struct dentry *dentry);
- int security_path_mknod(struct path *dir, struct dentry *dentry, umode_t mode,
+ int security_path_unlink(const struct path *dir, struct dentry *dentry);
+ int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t mode);
+ int security_path_rmdir(const struct path *dir, struct dentry *dentry);
+ int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t mode,
                        unsigned int dev);
- int security_path_truncate(struct path *path);
- int security_path_symlink(struct path *dir, struct dentry *dentry,
+ int security_path_truncate(const struct path *path);
+ int security_path_symlink(const struct path *dir, struct dentry *dentry,
                          const char *old_name);
- int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+ int security_path_link(struct dentry *old_dentry, const struct path *new_dir,
                       struct dentry *new_dentry);
- int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
-                        struct path *new_dir, struct dentry *new_dentry,
+ int security_path_rename(const struct path *old_dir, struct dentry *old_dentry,
+                        const struct path *new_dir, struct dentry *new_dentry,
                         unsigned int flags);
- int security_path_chmod(struct path *path, umode_t mode);
- int security_path_chown(struct path *path, kuid_t uid, kgid_t gid);
- int security_path_chroot(struct path *path);
+ int security_path_chmod(const struct path *path, umode_t mode);
+ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid);
+ int security_path_chroot(const struct path *path);
  #else /* CONFIG_SECURITY_PATH */
- static inline int security_path_unlink(struct path *dir, struct dentry *dentry)
+ static inline int security_path_unlink(const struct path *dir, struct dentry *dentry)
  {
        return 0;
  }
  
- static inline int security_path_mkdir(struct path *dir, struct dentry *dentry,
+ static inline int security_path_mkdir(const struct path *dir, struct dentry *dentry,
                                      umode_t mode)
  {
        return 0;
  }
  
- static inline int security_path_rmdir(struct path *dir, struct dentry *dentry)
+ static inline int security_path_rmdir(const struct path *dir, struct dentry *dentry)
  {
        return 0;
  }
  
- static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
+ static inline int security_path_mknod(const struct path *dir, struct dentry *dentry,
                                      umode_t mode, unsigned int dev)
  {
        return 0;
  }
  
- static inline int security_path_truncate(struct path *path)
+ static inline int security_path_truncate(const struct path *path)
  {
        return 0;
  }
  
- static inline int security_path_symlink(struct path *dir, struct dentry *dentry,
+ static inline int security_path_symlink(const struct path *dir, struct dentry *dentry,
                                        const char *old_name)
  {
        return 0;
  }
  
  static inline int security_path_link(struct dentry *old_dentry,
-                                    struct path *new_dir,
+                                    const struct path *new_dir,
                                     struct dentry *new_dentry)
  {
        return 0;
  }
  
- static inline int security_path_rename(struct path *old_dir,
+ static inline int security_path_rename(const struct path *old_dir,
                                       struct dentry *old_dentry,
-                                      struct path *new_dir,
+                                      const struct path *new_dir,
                                       struct dentry *new_dentry,
                                       unsigned int flags)
  {
        return 0;
  }
  
- static inline int security_path_chmod(struct path *path, umode_t mode)
+ static inline int security_path_chmod(const struct path *path, umode_t mode)
  {
        return 0;
  }
  
- static inline int security_path_chown(struct path *path, kuid_t uid, kgid_t gid)
+ static inline int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
  {
        return 0;
  }
  
- static inline int security_path_chroot(struct path *path)
+ static inline int security_path_chroot(const struct path *path)
  {
        return 0;
  }
diff --combined security/security.c
index 8c44a64f191d56df9fe93305e7b463b61974f731,f7af0aaa173eba8698598831d0d3a8b021cbb416..d17e4a6d269c5a4399cb6b377173ccf51d3cbb0f
@@@ -208,7 -208,7 +208,7 @@@ int security_syslog(int type
        return call_int_hook(syslog, 0, type);
  }
  
 -int security_settime(const struct timespec *ts, const struct timezone *tz)
 +int security_settime64(const struct timespec64 *ts, const struct timezone *tz)
  {
        return call_int_hook(settime, 0, ts, tz);
  }
@@@ -302,7 -302,7 +302,7 @@@ int security_sb_statfs(struct dentry *d
        return call_int_hook(sb_statfs, 0, dentry);
  }
  
- int security_sb_mount(const char *dev_name, struct path *path,
+ int security_sb_mount(const char *dev_name, const struct path *path,
                         const char *type, unsigned long flags, void *data)
  {
        return call_int_hook(sb_mount, 0, dev_name, path, type, flags, data);
@@@ -313,7 -313,7 +313,7 @@@ int security_sb_umount(struct vfsmount 
        return call_int_hook(sb_umount, 0, mnt, flags);
  }
  
- int security_sb_pivotroot(struct path *old_path, struct path *new_path)
+ int security_sb_pivotroot(const struct path *old_path, const struct path *new_path)
  {
        return call_int_hook(sb_pivotroot, 0, old_path, new_path);
  }
@@@ -410,7 -410,7 +410,7 @@@ int security_old_inode_init_security(st
  EXPORT_SYMBOL(security_old_inode_init_security);
  
  #ifdef CONFIG_SECURITY_PATH
- int security_path_mknod(struct path *dir, struct dentry *dentry, umode_t mode,
+ int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t mode,
                        unsigned int dev)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
  }
  EXPORT_SYMBOL(security_path_mknod);
  
- int security_path_mkdir(struct path *dir, struct dentry *dentry, umode_t mode)
+ int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t mode)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
                return 0;
  }
  EXPORT_SYMBOL(security_path_mkdir);
  
- int security_path_rmdir(struct path *dir, struct dentry *dentry)
+ int security_path_rmdir(const struct path *dir, struct dentry *dentry)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
                return 0;
        return call_int_hook(path_rmdir, 0, dir, dentry);
  }
  
- int security_path_unlink(struct path *dir, struct dentry *dentry)
+ int security_path_unlink(const struct path *dir, struct dentry *dentry)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
                return 0;
  }
  EXPORT_SYMBOL(security_path_unlink);
  
- int security_path_symlink(struct path *dir, struct dentry *dentry,
+ int security_path_symlink(const struct path *dir, struct dentry *dentry,
                          const char *old_name)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
        return call_int_hook(path_symlink, 0, dir, dentry, old_name);
  }
  
- int security_path_link(struct dentry *old_dentry, struct path *new_dir,
+ int security_path_link(struct dentry *old_dentry, const struct path *new_dir,
                       struct dentry *new_dentry)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
        return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry);
  }
  
- int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
-                        struct path *new_dir, struct dentry *new_dentry,
+ int security_path_rename(const struct path *old_dir, struct dentry *old_dentry,
+                        const struct path *new_dir, struct dentry *new_dentry,
                         unsigned int flags)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
  }
  EXPORT_SYMBOL(security_path_rename);
  
- int security_path_truncate(struct path *path)
+ int security_path_truncate(const struct path *path)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
                return 0;
        return call_int_hook(path_truncate, 0, path);
  }
  
- int security_path_chmod(struct path *path, umode_t mode)
+ int security_path_chmod(const struct path *path, umode_t mode)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
                return 0;
        return call_int_hook(path_chmod, 0, path, mode);
  }
  
- int security_path_chown(struct path *path, kuid_t uid, kgid_t gid)
+ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
  {
        if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
                return 0;
        return call_int_hook(path_chown, 0, path, uid, gid);
  }
  
- int security_path_chroot(struct path *path)
+ int security_path_chroot(const struct path *path)
  {
        return call_int_hook(path_chroot, 0, path);
  }
diff --combined security/selinux/hooks.c
index 469f5c75bd4b238742673e3aab30270cb0c63999,e3aeacc135457c7a1260d0944955360019b6600b..3140efa76a755fed3712598bbbc239f718eb4ce8
@@@ -506,8 -506,7 +506,8 @@@ static int sb_finish_set_opts(struct su
                        rc = -EOPNOTSUPP;
                        goto out;
                }
 -              rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
 +              rc = root_inode->i_op->getxattr(root, root_inode,
 +                                              XATTR_NAME_SELINUX, NULL, 0);
                if (rc < 0 && rc != -ENODATA) {
                        if (rc == -EOPNOTSUPP)
                                printk(KERN_WARNING "SELinux: (dev %s, type "
@@@ -1317,7 -1316,7 +1317,7 @@@ static int selinux_genfs_get_sid(struc
                                 u32 *sid)
  {
        int rc;
 -      struct super_block *sb = dentry->d_inode->i_sb;
 +      struct super_block *sb = dentry->d_sb;
        char *buffer, *path;
  
        buffer = (char *)__get_free_page(GFP_KERNEL);
@@@ -1413,13 -1412,13 +1413,13 @@@ static int inode_doinit_with_dentry(str
                        goto out_unlock;
                }
                context[len] = '\0';
 -              rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
 +              rc = inode->i_op->getxattr(dentry, inode, XATTR_NAME_SELINUX,
                                           context, len);
                if (rc == -ERANGE) {
                        kfree(context);
  
                        /* Need a larger buffer.  Query for the right size. */
 -                      rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
 +                      rc = inode->i_op->getxattr(dentry, inode, XATTR_NAME_SELINUX,
                                                   NULL, 0);
                        if (rc < 0) {
                                dput(dentry);
                                goto out_unlock;
                        }
                        context[len] = '\0';
 -                      rc = inode->i_op->getxattr(dentry,
 +                      rc = inode->i_op->getxattr(dentry, inode,
                                                   XATTR_NAME_SELINUX,
                                                   context, len);
                }
@@@ -2761,7 -2760,7 +2761,7 @@@ static int selinux_sb_statfs(struct den
  }
  
  static int selinux_mount(const char *dev_name,
-                        struct path *path,
+                        const struct path *path,
                         const char *type,
                         unsigned long flags,
                         void *data)