xfs: don't drain buffer lru on freeze and read-only remount
authorBrian Foster <bfoster@redhat.com>
Sat, 23 Jan 2021 00:48:20 +0000 (16:48 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Sat, 23 Jan 2021 00:54:50 +0000 (16:54 -0800)
xfs_buftarg_drain() is called from xfs_log_quiesce() to ensure the
buffer cache is reclaimed during unmount. xfs_log_quiesce() is also
called from xfs_quiesce_attr(), however, which means that cache
state is completely drained for filesystem freeze and read-only
remount. While technically harmless, this is unnecessarily
heavyweight. Both freeze and read-only mounts allow reads and thus
allow population of the buffer cache. Therefore, the transitional
sequence in either case really only needs to quiesce outstanding
writes to return the filesystem in a generally read-only state.

Additionally, some users have reported that attempts to freeze a
filesystem concurrent with a read-heavy workload causes the freeze
process to stall for a significant amount of time. This occurs
because, as mentioned above, the read workload repopulates the
buffer LRU while the freeze task attempts to drain it.

To improve this situation, replace the drain in xfs_log_quiesce()
with a buffer I/O quiesce and lift the drain into the unmount path.
This removes buffer LRU reclaim from freeze and read-only [re]mount,
but ensures the LRU is still drained before the filesystem unmounts.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_log.c

index 99ee8b0f499c6a734d217897ae350bd29a48d967..f6e5235df7c904a0936bb6862bf585a04ee64732 100644 (file)
@@ -1815,14 +1815,13 @@ xfs_buftarg_drain_rele(
        return LRU_REMOVED;
 }
 
+/*
+ * Wait for outstanding I/O on the buftarg to complete.
+ */
 void
-xfs_buftarg_drain(
+xfs_buftarg_wait(
        struct xfs_buftarg      *btp)
 {
-       LIST_HEAD(dispose);
-       int                     loop = 0;
-       bool                    write_fail = false;
-
        /*
         * First wait on the buftarg I/O count for all in-flight buffers to be
         * released. This is critical as new buffers do not make the LRU until
@@ -1838,6 +1837,17 @@ xfs_buftarg_drain(
        while (percpu_counter_sum(&btp->bt_io_count))
                delay(100);
        flush_workqueue(btp->bt_mount->m_buf_workqueue);
+}
+
+void
+xfs_buftarg_drain(
+       struct xfs_buftarg      *btp)
+{
+       LIST_HEAD(dispose);
+       int                     loop = 0;
+       bool                    write_fail = false;
+
+       xfs_buftarg_wait(btp);
 
        /* loop until there is nothing left on the lru list. */
        while (list_lru_count(&btp->bt_lru)) {
index d5e31ba205e02195c15de4a9b135536feca3d255..459ca34f26f58870d584fecb82e548bbbca6b2d0 100644 (file)
@@ -347,6 +347,7 @@ xfs_buf_update_cksum(struct xfs_buf *bp, unsigned long cksum_offset)
 extern struct xfs_buftarg *xfs_alloc_buftarg(struct xfs_mount *,
                struct block_device *, struct dax_device *);
 extern void xfs_free_buftarg(struct xfs_buftarg *);
+extern void xfs_buftarg_wait(struct xfs_buftarg *);
 extern void xfs_buftarg_drain(struct xfs_buftarg *);
 extern int xfs_setsize_buftarg(struct xfs_buftarg *, unsigned int);
 
index 5ad4d5e780191d3f06c8079f347cad6564bf7be3..46ea4017fceccf71c141f9d51b18c4aa4163fd80 100644 (file)
@@ -936,13 +936,13 @@ xfs_log_quiesce(
 
        /*
         * The superblock buffer is uncached and while xfs_ail_push_all_sync()
-        * will push it, xfs_buftarg_drain() will not wait for it. Further,
+        * will push it, xfs_buftarg_wait() will not wait for it. Further,
         * xfs_buf_iowait() cannot be used because it was pushed with the
         * XBF_ASYNC flag set, so we need to use a lock/unlock pair to wait for
         * the IO to complete.
         */
        xfs_ail_push_all_sync(mp->m_ail);
-       xfs_buftarg_drain(mp->m_ddev_targp);
+       xfs_buftarg_wait(mp->m_ddev_targp);
        xfs_buf_lock(mp->m_sb_bp);
        xfs_buf_unlock(mp->m_sb_bp);
 
@@ -962,6 +962,8 @@ xfs_log_unmount(
 {
        xfs_log_quiesce(mp);
 
+       xfs_buftarg_drain(mp->m_ddev_targp);
+
        xfs_trans_ail_destroy(mp);
 
        xfs_sysfs_del(&mp->m_log->l_kobj);