xc_cil_lock is not enough to protect the integrity of a trans logging. Taking the scenario: cpuA cpuB cpuC xlog_cil_insert_format_items() spin_lock(&cil->xc_cil_lock) link transA's items to xc_cil, including item1 spin_unlock(&cil->xc_cil_lock) xlog_cil_push() fetches transA's item under xc_cil_lock issue transB, modify item1 xlog_write(), but now, item1 contains content from transB and we have a broken transA Survive this race issue by putting under the protection of xc_ctx_lock. Meanwhile the xc_cil_lock can be dropped as xc_ctx_lock does it against xlog_cil_insert_items() Signed-off-by: Pingfan Liu <kernelfans@xxxxxxxxx> Cc: "Darrick J. Wong" <darrick.wong@xxxxxxxxxx> Cc: Brian Foster <bfoster@xxxxxxxxxx> To: linux-xfs@xxxxxxxxxxxxxxx Cc: linux-fsdevel@xxxxxxxxxxxxxxx --- fs/xfs/xfs_log_cil.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index 004af09..f8df3b5 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -723,22 +723,6 @@ xlog_cil_push( */ lv = NULL; num_iovecs = 0; - spin_lock(&cil->xc_cil_lock); - while (!list_empty(&cil->xc_cil)) { - struct xfs_log_item *item; - - item = list_first_entry(&cil->xc_cil, - struct xfs_log_item, li_cil); - list_del_init(&item->li_cil); - if (!ctx->lv_chain) - ctx->lv_chain = item->li_lv; - else - lv->lv_next = item->li_lv; - lv = item->li_lv; - item->li_lv = NULL; - num_iovecs += lv->lv_niovecs; - } - spin_unlock(&cil->xc_cil_lock); /* * initialise the new context and attach it to the CIL. Then attach @@ -783,6 +767,25 @@ xlog_cil_push( up_write(&cil->xc_ctx_lock); /* + * cil->xc_cil_lock around this loop can be dropped, since xc_ctx_lock + * protects us against xlog_cil_insert_items(). + */ + while (!list_empty(&cil->xc_cil)) { + struct xfs_log_item *item; + + item = list_first_entry(&cil->xc_cil, + struct xfs_log_item, li_cil); + list_del_init(&item->li_cil); + if (!ctx->lv_chain) + ctx->lv_chain = item->li_lv; + else + lv->lv_next = item->li_lv; + lv = item->li_lv; + item->li_lv = NULL; + num_iovecs += lv->lv_niovecs; + } + + /* * Build a checkpoint transaction header and write it to the log to * begin the transaction. We need to account for the space used by the * transaction header here as it is not accounted for in xlog_write(). -- 2.7.5