Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Dec 2019 01:00:04 +0000 (17:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Dec 2019 01:00:04 +0000 (17:00 -0800)
Pull vfs fixes from Al Viro:
 "Eric's s_inodes softlockup fixes + Jan's fix for recent regression
  from pipe rework"

* 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  fs: call fsnotify_sb_delete after evict_inodes
  fs: avoid softlockups in s_inodes iterators
  pipe: Fix bogus dereference in iov_iter_alignment()

fs/drop_caches.c
fs/inode.c
fs/notify/fsnotify.c
fs/quota/dquot.c
fs/super.c
lib/iov_iter.c

index d31b6c7..dc1a1d5 100644 (file)
@@ -35,11 +35,11 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
                spin_unlock(&inode->i_lock);
                spin_unlock(&sb->s_inode_list_lock);
 
-               cond_resched();
                invalidate_mapping_pages(inode->i_mapping, 0, -1);
                iput(toput_inode);
                toput_inode = inode;
 
+               cond_resched();
                spin_lock(&sb->s_inode_list_lock);
        }
        spin_unlock(&sb->s_inode_list_lock);
index fef457a..96d62d9 100644 (file)
@@ -676,6 +676,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
        struct inode *inode, *next;
        LIST_HEAD(dispose);
 
+again:
        spin_lock(&sb->s_inode_list_lock);
        list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
                spin_lock(&inode->i_lock);
@@ -698,6 +699,12 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
                inode_lru_list_del(inode);
                spin_unlock(&inode->i_lock);
                list_add(&inode->i_lru, &dispose);
+               if (need_resched()) {
+                       spin_unlock(&sb->s_inode_list_lock);
+                       cond_resched();
+                       dispose_list(&dispose);
+                       goto again;
+               }
        }
        spin_unlock(&sb->s_inode_list_lock);
 
index 3e77b72..46f2255 100644 (file)
@@ -57,6 +57,9 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
                 * doing an __iget/iput with SB_ACTIVE clear would actually
                 * evict all inodes with zero i_count from icache which is
                 * unnecessarily violent and may in fact be illegal to do.
+                * However, we should have been called /after/ evict_inodes
+                * removed all zero refcount inodes, in any case.  Test to
+                * be sure.
                 */
                if (!atomic_read(&inode->i_count)) {
                        spin_unlock(&inode->i_lock);
@@ -77,6 +80,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
 
                iput_inode = inode;
 
+               cond_resched();
                spin_lock(&sb->s_inode_list_lock);
        }
        spin_unlock(&sb->s_inode_list_lock);
index b0688c0..b6a4f69 100644 (file)
@@ -984,6 +984,7 @@ static int add_dquot_ref(struct super_block *sb, int type)
                 * later.
                 */
                old_inode = inode;
+               cond_resched();
                spin_lock(&sb->s_inode_list_lock);
        }
        spin_unlock(&sb->s_inode_list_lock);
index cfadab2..cd35253 100644 (file)
@@ -448,10 +448,12 @@ void generic_shutdown_super(struct super_block *sb)
                sync_filesystem(sb);
                sb->s_flags &= ~SB_ACTIVE;
 
-               fsnotify_sb_delete(sb);
                cgroup_writeback_umount();
 
+               /* evict all inodes with zero refcount */
                evict_inodes(sb);
+               /* only nonzero refcount inodes can have marks */
+               fsnotify_sb_delete(sb);
 
                if (sb->s_dio_done_wq) {
                        destroy_workqueue(sb->s_dio_done_wq);
index fb29c02..51595bf 100644 (file)
@@ -1222,11 +1222,12 @@ EXPORT_SYMBOL(iov_iter_discard);
 
 unsigned long iov_iter_alignment(const struct iov_iter *i)
 {
-       unsigned int p_mask = i->pipe->ring_size - 1;
        unsigned long res = 0;
        size_t size = i->count;
 
        if (unlikely(iov_iter_is_pipe(i))) {
+               unsigned int p_mask = i->pipe->ring_size - 1;
+
                if (size && i->iov_offset && allocated(&i->pipe->bufs[i->head & p_mask]))
                        return size | i->iov_offset;
                return size;