Skip to content

Commit 016a233

Browse files
dgchinnerdchinner
authored andcommitted
xfs: Add order IDs to log items in CIL
Before we split the ordered CIL up into per cpu lists, we need a mechanism to track the order of the items in the CIL. We need to do this because there are rules around the order in which related items must physically appear in the log even inside a single checkpoint transaction. An example of this is intents - an intent must appear in the log before it's intent done record so that log recovery can cancel the intent correctly. If we have these two records misordered in the CIL, then they will not be recovered correctly by journal replay. We also will not be able to move items to the tail of the CIL list when they are relogged, hence the log items will need some mechanism to allow the correct log item order to be recreated before we write log items to the hournal. Hence we need to have a mechanism for recording global order of transactions in the log items so that we can recover that order from un-ordered per-cpu lists. Do this with a simple monotonic increasing commit counter in the CIL context. Each log item in the transaction gets stamped with the current commit order ID before it is added to the CIL. If the item is already in the CIL, leave it where it is instead of moving it to the tail of the list and instead sort the list before we start the push work. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
1 parent df7a4a2 commit 016a233

3 files changed

Lines changed: 33 additions & 8 deletions

File tree

fs/xfs/xfs_log_cil.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ xlog_cil_insert_items(
550550
int len = 0;
551551
int iovhdr_res = 0, split_res = 0, ctx_res = 0;
552552
int space_used;
553+
int order;
553554
struct xlog_cil_pcp *cilpcp;
554555

555556
ASSERT(tp);
@@ -645,23 +646,22 @@ xlog_cil_insert_items(
645646
put_cpu_ptr(cilpcp);
646647

647648
/*
648-
* Now (re-)position everything modified at the tail of the CIL.
649+
* Now update the order of everything modified in the transaction
650+
* and insert items into the CIL if they aren't already there.
649651
* We do this here so we only need to take the CIL lock once during
650652
* the transaction commit.
651653
*/
654+
order = atomic_inc_return(&ctx->order_id);
652655
spin_lock(&cil->xc_cil_lock);
653656
list_for_each_entry(lip, &tp->t_items, li_trans) {
654657
/* Skip items which aren't dirty in this transaction. */
655658
if (!test_bit(XFS_LI_DIRTY, &lip->li_flags))
656659
continue;
657660

658-
/*
659-
* Only move the item if it isn't already at the tail. This is
660-
* to prevent a transient list_empty() state when reinserting
661-
* an item that is already the only item in the CIL.
662-
*/
663-
if (!list_is_last(&lip->li_cil, &cil->xc_cil))
664-
list_move_tail(&lip->li_cil, &cil->xc_cil);
661+
lip->li_order_id = order;
662+
if (!list_empty(&lip->li_cil))
663+
continue;
664+
list_add_tail(&lip->li_cil, &cil->xc_cil);
665665
}
666666

667667
spin_unlock(&cil->xc_cil_lock);
@@ -1082,6 +1082,26 @@ xlog_cil_build_trans_hdr(
10821082
tic->t_curr_res -= lvhdr->lv_bytes;
10831083
}
10841084

1085+
/*
1086+
* CIL item reordering compare function. We want to order in ascending ID order,
1087+
* but we want to leave items with the same ID in the order they were added to
1088+
* the list. This is important for operations like reflink where we log 4 order
1089+
* dependent intents in a single transaction when we overwrite an existing
1090+
* shared extent with a new shared extent. i.e. BUI(unmap), CUI(drop),
1091+
* CUI (inc), BUI(remap)...
1092+
*/
1093+
static int
1094+
xlog_cil_order_cmp(
1095+
void *priv,
1096+
const struct list_head *a,
1097+
const struct list_head *b)
1098+
{
1099+
struct xfs_log_item *l1 = container_of(a, struct xfs_log_item, li_cil);
1100+
struct xfs_log_item *l2 = container_of(b, struct xfs_log_item, li_cil);
1101+
1102+
return l1->li_order_id > l2->li_order_id;
1103+
}
1104+
10851105
/*
10861106
* Pull all the log vectors off the items in the CIL, and remove the items from
10871107
* the CIL. We don't need the CIL lock here because it's only needed on the
@@ -1101,6 +1121,8 @@ xlog_cil_build_lv_chain(
11011121
{
11021122
struct xfs_log_vec *lv = NULL;
11031123

1124+
list_sort(NULL, &cil->xc_cil, xlog_cil_order_cmp);
1125+
11041126
while (!list_empty(&cil->xc_cil)) {
11051127
struct xfs_log_item *item;
11061128

@@ -1114,6 +1136,7 @@ xlog_cil_build_lv_chain(
11141136
}
11151137

11161138
list_del_init(&item->li_cil);
1139+
item->li_order_id = 0;
11171140
if (!ctx->lv_chain)
11181141
ctx->lv_chain = item->li_lv;
11191142
else

fs/xfs/xfs_log_priv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ struct xfs_cil_ctx {
229229
struct list_head committing; /* ctx committing list */
230230
struct work_struct discard_endio_work;
231231
struct work_struct push_work;
232+
atomic_t order_id;
232233
};
233234

234235
/*

fs/xfs/xfs_trans.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct xfs_log_item {
4545
struct xfs_log_vec *li_lv; /* active log vector */
4646
struct xfs_log_vec *li_lv_shadow; /* standby vector */
4747
xfs_csn_t li_seq; /* CIL commit seq */
48+
uint32_t li_order_id; /* CIL commit order */
4849
};
4950

5051
/*

0 commit comments

Comments
 (0)