aboutsummaryrefslogtreecommitdiffstats
diff options
authorCarlos Maiolino <cem@kernel.org>2025-04-15 13:58:16 +0200
committerCarlos Maiolino <cem@kernel.org>2025-04-15 13:58:16 +0200
commita278637f86a2dfea50275cf158e742f2242c6a3a (patch)
treeb846a0df24774943ba39009f594bc7b3ad9bbb3d
parent08e06c6ea9de7da7a76149b8ff92cecb114b3fa1 (diff)
downloadxfs-linux-xfs_ail_improvements.tar.gz
patch stable_ail_replacementxfs_ail_improvements
-rw-r--r--fs/xfs/xfs_log_cil.c19
-rw-r--r--fs/xfs/xfs_log_priv.h2
-rw-r--r--fs/xfs/xfs_trans.h1
-rw-r--r--fs/xfs/xfs_trans_ail.c109
-rw-r--r--fs/xfs/xfs_trans_priv.h16
5 files changed, 116 insertions, 31 deletions
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
index 0560afe2123c7d..a3bd85bc41b8c1 100644
--- a/fs/xfs/xfs_log_cil.c
+++ b/fs/xfs/xfs_log_cil.c
@@ -107,6 +107,8 @@ xlog_cil_ctx_alloc(void)
INIT_LIST_HEAD(&ctx->committing);
INIT_LIST_HEAD(&ctx->log_items);
INIT_LIST_HEAD(&ctx->lv_chain);
+ INIT_LIST_HEAD(&ctx->ail_items);
+ INIT_LIST_HEAD(&ctx->ail_link);
INIT_WORK(&ctx->push_work, xlog_cil_push_work);
return ctx;
}
@@ -693,6 +695,7 @@ xlog_cil_insert_items(
static inline void
xlog_cil_ail_insert_batch(
struct xfs_ail *ailp,
+ struct xlog_chkpt *ctx,
struct xfs_ail_cursor *cur,
struct xfs_log_item **log_items,
int nr_items,
@@ -702,7 +705,7 @@ xlog_cil_ail_insert_batch(
spin_lock(&ailp->ail_lock);
/* xfs_trans_ail_update_bulk drops ailp->ail_lock */
- xfs_trans_ail_update_bulk(ailp, cur, log_items, nr_items, commit_lsn);
+ xfs_trans_ail_update_bulk(ailp, ctx, cur, log_items, nr_items, commit_lsn);
for (i = 0; i < nr_items; i++) {
struct xfs_log_item *lip = log_items[i];
@@ -837,7 +840,7 @@ xlog_cil_ail_insert(
*/
spin_lock(&ailp->ail_lock);
if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0)
- xfs_trans_ail_update(ailp, lip, item_lsn);
+ xfs_trans_ail_update(ailp, ctx, lip, item_lsn);
else
spin_unlock(&ailp->ail_lock);
if (lip->li_ops->iop_unpin)
@@ -848,7 +851,7 @@ xlog_cil_ail_insert(
/* Item is a candidate for bulk AIL insert. */
log_items[i++] = lv->lv_item;
if (i >= LOG_ITEM_BATCH_SIZE) {
- xlog_cil_ail_insert_batch(ailp, &cur, log_items,
+ xlog_cil_ail_insert_batch(ailp, ctx, &cur, log_items,
LOG_ITEM_BATCH_SIZE, ctx->start_lsn);
i = 0;
}
@@ -856,11 +859,17 @@ xlog_cil_ail_insert(
/* make sure we insert the remainder! */
if (i)
- xlog_cil_ail_insert_batch(ailp, &cur, log_items, i,
+ xlog_cil_ail_insert_batch(ailp, ctx, &cur, log_items, i,
ctx->start_lsn);
spin_lock(&ailp->ail_lock);
xfs_trans_ail_cursor_done(&cur);
+
+ /*
+ * All items should be in ctx->ail_items by now, add it
+ * to the ail
+ */
+ list_add_tail(&ctx->ail_link, &ailp->ail_head);
spin_unlock(&ailp->ail_lock);
}
@@ -924,9 +933,7 @@ xlog_cil_committed(
spin_unlock(&ctx->cil->xc_push_lock);
xlog_cil_free_logvec(&ctx->lv_chain);
-
xfs_discard_extents(mp, extents);
- kfree(ctx);
}
void
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index 0f4db91675fbb9..5bb9f34d9ca224 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -228,6 +228,8 @@ struct xlog_chkpt {
struct xfs_busy_extents *busy_extents;
struct list_head log_items; /* log items in chkpt */
struct list_head lv_chain; /* logvecs being pushed */
+ struct list_head ail_items; /* ctx items in AIL */
+ struct list_head ail_link; /* Link to AIL head */
struct list_head iclog_entry;
struct list_head committing; /* ctx committing list */
struct work_struct push_work;
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 2b366851e9a4f4..aa8529f0aec4ea 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -42,6 +42,7 @@ struct xfs_log_item {
/* delayed logging */
struct list_head li_cil; /* CIL pointers */
+ struct xlog_chkpt *li_ctx; /* chkpt ctx this item belongs to */
struct xfs_log_vec *li_lv; /* active log vector */
struct xfs_log_vec *li_lv_shadow; /* standby vector */
xfs_csn_t li_seq; /* CIL commit seq */
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 0fcb1828e598fb..272f05a4ee55ba 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -74,6 +74,31 @@ xfs_ail_check(
#endif /* DEBUG */
/*
+ * Return a pointer to the first item in the AIL. If the AIL is empty, then
+ * return NULL.
+ */
+static inline struct xfs_log_item *
+xfs_ail_min(
+ struct xfs_ail *ailp)
+{
+ struct xlog_chkpt *ctx = NULL;
+
+ if (list_empty(&ailp->ail_head))
+ return NULL;
+
+ list_for_each_entry(ctx, &ailp->ail_head, ail_link) {
+ if (list_empty(&ctx->ail_items))
+ continue;
+
+ return list_first_entry_or_null(&ctx->ail_items,
+ struct xfs_log_item,
+ li_ail);
+ }
+
+ return NULL;
+}
+
+/*
* Return a pointer to the last item in the AIL. If the AIL is empty, then
* return NULL.
*/
@@ -81,23 +106,54 @@ static struct xfs_log_item *
xfs_ail_max(
struct xfs_ail *ailp)
{
+
+ struct xlog_chkpt *ctx;
+ struct xfs_log_item *lip = NULL;
+
if (list_empty(&ailp->ail_head))
return NULL;
- return list_entry(ailp->ail_head.prev, struct xfs_log_item, li_ail);
+ /*
+ * Search for the last item added to the ail, but take into
+ * consideration the very last context might be empty.
+ */
+ list_for_each_entry_reverse(ctx, &ailp->ail_head, ail_link) {
+ if (list_empty(&ctx->ail_items))
+ continue;
+
+ lip = list_last_entry(&ctx->ail_items,
+ struct xfs_log_item, li_ail);
+ }
+
+ return lip;
}
/*
* Return a pointer to the item which follows the given item in the AIL. If
* the given item is the last item in the list, then return NULL.
+ *
+ * Note we are dealing with two ordered lists here, the ail contexts list
+ * and the items list within each context.
+ * We need to search for the existence of both the next item in the
+ * current context and a possible next item on the next context.
*/
static struct xfs_log_item *
xfs_ail_next(
struct xfs_ail *ailp,
struct xfs_log_item *lip)
{
- if (lip->li_ail.next == &ailp->ail_head)
- return NULL;
+ struct xlog_chkpt *ctx = lip->li_ctx;
+
+ if (lip->li_ail.next == &ctx->ail_items) {
+ if (ctx->ail_link.next == &ailp->ail_head) {
+ return NULL;
+ } else {
+ ctx = list_first_entry(&ctx->ail_link, struct xlog_chkpt,
+ ail_link);
+ return list_first_entry(&ctx->ail_items, struct xfs_log_item,
+ li_ail);
+ }
+ }
return list_first_entry(&lip->li_ail, struct xfs_log_item, li_ail);
}
@@ -240,11 +296,15 @@ __xfs_trans_ail_cursor_last(
struct xfs_ail *ailp,
xfs_lsn_t lsn)
{
+ struct xlog_chkpt *ctx;
struct xfs_log_item *lip;
- list_for_each_entry_reverse(lip, &ailp->ail_head, li_ail) {
- if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0)
- return lip;
+ list_for_each_entry_reverse(ctx, &ailp->ail_head, ail_link) {
+ /* XXX: Can I assume we'll have a context here? */
+ list_for_each_entry_reverse(lip, &ctx->ail_items, li_ail) {
+ if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0)
+ return lip;
+ }
}
return NULL;
}
@@ -275,6 +335,7 @@ xfs_trans_ail_cursor_last(
static void
xfs_ail_splice(
struct xfs_ail *ailp,
+ struct xlog_chkpt *ctx,
struct xfs_ail_cursor *cur,
struct list_head *list,
xfs_lsn_t lsn)
@@ -306,12 +367,14 @@ xfs_ail_splice(
* Finally perform the splice. Unless the AIL was empty,
* lip points to the item in the AIL _after_ which the new
* items should go. If lip is null the AIL was empty, so
- * the new items go at the head of the AIL.
+ * the new items go at the head of the new checkpoint context.
*/
- if (lip)
- list_splice(list, &lip->li_ail);
- else
- list_splice(list, &ailp->ail_head);
+
+ /*
+ * Whether the context is empty or not, we can splice straight to
+ * the ctx tail
+ */
+ list_splice_tail(list, &ctx->ail_items);
}
/*
@@ -322,8 +385,16 @@ xfs_ail_delete(
struct xfs_ail *ailp,
struct xfs_log_item *lip)
{
+ struct xlog_chkpt *ctx = lip->li_ctx;
+
xfs_ail_check(ailp, lip);
list_del(&lip->li_ail);
+ lip->li_ctx = NULL;
+
+ if (list_empty(&ctx->ail_items)) {
+ list_del(&ctx->ail_link);
+ kfree(ctx);
+ }
xfs_trans_ail_cursor_clear(ailp, lip);
}
@@ -801,6 +872,7 @@ xfs_ail_update_finish(
void
xfs_trans_ail_update_bulk(
struct xfs_ail *ailp,
+ struct xlog_chkpt *ctx,
struct xfs_ail_cursor *cur,
struct xfs_log_item **log_items,
int nr_items,
@@ -811,6 +883,14 @@ xfs_trans_ail_update_bulk(
int i;
LIST_HEAD(tmp);
+ /*
+ * FIXME: Only caller with a NULL ctx for now, is the recovery
+ * code. Just ignore it as I'm not interested in recovery
+ * code for now
+ */
+ if (!ctx)
+ return;
+
ASSERT(nr_items > 0); /* Not required, but true. */
mlip = xfs_ail_min(ailp);
@@ -830,11 +910,12 @@ xfs_trans_ail_update_bulk(
trace_xfs_ail_insert(lip, 0, lsn);
}
lip->li_lsn = lsn;
+ lip->li_ctx = ctx;
list_add_tail(&lip->li_ail, &tmp);
}
if (!list_empty(&tmp))
- xfs_ail_splice(ailp, cur, &tmp, lsn);
+ xfs_ail_splice(ailp, ctx, cur, &tmp, lsn);
/*
* If this is the first insert, wake up the push daemon so it can
@@ -860,7 +941,9 @@ xfs_trans_ail_insert(
xfs_lsn_t lsn)
{
spin_lock(&ailp->ail_lock);
- xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
+
+ /* This comes from log recovery, we should create its own context */
+ xfs_trans_ail_update_bulk(ailp, NULL, NULL, &lip, 1, lsn);
}
/*
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index bd841df93021ff..5c04f0d035d6a8 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -12,6 +12,7 @@ struct xfs_mount;
struct xfs_trans;
struct xfs_ail;
struct xfs_log_vec;
+struct xlog_chkpt;
void xfs_trans_init(struct xfs_mount *);
@@ -70,28 +71,19 @@ struct xfs_ail {
* From xfs_trans_ail.c
*/
void xfs_trans_ail_update_bulk(struct xfs_ail *ailp,
+ struct xlog_chkpt *ctx,
struct xfs_ail_cursor *cur,
struct xfs_log_item **log_items, int nr_items,
xfs_lsn_t lsn) __releases(ailp->ail_lock);
-/*
- * Return a pointer to the first item in the AIL. If the AIL is empty, then
- * return NULL.
- */
-static inline struct xfs_log_item *
-xfs_ail_min(
- struct xfs_ail *ailp)
-{
- return list_first_entry_or_null(&ailp->ail_head, struct xfs_log_item,
- li_ail);
-}
static inline void
xfs_trans_ail_update(
struct xfs_ail *ailp,
+ struct xlog_chkpt *ctx,
struct xfs_log_item *lip,
xfs_lsn_t lsn) __releases(ailp->ail_lock)
{
- xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
+ xfs_trans_ail_update_bulk(ailp, ctx, NULL, &lip, 1, lsn);
}
void xfs_trans_ail_insert(struct xfs_ail *ailp, struct xfs_log_item *lip,