summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_log_cil.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2010-05-17 15:52:13 +1000
committerAlex Elder <aelder@sgi.com>2010-05-24 10:38:20 -0500
commitdf806158b0f6eb24247773b4a19b8b59d7217e59 (patch)
treea6fb142258aabf03011aadd14c9cf6ade9033d58 /fs/xfs/xfs_log_cil.c
parent9da1ab181ac1790f86528b86ba5876f037e8dcdc (diff)
downloadlwn-df806158b0f6eb24247773b4a19b8b59d7217e59.tar.gz
lwn-df806158b0f6eb24247773b4a19b8b59d7217e59.zip
xfs: enable background pushing of the CIL
If we let the CIL grow without bound, it will grow large enough to violate recovery constraints (must be at least one complete transaction in the log at all times) or take forever to write out through the log buffers. Hence we need a check during asynchronous transactions as to whether the CIL needs to be pushed. We track the amount of log space the CIL consumes, so it is relatively simple to limit it on a pure size basis. Make the limit the minimum of just under half the log size (recovery constraint) or 8MB of log space (which is an awful lot of metadata). Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_log_cil.c')
-rw-r--r--fs/xfs/xfs_log_cil.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
index 53abd6b0a333..9b21f80f31ce 100644
--- a/fs/xfs/xfs_log_cil.c
+++ b/fs/xfs/xfs_log_cil.c
@@ -336,6 +336,7 @@ xfs_log_commit_cil(
{
struct log *log = mp->m_log;
int log_flags = 0;
+ int push = 0;
if (flags & XFS_TRANS_RELEASE_LOG_RES)
log_flags = XFS_LOG_REL_PERM_RESERV;
@@ -365,8 +366,20 @@ xfs_log_commit_cil(
xfs_log_done(mp, tp->t_ticket, NULL, log_flags);
xfs_trans_unreserve_and_mod_sb(tp);
- /* background commit is allowed again */
+ /* check for background commit before unlock */
+ if (log->l_cilp->xc_ctx->space_used > XLOG_CIL_SPACE_LIMIT(log))
+ push = 1;
up_read(&log->l_cilp->xc_ctx_lock);
+
+ /*
+ * We need to push CIL every so often so we don't cache more than we
+ * can fit in the log. The limit really is that a checkpoint can't be
+ * more than half the log (the current checkpoint is not allowed to
+ * overwrite the previous checkpoint), but commit latency and memory
+ * usage limit this to a smaller size in most cases.
+ */
+ if (push)
+ xlog_cil_push(log, 0);
return 0;
}
@@ -429,18 +442,25 @@ xlog_cil_push(
if (!cil)
return 0;
- /* XXX: don't sleep for background? */
new_ctx = kmem_zalloc(sizeof(*new_ctx), KM_SLEEP|KM_NOFS);
new_ctx->ticket = xlog_cil_ticket_alloc(log);
- /* lock out transaction commit */
- down_write(&cil->xc_ctx_lock);
+ /* lock out transaction commit, but don't block on background push */
+ if (!down_write_trylock(&cil->xc_ctx_lock)) {
+ if (!push_now)
+ goto out_free_ticket;
+ down_write(&cil->xc_ctx_lock);
+ }
ctx = cil->xc_ctx;
/* check if we've anything to push */
if (list_empty(&cil->xc_cil))
goto out_skip;
+ /* check for spurious background flush */
+ if (!push_now && cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log))
+ goto out_skip;
+
/*
* pull all the log vectors off the items in the CIL, and
* remove the items from the CIL. We don't need the CIL lock
@@ -584,6 +604,7 @@ restart:
out_skip:
up_write(&cil->xc_ctx_lock);
+out_free_ticket:
xfs_log_ticket_put(new_ctx->ticket);
kmem_free(new_ctx);
return 0;