xfs: acquire superblock freeze protection on eofblocks scans
authorBrian Foster <bfoster@redhat.com>
Sun, 12 Apr 2020 20:11:10 +0000 (13:11 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 2 May 2020 15:25:51 +0000 (17:25 +0200)
commit 4b674b9ac852937af1f8c62f730c325fb6eadcdb upstream.

The filesystem freeze sequence in XFS waits on any background
eofblocks or cowblocks scans to complete before the filesystem is
quiesced. At this point, the freezer has already stopped the
transaction subsystem, however, which means a truncate or cowblock
cancellation in progress is likely blocked in transaction
allocation. This results in a deadlock between freeze and the
associated scanner.

Fix this problem by holding superblock write protection across calls
into the block reapers. Since protection for background scans is
acquired from the workqueue task context, trylock to avoid a similar
deadlock between freeze and blocking on the write lock.

Fixes: d6b636ebb1c9f ("xfs: halt auto-reclamation activities while rebuilding rmap")
Reported-by: Paul Furtado <paulfurtado91@gmail.com>
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/xfs/xfs_icache.c
fs/xfs/xfs_ioctl.c

index 245483cc282ba0032f5f0a16649d5b7dbd45cffb..901f27ac94abc0c16a6a4065478e0a6a3791b551 100644 (file)
@@ -902,7 +902,12 @@ xfs_eofblocks_worker(
 {
        struct xfs_mount *mp = container_of(to_delayed_work(work),
                                struct xfs_mount, m_eofblocks_work);
+
+       if (!sb_start_write_trylock(mp->m_super))
+               return;
        xfs_icache_free_eofblocks(mp, NULL);
+       sb_end_write(mp->m_super);
+
        xfs_queue_eofblocks(mp);
 }
 
@@ -929,7 +934,12 @@ xfs_cowblocks_worker(
 {
        struct xfs_mount *mp = container_of(to_delayed_work(work),
                                struct xfs_mount, m_cowblocks_work);
+
+       if (!sb_start_write_trylock(mp->m_super))
+               return;
        xfs_icache_free_cowblocks(mp, NULL);
+       sb_end_write(mp->m_super);
+
        xfs_queue_cowblocks(mp);
 }
 
index bad90479ade2a4c13db8bc0404597f97324a87d0..6ffb53edf1b4a1b5eea3cedb33e61561348c4e5d 100644 (file)
@@ -2182,7 +2182,10 @@ xfs_file_ioctl(
                if (error)
                        return error;
 
-               return xfs_icache_free_eofblocks(mp, &keofb);
+               sb_start_write(mp->m_super);
+               error = xfs_icache_free_eofblocks(mp, &keofb);
+               sb_end_write(mp->m_super);
+               return error;
        }
 
        default: