diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 423ceaf0aeb03e2508e1a52aa5819051678a88b6..b20b15761e9c3426bc8d224a38cec1f7d4464c74 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -185,6 +185,22 @@ xlog_cil_prepare_log_vecs( buf_size = sizeof(struct xfs_log_vec) + nbytes + niovecs * sizeof(struct xfs_log_iovec); + /* compare to existing item size */ + if (lip->li_lv && buf_size <= lip->li_lv->lv_size) { + /* same or smaller, optimise common overwrite case */ + lv = lip->li_lv; + lv->lv_next = NULL; + + if (ordered) + goto insert; + + /* Ensure the lv is set up according to ->iop_size */ + lv->lv_niovecs = niovecs; + lv->lv_buf = (char *)lv + buf_size - nbytes; + lv->lv_buf_len = xlog_cil_lv_item_format(lip, lv); + goto insert; + } + /* allocate new data chunk */ lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS); lv->lv_item = lip; @@ -204,8 +220,8 @@ xlog_cil_prepare_log_vecs( lv->lv_buf = (char *)lv + buf_size - nbytes; lv->lv_buf_len = xlog_cil_lv_item_format(lip, lv); - ASSERT(lv->lv_buf_len <= nbytes); insert: + ASSERT(lv->lv_buf_len <= nbytes); if (!ret_lv) ret_lv = lv; else @@ -230,7 +246,17 @@ xfs_cil_prepare_item( { struct xfs_log_vec *old = lv->lv_item->li_lv; - if (old) { + if (!old) { + /* new lv, must pin the log item */ + ASSERT(!lv->lv_item->li_lv); + + if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) { + *len += lv->lv_buf_len; + *diff_iovecs += lv->lv_niovecs; + } + lv->lv_item->li_ops->iop_pin(lv->lv_item); + + } else if (old != lv) { /* existing lv on log item, space used is a delta */ ASSERT((old->lv_buf && old->lv_buf_len && old->lv_niovecs) || old->lv_buf_len == XFS_LOG_VEC_ORDERED); @@ -249,15 +275,8 @@ xfs_cil_prepare_item( *diff_iovecs += lv->lv_niovecs - old->lv_niovecs; kmem_free(old); } else { - /* new lv, must pin the log item */ - ASSERT(!lv->lv_item->li_lv); - - if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) { - *len += lv->lv_buf_len; - *diff_iovecs += lv->lv_niovecs; - } - IOP_PIN(lv->lv_item); - + /* re-used lv */ + /* XXX: can't account for len/diff_iovecs yet */ } /* attach new log vector to log item */ @@ -733,18 +752,13 @@ xfs_log_commit_cil( if (flags & XFS_TRANS_RELEASE_LOG_RES) log_flags = XFS_LOG_REL_PERM_RESERV; - /* - * Do all the hard work of formatting items (including memory - * allocation) outside the CIL context lock. This prevents stalling CIL - * pushes when we are low on memory and a transaction commit spends a - * lot of time in memory reclaim. - */ + /* lock out background commit */ + down_read(&log->l_cilp->xc_ctx_lock); + log_vector = xlog_cil_prepare_log_vecs(tp); if (!log_vector) return ENOMEM; - /* lock out background commit */ - down_read(&log->l_cilp->xc_ctx_lock); if (commit_lsn) *commit_lsn = log->l_cilp->xc_ctx->sequence; diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 24bbdcd297c794eb9de40a51545092ccd1f00e3d..4786170baeb0b891227ec8597cc7f1876aa17310 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -77,7 +77,6 @@ struct xfs_item_ops { void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); }; -#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip) #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_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip)