summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_icache.c17
-rw-r--r--fs/xfs/xfs_super.c18
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) {
/*