diff options
-rw-r--r-- | fs/xfs/xfs_log_cil.c | 19 | ||||
-rw-r--r-- | fs/xfs/xfs_log_priv.h | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_trans.h | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_ail.c | 109 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_priv.h | 16 |
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, |