#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 */
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,
static void
xlog_write_region(
- struct xlog_ticket *ticket,
- struct xlog_in_core *iclog,
- uint32_t *log_offset,
- struct xfs_log_iovec *reg,
- int *bytes_left,
- uint32_t *record_cnt,
- uint32_t *data_cnt)
+ struct xlog_write_data *data,
+ struct xfs_log_iovec *reg)
{
- struct xlog_op_header *ophdr = iclog->ic_datap + *log_offset;
+ struct xlog_in_core *iclog = data->iclog;
+ struct xlog_op_header *ophdr = iclog->ic_datap + data->log_offset;
uint32_t rlen;
- ASSERT(*log_offset < iclog->ic_log->l_iclog_size);
- ASSERT(*log_offset % sizeof(int32_t) == 0);
+ ASSERT(data->log_offset < iclog->ic_log->l_iclog_size);
+ ASSERT(data->log_offset % sizeof(int32_t) == 0);
ASSERT(reg->i_len % sizeof(int32_t) == 0);
- *log_offset += sizeof(struct xlog_op_header);
- *bytes_left -= sizeof(struct xlog_op_header);
- *data_cnt += sizeof(struct xlog_op_header);
+ data->log_offset += sizeof(struct xlog_op_header);
+ data->bytes_left -= sizeof(struct xlog_op_header);
+ data->data_cnt += sizeof(struct xlog_op_header);
- ASSERT(iclog->ic_size - *log_offset > 0);
- rlen = min_t(uint32_t, reg->i_len, iclog->ic_size - *log_offset);
+ ASSERT(iclog->ic_size - data->log_offset > 0);
+ rlen = min_t(uint32_t, reg->i_len, iclog->ic_size - data->log_offset);
if (rlen) {
- memcpy(iclog->ic_datap + *log_offset, reg->i_addr, rlen);
- *log_offset += rlen;
- *bytes_left -= rlen;
- *data_cnt += rlen;
+ memcpy(iclog->ic_datap + data->log_offset, reg->i_addr, rlen);
+ data->log_offset += rlen;
+ data->bytes_left -= rlen;
+ data->data_cnt += rlen;
reg->i_addr += rlen;
reg->i_len -= rlen;
}
- 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);
ophdr->oh_clientid = XFS_TRANSACTION;
ophdr->oh_flags = 0;
break;
}
- (*record_cnt)++;
+ data->record_cnt++;
}
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;
}
*/
static int
xlog_write_remainder(
- 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 xfs_log_iovec *reg)
{
int error;
* continuation opheader needs to be accounted to the ticket as the
* space it 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, iclogp, 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;
- xlog_write_region(ticket, *iclogp, log_offset, reg, len,
- record_cnt, data_cnt);
- ticket->t_curr_res -= sizeof(struct xlog_op_header);
+ xlog_write_region(data, reg);
+ data->ticket->t_curr_res -= sizeof(struct xlog_op_header);
return 0;
}
*/
static int
xlog_write_vec(
- 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 xfs_log_vec *lv)
{
- struct xlog_in_core *iclog = *iclogp;
int index = 0;
/* walk the logvec, copying until we run out of space in the iclog */
* 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;
}
/*
* Write the amount that fits into this iclog.
*/
- xlog_write_region(ticket, iclog, log_offset, reg, len,
- record_cnt, data_cnt);
+ xlog_write_region(data, reg);
/*
* We now have an at least partially written iovec, but it can
* complete the iovec.
*/
while (reg->i_len > 0) {
- error = xlog_write_remainder(ticket, &iclog, log_offset,
- len, record_cnt, data_cnt, reg);
+ error = xlog_write_remainder(data, reg);
if (error)
return error;
}
}
- /*
- * 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;
}
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,
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
* 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) {
- error = xlog_write_vec(lv, ticket, &iclog, &log_offset, &len,
- &record_cnt, &data_cnt);
+ error = xlog_write_vec(&data, lv);
if (error)
return error;
}
- ASSERT(len == 0);
+ ASSERT(data.bytes_left == 0);
/*
* We've already been guaranteed that the last writes will fit inside
* 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;
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;
- xlog_rec_header_t *head;
- xlog_in_core_t *iclog;
+ int log_offset;
+ struct xlog_rec_header *head;
+ struct xlog_in_core *iclog;
restart:
spin_lock(&log->l_icloglock);
* 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));
* 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;
* 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;
}