[PATCH 11/17] xfs: factor the split iclog handling out of xlog_write_partial

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add a new xlog_write_remainder handler that writes a continuation op
header and copies all fitting data out of xlog_write_partial into a
separate helper to clean up xlog_write_partial a bit.

Signed-off-by: Christoph Hellwig <hch@xxxxxx>
---
 fs/xfs/xfs_log.c | 94 +++++++++++++++++++++++++++---------------------
 1 file changed, 54 insertions(+), 40 deletions(-)

diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 00b1174d4a30..aa158bc4d36b 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -2023,6 +2023,49 @@ xlog_write_get_more_iclog_space(
 	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
@@ -2041,11 +2084,11 @@ xlog_write_partial(
 {
 	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
@@ -2067,52 +2110,23 @@ xlog_write_partial(
 				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);
+		}
 	}
 
 	/*
-- 
2.47.2





[Index of Archives]     [XFS Filesystem Development (older mail)]     [Linux Filesystem Development]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux RAID]     [Linux SCSI]


  Powered by Linux