Skip to content

Commit d9f6877

Browse files
dgchinnerdchinner
authored andcommitted
xfs: xlog_sync() manually adjusts grant head space
When xlog_sync() rounds off the tail the iclog that is being flushed, it manually subtracts that space from the grant heads. This space is actually reserved by the transaction ticket that covers the xlog_sync() call from xlog_write(), but we don't plumb the ticket down far enough for it to account for the space consumed in the current log ticket. The grant heads are hot, so we really should be accounting this to the ticket is we can, rather than adding thousands of extra grant head updates every CIL commit. Interestingly, this actually indicates a potential log space overrun can occur when we force the log. By the time that xfs_log_force() pushes out an active iclog and consumes the roundoff space, the reservation for that roundoff space has been returned to the grant heads and is no longer covered by a reservation. In theory the roundoff added to log force on an already full log could push the write head past the tail. In practice, the CIL commit that writes to the log and needs the iclog pushed will have reserved space for roundoff, so when it releases the ticket there will still be physical space for the roundoff to be committed to the log, even though it is no longer reserved. This roundoff won't be enough space to allow a transaction to be woken if the log is full, so overruns should not actually occur in practice. That said, it indicates that we should not release the CIL context log ticket until after we've released the commit iclog. It also means that xlog_sync() still needs the direct grant head manipulation if we don't provide it with a ticket. Log forces are rare when we are in fast paths running 1.5 million transactions/s that make the grant heads hot, so let's optimise the hot case and pass CIL log tickets down to the xlog_sync() code. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
1 parent 1ccb074 commit d9f6877

3 files changed

Lines changed: 41 additions & 17 deletions

File tree

