aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_trans_ail.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2011-07-17 23:40:16 -0400
committerAlex Elder <aelder@sgi.com>2011-07-20 19:37:20 -0400
commit1d8c95a363bf8cd4d4182dd19c01693b635311c2 (patch)
tree839d26eb6a1f6814c687e2c6855feb377b74c0f9 /fs/xfs/xfs_trans_ail.c
parentad1a2c878ca70829874b4fcc83223cccb4e26dab (diff)
xfs: use a cursor for bulk AIL insertion
Delayed logging can insert tens of thousands of log items into the AIL at the same LSN. When the committing of log commit records occur, we can get insertions occurring at an LSN that is not at the end of the AIL. If there are thousands of items in the AIL on the tail LSN, each insertion has to walk the AIL to find the correct place to insert the new item into the AIL. This can consume large amounts of CPU time and block other operations from occurring while the traversals are in progress. To avoid this repeated walk, use a AIL cursor to record where we should be inserting the new items into the AIL without having to repeat the walk. The cursor infrastructure already provides this functionality for push walks, so is a simple extension of existing code. While this will not avoid the initial walk, it will avoid repeating it tens of thousands of times during a single checkpoint commit. This version includes logic improvements from Christoph Hellwig. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Alex Elder <aelder@sgi.com>
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);