diff options
author | Mark Brown <broonie@kernel.org> | 2023-07-17 08:12:31 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2023-07-17 08:12:31 +0300 |
commit | 0791faebfe750292a8a842b64795a390ca4a3b51 (patch) | |
tree | 0e6095a5a0130398b0693bddfdc421c41eebda7c /fs/xfs/xfs_extent_busy.c | |
parent | e8bf1741c14eb8e4a4e1364d45aeeab66660ab9b (diff) | |
parent | fdf0eaf11452d72945af31804e2a1048ee1b574c (diff) | |
download | linux-0791faebfe750292a8a842b64795a390ca4a3b51.tar.xz |
ASoC: Merge v6.5-rc2
Get a similar baseline to my other branches, and fixes for people using
the branch.
Diffstat (limited to 'fs/xfs/xfs_extent_busy.c')
-rw-r--r-- | fs/xfs/xfs_extent_busy.c | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c index f3d328e4a440..7c2fdc71e42d 100644 --- a/fs/xfs/xfs_extent_busy.c +++ b/fs/xfs/xfs_extent_busy.c @@ -566,20 +566,45 @@ xfs_extent_busy_clear( /* * Flush out all busy extents for this AG. + * + * If the current transaction is holding busy extents, the caller may not want + * to wait for committed busy extents to resolve. If we are being told just to + * try a flush or progress has been made since we last skipped a busy extent, + * return immediately to allow the caller to try again. + * + * If we are freeing extents, we might actually be holding the only free extents + * in the transaction busy list and the log force won't resolve that situation. + * In this case, we must return -EAGAIN to avoid a deadlock by informing the + * caller it needs to commit the busy extents it holds before retrying the + * extent free operation. */ -void +int xfs_extent_busy_flush( - struct xfs_mount *mp, + struct xfs_trans *tp, struct xfs_perag *pag, - unsigned busy_gen) + unsigned busy_gen, + uint32_t alloc_flags) { DEFINE_WAIT (wait); int error; - error = xfs_log_force(mp, XFS_LOG_SYNC); + error = xfs_log_force(tp->t_mountp, XFS_LOG_SYNC); if (error) - return; + return error; + + /* Avoid deadlocks on uncommitted busy extents. */ + if (!list_empty(&tp->t_busy)) { + if (alloc_flags & XFS_ALLOC_FLAG_TRYFLUSH) + return 0; + + if (busy_gen != READ_ONCE(pag->pagb_gen)) + return 0; + + if (alloc_flags & XFS_ALLOC_FLAG_FREEING) + return -EAGAIN; + } + /* Wait for committed busy extents to resolve. */ do { prepare_to_wait(&pag->pagb_wait, &wait, TASK_KILLABLE); if (busy_gen != READ_ONCE(pag->pagb_gen)) @@ -588,6 +613,7 @@ xfs_extent_busy_flush( } while (1); finish_wait(&pag->pagb_wait, &wait); + return 0; } void |