fs/xfs/xfs_log.c

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ xlog_grant_push_ail(
5757
STATIC void
5858
xlog_sync(
5959
struct xlog *log,
60-
struct xlog_in_core *iclog);
60+
struct xlog_in_core *iclog,
61+
struct xlog_ticket *ticket);
6162
#if defined(DEBUG)
6263
STATIC void
6364
xlog_verify_grant_tail(
@@ -567,7 +568,8 @@ xlog_state_shutdown_callbacks(
567568
int
568569
xlog_state_release_iclog(
569570
struct xlog *log,
570-
struct xlog_in_core *iclog)
571+
struct xlog_in_core *iclog,
572+
struct xlog_ticket *ticket)
571573
{
572574
xfs_lsn_t tail_lsn;
573575
bool last_ref;
@@ -614,7 +616,7 @@ xlog_state_release_iclog(
614616
trace_xlog_iclog_syncing(iclog, _RET_IP_);
615617

616618
spin_unlock(&log->l_icloglock);
617-
xlog_sync(log, iclog);
619+
xlog_sync(log, iclog, ticket);
618620
spin_lock(&log->l_icloglock);
619621
return 0;
620622
}
@@ -881,7 +883,7 @@ xlog_force_iclog(
881883
iclog->ic_flags |= XLOG_ICL_NEED_FLUSH | XLOG_ICL_NEED_FUA;
882884
if (iclog->ic_state == XLOG_STATE_ACTIVE)
883885
xlog_state_switch_iclogs(iclog->ic_log, iclog, 0);
884-
return xlog_state_release_iclog(iclog->ic_log, iclog);
886+
return xlog_state_release_iclog(iclog->ic_log, iclog, NULL);
885887
}
886888

887889
/*
@@ -2027,7 +2029,8 @@ xlog_calc_iclog_size(
20272029
STATIC void
20282030
xlog_sync(
20292031
struct xlog *log,
2030-
struct xlog_in_core *iclog)
2032+
struct xlog_in_core *iclog,
2033+
struct xlog_ticket *ticket)
20312034
{
20322035
unsigned int count; /* byte count of bwrite */
20332036
unsigned int roundoff; /* roundoff to BB or stripe */
@@ -2039,12 +2042,20 @@ xlog_sync(
20392042

20402043
count = xlog_calc_iclog_size(log, iclog, &roundoff);
20412044

2042-
/* move grant heads by roundoff in sync */
2043-
xlog_grant_add_space(log, &log->l_reserve_head.grant, roundoff);
2044-
xlog_grant_add_space(log, &log->l_write_head.grant, roundoff);
2045+
/*
2046+
* If we have a ticket, account for the roundoff via the ticket
2047+
* reservation to avoid touching the hot grant heads needlessly.
2048+
* Otherwise, we have to move grant heads directly.
2049+
*/
2050+
if (ticket) {
2051+
ticket->t_curr_res -= roundoff;
2052+
} else {
2053+
xlog_grant_add_space(log, &log->l_reserve_head.grant, roundoff);
2054+
xlog_grant_add_space(log, &log->l_write_head.grant, roundoff);
2055+
}
20452056

20462057
/* put cycle number in every block */
2047-
xlog_pack_data(log, iclog, roundoff);
2058+
xlog_pack_data(log, iclog, roundoff);
20482059

20492060
/* real byte length */
20502061
size = iclog->ic_offset;
@@ -2277,7 +2288,7 @@ xlog_write_get_more_iclog_space(
22772288
spin_lock(&log->l_icloglock);
22782289
ASSERT(iclog->ic_state == XLOG_STATE_WANT_SYNC);
22792290
xlog_state_finish_copy(log, iclog, *record_cnt, *data_cnt);
2280-
error = xlog_state_release_iclog(log, iclog);
2291+
error = xlog_state_release_iclog(log, iclog, ticket);
22812292
spin_unlock(&log->l_icloglock);
22822293
if (error)
22832294
return error;
@@ -2539,7 +2550,7 @@ xlog_write(
25392550
*/
25402551
spin_lock(&log->l_icloglock);
25412552
xlog_state_finish_copy(log, iclog, record_cnt, 0);
2542-
error = xlog_state_release_iclog(log, iclog);
2553+
error = xlog_state_release_iclog(log, iclog, ticket);
25432554
spin_unlock(&log->l_icloglock);
25442555

25452556
return error;
@@ -2959,7 +2970,7 @@ xlog_state_get_iclog_space(
29592970
* reference to the iclog.
29602971
*/
29612972
if (!atomic_add_unless(&iclog->ic_refcnt, -1, 1))
2962-
error = xlog_state_release_iclog(log, iclog);
2973+
error = xlog_state_release_iclog(log, iclog, ticket);
29632974
spin_unlock(&log->l_icloglock);
29642975
if (error)
29652976
return error;

fs/xfs/xfs_log_cil.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,7 @@ xlog_cil_push_work(
11891189
xfs_csn_t push_seq;
11901190
bool push_commit_stable;
11911191
LIST_HEAD (whiteouts);
1192+
struct xlog_ticket *ticket;
11921193

11931194
new_ctx = xlog_cil_ctx_alloc();
11941195
new_ctx->ticket = xlog_cil_ticket_alloc(log);
@@ -1323,7 +1324,14 @@ xlog_cil_push_work(
13231324
if (error)
13241325
goto out_abort_free_ticket;
13251326

1326-
xfs_log_ticket_ungrant(log, ctx->ticket);
1327+
/*
1328+
* Grab the ticket from the ctx so we can ungrant it after releasing the
1329+
* commit_iclog. The ctx may be freed by the time we return from
1330+
* releasing the commit_iclog (i.e. checkpoint has been completed and
1331+
* callback run) so we can't reference the ctx after the call to
1332+
* xlog_state_release_iclog().
1333+
*/
1334+
ticket = ctx->ticket;
13271335

13281336
/*
13291337
* If the checkpoint spans multiple iclogs, wait for all previous iclogs
@@ -1373,12 +1381,14 @@ xlog_cil_push_work(
13731381
if (push_commit_stable &&
13741382
ctx->commit_iclog->ic_state == XLOG_STATE_ACTIVE)
13751383
xlog_state_switch_iclogs(log, ctx->commit_iclog, 0);
1376-
xlog_state_release_iclog(log, ctx->commit_iclog);
1384+
ticket = ctx->ticket;
1385+
xlog_state_release_iclog(log, ctx->commit_iclog, ticket);
13771386

13781387
/* Not safe to reference ctx now! */
13791388

13801389
spin_unlock(&log->l_icloglock);
13811390
xlog_cil_cleanup_whiteouts(&whiteouts);
1391+
xfs_log_ticket_ungrant(log, ticket);
13821392
return;
13831393

13841394
out_skip:
@@ -1388,17 +1398,19 @@ xlog_cil_push_work(
13881398
return;
13891399

13901400
out_abort_free_ticket:
1391-
xfs_log_ticket_ungrant(log, ctx->ticket);
13921401
ASSERT(xlog_is_shutdown(log));
13931402
xlog_cil_cleanup_whiteouts(&whiteouts);
13941403
if (!ctx->commit_iclog) {
1404+
xfs_log_ticket_ungrant(log, ctx->ticket);
13951405
xlog_cil_committed(ctx);
13961406
return;
13971407
}
13981408
spin_lock(&log->l_icloglock);
1399-
xlog_state_release_iclog(log, ctx->commit_iclog);
1409+
ticket = ctx->ticket;
1410+
xlog_state_release_iclog(log, ctx->commit_iclog, ticket);
14001411
/* Not safe to reference ctx now! */
14011412
spin_unlock(&log->l_icloglock);
1413+
xfs_log_ticket_ungrant(log, ticket);
14021414
}
14031415

14041416
/*

fs/xfs/xfs_log_priv.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,8 @@ void xfs_log_ticket_regrant(struct xlog *log, struct xlog_ticket *ticket);
515515

516516
void xlog_state_switch_iclogs(struct xlog *log, struct xlog_in_core *iclog,
517517
int eventual_size);
518-
int xlog_state_release_iclog(struct xlog *log, struct xlog_in_core *iclog);
518+
int xlog_state_release_iclog(struct xlog *log, struct xlog_in_core *iclog,
519+
struct xlog_ticket *ticket);
519520

520521
/*
521522
* When we crack an atomic LSN, we sample it first so that the value will not

0 commit comments

Comments
 (0)