Skip to content

Commit 5e672cd

Browse files
Dave ChinnerDarrick J. Wong
authored andcommitted
xfs: introduce xfs_inodegc_push()
The current blocking mechanism for pushing the inodegc queue out to disk can result in systems becoming unusable when there is a long running inodegc operation. This is because the statfs() implementation currently issues a blocking flush of the inodegc queue and a significant number of common system utilities will call statfs() to discover something about the underlying filesystem. This can result in userspace operations getting stuck on inodegc progress, and when trying to remove a heavily reflinked file on slow storage with a full journal, this can result in delays measuring in hours. Avoid this problem by adding "push" function that expedites the flushing of the inodegc queue, but doesn't wait for it to complete. Convert xfs_fs_statfs() and xfs_qm_scall_getquota() to use this mechanism so they don't block but still ensure that queued operations are expedited. Fixes: ab23a77 ("xfs: per-cpu deferred inode inactivation queues") Reported-by: Chris Dunlop <[email protected]> Signed-off-by: Dave Chinner <[email protected]> [djwong: fix _getquota_next to use _inodegc_push too] Reviewed-by: Darrick J. Wong <[email protected]> Signed-off-by: Darrick J. Wong <[email protected]>
1 parent 7cf2b0f commit 5e672cd

File tree

5 files changed

+28
-10
lines changed

5 files changed

+28
-10
lines changed

fs/xfs/xfs_icache.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,19 +1862,29 @@ xfs_inodegc_worker(
18621862
}
18631863

18641864
/*
1865-
* Force all currently queued inode inactivation work to run immediately and
1866-
* wait for the work to finish.
1865+
* Expedite all pending inodegc work to run immediately. This does not wait for
1866+
* completion of the work.
18671867
*/
18681868
void
1869-
xfs_inodegc_flush(
1869+
xfs_inodegc_push(
18701870
struct xfs_mount *mp)
18711871
{
18721872
if (!xfs_is_inodegc_enabled(mp))
18731873
return;
1874+
trace_xfs_inodegc_push(mp, __return_address);
1875+
xfs_inodegc_queue_all(mp);
1876+
}
18741877

1878+
/*
1879+
* Force all currently queued inode inactivation work to run immediately and
1880+
* wait for the work to finish.
1881+
*/
1882+
void
1883+
xfs_inodegc_flush(
1884+
struct xfs_mount *mp)
1885+
{
1886+
xfs_inodegc_push(mp);
18751887
trace_xfs_inodegc_flush(mp, __return_address);
1876-
1877-
xfs_inodegc_queue_all(mp);
18781888
flush_workqueue(mp->m_inodegc_wq);
18791889
}
18801890

fs/xfs/xfs_icache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ void xfs_blockgc_stop(struct xfs_mount *mp);
7676
void xfs_blockgc_start(struct xfs_mount *mp);
7777

7878
void xfs_inodegc_worker(struct work_struct *work);
79+
void xfs_inodegc_push(struct xfs_mount *mp);
7980
void xfs_inodegc_flush(struct xfs_mount *mp);
8081
void xfs_inodegc_stop(struct xfs_mount *mp);
8182
void xfs_inodegc_start(struct xfs_mount *mp);

fs/xfs/xfs_qm_syscalls.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,9 +454,12 @@ xfs_qm_scall_getquota(
454454
struct xfs_dquot *dqp;
455455
int error;
456456

457-
/* Flush inodegc work at the start of a quota reporting scan. */
457+
/*
458+
* Expedite pending inodegc work at the start of a quota reporting
459+
* scan but don't block waiting for it to complete.
460+
*/
458461
if (id == 0)
459-
xfs_inodegc_flush(mp);
462+
xfs_inodegc_push(mp);
460463

461464
/*
462465
* Try to get the dquot. We don't want it allocated on disk, so don't
@@ -498,7 +501,7 @@ xfs_qm_scall_getquota_next(
498501

499502
/* Flush inodegc work at the start of a quota reporting scan. */
500503
if (*id == 0)
501-
xfs_inodegc_flush(mp);
504+
xfs_inodegc_push(mp);
502505

503506
error = xfs_qm_dqget_next(mp, *id, type, &dqp);
504507
if (error)

fs/xfs/xfs_super.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -797,8 +797,11 @@ xfs_fs_statfs(
797797
xfs_extlen_t lsize;
798798
int64_t ffree;
799799

800-
/* Wait for whatever inactivations are in progress. */
801-
xfs_inodegc_flush(mp);
800+
/*
801+
* Expedite background inodegc but don't wait. We do not want to block
802+
* here waiting hours for a billion extent file to be truncated.
803+
*/
804+
xfs_inodegc_push(mp);
802805

803806
statp->f_type = XFS_SUPER_MAGIC;
804807
statp->f_namelen = MAXNAMELEN - 1;

fs/xfs/xfs_trace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ DEFINE_EVENT(xfs_fs_class, name, \
240240
TP_PROTO(struct xfs_mount *mp, void *caller_ip), \
241241
TP_ARGS(mp, caller_ip))
242242
DEFINE_FS_EVENT(xfs_inodegc_flush);
243+
DEFINE_FS_EVENT(xfs_inodegc_push);
243244
DEFINE_FS_EVENT(xfs_inodegc_start);
244245
DEFINE_FS_EVENT(xfs_inodegc_stop);
245246
DEFINE_FS_EVENT(xfs_inodegc_queue);

0 commit comments

Comments
 (0)