Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Dec 2020 18:54:29 +0000 (10:54 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Dec 2020 18:54:29 +0000 (10:54 -0800)
Pull misc vfs updates from Al Viro:
 "Assorted patches from previous cycle(s)..."

* 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  fix hostfs_open() use of ->f_path.dentry
  Make sure that make_create_in_sticky() never sees uninitialized value of dir_mode
  fs: Kill DCACHE_DONTCACHE dentry even if DCACHE_REFERENCED is set
  fs: Handle I_DONTCACHE in iput_final() instead of generic_drop_inode()
  fs/namespace.c: WARN if mnt_count has become negative

1  2 
fs/inode.c
fs/namei.c
fs/namespace.c
include/linux/fs.h

diff --combined fs/inode.c
@@@ -155,6 -155,7 +155,6 @@@ int inode_init_always(struct super_bloc
        inode->i_bytes = 0;
        inode->i_generation = 0;
        inode->i_pipe = NULL;
 -      inode->i_bdev = NULL;
        inode->i_cdev = NULL;
        inode->i_link = NULL;
        inode->i_dir_seq = 0;
@@@ -579,6 -580,8 +579,6 @@@ static void evict(struct inode *inode
                truncate_inode_pages_final(&inode->i_data);
                clear_inode(inode);
        }
 -      if (S_ISBLK(inode->i_mode) && inode->i_bdev)
 -              bd_forget(inode);
        if (S_ISCHR(inode->i_mode) && inode->i_cdev)
                cd_forget(inode);
  
@@@ -1624,7 -1627,9 +1624,9 @@@ static void iput_final(struct inode *in
        else
                drop = generic_drop_inode(inode);
  
-       if (!drop && (sb->s_flags & SB_ACTIVE)) {
+       if (!drop &&
+           !(inode->i_state & I_DONTCACHE) &&
+           (sb->s_flags & SB_ACTIVE)) {
                inode_add_lru(inode);
                spin_unlock(&inode->i_lock);
                return;
diff --combined fs/namei.c
@@@ -2114,8 -2114,10 +2114,10 @@@ static int link_path_walk(const char *n
                return PTR_ERR(name);
        while (*name=='/')
                name++;
-       if (!*name)
+       if (!*name) {
+               nd->dir_mode = 0; // short-circuit the 'hardening' idiocy
                return 0;
+       }
  
        /* At this point we know we have a real path component. */
        for(;;) {
@@@ -4346,8 -4348,8 +4348,8 @@@ out
  }
  EXPORT_SYMBOL(vfs_rename);
  
 -static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,
 -                      const char __user *newname, unsigned int flags)
 +int do_renameat2(int olddfd, struct filename *from, int newdfd,
 +               struct filename *to, unsigned int flags)
  {
        struct dentry *old_dentry, *new_dentry;
        struct dentry *trap;
        struct qstr old_last, new_last;
        int old_type, new_type;
        struct inode *delegated_inode = NULL;
 -      struct filename *from;
 -      struct filename *to;
        unsigned int lookup_flags = 0, target_flags = LOOKUP_RENAME_TARGET;
        bool should_retry = false;
 -      int error;
 +      int error = -EINVAL;
  
        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
 -              return -EINVAL;
 +              goto put_both;
  
        if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
            (flags & RENAME_EXCHANGE))
 -              return -EINVAL;
 +              goto put_both;
  
        if (flags & RENAME_EXCHANGE)
                target_flags = 0;
  
  retry:
 -      from = filename_parentat(olddfd, getname(oldname), lookup_flags,
 -                              &old_path, &old_last, &old_type);
 +      from = filename_parentat(olddfd, from, lookup_flags, &old_path,
 +                                      &old_last, &old_type);
        if (IS_ERR(from)) {
                error = PTR_ERR(from);
 -              goto exit;
 +              goto put_new;
        }
  
 -      to = filename_parentat(newdfd, getname(newname), lookup_flags,
 -                              &new_path, &new_last, &new_type);
 +      to = filename_parentat(newdfd, to, lookup_flags, &new_path, &new_last,
 +                              &new_type);
        if (IS_ERR(to)) {
                error = PTR_ERR(to);
                goto exit1;
@@@ -4471,40 -4475,34 +4473,40 @@@ exit2
        if (retry_estale(error, lookup_flags))
                should_retry = true;
        path_put(&new_path);
 -      putname(to);
  exit1:
        path_put(&old_path);
 -      putname(from);
        if (should_retry) {
                should_retry = false;
                lookup_flags |= LOOKUP_REVAL;
                goto retry;
        }
 -exit:
 +put_both:
 +      if (!IS_ERR(from))
 +              putname(from);
 +put_new:
 +      if (!IS_ERR(to))
 +              putname(to);
        return error;
  }
  
  SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
                int, newdfd, const char __user *, newname, unsigned int, flags)
  {
 -      return do_renameat2(olddfd, oldname, newdfd, newname, flags);
 +      return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname),
 +                              flags);
  }
  
  SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
                int, newdfd, const char __user *, newname)
  {
 -      return do_renameat2(olddfd, oldname, newdfd, newname, 0);
 +      return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname),
 +                              0);
  }
  
  SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname)
  {
 -      return do_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
 +      return do_renameat2(AT_FDCWD, getname(oldname), AT_FDCWD,
 +                              getname(newname), 0);
  }
  
  int readlink_copy(char __user *buffer, int buflen, const char *link)
