]> www.infradead.org Git - users/hch/misc.git/commitdiff
xfs: factor the split iclog handling out of xlog_write_partial
authorChristoph Hellwig <hch@lst.de>
Thu, 22 May 2025 05:12:39 +0000 (07:12 +0200)
committerChristoph Hellwig <hch@lst.de>
Tue, 10 Jun 2025 05:09:55 +0000 (07:09 +0200)
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@lst.de>
fs/xfs/xfs_log.c

index 00b1174d4a30a4596a06f528b3b80f3318ddad1f..aa158bc4d36b3497d0c5d67f8e21c9fa7317bd15 100644 (file)
@@ -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);
+               }
        }
 
        /*