From: Christoph Hellwig Date: Thu, 22 May 2025 05:12:39 +0000 (+0200) Subject: xfs: factor the split iclog handling out of xlog_write_partial X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=e6fb853816411962cb8b473f68a2a3afb003fd4f;p=users%2Fhch%2Fmisc.git xfs: factor the split iclog handling out of xlog_write_partial 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 --- 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); + } } /*