proc: In proc_prune_siblings_dcache cache an aquired super block
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 21 Feb 2020 14:33:57 +0000 (08:33 -0600)
committerEric W. Biederman <ebiederm@xmission.com>
Fri, 21 Feb 2020 20:06:42 +0000 (14:06 -0600)
Because there are likely to be several sysctls in a row on the
same superblock cache the super_block after the count has
been raised and don't deactivate it until we are processing
another super_block.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
fs/proc/inode.c

index 74ce4a8..fa2dc73 100644 (file)
@@ -108,10 +108,11 @@ void proc_prune_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock)
        struct inode *inode;
        struct proc_inode *ei;
        struct hlist_node *node;
-       struct super_block *sb;
+       struct super_block *old_sb = NULL;
 
        rcu_read_lock();
        for (;;) {
+               struct super_block *sb;
                node = hlist_first_rcu(inodes);
                if (!node)
                        break;
@@ -122,23 +123,28 @@ void proc_prune_siblings_dcache(struct hlist_head *inodes, spinlock_t *lock)
 
                inode = &ei->vfs_inode;
                sb = inode->i_sb;
-               if (!atomic_inc_not_zero(&sb->s_active))
+               if ((sb != old_sb) && !atomic_inc_not_zero(&sb->s_active))
                        continue;
                inode = igrab(inode);
                rcu_read_unlock();
+               if (sb != old_sb) {
+                       if (old_sb)
+                               deactivate_super(old_sb);
+                       old_sb = sb;
+               }
                if (unlikely(!inode)) {
-                       deactivate_super(sb);
                        rcu_read_lock();
                        continue;
                }
 
                d_prune_aliases(inode);
                iput(inode);
-               deactivate_super(sb);
 
                rcu_read_lock();
        }
        rcu_read_unlock();
+       if (old_sb)
+               deactivate_super(old_sb);
 }
 
 static int proc_show_options(struct seq_file *seq, struct dentry *root)