Commit 80168676ebfe4af51407d30f336d67f082d45201

Authored by Dave Chinner
Committed by Alex Elder
1 parent 899611ee7d

xfs: force background CIL push under sustained load

I have been seeing occasional pauses in transaction throughput up to
30s long under heavy parallel workloads. The only notable thing was
that the xfsaild was trying to be active during the pauses, but
making no progress. It was running exactly 20 times a second (on the
50ms no-progress backoff), and the number of pushbuf events was
constant across this time as well.  IOWs, the xfsaild appeared to be
stuck on buffers that it could not push out.

Further investigation indicated that it was trying to push out inode
buffers that were pinned and/or locked. The xfsbufd was also getting
woken at the same frequency (by the xfsaild, no doubt) to push out
delayed write buffers. The xfsbufd was not making any progress
because all the buffers in the delwri queue were pinned. This scan-
and-make-no-progress dance went one in the trace for some seconds,
before the xfssyncd came along an issued a log force, and then
things started going again.

However, I noticed something strange about the log force - there
were way too many IO's issued. 516 log buffers were written, to be
exact. That added up to 129MB of log IO, which got me very
interested because it's almost exactly 25% of the size of the log.
He delayed logging code is suppose to aggregate the minimum of 25%
of the log or 8MB worth of changes before flushing. That's what
really puzzled me - why did a log force write 129MB instead of only
8MB?

Essentially what has happened is that no CIL pushes had occurred
since the previous tail push which cleared out 25% of the log space.
That caused all the new transactions to block because there wasn't
log space for them, but they kick the xfsaild to push the tail.
However, the xfsaild was not making progress because there were
buffers it could not lock and flush, and the xfsbufd could not flush
them because they were pinned. As a result, both the xfsaild and the
xfsbufd could not move the tail of the log forward without the CIL
first committing.

The cause of the problem was that the background CIL push, which
should happen when 8MB of aggregated changes have been committed, is
being held off by the concurrent transaction commit load. The
background push does a down_write_trylock() which will fail if there
is a concurrent transaction commit holding the push lock in read
mode. With 8 CPUs all doing transactions as fast as they can, there
was enough concurrent transaction commits to hold off the background
push until tail-pushing could no longer free log space, and the halt
would occur.

It should be noted that there is no reason why it would halt at 25%
of log space used by a single CIL checkpoint. This bug could
definitely violate the "no transaction should be larger than half
the log" requirement and hence result in corruption if the system
crashed under heavy load. This sort of bug is exactly the reason why
delayed logging was tagged as experimental....

The fix is to start blocking background pushes once the threshold
has been exceeded. Rework the threshold calculations to keep the
amount of log space a CIL checkpoint can use to below that of the
AIL push threshold to avoid the problem completely.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Alex Elder <aelder@sgi.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>

Showing 2 changed files with 30 additions and 19 deletions Side-by-side Diff

fs/xfs/xfs_log_cil.c
... ... @@ -405,9 +405,15 @@
405 405 new_ctx = kmem_zalloc(sizeof(*new_ctx), KM_SLEEP|KM_NOFS);
406 406 new_ctx->ticket = xlog_cil_ticket_alloc(log);
407 407  
408   - /* lock out transaction commit, but don't block on background push */
  408 + /*
  409 + * Lock out transaction commit, but don't block for background pushes
  410 + * unless we are well over the CIL space limit. See the definition of
  411 + * XLOG_CIL_HARD_SPACE_LIMIT() for the full explanation of the logic
  412 + * used here.
  413 + */
409 414 if (!down_write_trylock(&cil->xc_ctx_lock)) {
410   - if (!push_seq)
  415 + if (!push_seq &&
  416 + cil->xc_ctx->space_used < XLOG_CIL_HARD_SPACE_LIMIT(log))
411 417 goto out_free_ticket;
412 418 down_write(&cil->xc_ctx_lock);
413 419 }
... ... @@ -422,7 +428,7 @@
422 428 goto out_skip;
423 429  
424 430 /* check for a previously pushed seqeunce */
425   - if (push_seq < cil->xc_ctx->sequence)
  431 + if (push_seq && push_seq < cil->xc_ctx->sequence)
426 432 goto out_skip;
427 433  
428 434 /*
fs/xfs/xfs_log_priv.h
... ... @@ -426,13 +426,13 @@
426 426 };
427 427  
428 428 /*
429   - * The amount of log space we should the CIL to aggregate is difficult to size.
430   - * Whatever we chose we have to make we can get a reservation for the log space
431   - * effectively, that it is large enough to capture sufficient relogging to
432   - * reduce log buffer IO significantly, but it is not too large for the log or
433   - * induces too much latency when writing out through the iclogs. We track both
434   - * space consumed and the number of vectors in the checkpoint context, so we
435   - * need to decide which to use for limiting.
  429 + * The amount of log space we allow the CIL to aggregate is difficult to size.
  430 + * Whatever we choose, we have to make sure we can get a reservation for the
  431 + * log space effectively, that it is large enough to capture sufficient
  432 + * relogging to reduce log buffer IO significantly, but it is not too large for
  433 + * the log or induces too much latency when writing out through the iclogs. We
  434 + * track both space consumed and the number of vectors in the checkpoint
  435 + * context, so we need to decide which to use for limiting.
436 436 *
437 437 * Every log buffer we write out during a push needs a header reserved, which
438 438 * is at least one sector and more for v2 logs. Hence we need a reservation of
439 439  
... ... @@ -459,16 +459,21 @@
459 459 * checkpoint transaction ticket is specific to the checkpoint context, rather
460 460 * than the CIL itself.
461 461 *
462   - * With dynamic reservations, we can basically make up arbitrary limits for the
463   - * checkpoint size so long as they don't violate any other size rules. Hence
464   - * the initial maximum size for the checkpoint transaction will be set to a
465   - * quarter of the log or 8MB, which ever is smaller. 8MB is an arbitrary limit
466   - * right now based on the latency of writing out a large amount of data through
467   - * the circular iclog buffers.
  462 + * With dynamic reservations, we can effectively make up arbitrary limits for
  463 + * the checkpoint size so long as they don't violate any other size rules.
  464 + * Recovery imposes a rule that no transaction exceed half the log, so we are
  465 + * limited by that. Furthermore, the log transaction reservation subsystem
  466 + * tries to keep 25% of the log free, so we need to keep below that limit or we
  467 + * risk running out of free log space to start any new transactions.
  468 + *
  469 + * In order to keep background CIL push efficient, we will set a lower
  470 + * threshold at which background pushing is attempted without blocking current
  471 + * transaction commits. A separate, higher bound defines when CIL pushes are
  472 + * enforced to ensure we stay within our maximum checkpoint size bounds.
  473 + * threshold, yet give us plenty of space for aggregation on large logs.
468 474 */
469   -
470   -#define XLOG_CIL_SPACE_LIMIT(log) \
471   - (min((log->l_logsize >> 2), (8 * 1024 * 1024)))
  475 +#define XLOG_CIL_SPACE_LIMIT(log) (log->l_logsize >> 3)
  476 +#define XLOG_CIL_HARD_SPACE_LIMIT(log) (3 * (log->l_logsize >> 4))
472 477  
473 478 /*
474 479 * The reservation head lsn is not made up of a cycle number and block number.