fs/fs-writeback.c | 58 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 3be57189efd5..3dcc8b202a40 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1206,6 +1206,52 @@ out_unlock_inode: } EXPORT_SYMBOL(__mark_inode_dirty); +/* + * Do we want to get the inode for writeback? + */ +static int get_inode_for_writeback(struct inode *inode) +{ + struct address_space *mapping = inode->i_mapping; + + /* + * It's a data integrity sync, but we don't care about + * racing with new pages - we're about data integrity + * of things in the past, not the future + */ + if (!ACCESS_ONCE(mapping->nrpages)) + return 0; + + /* Similar logic wrt the I_NEW bit */ + if (ACCESS_ONCE(inode->i_state) & I_NEW) + return 0; + + /* + * When the inode count goes down to zero, the + * I_WILL_FREE and I_FREEING bits might get set. + * But not before. + * + * So if we get this, we know those bits are + * clear, and the inode is still interesting. + */ + if (atomic_inc_not_zero(&inode->i_count)) + return 1; + + /* + * Slow path never happens normally, since any + * active inode will be referenced by a dentry + * and thus caught above + */ + spin_lock(&inode->i_lock); + if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || + (mapping->nrpages == 0)) { + spin_unlock(&inode->i_lock); + return 0; + } + __iget(inode); + spin_unlock(&inode->i_lock); + return 1; +} + static void wait_sb_inodes(struct super_block *sb) { struct inode *inode, *old_inode = NULL; @@ -1226,16 +1272,8 @@ static void wait_sb_inodes(struct super_block *sb) * we still have to wait for that writeout. */ list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { - struct address_space *mapping = inode->i_mapping; - - spin_lock(&inode->i_lock); - if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || - (mapping->nrpages == 0)) { - spin_unlock(&inode->i_lock); + if (!get_inode_for_writeback(inode)) continue; - } - __iget(inode); - spin_unlock(&inode->i_lock); spin_unlock(&inode_sb_list_lock); /* @@ -1249,7 +1287,7 @@ static void wait_sb_inodes(struct super_block *sb) iput(old_inode); old_inode = inode; - filemap_fdatawait(mapping); + filemap_fdatawait(inode->i_mapping); cond_resched();