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); |