diff --combined fs/namespace.c
@@@ -156,10 -156,10 +156,10 @@@ static inline void mnt_add_count(struc
  /*
   * vfsmount lock must be held for write
   */
unsigned int mnt_get_count(struct mount *mnt)
+ int mnt_get_count(struct mount *mnt)
  {
  #ifdef CONFIG_SMP
-       unsigned int count = 0;
+       int count = 0;
        int cpu;
  
        for_each_possible_cpu(cpu) {
@@@ -1139,6 -1139,7 +1139,7 @@@ static DECLARE_DELAYED_WORK(delayed_mnt
  static void mntput_no_expire(struct mount *mnt)
  {
        LIST_HEAD(list);
+       int count;
  
        rcu_read_lock();
        if (likely(READ_ONCE(mnt->mnt_ns))) {
         */
        smp_mb();
        mnt_add_count(mnt, -1);
-       if (mnt_get_count(mnt)) {
+       count = mnt_get_count(mnt);
+       if (count != 0) {
+               WARN_ON(count < 0);
                rcu_read_unlock();
                unlock_mount_hash();
                return;
@@@ -3274,7 -3277,7 +3277,7 @@@ static struct mnt_namespace *alloc_mnt_
        new_ns->ns.ops = &mntns_operations;
        if (!anon)
                new_ns->seq = atomic64_add_return(1, &mnt_ns_seq);
 -      atomic_set(&new_ns->count, 1);
 +      refcount_set(&new_ns->ns.count, 1);
        INIT_LIST_HEAD(&new_ns->list);
        init_waitqueue_head(&new_ns->poll);
        spin_lock_init(&new_ns->ns_lock);
@@@ -3848,7 -3851,7 +3851,7 @@@ void __init mnt_init(void
  
  void put_mnt_ns(struct mnt_namespace *ns)
  {
 -      if (!atomic_dec_and_test(&ns->count))
 +      if (!refcount_dec_and_test(&ns->ns.count))
                return;
        drop_collected_mounts(&ns->root->mnt);
        free_mnt_ns(ns);
diff --combined include/linux/fs.h
@@@ -696,6 -696,7 +696,6 @@@ struct inode 
        struct list_head        i_devices;
        union {
                struct pipe_inode_info  *i_pipe;
 -              struct block_device     *i_bdev;
                struct cdev             *i_cdev;
                char                    *i_link;
                unsigned                i_dir_seq;
@@@ -922,7 -923,7 +922,7 @@@ struct file 
        const struct file_operations    *f_op;
  
        /*
 -       * Protects f_ep_links, f_flags.
 +       * Protects f_ep, f_flags.
         * Must not be taken from IRQ context.
         */
        spinlock_t              f_lock;
  
  #ifdef CONFIG_EPOLL
        /* Used by fs/eventpoll.c to link all the hooks to this file */
 -      struct list_head        f_ep_links;
 -      struct list_head        f_tfile_llink;
 +      struct hlist_head       *f_ep;
  #endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;
        errseq_t                f_wb_err;
@@@ -1407,7 -1409,7 +1407,7 @@@ enum 
  
  struct sb_writers {
        int                             frozen;         /* Is sb frozen? */
 -      wait_queue_head_t               wait_unfrozen;  /* for get_super_thawed() */
 +      wait_queue_head_t               wait_unfrozen;  /* wait for thaw */
        struct percpu_rw_semaphore      rw_sem[SB_FREEZE_LEVELS];
  };
  
@@@ -2876,8 -2878,7 +2876,7 @@@ extern int inode_needs_sync(struct inod
  extern int generic_delete_inode(struct inode *inode);
  static inline int generic_drop_inode(struct inode *inode)
  {
-       return !inode->i_nlink || inode_unhashed(inode) ||
-               (inode->i_state & I_DONTCACHE);
+       return !inode->i_nlink || inode_unhashed(inode);
  }
  extern void d_mark_dontcache(struct inode *inode);
  
@@@ -3130,6 -3131,8 +3129,6 @@@ extern struct file_system_type *get_fil
  extern void put_filesystem(struct file_system_type *fs);
  extern struct file_system_type *get_fs_type(const char *name);
  extern struct super_block *get_super(struct block_device *);
 -extern struct super_block *get_super_thawed(struct block_device *);
 -extern struct super_block *get_super_exclusive_thawed(struct block_device *bdev);
  extern struct super_block *get_active_super(struct block_device *bdev);
  extern void drop_super(struct super_block *sb);
  extern void drop_super_exclusive(struct super_block *sb);
@@@ -3198,7 -3201,6 +3197,7 @@@ extern int generic_ci_d_hash(const stru
  extern int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
                                const char *str, const struct qstr *name);
  #endif
 +extern void generic_set_encrypted_ci_d_ops(struct dentry *dentry);
  
  #ifdef CONFIG_MIGRATION
  extern int buffer_migrate_page(struct address_space *,
@@@ -3227,7 -3229,7 +3226,7 @@@ static inline bool vma_is_fsdax(struct 
  {
        struct inode *inode;
  
 -      if (!vma->vm_file)
 +      if (!IS_ENABLED(CONFIG_FS_DAX) || !vma->vm_file)
                return false;
        if (!vma_is_dax(vma))
                return false;