aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_trans_ail.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_trans_ail.c')
-rw-r--r--fs/xfs/xfs_trans_ail.c109
1 files changed, 88 insertions, 21 deletions
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 5fc2380092c8..9a69dc06ea86 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -272,9 +272,9 @@ xfs_trans_ail_cursor_clear(
272} 272}
273 273
274/* 274/*
275 * Return the item in the AIL with the current lsn. 275 * Initialise the cursor to the first item in the AIL with the given @lsn.
276 * Return the current tree generation number for use 276 * This searches the list from lowest LSN to highest. Pass a @lsn of zero
277 * in calls to xfs_trans_next_ail(). 277 * to initialise the cursor to the first item in the AIL.
278 */ 278 */
279xfs_log_item_t * 279xfs_log_item_t *
280xfs_trans_ail_cursor_first( 280xfs_trans_ail_cursor_first(
@@ -300,31 +300,97 @@ out:
300} 300}
301 301
302/* 302/*
303 * splice the log item list into the AIL at the given LSN. 303 * Initialise the cursor to the last item in the AIL with the given @lsn.
304 * This searches the list from highest LSN to lowest. If there is no item with
305 * the value of @lsn, then it sets the cursor to the last item with an LSN lower
306 * than @lsn.
307 */
308static struct xfs_log_item *
309__xfs_trans_ail_cursor_last(
310 struct xfs_ail *ailp,
311 xfs_lsn_t lsn)
312{
313 xfs_log_item_t *lip;
314
315 list_for_each_entry_reverse(lip, &ailp->xa_ail, li_ail) {
316 if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0)
317 return lip;
318 }
319 return NULL;
320}
321
322/*
323 * Initialise the cursor to the last item in the AIL with the given @lsn.
324 * This searches the list from highest LSN to lowest.
325 */
326struct xfs_log_item *
327xfs_trans_ail_cursor_last(
328 struct xfs_ail *ailp,
329 struct xfs_ail_cursor *cur,
330 xfs_lsn_t lsn)
331{
332 xfs_trans_ail_cursor_init(ailp, cur);
333 cur->item = __xfs_trans_ail_cursor_last(ailp, lsn);
334 return cur->item;
335}
336
337/*
338 * splice the log item list into the AIL at the given LSN. We splice to the
339 * tail of the given LSN to maintain insert order for push traversals. The
340 * cursor is optional, allowing repeated updates to the same LSN to avoid
341 * repeated traversals.
304 */ 342 */
305static void 343static void
306xfs_ail_splice( 344xfs_ail_splice(
307 struct xfs_ail *ailp, 345 struct xfs_ail *ailp,
308 struct list_head *list, 346 struct xfs_ail_cursor *cur,
309 xfs_lsn_t lsn) 347 struct list_head *list,
348 xfs_lsn_t lsn)
310{ 349{
311 xfs_log_item_t *next_lip; 350 struct xfs_log_item *lip = cur ? cur->item : NULL;
351 struct xfs_log_item *next_lip;
312 352
313 /* If the list is empty, just insert the item. */ 353 /*
314 if (list_empty(&ailp->xa_ail)) { 354 * Get a new cursor if we don't have a placeholder or the existing one
315 list_splice(list, &ailp->xa_ail); 355 * has been invalidated.
316 return; 356 */
357 if (!lip || (__psint_t)lip & 1) {
358 lip = __xfs_trans_ail_cursor_last(ailp, lsn);
359
360 if (!lip) {
361 /* The list is empty, so just splice and return. */
362 if (cur)
363 cur->item = NULL;
364 list_splice(list, &ailp->xa_ail);
365 return;
366 }
317 } 367 }
318 368
319 list_for_each_entry_reverse(next_lip, &ailp->xa_ail, li_ail) { 369 /*
320 if (XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0) 370 * Our cursor points to the item we want to insert _after_, so we have
321 break; 371 * to update the cursor to point to the end of the list we are splicing
372 * in so that it points to the correct location for the next splice.
373 * i.e. before the splice
374 *
375 * lsn -> lsn -> lsn + x -> lsn + x ...
376 * ^
377 * | cursor points here
378 *
379 * After the splice we have:
380 *
381 * lsn -> lsn -> lsn -> lsn -> .... -> lsn -> lsn + x -> lsn + x ...
382 * ^ ^
383 * | cursor points here | needs to move here
384 *
385 * So we set the cursor to the last item in the list to be spliced
386 * before we execute the splice, resulting in the cursor pointing to
387 * the correct item after the splice occurs.
388 */
389 if (cur) {
390 next_lip = list_entry(list->prev, struct xfs_log_item, li_ail);
391 cur->item = next_lip;
322 } 392 }
323 393 list_splice(list, &lip->li_ail);
324 ASSERT(&next_lip->li_ail == &ailp->xa_ail ||
325 XFS_LSN_CMP(next_lip->li_lsn, lsn) <= 0);
326
327 list_splice_init(list, &next_lip->li_ail);
328} 394}
329 395
330/* 396/*
@@ -645,6 +711,7 @@ xfs_trans_unlocked_item(
645void 711void
646xfs_trans_ail_update_bulk( 712xfs_trans_ail_update_bulk(
647 struct xfs_ail *ailp, 713 struct xfs_ail *ailp,
714 struct xfs_ail_cursor *cur,
648 struct xfs_log_item **log_items, 715 struct xfs_log_item **log_items,
649 int nr_items, 716 int nr_items,
650 xfs_lsn_t lsn) __releases(ailp->xa_lock) 717 xfs_lsn_t lsn) __releases(ailp->xa_lock)
@@ -674,7 +741,7 @@ xfs_trans_ail_update_bulk(
674 list_add(&lip->li_ail, &tmp); 741 list_add(&lip->li_ail, &tmp);
675 } 742 }
676 743
677 xfs_ail_splice(ailp, &tmp, lsn); 744 xfs_ail_splice(ailp, cur, &tmp, lsn);
678 745
679 if (!mlip_changed) { 746 if (!mlip_changed) {
680 spin_unlock(&ailp->xa_lock); 747 spin_unlock(&ailp->xa_lock);