Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

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()
This commit is contained in:
Linus Torvalds 2019-12-22 17:00:04 -08:00
commit 9efa3ed504
6 changed files with 18 additions and 3 deletions

View File

@ -35,11 +35,11 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
spin_unlock(&sb->s_inode_list_lock); spin_unlock(&sb->s_inode_list_lock);
cond_resched();
invalidate_mapping_pages(inode->i_mapping, 0, -1); invalidate_mapping_pages(inode->i_mapping, 0, -1);
iput(toput_inode); iput(toput_inode);
toput_inode = inode; toput_inode = inode;
cond_resched();
spin_lock(&sb->s_inode_list_lock); spin_lock(&sb->s_inode_list_lock);
} }
spin_unlock(&sb->s_inode_list_lock); spin_unlock(&sb->s_inode_list_lock);

View File

@ -676,6 +676,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
struct inode *inode, *next; struct inode *inode, *next;
LIST_HEAD(dispose); LIST_HEAD(dispose);
again:
spin_lock(&sb->s_inode_list_lock); spin_lock(&sb->s_inode_list_lock);
list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
@ -698,6 +699,12 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
inode_lru_list_del(inode); inode_lru_list_del(inode);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
list_add(&inode->i_lru, &dispose); 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); spin_unlock(&sb->s_inode_list_lock);

View File

@ -57,6 +57,9 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
* doing an __iget/iput with SB_ACTIVE clear would actually * doing an __iget/iput with SB_ACTIVE clear would actually
* evict all inodes with zero i_count from icache which is * evict all inodes with zero i_count from icache which is
* unnecessarily violent and may in fact be illegal to do. * 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)) { if (!atomic_read(&inode->i_count)) {
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
@ -77,6 +80,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
iput_inode = inode; iput_inode = inode;
cond_resched();
spin_lock(&sb->s_inode_list_lock); spin_lock(&sb->s_inode_list_lock);
} }
spin_unlock(&sb->s_inode_list_lock); spin_unlock(&sb->s_inode_list_lock);

View File

@ -984,6 +984,7 @@ static int add_dquot_ref(struct super_block *sb, int type)
* later. * later.
*/ */
old_inode = inode; old_inode = inode;
cond_resched();
spin_lock(&sb->s_inode_list_lock); spin_lock(&sb->s_inode_list_lock);
} }
spin_unlock(&sb->s_inode_list_lock); spin_unlock(&sb->s_inode_list_lock);

View File

@ -448,10 +448,12 @@ void generic_shutdown_super(struct super_block *sb)
sync_filesystem(sb); sync_filesystem(sb);
sb->s_flags &= ~SB_ACTIVE; sb->s_flags &= ~SB_ACTIVE;
fsnotify_sb_delete(sb);
cgroup_writeback_umount(); cgroup_writeback_umount();
/* evict all inodes with zero refcount */
evict_inodes(sb); evict_inodes(sb);
/* only nonzero refcount inodes can have marks */
fsnotify_sb_delete(sb);
if (sb->s_dio_done_wq) { if (sb->s_dio_done_wq) {
destroy_workqueue(sb->s_dio_done_wq); destroy_workqueue(sb->s_dio_done_wq);

View File

@ -1222,11 +1222,12 @@ EXPORT_SYMBOL(iov_iter_discard);
unsigned long iov_iter_alignment(const struct iov_iter *i) unsigned long iov_iter_alignment(const struct iov_iter *i)
{ {
unsigned int p_mask = i->pipe->ring_size - 1;
unsigned long res = 0; unsigned long res = 0;
size_t size = i->count; size_t size = i->count;
if (unlikely(iov_iter_is_pipe(i))) { 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])) if (size && i->iov_offset && allocated(&i->pipe->bufs[i->head & p_mask]))
return size | i->iov_offset; return size | i->iov_offset;
return size; return size;