Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 213251
b: refs/heads/master
c: d1583a3
h: refs/heads/master
i:
  213249: 1126b10
  213247: bf2821d
v: v3
  • Loading branch information
Dave Chinner authored and Alex Elder committed Oct 18, 2010
1 parent a08fb50 commit 798cc70
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 106 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9c169915ad374cd9efb1556943b2074ec07e1749
refs/heads/master: d1583a3833290ab9f8b13a064acbb5e508c59f60
232 changes: 127 additions & 105 deletions trunk/fs/xfs/xfs_log_cil.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,102 +145,6 @@ xlog_cil_init_post_recovery(
log->l_curr_block);
}

/*
* Insert the log item into the CIL and calculate the difference in space
* consumed by the item. Add the space to the checkpoint ticket and calculate
* if the change requires additional log metadata. If it does, take that space
* as well. Remove the amount of space we addded to the checkpoint ticket from
* the current transaction ticket so that the accounting works out correctly.
*
* If this is the first time the item is being placed into the CIL in this
* context, pin it so it can't be written to disk until the CIL is flushed to
* the iclog and the iclog written to disk.
*/
static void
xlog_cil_insert(
struct log *log,
struct xlog_ticket *ticket,
struct xfs_log_item *item,
struct xfs_log_vec *lv)
{
struct xfs_cil *cil = log->l_cilp;
struct xfs_log_vec *old = lv->lv_item->li_lv;
struct xfs_cil_ctx *ctx = cil->xc_ctx;
int len;
int diff_iovecs;
int iclog_space;

if (old) {
/* existing lv on log item, space used is a delta */
ASSERT(!list_empty(&item->li_cil));
ASSERT(old->lv_buf && old->lv_buf_len && old->lv_niovecs);

len = lv->lv_buf_len - old->lv_buf_len;
diff_iovecs = lv->lv_niovecs - old->lv_niovecs;
kmem_free(old->lv_buf);
kmem_free(old);
} else {
/* new lv, must pin the log item */
ASSERT(!lv->lv_item->li_lv);
ASSERT(list_empty(&item->li_cil));

len = lv->lv_buf_len;
diff_iovecs = lv->lv_niovecs;
IOP_PIN(lv->lv_item);

}
len += diff_iovecs * sizeof(xlog_op_header_t);

/* attach new log vector to log item */
lv->lv_item->li_lv = lv;

spin_lock(&cil->xc_cil_lock);
list_move_tail(&item->li_cil, &cil->xc_cil);
ctx->nvecs += diff_iovecs;

/*
* If this is the first time the item is being committed to the CIL,
* store the sequence number on the log item so we can tell
* in future commits whether this is the first checkpoint the item is
* being committed into.
*/
if (!item->li_seq)
item->li_seq = ctx->sequence;

/*
* Now transfer enough transaction reservation to the context ticket
* for the checkpoint. The context ticket is special - the unit
* reservation has to grow as well as the current reservation as we
* steal from tickets so we can correctly determine the space used
* during the transaction commit.
*/
if (ctx->ticket->t_curr_res == 0) {
/* first commit in checkpoint, steal the header reservation */
ASSERT(ticket->t_curr_res >= ctx->ticket->t_unit_res + len);
ctx->ticket->t_curr_res = ctx->ticket->t_unit_res;
ticket->t_curr_res -= ctx->ticket->t_unit_res;
}

/* do we need space for more log record headers? */
iclog_space = log->l_iclog_size - log->l_iclog_hsize;
if (len > 0 && (ctx->space_used / iclog_space !=
(ctx->space_used + len) / iclog_space)) {
int hdrs;

hdrs = (len + iclog_space - 1) / iclog_space;
/* need to take into account split region headers, too */
hdrs *= log->l_iclog_hsize + sizeof(struct xlog_op_header);
ctx->ticket->t_unit_res += hdrs;
ctx->ticket->t_curr_res += hdrs;
ticket->t_curr_res -= hdrs;
ASSERT(ticket->t_curr_res >= len);
}
ticket->t_curr_res -= len;
ctx->space_used += len;

spin_unlock(&cil->xc_cil_lock);
}

