mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 19:13:47 +02:00
xfs: improve the calling convention for the xlog_write helpers
The xlog_write chain passes around the same seven variables that are often passed by reference. Add a xlog_write_data structure to contain them to improve code generation and readability. This change increases the generated code size by about 140 bytes for my x86_64 build, which is hopefully worth the much easier to follow code: $ size fs/xfs/xfs_log.o* text data bss dec hex filename 29300 1730 176 31206 79e6 fs/xfs/xfs_log.o 29160 1730 176 31066 795a fs/xfs/xfs_log.o.old Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Carlos Maiolino <cem@kernel.org>
This commit is contained in:
parent
a82d7aac75
commit
a3eb1f9cf8
187
fs/xfs/xfs_log.c
187
fs/xfs/xfs_log.c
|
|
@ -22,6 +22,15 @@
|
|||
#include "xfs_health.h"
|
||||
#include "xfs_zone_alloc.h"
|
||||
|
||||
struct xlog_write_data {
|
||||
struct xlog_ticket *ticket;
|
||||
struct xlog_in_core *iclog;
|
||||
uint32_t bytes_left;
|
||||
uint32_t record_cnt;
|
||||
uint32_t data_cnt;
|
||||
int log_offset;
|
||||
};
|
||||
|
||||
struct kmem_cache *xfs_log_ticket_cache;
|
||||
|
||||
/* Local miscellaneous function prototypes */
|
||||
|
|
@ -43,10 +52,7 @@ STATIC void xlog_state_do_callback(
|
|||
STATIC int
|
||||
xlog_state_get_iclog_space(
|
||||
struct xlog *log,
|
||||
int len,
|
||||
struct xlog_in_core **iclog,
|
||||
struct xlog_ticket *ticket,
|
||||
int *logoffsetp);
|
||||
struct xlog_write_data *data);
|
||||
STATIC void
|
||||
xlog_sync(
|
||||
struct xlog *log,
|
||||
|
|
@ -1876,23 +1882,19 @@ xlog_print_trans(
|
|||
|
||||
static inline void
|
||||
xlog_write_iovec(
|
||||
struct xlog_in_core *iclog,
|
||||
uint32_t *log_offset,
|
||||
void *data,
|
||||
uint32_t write_len,
|
||||
int *bytes_left,
|
||||
uint32_t *record_cnt,
|
||||
uint32_t *data_cnt)
|
||||
struct xlog_write_data *data,
|
||||
void *buf,
|
||||
uint32_t buf_len)
|
||||
{
|
||||
ASSERT(*log_offset < iclog->ic_log->l_iclog_size);
|
||||
ASSERT(*log_offset % sizeof(int32_t) == 0);
|
||||
ASSERT(write_len % sizeof(int32_t) == 0);
|
||||
ASSERT(data->log_offset < data->iclog->ic_log->l_iclog_size);
|
||||
ASSERT(data->log_offset % sizeof(int32_t) == 0);
|
||||
ASSERT(buf_len % sizeof(int32_t) == 0);
|
||||
|
||||
memcpy(iclog->ic_datap + *log_offset, data, write_len);
|
||||
*log_offset += write_len;
|
||||
*bytes_left -= write_len;
|
||||
(*record_cnt)++;
|
||||
*data_cnt += write_len;
|
||||
memcpy(data->iclog->ic_datap + data->log_offset, buf, buf_len);
|
||||
data->log_offset += buf_len;
|
||||
data->bytes_left -= buf_len;
|
||||
data->record_cnt++;
|
||||
data->data_cnt += buf_len;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1902,17 +1904,12 @@ xlog_write_iovec(
|
|||
static void
|
||||
xlog_write_full(
|
||||
struct xfs_log_vec *lv,
|
||||
struct xlog_ticket *ticket,
|
||||
struct xlog_in_core *iclog,
|
||||
uint32_t *log_offset,
|
||||
uint32_t *len,
|
||||
uint32_t *record_cnt,
|
||||
uint32_t *data_cnt)
|
||||
struct xlog_write_data *data)
|
||||
{
|
||||
int index;
|
||||
|
||||
ASSERT(*log_offset + *len <= iclog->ic_size ||
|
||||
iclog->ic_state == XLOG_STATE_WANT_SYNC);
|
||||
ASSERT(data->log_offset + data->bytes_left <= data->iclog->ic_size ||
|
||||
data->iclog->ic_state == XLOG_STATE_WANT_SYNC);
|
||||
|
||||
/*
|
||||
* Ordered log vectors have no regions to write so this
|
||||
|
|
@ -1922,40 +1919,32 @@ xlog_write_full(
|
|||
struct xfs_log_iovec *reg = &lv->lv_iovecp[index];
|
||||
struct xlog_op_header *ophdr = reg->i_addr;
|
||||
|
||||
ophdr->oh_tid = cpu_to_be32(ticket->t_tid);
|
||||
xlog_write_iovec(iclog, log_offset, reg->i_addr,
|
||||
reg->i_len, len, record_cnt, data_cnt);
|
||||
ophdr->oh_tid = cpu_to_be32(data->ticket->t_tid);
|
||||
xlog_write_iovec(data, reg->i_addr, reg->i_len);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
xlog_write_get_more_iclog_space(
|
||||
struct xlog_ticket *ticket,
|
||||
struct xlog_in_core **iclogp,
|
||||
uint32_t *log_offset,
|
||||
uint32_t len,
|
||||
uint32_t *record_cnt,
|
||||
uint32_t *data_cnt)
|
||||
struct xlog_write_data *data)
|
||||
{
|
||||
struct xlog_in_core *iclog = *iclogp;
|
||||
struct xlog *log = iclog->ic_log;
|
||||
struct xlog *log = data->iclog->ic_log;
|
||||
int error;
|
||||
|
||||
spin_lock(&log->l_icloglock);
|
||||
ASSERT(iclog->ic_state == XLOG_STATE_WANT_SYNC);
|
||||
xlog_state_finish_copy(log, iclog, *record_cnt, *data_cnt);
|
||||
error = xlog_state_release_iclog(log, iclog, ticket);
|
||||
ASSERT(data->iclog->ic_state == XLOG_STATE_WANT_SYNC);
|
||||
xlog_state_finish_copy(log, data->iclog, data->record_cnt,
|
||||
data->data_cnt);
|
||||
error = xlog_state_release_iclog(log, data->iclog, data->ticket);
|
||||
spin_unlock(&log->l_icloglock);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = xlog_state_get_iclog_space(log, len, &iclog, ticket,
|
||||
log_offset);
|
||||
error = xlog_state_get_iclog_space(log, data);
|
||||
if (error)
|
||||
return error;
|
||||
*record_cnt = 0;
|
||||
*data_cnt = 0;
|
||||
*iclogp = iclog;
|
||||
data->record_cnt = 0;
|
||||
data->data_cnt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1968,14 +1957,8 @@ xlog_write_get_more_iclog_space(
|
|||
static int
|
||||
xlog_write_partial(
|
||||
struct xfs_log_vec *lv,
|
||||
struct xlog_ticket *ticket,
|
||||
struct xlog_in_core **iclogp,
|
||||
uint32_t *log_offset,
|
||||
uint32_t *len,
|
||||
uint32_t *record_cnt,
|
||||
uint32_t *data_cnt)
|
||||
struct xlog_write_data *data)
|
||||
{
|
||||
struct xlog_in_core *iclog = *iclogp;
|
||||
struct xlog_op_header *ophdr;
|
||||
int index = 0;
|
||||
uint32_t rlen;
|
||||
|
|
@ -1997,25 +1980,23 @@ xlog_write_partial(
|
|||
* Hence if there isn't space for region data after the
|
||||
* opheader, then we need to start afresh with a new iclog.
|
||||
*/
|
||||
if (iclog->ic_size - *log_offset <=
|
||||
if (data->iclog->ic_size - data->log_offset <=
|
||||
sizeof(struct xlog_op_header)) {
|
||||
error = xlog_write_get_more_iclog_space(ticket,
|
||||
&iclog, log_offset, *len, record_cnt,
|
||||
data_cnt);
|
||||
error = xlog_write_get_more_iclog_space(data);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
ophdr = reg->i_addr;
|
||||
rlen = min_t(uint32_t, reg->i_len, iclog->ic_size - *log_offset);
|
||||
rlen = min_t(uint32_t, reg->i_len,
|
||||
data->iclog->ic_size - data->log_offset);
|
||||
|
||||
ophdr->oh_tid = cpu_to_be32(ticket->t_tid);
|
||||
ophdr->oh_tid = cpu_to_be32(data->ticket->t_tid);
|
||||
ophdr->oh_len = cpu_to_be32(rlen - sizeof(struct xlog_op_header));
|
||||
if (rlen != reg->i_len)
|
||||
ophdr->oh_flags |= XLOG_CONTINUE_TRANS;
|
||||
|
||||
xlog_write_iovec(iclog, log_offset, reg->i_addr,
|
||||
rlen, len, record_cnt, data_cnt);
|
||||
xlog_write_iovec(data, reg->i_addr, rlen);
|
||||
|
||||
/* If we wrote the whole region, move to the next. */
|
||||
if (rlen == reg->i_len)
|
||||
|
|
@ -2050,23 +2031,22 @@ xlog_write_partial(
|
|||
* consumes hasn't been accounted to the lv we are
|
||||
* writing.
|
||||
*/
|
||||
*len += sizeof(struct xlog_op_header);
|
||||
error = xlog_write_get_more_iclog_space(ticket,
|
||||
&iclog, log_offset, *len, record_cnt,
|
||||
data_cnt);
|
||||
data->bytes_left += sizeof(struct xlog_op_header);
|
||||
error = xlog_write_get_more_iclog_space(data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ophdr = iclog->ic_datap + *log_offset;
|
||||
ophdr->oh_tid = cpu_to_be32(ticket->t_tid);
|
||||
ophdr = data->iclog->ic_datap + data->log_offset;
|
||||
ophdr->oh_tid = cpu_to_be32(data->ticket->t_tid);
|
||||
ophdr->oh_clientid = XFS_TRANSACTION;
|
||||
ophdr->oh_res2 = 0;
|
||||
ophdr->oh_flags = XLOG_WAS_CONT_TRANS;
|
||||
|
||||
ticket->t_curr_res -= sizeof(struct xlog_op_header);
|
||||
*log_offset += sizeof(struct xlog_op_header);
|
||||
*data_cnt += sizeof(struct xlog_op_header);
|
||||
*len -= sizeof(struct xlog_op_header);
|
||||
data->ticket->t_curr_res -=
|
||||
sizeof(struct xlog_op_header);
|
||||
data->log_offset += sizeof(struct xlog_op_header);
|
||||
data->data_cnt += sizeof(struct xlog_op_header);
|
||||
data->bytes_left -= sizeof(struct xlog_op_header);
|
||||
|
||||
/*
|
||||
* If rlen fits in the iclog, then end the region
|
||||
|
|
@ -2074,26 +2054,19 @@ xlog_write_partial(
|
|||
*/
|
||||
reg_offset += rlen;
|
||||
rlen = reg->i_len - reg_offset;
|
||||
if (rlen <= iclog->ic_size - *log_offset)
|
||||
if (rlen <= data->iclog->ic_size - data->log_offset)
|
||||
ophdr->oh_flags |= XLOG_END_TRANS;
|
||||
else
|
||||
ophdr->oh_flags |= XLOG_CONTINUE_TRANS;
|
||||
|
||||
rlen = min_t(uint32_t, rlen, iclog->ic_size - *log_offset);
|
||||
rlen = min_t(uint32_t, rlen,
|
||||
data->iclog->ic_size - data->log_offset);
|
||||
ophdr->oh_len = cpu_to_be32(rlen);
|
||||
|
||||
xlog_write_iovec(iclog, log_offset,
|
||||
reg->i_addr + reg_offset,
|
||||
rlen, len, record_cnt, data_cnt);
|
||||
|
||||
xlog_write_iovec(data, reg->i_addr + reg_offset, rlen);
|
||||
} while (ophdr->oh_flags & XLOG_CONTINUE_TRANS);
|
||||
}
|
||||
|
||||
/*
|
||||
* No more iovecs remain in this logvec so return the next log vec to
|
||||
* the caller so it can go back to fast path copying.
|
||||
*/
|
||||
*iclogp = iclog;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2146,12 +2119,12 @@ xlog_write(
|
|||
uint32_t len)
|
||||
|
||||
{
|
||||
struct xlog_in_core *iclog = NULL;
|
||||
struct xfs_log_vec *lv;
|
||||
uint32_t record_cnt = 0;
|
||||
uint32_t data_cnt = 0;
|
||||
int error = 0;
|
||||
int log_offset;
|
||||
struct xlog_write_data data = {
|
||||
.ticket = ticket,
|
||||
.bytes_left = len,
|
||||
};
|
||||
int error;
|
||||
|
||||
if (ticket->t_curr_res < 0) {
|
||||
xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES,
|
||||
|
|
@ -2160,12 +2133,11 @@ xlog_write(
|
|||
xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR);
|
||||
}
|
||||
|
||||
error = xlog_state_get_iclog_space(log, len, &iclog, ticket,
|
||||
&log_offset);
|
||||
error = xlog_state_get_iclog_space(log, &data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ASSERT(log_offset <= iclog->ic_size - 1);
|
||||
ASSERT(data.log_offset <= data.iclog->ic_size - 1);
|
||||
|
||||
/*
|
||||
* If we have a context pointer, pass it the first iclog we are
|
||||
|
|
@ -2173,7 +2145,7 @@ xlog_write(
|
|||
* ordering.
|
||||
*/
|
||||
if (ctx)
|
||||
xlog_cil_set_ctx_write_state(ctx, iclog);
|
||||
xlog_cil_set_ctx_write_state(ctx, data.iclog);
|
||||
|
||||
list_for_each_entry(lv, lv_chain, lv_list) {
|
||||
/*
|
||||
|
|
@ -2181,10 +2153,8 @@ xlog_write(
|
|||
* the partial copy loop which can handle this case.
|
||||
*/
|
||||
if (lv->lv_niovecs &&
|
||||
lv->lv_bytes > iclog->ic_size - log_offset) {
|
||||
error = xlog_write_partial(lv, ticket, &iclog,
|
||||
&log_offset, &len, &record_cnt,
|
||||
&data_cnt);
|
||||
lv->lv_bytes > data.iclog->ic_size - data.log_offset) {
|
||||
error = xlog_write_partial(lv, &data);
|
||||
if (error) {
|
||||
/*
|
||||
* We have no iclog to release, so just return
|
||||
|
|
@ -2193,11 +2163,10 @@ xlog_write(
|
|||
return error;
|
||||
}
|
||||
} else {
|
||||
xlog_write_full(lv, ticket, iclog, &log_offset,
|
||||
&len, &record_cnt, &data_cnt);
|
||||
xlog_write_full(lv, &data);
|
||||
}
|
||||
}
|
||||
ASSERT(len == 0);
|
||||
ASSERT(data.bytes_left == 0);
|
||||
|
||||
/*
|
||||
* We've already been guaranteed that the last writes will fit inside
|
||||
|
|
@ -2206,8 +2175,8 @@ xlog_write(
|
|||
* iclog with the number of bytes written here.
|
||||
*/
|
||||
spin_lock(&log->l_icloglock);
|
||||
xlog_state_finish_copy(log, iclog, record_cnt, 0);
|
||||
error = xlog_state_release_iclog(log, iclog, ticket);
|
||||
xlog_state_finish_copy(log, data.iclog, data.record_cnt, 0);
|
||||
error = xlog_state_release_iclog(log, data.iclog, ticket);
|
||||
spin_unlock(&log->l_icloglock);
|
||||
|
||||
return error;
|
||||
|
|
@ -2529,10 +2498,7 @@ xlog_state_done_syncing(
|
|||
STATIC int
|
||||
xlog_state_get_iclog_space(
|
||||
struct xlog *log,
|
||||
int len,
|
||||
struct xlog_in_core **iclogp,
|
||||
struct xlog_ticket *ticket,
|
||||
int *logoffsetp)
|
||||
struct xlog_write_data *data)
|
||||
{
|
||||
int log_offset;
|
||||
struct xlog_rec_header *head;
|
||||
|
|
@ -2567,7 +2533,7 @@ xlog_state_get_iclog_space(
|
|||
* must be written.
|
||||
*/
|
||||
if (log_offset == 0) {
|
||||
ticket->t_curr_res -= log->l_iclog_hsize;
|
||||
data->ticket->t_curr_res -= log->l_iclog_hsize;
|
||||
head->h_cycle = cpu_to_be32(log->l_curr_cycle);
|
||||
head->h_lsn = cpu_to_be64(
|
||||
xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block));
|
||||
|
|
@ -2597,7 +2563,8 @@ xlog_state_get_iclog_space(
|
|||
* reference to the iclog.
|
||||
*/
|
||||
if (!atomic_add_unless(&iclog->ic_refcnt, -1, 1))
|
||||
error = xlog_state_release_iclog(log, iclog, ticket);
|
||||
error = xlog_state_release_iclog(log, iclog,
|
||||
data->ticket);
|
||||
spin_unlock(&log->l_icloglock);
|
||||
if (error)
|
||||
return error;
|
||||
|
|
@ -2610,16 +2577,16 @@ xlog_state_get_iclog_space(
|
|||
* iclogs (to mark it taken), this particular iclog will release/sync
|
||||
* to disk in xlog_write().
|
||||
*/
|
||||
if (len <= iclog->ic_size - iclog->ic_offset)
|
||||
iclog->ic_offset += len;
|
||||
if (data->bytes_left <= iclog->ic_size - iclog->ic_offset)
|
||||
iclog->ic_offset += data->bytes_left;
|
||||
else
|
||||
xlog_state_switch_iclogs(log, iclog, iclog->ic_size);
|
||||
*iclogp = iclog;
|
||||
data->iclog = iclog;
|
||||
|
||||
ASSERT(iclog->ic_offset <= iclog->ic_size);
|
||||
spin_unlock(&log->l_icloglock);
|
||||
|
||||
*logoffsetp = log_offset;
|
||||
data->log_offset = log_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user