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

fs/dcache.c
fs/hostfs/hostfs_kern.c
fs/inode.c
fs/namei.c
fs/namespace.c
fs/pnode.h
include/linux/fs.h

index ea04858..97e81a8 100644 (file)
@@ -793,10 +793,17 @@ static inline bool fast_dput(struct dentry *dentry)
         * a reference to the dentry and change that, but
         * our work is done - we can leave the dentry
         * around with a zero refcount.
+        *
+        * Nevertheless, there are two cases that we should kill
+        * the dentry anyway.
+        * 1. free disconnected dentries as soon as their refcount
+        *    reached zero.
+        * 2. free dentries if they should not be cached.
         */
        smp_rmb();
        d_flags = READ_ONCE(dentry->d_flags);
-       d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST | DCACHE_DISCONNECTED;
+       d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST |
+                       DCACHE_DISCONNECTED | DCACHE_DONTCACHE;
 
        /* Nothing to do? Dropping the reference was all we needed? */
        if (d_flags == (DCACHE_REFERENCED | DCACHE_LRU_LIST) && !d_unhashed(dentry))
index c070c0d..aea3545 100644 (file)
@@ -315,7 +315,7 @@ retry:
        if (mode & FMODE_WRITE)
                r = w = 1;
 
-       name = dentry_name(file->f_path.dentry);
+       name = dentry_name(d_real(file->f_path.dentry, file->f_inode));
        if (name == NULL)
                return -ENOMEM;
 
index cb008ac..6442d97 100644 (file)
@@ -1624,7 +1624,9 @@ static void iput_final(struct inode *inode)
        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;
index 03d0e11..78443a8 100644 (file)
@@ -2114,8 +2114,10 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                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(;;) {
index 2b681f6..d2db7df 100644 (file)
@@ -156,10 +156,10 @@ static inline void mnt_add_count(struct mount *mnt, int n)
 /*
  * 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 @@ static DECLARE_DELAYED_WORK(delayed_mntput_work, delayed_mntput);
 static void mntput_no_expire(struct mount *mnt)
 {
        LIST_HEAD(list);
+       int count;
 
        rcu_read_lock();
        if (likely(READ_ONCE(mnt->mnt_ns))) {
@@ -1162,7 +1163,9 @@ static void mntput_no_expire(struct mount *mnt)
         */
        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;
index 49a058c..26f74e0 100644 (file)
@@ -44,7 +44,7 @@ int propagate_mount_busy(struct mount *, int);
 void propagate_mount_unlock(struct mount *);
 void mnt_release_group_id(struct mount *);
 int get_dominating_id(struct mount *mnt, const struct path *root);
-unsigned int mnt_get_count(struct mount *mnt);
+int mnt_get_count(struct mount *mnt);
 void mnt_set_mountpoint(struct mount *, struct mountpoint *,
                        struct mount *);
 void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp,
index ad4cf1b..fd47dee 100644 (file)
@@ -2876,8 +2876,7 @@ extern int inode_needs_sync(struct inode *inode);
 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);