diff options
-rw-r--r-- | fs/xfs/xfs_icache.c | 17 | ||||
-rw-r--r-- | fs/xfs/xfs_super.c | 18 |
2 files changed, 30 insertions, 5 deletions
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 3457da5b34fb..ba6fba0f5e04 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -2168,6 +2168,7 @@ xfs_inode_free_cowblocks( void *args) { struct xfs_eofblocks *eofb = args; + uint lock_mode = 0; int ret = 0; if (!xfs_prep_free_cowblocks(ip)) @@ -2176,9 +2177,15 @@ xfs_inode_free_cowblocks( if (!xfs_inode_matches_eofb(ip, eofb)) return 0; - /* Free the CoW blocks */ - xfs_ilock(ip, XFS_IOLOCK_EXCL); - xfs_ilock(ip, XFS_MMAPLOCK_EXCL); + /* + * Free the CoW blocks. We don't need to lock the inode if we're in + * the process of freezing the filesystem because we've already locked + * out writes and page faults. + */ + if (ip->i_mount->m_super->s_writers.frozen == SB_UNFROZEN) + lock_mode = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL; + if (lock_mode) + xfs_ilock(ip, lock_mode); /* * Check again, nobody else should be able to dirty blocks or change @@ -2187,8 +2194,8 @@ xfs_inode_free_cowblocks( if (xfs_prep_free_cowblocks(ip)) ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, false); - xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); - xfs_iunlock(ip, XFS_IOLOCK_EXCL); + if (lock_mode) + xfs_iunlock(ip, lock_mode); return ret; } diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index b234e484fad0..919c6f4b0c22 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1116,6 +1116,24 @@ xfs_fs_sync_fs( if (!wait) return 0; + /* + * If we're in the middle of freezing the filesystem, this is our last + * chance to run regular transactions. Clear all the COW staging + * extents so that we can freeze the filesystem with as little recovery + * work to do at the next mount as possible. It's safe to do this + * without locking inodes because the freezer code flushed all the + * dirty data from the page cache and locked out writes and page faults. + */ + if (sb->s_writers.frozen == SB_FREEZE_PAGEFAULT) { + int error; + + error = xfs_icache_free_cowblocks(mp, NULL); + if (error) { + xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); + return error; + } + } + xfs_log_force(mp, XFS_LOG_SYNC); if (laptop_mode) { /* |