On Wed, Oct 30, 2019 at 09:37:11PM +0800, Pingfan Liu wrote: > 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() How did you trigger this race? Is there a test case to reproduce, or did you figure this out via code inspection? --D > > 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 >