xfs: evict all inodes involved with log redo item
authorDarrick J. Wong <darrick.wong@oracle.com>
Sat, 19 Aug 2017 01:08:25 +0000 (18:08 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Fri, 1 Sep 2017 17:55:30 +0000 (10:55 -0700)
When we introduced the bmap redo log items, we set MS_ACTIVE on the
mountpoint and XFS_IRECOVERY on the inode to prevent unlinked inodes
from being truncated prematurely during log recovery.  This also had the
effect of putting linked inodes on the lru instead of evicting them.

Unfortunately, we neglected to find all those unreferenced lru inodes
and evict them after finishing log recovery, which means that we leak
them if anything goes wrong in the rest of xfs_mountfs, because the lru
is only cleaned out on unmount.

Therefore, evict unreferenced inodes in the lru list immediately
after clearing MS_ACTIVE.

Fixes: 17c12bcd30 ("xfs: when replaying bmap operations, don't let unlinked inodes get reaped")
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Cc: viro@ZenIV.linux.org.uk
Reviewed-by: Brian Foster <bfoster@redhat.com>
fs/inode.c
fs/internal.h
fs/xfs/xfs_log.c
include/linux/fs.h

index 50370599e37104708b95ede3a627052cc0d910d3..6a1626e0edafc572d1428279b0e741945b1da5fe 100644 (file)
@@ -637,6 +637,7 @@ again:
 
        dispose_list(&dispose);
 }
+EXPORT_SYMBOL_GPL(evict_inodes);
 
 /**
  * invalidate_inodes   - attempt to free all inodes on a superblock
index 9676fe11c093538d284ec5c2c59e9a2a9e37c1f6..fedfe94d84ba56a45ee9ab24948824ecc999b388 100644 (file)
@@ -132,7 +132,6 @@ static inline bool atime_needs_update_rcu(const struct path *path,
 extern void inode_io_list_del(struct inode *inode);
 
 extern long get_nr_dirty_inodes(void);
-extern void evict_inodes(struct super_block *);
 extern int invalidate_inodes(struct super_block *, bool);
 
 /*
index f467f1230444f6d5d7f1109a3eae820859374edf..bcb2f860e508dc8567d5310713ec9587bf862afc 100644 (file)
@@ -761,12 +761,24 @@ xfs_log_mount_finish(
         * inodes.  Turn it off immediately after recovery finishes
         * so that we don't leak the quota inodes if subsequent mount
         * activities fail.
+        *
+        * We let all inodes involved in redo item processing end up on
+        * the LRU instead of being evicted immediately so that if we do
+        * something to an unlinked inode, the irele won't cause
+        * premature truncation and freeing of the inode, which results
+        * in log recovery failure.  We have to evict the unreferenced
+        * lru inodes after clearing MS_ACTIVE because we don't
+        * otherwise clean up the lru if there's a subsequent failure in
+        * xfs_mountfs, which leads to us leaking the inodes if nothing
+        * else (e.g. quotacheck) references the inodes before the
+        * mount failure occurs.
         */
        mp->m_super->s_flags |= MS_ACTIVE;
        error = xlog_recover_finish(mp->m_log);
        if (!error)
                xfs_log_work_queue(mp);
        mp->m_super->s_flags &= ~MS_ACTIVE;
+       evict_inodes(mp->m_super);
 
        if (readonly)
                mp->m_flags |= XFS_MOUNT_RDONLY;
index 6e1fd5d2124877c16bbbfab4487a772c8f7e37ee..00f46e0183706134e0dda3bf6cbe95b6e9acb74d 100644 (file)
@@ -2831,6 +2831,7 @@ static inline void lockdep_annotate_inode_mutex_key(struct inode *inode) { };
 #endif
 extern void unlock_new_inode(struct inode *);
 extern unsigned int get_next_ino(void);
+extern void evict_inodes(struct super_block *sb);
 
 extern void __iget(struct inode * inode);
 extern void iget_failed(struct inode *);