Commit a3eb1f9c authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Carlos Maiolino
Browse files

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: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarCarlos Maiolino <cem@kernel.org>
parent a82d7aac
Loading
Loading
Loading
Loading
+77 −110
Original line number Diff line number Diff line
@@ -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;
}