Commit 7492c5b4 authored by Dave Chinner's avatar Dave Chinner Committed by Ben Myers

xfs: Reduce allocations during CIL insertion

Now that we have the size of the object before the formatting pass
is called, we can allocation the log vector and it's buffer in a
single allocation rather than two separate allocations.

Store the size of the allocated buffer in the log vector so that
we potentially avoid allocation for future modifications of the
object.

While touching this code, remove the IOP_FORMAT definition.
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarMark Tinguely <tinguely@sgi.com>
Signed-off-by: default avatarBen Myers <bpm@sgi.com>
parent 166d1368
...@@ -27,6 +27,7 @@ struct xfs_log_vec { ...@@ -27,6 +27,7 @@ struct xfs_log_vec {
struct xfs_log_item *lv_item; /* owner */ struct xfs_log_item *lv_item; /* owner */
char *lv_buf; /* formatted buffer */ char *lv_buf; /* formatted buffer */
int lv_buf_len; /* size of formatted buffer */ int lv_buf_len; /* size of formatted buffer */
int lv_size; /* size of allocated lv */
}; };
#define XFS_LOG_VEC_ORDERED (-1) #define XFS_LOG_VEC_ORDERED (-1)
......
...@@ -80,6 +80,36 @@ xlog_cil_init_post_recovery( ...@@ -80,6 +80,36 @@ xlog_cil_init_post_recovery(
log->l_curr_block); log->l_curr_block);
} }
STATIC int
xlog_cil_lv_item_format(
struct xfs_log_item *lip,
struct xfs_log_vec *lv)
{
int index;
char *ptr;
/* format new vectors into array */
lip->li_ops->iop_format(lip, lv->lv_iovecp);
/* copy data into existing array */
ptr = lv->lv_buf;
for (index = 0; index < lv->lv_niovecs; index++) {
struct xfs_log_iovec *vec = &lv->lv_iovecp[index];
memcpy(ptr, vec->i_addr, vec->i_len);
vec->i_addr = ptr;
ptr += vec->i_len;
}
/*
* some size calculations for log vectors over-estimate, so the caller
* doesn't know the amount of space actually used by the item. Return
* the byte count to the caller so they can check and store it
* appropriately.
*/
return ptr - lv->lv_buf;
}
/* /*
* Format log item into a flat buffers * Format log item into a flat buffers
* *
...@@ -111,7 +141,7 @@ xlog_cil_prepare_log_vecs( ...@@ -111,7 +141,7 @@ xlog_cil_prepare_log_vecs(
struct xfs_trans *tp) struct xfs_trans *tp)
{ {
struct xfs_log_item_desc *lidp; struct xfs_log_item_desc *lidp;
struct xfs_log_vec *lv = NULL; struct xfs_log_vec *prev_lv = NULL;
struct xfs_log_vec *ret_lv = NULL; struct xfs_log_vec *ret_lv = NULL;
...@@ -123,12 +153,10 @@ xlog_cil_prepare_log_vecs( ...@@ -123,12 +153,10 @@ xlog_cil_prepare_log_vecs(
list_for_each_entry(lidp, &tp->t_items, lid_trans) { list_for_each_entry(lidp, &tp->t_items, lid_trans) {
struct xfs_log_item *lip = lidp->lid_item; struct xfs_log_item *lip = lidp->lid_item;
struct xfs_log_vec *new_lv; struct xfs_log_vec *lv;
void *ptr; int niovecs = 0;
int index; int nbytes = 0;
int len = 0; int buf_size;
uint niovecs = 0;
uint nbytes = 0;
bool ordered = false; bool ordered = false;
/* Skip items which aren't dirty in this transaction. */ /* Skip items which aren't dirty in this transaction. */
...@@ -150,48 +178,39 @@ xlog_cil_prepare_log_vecs( ...@@ -150,48 +178,39 @@ xlog_cil_prepare_log_vecs(
if (niovecs == XFS_LOG_VEC_ORDERED) { if (niovecs == XFS_LOG_VEC_ORDERED) {
ordered = true; ordered = true;
niovecs = 0; niovecs = 0;
nbytes = 0;
} }
new_lv = kmem_zalloc(sizeof(*new_lv) + /* calc buffer size */
niovecs * sizeof(struct xfs_log_iovec), buf_size = sizeof(struct xfs_log_vec) + nbytes +
KM_SLEEP|KM_NOFS); niovecs * sizeof(struct xfs_log_iovec);
new_lv->lv_item = lip; /* allocate new data chunk */
new_lv->lv_niovecs = niovecs; lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS);
lv->lv_item = lip;
lv->lv_size = buf_size;
lv->lv_niovecs = niovecs;
if (ordered) { if (ordered) {
/* track as an ordered logvec */ /* track as an ordered logvec */
new_lv->lv_buf_len = XFS_LOG_VEC_ORDERED; ASSERT(lip->li_lv == NULL);
goto next; lv->lv_buf_len = XFS_LOG_VEC_ORDERED;
goto insert;
} }
/* The allocated iovec region lies beyond the log vector. */ /* The allocated iovec region lies beyond the log vector. */
new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1]; lv->lv_iovecp = (struct xfs_log_iovec *)&lv[1];
/* build the vector array and calculate it's length */
IOP_FORMAT(new_lv->lv_item, new_lv->lv_iovecp);
for (index = 0; index < new_lv->lv_niovecs; index++)
len += new_lv->lv_iovecp[index].i_len;
new_lv->lv_buf_len = len; /* The allocated data region lies beyond the iovec region */
new_lv->lv_buf = kmem_alloc(new_lv->lv_buf_len, lv->lv_buf = (char *)lv + buf_size - nbytes;
KM_SLEEP|KM_NOFS);
ptr = new_lv->lv_buf;
for (index = 0; index < new_lv->lv_niovecs; index++) {
struct xfs_log_iovec *vec = &new_lv->lv_iovecp[index];
memcpy(ptr, vec->i_addr, vec->i_len);
vec->i_addr = ptr;
ptr += vec->i_len;
}
ASSERT(ptr == new_lv->lv_buf + new_lv->lv_buf_len);
next: lv->lv_buf_len = xlog_cil_lv_item_format(lip, lv);
ASSERT(lv->lv_buf_len <= nbytes);
insert:
if (!ret_lv) if (!ret_lv)
ret_lv = new_lv; ret_lv = lv;
else else
lv->lv_next = new_lv; prev_lv->lv_next = lv;
lv = new_lv; prev_lv = lv;
} }
return ret_lv; return ret_lv;
...@@ -228,7 +247,6 @@ xfs_cil_prepare_item( ...@@ -228,7 +247,6 @@ xfs_cil_prepare_item(
*len += lv->lv_buf_len - old->lv_buf_len; *len += lv->lv_buf_len - old->lv_buf_len;
*diff_iovecs += lv->lv_niovecs - old->lv_niovecs; *diff_iovecs += lv->lv_niovecs - old->lv_niovecs;
kmem_free(old->lv_buf);
kmem_free(old); kmem_free(old);
} else { } else {
/* new lv, must pin the log item */ /* new lv, must pin the log item */
...@@ -354,7 +372,6 @@ xlog_cil_free_logvec( ...@@ -354,7 +372,6 @@ xlog_cil_free_logvec(
for (lv = log_vector; lv; ) { for (lv = log_vector; lv; ) {
struct xfs_log_vec *next = lv->lv_next; struct xfs_log_vec *next = lv->lv_next;
kmem_free(lv->lv_buf);
kmem_free(lv); kmem_free(lv);
lv = next; lv = next;
} }
......
...@@ -77,7 +77,6 @@ struct xfs_item_ops { ...@@ -77,7 +77,6 @@ struct xfs_item_ops {
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
}; };
#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp)
#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip) #define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip)
#define IOP_UNPIN(ip, remove) (*(ip)->li_ops->iop_unpin)(ip, remove) #define IOP_UNPIN(ip, remove) (*(ip)->li_ops->iop_unpin)(ip, remove)
#define IOP_PUSH(ip, list) (*(ip)->li_ops->iop_push)(ip, list) #define IOP_PUSH(ip, list) (*(ip)->li_ops->iop_push)(ip, list)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment