From: Dave Chinner dchinner@redhat.com
mainline-inclusion from mainline-v5.14-rc4 commit c45aba40cf5b2988c0bebee8c9b846c88aa651eb category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4V7IK CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
-------------------------------------------------
Pass the CIL context to xlog_write() rather than a pointer to a LSN variable. Only the CIL checkpoint calls to xlog_write() need to know about the start LSN of the writes, so rework xlog_write to directly write the LSNs into the CIL context structure.
This removes the commit_lsn variable from xlog_cil_push_work(), so now we only have to issue the commit record ordering wakeup from there.
Signed-off-by: Dave Chinner dchinner@redhat.com Reviewed-by: Christoph Hellwig hch@lst.de Reviewed-by: Darrick J. Wong djwong@kernel.org Signed-off-by: Darrick J. Wong djwong@kernel.org Signed-off-by: Lihong Kou koulihong@huawei.com Reviewed-by: guoxuenan guoxuenan@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/xfs/xfs_log.c | 18 +++++++++------ fs/xfs/xfs_log_cil.c | 52 ++++++++++++++++++++++++++++++------------- fs/xfs/xfs_log_priv.h | 7 ++++-- 3 files changed, 52 insertions(+), 25 deletions(-)
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index a9e5b5025d14..7f31fb697135 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -881,7 +881,7 @@ xlog_write_unmount_record( /* account for space used by record data */ ticket->t_curr_res -= sizeof(ulf);
- return xlog_write(log, &vec, ticket, NULL, NULL, XLOG_UNMOUNT_TRANS); + return xlog_write(log, NULL, &vec, ticket, NULL, XLOG_UNMOUNT_TRANS); }
/* @@ -2322,9 +2322,9 @@ xlog_write_copy_finish( int xlog_write( struct xlog *log, + struct xfs_cil_ctx *ctx, struct xfs_log_vec *log_vector, struct xlog_ticket *ticket, - xfs_lsn_t *start_lsn, struct xlog_in_core **commit_iclog, uint optype) { @@ -2355,8 +2355,6 @@ xlog_write( }
len = xlog_write_calc_vec_length(ticket, log_vector, optype); - if (start_lsn) - *start_lsn = 0; while (lv && (!lv->lv_niovecs || index < lv->lv_niovecs)) { void *ptr; int log_offset; @@ -2369,9 +2367,15 @@ xlog_write( ASSERT(log_offset <= iclog->ic_size - 1); ptr = iclog->ic_datap + log_offset;
- /* Start_lsn is the first lsn written to. */ - if (start_lsn && !*start_lsn) - *start_lsn = be64_to_cpu(iclog->ic_header.h_lsn); + /* + * If we have a context pointer, pass it the first iclog we are + * writing to so it can record state needed for iclog write + * ordering. + */ + if (ctx) { + xlog_cil_set_ctx_write_state(ctx, iclog); + ctx = NULL; + }
/* * This loop writes out as many regions as can fit in the amount diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 52586e64a7c6..4460d9981dfa 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -659,6 +659,30 @@ xlog_cil_process_committed( } }
+/* +* Record the LSN of the iclog we were just granted space to start writing into. +* If the context doesn't have a start_lsn recorded, then this iclog will +* contain the start record for the checkpoint. Otherwise this write contains +* the commit record for the checkpoint. +*/ +void +xlog_cil_set_ctx_write_state( + struct xfs_cil_ctx *ctx, + struct xlog_in_core *iclog) +{ + struct xfs_cil *cil = ctx->cil; + xfs_lsn_t lsn = be64_to_cpu(iclog->ic_header.h_lsn); + + ASSERT(!ctx->commit_lsn); + spin_lock(&cil->xc_push_lock); + if (!ctx->start_lsn) + ctx->start_lsn = lsn; + else + ctx->commit_lsn = lsn; + spin_unlock(&cil->xc_push_lock); +} + + /* * Write out the commit record of a checkpoint transaction associated with the * given ticket to close off a running log write. Return the lsn of the commit @@ -666,26 +690,26 @@ xlog_cil_process_committed( */ static int xlog_cil_write_commit_record( - struct xlog *log, - struct xlog_ticket *ticket, - struct xlog_in_core **iclog, - xfs_lsn_t *lsn) + struct xfs_cil_ctx *ctx, + struct xlog_in_core **iclog) { - struct xfs_log_iovec reg = { + struct xlog *log = ctx->cil->xc_log; + struct xfs_log_iovec reg = { .i_addr = NULL, .i_len = 0, .i_type = XLOG_REG_TYPE_COMMIT, }; - struct xfs_log_vec vec = { + struct xfs_log_vec vec = { .lv_niovecs = 1, .lv_iovecp = ®, }; - int error; + int error;
if (xlog_is_shutdown(log)) return -EIO;
- error = xlog_write(log, &vec, ticket, lsn, iclog, XLOG_COMMIT_TRANS); + error = xlog_write(log, ctx, &vec, ctx->ticket, iclog, + XLOG_COMMIT_TRANS); if (error) xfs_force_shutdown(log->l_mp, SHUTDOWN_LOG_IO_ERROR); return error; @@ -723,7 +747,6 @@ xlog_cil_push_work( struct xfs_log_iovec lhdr; struct xfs_log_vec lvhdr = { NULL }; xfs_lsn_t preflush_tail_lsn; - xfs_lsn_t commit_lsn; xfs_csn_t push_seq; struct bio bio; DECLARE_COMPLETION_ONSTACK(bdev_flush); @@ -895,8 +918,7 @@ xlog_cil_push_work( */ wait_for_completion(&bdev_flush);
- error = xlog_write(log, &lvhdr, tic, &ctx->start_lsn, NULL, - XLOG_START_TRANS); + error = xlog_write(log, ctx, &lvhdr, tic, NULL, XLOG_START_TRANS); if (error) goto out_abort_free_ticket;
@@ -934,8 +956,7 @@ xlog_cil_push_work( } spin_unlock(&cil->xc_push_lock);
- error = xlog_cil_write_commit_record(log, tic, &commit_iclog, - &commit_lsn); + error = xlog_cil_write_commit_record(ctx, &commit_iclog); if (error) goto out_abort_free_ticket;
@@ -962,7 +983,6 @@ xlog_cil_push_work( * and wake up anyone who is waiting for the commit to complete. */ spin_lock(&cil->xc_push_lock); - ctx->commit_lsn = commit_lsn; wake_up_all(&cil->xc_commit_wait); spin_unlock(&cil->xc_push_lock);
@@ -978,11 +998,11 @@ xlog_cil_push_work( * iclog header lsn and compare it to the commit lsn to determine if we * need to wait on iclogs or not. */ - if (ctx->start_lsn != commit_lsn) { + if (ctx->start_lsn != ctx->commit_lsn) { xfs_lsn_t plsn;
plsn = be64_to_cpu(commit_iclog->ic_prev->ic_header.h_lsn); - if (plsn && XFS_LSN_CMP(plsn, commit_lsn) < 0) { + if (plsn && XFS_LSN_CMP(plsn, ctx->commit_lsn) < 0) { /* * Waiting on ic_force_wait orders the completion of * iclogs older than ic_prev. Hence we only need to wait diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index 3b007fd1f82c..ad45a204bbc9 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -504,8 +504,8 @@ xlog_write_adv_cnt(void **ptr, int *len, int *off, size_t bytes)
void xlog_print_tic_res(struct xfs_mount *mp, struct xlog_ticket *ticket); void xlog_print_trans(struct xfs_trans *); -int xlog_write(struct xlog *log, struct xfs_log_vec *log_vector, - struct xlog_ticket *tic, xfs_lsn_t *start_lsn, +int xlog_write(struct xlog *log, struct xfs_cil_ctx *ctx, + struct xfs_log_vec *log_vector, struct xlog_ticket *tic, struct xlog_in_core **commit_iclog, uint optype); void xfs_log_ticket_ungrant(struct xlog *log, struct xlog_ticket *ticket); void xfs_log_ticket_regrant(struct xlog *log, struct xlog_ticket *ticket); @@ -579,6 +579,9 @@ void xlog_cil_destroy(struct xlog *log); bool xlog_cil_empty(struct xlog *log); void xlog_cil_commit(struct xlog *log, struct xfs_trans *tp, xfs_csn_t *commit_seq, bool regrant); +void xlog_cil_set_ctx_write_state(struct xfs_cil_ctx *ctx, + struct xlog_in_core *iclog); +
/* * CIL force routines