/*
* Format log item into a flat buffers
*
Expand Down Expand Up @@ -286,7 +190,7 @@ xlog_cil_format_items(
len += lv->lv_iovecp[index].i_len;

lv->lv_buf_len = len;
lv->lv_buf = kmem_zalloc(lv->lv_buf_len, KM_SLEEP|KM_NOFS);
lv->lv_buf = kmem_alloc(lv->lv_buf_len, KM_SLEEP|KM_NOFS);
ptr = lv->lv_buf;

for (index = 0; index < lv->lv_niovecs; index++) {
Expand All @@ -300,21 +204,136 @@ xlog_cil_format_items(
}
}

/*
* Prepare the log item for insertion into the CIL. Calculate the difference in
* log space and vectors it will consume, and if it is a new item pin it as
* well.
*/
STATIC void
xfs_cil_prepare_item(
struct log *log,
struct xfs_log_vec *lv,
int *len,
int *diff_iovecs)
{
struct xfs_log_vec *old = lv->lv_item->li_lv;

if (old) {
/* existing lv on log item, space used is a delta */
ASSERT(!list_empty(&lv->lv_item->li_cil));
ASSERT(old->lv_buf && old->lv_buf_len && old->lv_niovecs);

*len += lv->lv_buf_len - old->lv_buf_len;
*diff_iovecs += lv->lv_niovecs - old->lv_niovecs;
kmem_free(old->lv_buf);
kmem_free(old);
} else {
/* new lv, must pin the log item */
ASSERT(!lv->lv_item->li_lv);
ASSERT(list_empty(&lv->lv_item->li_cil));

*len += lv->lv_buf_len;
*diff_iovecs += lv->lv_niovecs;
IOP_PIN(lv->lv_item);

}

/* attach new log vector to log item */
lv->lv_item->li_lv = lv;

/*
* If this is the first time the item is being committed to the
* CIL, store the sequence number on the log item so we can
* tell in future commits whether this is the first checkpoint
* the item is being committed into.
*/
if (!lv->lv_item->li_seq)
lv->lv_item->li_seq = log->l_cilp->xc_ctx->sequence;
}

/*
* Insert the log items into the CIL and calculate the difference in space
* consumed by the item. Add the space to the checkpoint ticket and calculate
* if the change requires additional log metadata. If it does, take that space
* as well. Remove the amount of space we addded to the checkpoint ticket from
* the current transaction ticket so that the accounting works out correctly.
*/
static void
xlog_cil_insert_items(
struct log *log,
struct xfs_log_vec *log_vector,
struct xlog_ticket *ticket,
xfs_lsn_t *start_lsn)
struct xlog_ticket *ticket)
{
struct xfs_log_vec *lv;

if (start_lsn)
*start_lsn = log->l_cilp->xc_ctx->sequence;
struct xfs_cil *cil = log->l_cilp;
struct xfs_cil_ctx *ctx = cil->xc_ctx;
struct xfs_log_vec *lv;
int len = 0;
int diff_iovecs = 0;
int iclog_space;

ASSERT(log_vector);

/*
* Do all the accounting aggregation and switching of log vectors
* around in a separate loop to the insertion of items into the CIL.
* Then we can do a separate loop to update the CIL within a single
* lock/unlock pair. This reduces the number of round trips on the CIL
* lock from O(nr_logvectors) to O(1) and greatly reduces the overall
* hold time for the transaction commit.
*
* If this is the first time the item is being placed into the CIL in
* this context, pin it so it can't be written to disk until the CIL is
* flushed to the iclog and the iclog written to disk.
*
* We can do this safely because the context can't checkpoint until we
* are done so it doesn't matter exactly how we update the CIL.
*/
for (lv = log_vector; lv; lv = lv->lv_next)
xfs_cil_prepare_item(log, lv, &len, &diff_iovecs);

/* account for space used by new iovec headers */
len += diff_iovecs * sizeof(xlog_op_header_t);

spin_lock(&cil->xc_cil_lock);

/* move the items to the tail of the CIL */
for (lv = log_vector; lv; lv = lv->lv_next)
xlog_cil_insert(log, ticket, lv->lv_item, lv);
list_move_tail(&lv->lv_item->li_cil, &cil->xc_cil);

ctx->nvecs += diff_iovecs;

/*
* Now transfer enough transaction reservation to the context ticket
* for the checkpoint. The context ticket is special - the unit
* reservation has to grow as well as the current reservation as we
* steal from tickets so we can correctly determine the space used
* during the transaction commit.
*/
if (ctx->ticket->t_curr_res == 0) {
/* first commit in checkpoint, steal the header reservation */
ASSERT(ticket->t_curr_res >= ctx->ticket->t_unit_res + len);
ctx->ticket->t_curr_res = ctx->ticket->t_unit_res;
ticket->t_curr_res -= ctx->ticket->t_unit_res;
}

/* do we need space for more log record headers? */
iclog_space = log->l_iclog_size - log->l_iclog_hsize;
if (len > 0 && (ctx->space_used / iclog_space !=
(ctx->space_used + len) / iclog_space)) {
int hdrs;

hdrs = (len + iclog_space - 1) / iclog_space;
/* need to take into account split region headers, too */
hdrs *= log->l_iclog_hsize + sizeof(struct xlog_op_header);
ctx->ticket->t_unit_res += hdrs;
ctx->ticket->t_curr_res += hdrs;
ticket->t_curr_res -= hdrs;
ASSERT(ticket->t_curr_res >= len);
}
ticket->t_curr_res -= len;
ctx->space_used += len;

spin_unlock(&cil->xc_cil_lock);
}

static void
Expand Down Expand Up @@ -638,7 +657,10 @@ xfs_log_commit_cil(

/* lock out background commit */
down_read(&log->l_cilp->xc_ctx_lock);
xlog_cil_insert_items(log, log_vector, tp->t_ticket, commit_lsn);
if (commit_lsn)
*commit_lsn = log->l_cilp->xc_ctx->sequence;

xlog_cil_insert_items(log, log_vector, tp->t_ticket);

/* check we didn't blow the reservation */
if (tp->t_ticket->t_curr_res < 0)
Expand Down

0 comments on commit 798cc70

Please sign in to comment.