return 0;
}
+/*
+ * Write the remainder or at least the start of it for an iovec spans more than
+ * a single iclog.
+ *
+ * First we release the iclog we currently have, then we get a new iclog and add
+ * a new opheader. If we did not finish the iovec, the caller will call us
+ * again until we are done.
+ *
+ * This is complicated by the tail of a region using all the space in an iclog
+ * and hence requiring us to release the iclog and get a new one before
+ * returning to the outer loop. We must always guarantee that we exit this
+ * with at least space for log transaction opheaders left in the current iclog.
+ */
+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 xfs_log_iovec *reg)
+{
+ int error;
+
+ /*
+ * Ensure we include the continuation opheader in the space we need in
+ * the new iclog by adding that size to the length we require. This
+ * 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);
+ 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);
+ return 0;
+}
+
/*
* Write log vectors into a single iclog which is smaller than the current chain
* length. We write until we cannot fit a full record into the remaining space
{
struct xlog_in_core *iclog = *iclogp;
int index = 0;
- int error;
/* walk the logvec, copying until we run out of space in the iclog */
for (index = 0; index < lv->lv_niovecs; index++) {
struct xfs_log_iovec *reg = &lv->lv_iovecp[index];
+ int error;
/*
* The first region of a continuation must have a non-zero
return error;
}
+ /*
+ * Write the amount that fits into this iclog.
+ */
xlog_write_region(ticket, iclog, log_offset, reg, len,
record_cnt, data_cnt);
- /* If we wrote the whole region, move to the next. */
- if (reg->i_len == 0)
- continue;
-
/*
- * We now have a partially written iovec, but it can span
- * multiple iclogs so we loop here. First we release the iclog
- * we currently have, then we get a new iclog and add a new
- * opheader. Then we continue copying from where we were until
- * we either complete the iovec or fill the iclog. If we
- * complete the iovec, then we increment the index and go right
- * back to the top of the outer loop. if we fill the iclog, we
- * run the inner loop again.
- *
- * This is complicated by the tail of a region using all the
- * space in an iclog and hence requiring us to release the iclog
- * and get a new one before returning to the outer loop. We must
- * always guarantee that we exit this inner loop with at least
- * space for log transaction opheaders left in the current
- * iclog, hence we cannot just terminate the loop at the end
- * of the of the continuation. So we loop while there is no
- * space left in the current iclog, and check for the end of the
- * continuation after getting a new iclog.
+ * We now have an at least partially written iovec, but it can
+ * span multiple iclogs so we loop over iclogs here until we
+ * complete the iovec.
*/
- do {
- /*
- * Ensure we include the continuation opheader in the
- * space we need in the new iclog by adding that size
- * to the length we require. This 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, &iclog,
- log_offset, *len, record_cnt, data_cnt);
+ while (reg->i_len > 0) {
+ error = xlog_write_remainder(ticket, &iclog, log_offset,
+ len, record_cnt, data_cnt, reg);
if (error)
return error;
-
- xlog_write_region(ticket, iclog, log_offset, reg, len,
- record_cnt, data_cnt);
- ticket->t_curr_res -= sizeof(struct xlog_op_header);
- } while (reg->i_len > 0);
+ }
}
/*