Skip to content

Commit

Permalink
xfs: introduce xfs_inodegc_push()
Browse files Browse the repository at this point in the history
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 <chris@onthe.net.au>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
[djwong: fix _getquota_next to use _inodegc_push too]
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
  • Loading branch information
Dave Chinner authored and Darrick J. Wong committed Jun 23, 2022
1 parent 7cf2b0f commit 5e672cd
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 10 deletions.
20 changes: 15 additions & 5 deletions fs/xfs/xfs_icache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1862,19 +1862,29 @@ xfs_inodegc_worker(
}

/*
* Force all currently queued inode inactivation work to run immediately and
* wait for the work to finish.
* Expedite all pending inodegc work to run immediately. This does not wait for
* completion of the work.
*/
void
xfs_inodegc_flush(
xfs_inodegc_push(
struct xfs_mount *mp)
{
if (!xfs_is_inodegc_enabled(mp))
return;
trace_xfs_inodegc_push(mp, __return_address);
xfs_inodegc_queue_all(mp);
}

/*
* Force all currently queued inode inactivation work to run immediately and
* wait for the work to finish.
*/
void
xfs_inodegc_flush(
struct xfs_mount *mp)
{
xfs_inodegc_push(mp);
trace_xfs_inodegc_flush(mp, __return_address);

xfs_inodegc_queue_all(mp);
flush_workqueue(mp->m_inodegc_wq);
}

Expand Down
1 change: 1 addition & 0 deletions fs/xfs/xfs_icache.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ void xfs_blockgc_stop(struct xfs_mount *mp);
void xfs_blockgc_start(struct xfs_mount *mp);

void xfs_inodegc_worker(struct work_struct *work);
void xfs_inodegc_push(struct xfs_mount *mp);
void xfs_inodegc_flush(struct xfs_mount *mp);
void xfs_inodegc_stop(struct xfs_mount *mp);
void xfs_inodegc_start(struct xfs_mount *mp);
Expand Down
9 changes: 6 additions & 3 deletions fs/xfs/xfs_qm_syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -454,9 +454,12 @@ xfs_qm_scall_getquota(
struct xfs_dquot *dqp;
int error;

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

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

/* Flush inodegc work at the start of a quota reporting scan. */
if (*id == 0)
xfs_inodegc_flush(mp);
xfs_inodegc_push(mp);

error = xfs_qm_dqget_next(mp, *id, type, &dqp);
if (error)
Expand Down
7 changes: 5 additions & 2 deletions fs/xfs/xfs_super.c
Original file line number Diff line number Diff line change
Expand Up @@ -797,8 +797,11 @@ xfs_fs_statfs(
xfs_extlen_t lsize;
int64_t ffree;

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

statp->f_type = XFS_SUPER_MAGIC;
statp->f_namelen = MAXNAMELEN - 1;
Expand Down
1 change: 1 addition & 0 deletions fs/xfs/xfs_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ DEFINE_EVENT(xfs_fs_class, name, \
TP_PROTO(struct xfs_mount *mp, void *caller_ip), \
TP_ARGS(mp, caller_ip))
DEFINE_FS_EVENT(xfs_inodegc_flush);
DEFINE_FS_EVENT(xfs_inodegc_push);
DEFINE_FS_EVENT(xfs_inodegc_start);
DEFINE_FS_EVENT(xfs_inodegc_stop);
DEFINE_FS_EVENT(xfs_inodegc_queue);
Expand Down

0 comments on commit 5e672cd

Please sign in to comment.