Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xfs: don't commit the first deferred transaction without intents

If the first operation in a string of defer ops has no intents,
then there is no reason to commit it before running the first call
to xfs_defer_finish_one(). This allows the defer ops to be used
effectively for non-intent based operations without requiring an
unnecessary extra transaction commit when first called.

This fixes a regression in per-attribute modification transaction
count when delayed attributes are not being used.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>

authored by

Dave Chinner and committed by
Dave Chinner
5ddd658e b2c28035

+18 -12
+18 -12
fs/xfs/libxfs/xfs_defer.c
··· 186 186 [XFS_DEFER_OPS_TYPE_AGFL_FREE] = &xfs_agfl_free_defer_type, 187 187 }; 188 188 189 - static void 189 + static bool 190 190 xfs_defer_create_intent( 191 191 struct xfs_trans *tp, 192 192 struct xfs_defer_pending *dfp, ··· 197 197 if (!dfp->dfp_intent) 198 198 dfp->dfp_intent = ops->create_intent(tp, &dfp->dfp_work, 199 199 dfp->dfp_count, sort); 200 + return dfp->dfp_intent != NULL; 200 201 } 201 202 202 203 /* ··· 205 204 * associated extents, then add the entire intake list to the end of 206 205 * the pending list. 207 206 */ 208 - STATIC void 207 + static bool 209 208 xfs_defer_create_intents( 210 209 struct xfs_trans *tp) 211 210 { 212 211 struct xfs_defer_pending *dfp; 212 + bool ret = false; 213 213 214 214 list_for_each_entry(dfp, &tp->t_dfops, dfp_list) { 215 215 trace_xfs_defer_create_intent(tp->t_mountp, dfp); 216 - xfs_defer_create_intent(tp, dfp, true); 216 + ret |= xfs_defer_create_intent(tp, dfp, true); 217 217 } 218 + return ret; 218 219 } 219 220 220 221 /* Abort all the intents that were committed. */ ··· 490 487 xfs_defer_finish_noroll( 491 488 struct xfs_trans **tp) 492 489 { 493 - struct xfs_defer_pending *dfp; 490 + struct xfs_defer_pending *dfp = NULL; 494 491 int error = 0; 495 492 LIST_HEAD(dop_pending); 496 493 ··· 509 506 * of time that any one intent item can stick around in memory, 510 507 * pinning the log tail. 511 508 */ 512 - xfs_defer_create_intents(*tp); 509 + bool has_intents = xfs_defer_create_intents(*tp); 510 + 513 511 list_splice_init(&(*tp)->t_dfops, &dop_pending); 514 512 515 - error = xfs_defer_trans_roll(tp); 516 - if (error) 517 - goto out_shutdown; 513 + if (has_intents || dfp) { 514 + error = xfs_defer_trans_roll(tp); 515 + if (error) 516 + goto out_shutdown; 518 517 519 - /* Possibly relog intent items to keep the log moving. */ 520 - error = xfs_defer_relog(tp, &dop_pending); 521 - if (error) 522 - goto out_shutdown; 518 + /* Relog intent items to keep the log moving. */ 519 + error = xfs_defer_relog(tp, &dop_pending); 520 + if (error) 521 + goto out_shutdown; 522 + } 523 523 524 524 dfp = list_first_entry(&dop_pending, struct xfs_defer_pending, 525 525 dfp_list);