diff options
Diffstat (limited to 'fs/xfs/xfs_trans_ail.c')
-rw-r--r-- | fs/xfs/xfs_trans_ail.c | 67 |
1 files changed, 29 insertions, 38 deletions
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 43233e92f0f6..c15aa29fa169 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c | |||
@@ -299,7 +299,7 @@ xfs_trans_ail_cursor_last( | |||
299 | * Splice the log item list into the AIL at the given LSN. We splice to the | 299 | * Splice the log item list into the AIL at the given LSN. We splice to the |
300 | * tail of the given LSN to maintain insert order for push traversals. The | 300 | * tail of the given LSN to maintain insert order for push traversals. The |
301 | * cursor is optional, allowing repeated updates to the same LSN to avoid | 301 | * cursor is optional, allowing repeated updates to the same LSN to avoid |
302 | * repeated traversals. | 302 | * repeated traversals. This should not be called with an empty list. |
303 | */ | 303 | */ |
304 | static void | 304 | static void |
305 | xfs_ail_splice( | 305 | xfs_ail_splice( |
@@ -308,50 +308,39 @@ xfs_ail_splice( | |||
308 | struct list_head *list, | 308 | struct list_head *list, |
309 | xfs_lsn_t lsn) | 309 | xfs_lsn_t lsn) |
310 | { | 310 | { |
311 | struct xfs_log_item *lip = cur ? cur->item : NULL; | 311 | struct xfs_log_item *lip; |
312 | struct xfs_log_item *next_lip; | 312 | |
313 | ASSERT(!list_empty(list)); | ||
313 | 314 | ||
314 | /* | 315 | /* |
315 | * Get a new cursor if we don't have a placeholder or the existing one | 316 | * Use the cursor to determine the insertion point if one is |
316 | * has been invalidated. | 317 | * provided. If not, or if the one we got is not valid, |
318 | * find the place in the AIL where the items belong. | ||
317 | */ | 319 | */ |
318 | if (!lip || (__psint_t)lip & 1) { | 320 | lip = cur ? cur->item : NULL; |
321 | if (!lip || (__psint_t) lip & 1) | ||
319 | lip = __xfs_trans_ail_cursor_last(ailp, lsn); | 322 | lip = __xfs_trans_ail_cursor_last(ailp, lsn); |
320 | 323 | ||
321 | if (!lip) { | 324 | /* |
322 | /* The list is empty, so just splice and return. */ | 325 | * If a cursor is provided, we know we're processing the AIL |
323 | if (cur) | 326 | * in lsn order, and future items to be spliced in will |
324 | cur->item = NULL; | 327 | * follow the last one being inserted now. Update the |
325 | list_splice(list, &ailp->xa_ail); | 328 | * cursor to point to that last item, now while we have a |
326 | return; | 329 | * reliable pointer to it. |
327 | } | 330 | */ |
328 | } | 331 | if (cur) |
332 | cur->item = list_entry(list->prev, struct xfs_log_item, li_ail); | ||
329 | 333 | ||
330 | /* | 334 | /* |
331 | * Our cursor points to the item we want to insert _after_, so we have | 335 | * Finally perform the splice. Unless the AIL was empty, |
332 | * to update the cursor to point to the end of the list we are splicing | 336 | * lip points to the item in the AIL _after_ which the new |
333 | * in so that it points to the correct location for the next splice. | 337 | * items should go. If lip is null the AIL was empty, so |
334 | * i.e. before the splice | 338 | * the new items go at the head of the AIL. |
335 | * | ||
336 | * lsn -> lsn -> lsn + x -> lsn + x ... | ||
337 | * ^ | ||
338 | * | cursor points here | ||
339 | * | ||
340 | * After the splice we have: | ||
341 | * | ||
342 | * lsn -> lsn -> lsn -> lsn -> .... -> lsn -> lsn + x -> lsn + x ... | ||
343 | * ^ ^ | ||
344 | * | cursor points here | needs to move here | ||
345 | * | ||
346 | * So we set the cursor to the last item in the list to be spliced | ||
347 | * before we execute the splice, resulting in the cursor pointing to | ||
348 | * the correct item after the splice occurs. | ||
349 | */ | 339 | */ |
350 | if (cur) { | 340 | if (lip) |
351 | next_lip = list_entry(list->prev, struct xfs_log_item, li_ail); | 341 | list_splice(list, &lip->li_ail); |
352 | cur->item = next_lip; | 342 | else |
353 | } | 343 | list_splice(list, &ailp->xa_ail); |
354 | list_splice(list, &lip->li_ail); | ||
355 | } | 344 | } |
356 | 345 | ||
357 | /* | 346 | /* |
@@ -682,6 +671,7 @@ xfs_trans_ail_update_bulk( | |||
682 | int i; | 671 | int i; |
683 | LIST_HEAD(tmp); | 672 | LIST_HEAD(tmp); |
684 | 673 | ||
674 | ASSERT(nr_items > 0); /* Not required, but true. */ | ||
685 | mlip = xfs_ail_min(ailp); | 675 | mlip = xfs_ail_min(ailp); |
686 | 676 | ||
687 | for (i = 0; i < nr_items; i++) { | 677 | for (i = 0; i < nr_items; i++) { |
@@ -701,7 +691,8 @@ xfs_trans_ail_update_bulk( | |||
701 | list_add(&lip->li_ail, &tmp); | 691 | list_add(&lip->li_ail, &tmp); |
702 | } | 692 | } |
703 | 693 | ||
704 | xfs_ail_splice(ailp, cur, &tmp, lsn); | 694 | if (!list_empty(&tmp)) |
695 | xfs_ail_splice(ailp, cur, &tmp, lsn); | ||
705 | 696 | ||
706 | if (!mlip_changed) { | 697 | if (!mlip_changed) { |
707 | spin_unlock(&ailp->xa_lock); | 698 | spin_unlock(&ailp->xa_lock); |