aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_log.c4
-rw-r--r--fs/xfs/xfs_log_recover.c61
-rw-r--r--fs/xfs/xfs_trans_ail.c207
-rw-r--r--fs/xfs/xfs_trans_priv.h55
4 files changed, 218 insertions, 109 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 0b02c6443551..4184085d44af 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -900,7 +900,7 @@ xfs_log_move_tail(xfs_mount_t *mp,
900int 900int
901xfs_log_need_covered(xfs_mount_t *mp) 901xfs_log_need_covered(xfs_mount_t *mp)
902{ 902{
903 int needed = 0, gen; 903 int needed = 0;
904 xlog_t *log = mp->m_log; 904 xlog_t *log = mp->m_log;
905 905
906 if (!xfs_fs_writable(mp)) 906 if (!xfs_fs_writable(mp))
@@ -909,7 +909,7 @@ xfs_log_need_covered(xfs_mount_t *mp)
909 spin_lock(&log->l_icloglock); 909 spin_lock(&log->l_icloglock);
910 if (((log->l_covered_state == XLOG_STATE_COVER_NEED) || 910 if (((log->l_covered_state == XLOG_STATE_COVER_NEED) ||
911 (log->l_covered_state == XLOG_STATE_COVER_NEED2)) 911 (log->l_covered_state == XLOG_STATE_COVER_NEED2))
912 && !xfs_trans_first_ail(mp, &gen) 912 && !xfs_trans_first_ail(mp, NULL)
913 && xlog_iclogs_empty(log)) { 913 && xlog_iclogs_empty(log)) {
914 if (log->l_covered_state == XLOG_STATE_COVER_NEED) 914 if (log->l_covered_state == XLOG_STATE_COVER_NEED)
915 log->l_covered_state = XLOG_STATE_COVER_DONE; 915 log->l_covered_state = XLOG_STATE_COVER_DONE;
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 199c8ea36474..37ba4899f3e6 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -54,10 +54,8 @@ STATIC void xlog_recover_insert_item_backq(xlog_recover_item_t **q,
54 xlog_recover_item_t *item); 54 xlog_recover_item_t *item);
55#if defined(DEBUG) 55#if defined(DEBUG)
56STATIC void xlog_recover_check_summary(xlog_t *); 56STATIC void xlog_recover_check_summary(xlog_t *);
57STATIC void xlog_recover_check_ail(xfs_mount_t *, xfs_log_item_t *, int);
58#else 57#else
59#define xlog_recover_check_summary(log) 58#define xlog_recover_check_summary(log)
60#define xlog_recover_check_ail(mp, lip, gen)
61#endif 59#endif
62 60
63 61
@@ -2710,8 +2708,8 @@ xlog_recover_do_efd_trans(
2710 xfs_efd_log_format_t *efd_formatp; 2708 xfs_efd_log_format_t *efd_formatp;
2711 xfs_efi_log_item_t *efip = NULL; 2709 xfs_efi_log_item_t *efip = NULL;
2712 xfs_log_item_t *lip; 2710 xfs_log_item_t *lip;
2713 int gen;
2714 __uint64_t efi_id; 2711 __uint64_t efi_id;
2712 struct xfs_ail_cursor cur;
2715 2713
2716 if (pass == XLOG_RECOVER_PASS1) { 2714 if (pass == XLOG_RECOVER_PASS1) {
2717 return; 2715 return;
@@ -2730,7 +2728,8 @@ xlog_recover_do_efd_trans(
2730 */ 2728 */
2731 mp = log->l_mp; 2729 mp = log->l_mp;
2732 spin_lock(&mp->m_ail_lock); 2730 spin_lock(&mp->m_ail_lock);
2733 lip = xfs_trans_first_ail(mp, &gen); 2731 xfs_trans_ail_cursor_init(mp->m_ail, &cur);
2732 lip = xfs_trans_first_ail(mp, &cur);
2734 while (lip != NULL) { 2733 while (lip != NULL) {
2735 if (lip->li_type == XFS_LI_EFI) { 2734 if (lip->li_type == XFS_LI_EFI) {
2736 efip = (xfs_efi_log_item_t *)lip; 2735 efip = (xfs_efi_log_item_t *)lip;
@@ -2741,11 +2740,13 @@ xlog_recover_do_efd_trans(
2741 */ 2740 */
2742 xfs_trans_delete_ail(mp, lip); 2741 xfs_trans_delete_ail(mp, lip);
2743 xfs_efi_item_free(efip); 2742 xfs_efi_item_free(efip);
2744 return; 2743 spin_lock(&mp->m_ail_lock);
2744 break;
2745 } 2745 }
2746 } 2746 }
2747 lip = xfs_trans_next_ail(mp, lip, &gen, NULL); 2747 lip = xfs_trans_next_ail(mp, &cur);
2748 } 2748 }
2749 xfs_trans_ail_cursor_done(mp->m_ail, &cur);
2749 spin_unlock(&mp->m_ail_lock); 2750 spin_unlock(&mp->m_ail_lock);
2750} 2751}
2751 2752
@@ -3030,33 +3031,6 @@ abort_error:
3030} 3031}
3031 3032
3032/* 3033/*
3033 * Verify that once we've encountered something other than an EFI
3034 * in the AIL that there are no more EFIs in the AIL.
3035 */
3036#if defined(DEBUG)
3037STATIC void
3038xlog_recover_check_ail(
3039 xfs_mount_t *mp,
3040 xfs_log_item_t *lip,
3041 int gen)
3042{
3043 int orig_gen = gen;
3044
3045 do {
3046 ASSERT(lip->li_type != XFS_LI_EFI);
3047 lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
3048 /*
3049 * The check will be bogus if we restart from the
3050 * beginning of the AIL, so ASSERT that we don't.
3051 * We never should since we're holding the AIL lock
3052 * the entire time.
3053 */
3054 ASSERT(gen == orig_gen);
3055 } while (lip != NULL);
3056}
3057#endif /* DEBUG */
3058
3059/*
3060 * When this is called, all of the EFIs which did not have 3034 * When this is called, all of the EFIs which did not have
3061 * corresponding EFDs should be in the AIL. What we do now 3035 * corresponding EFDs should be in the AIL. What we do now
3062 * is free the extents associated with each one. 3036 * is free the extents associated with each one.
@@ -3080,20 +3054,25 @@ xlog_recover_process_efis(
3080{ 3054{
3081 xfs_log_item_t *lip; 3055 xfs_log_item_t *lip;
3082 xfs_efi_log_item_t *efip; 3056 xfs_efi_log_item_t *efip;
3083 int gen;
3084 xfs_mount_t *mp; 3057 xfs_mount_t *mp;
3085 int error = 0; 3058 int error = 0;
3059 struct xfs_ail_cursor cur;
3086 3060
3087 mp = log->l_mp; 3061 mp = log->l_mp;
3088 spin_lock(&mp->m_ail_lock); 3062 spin_lock(&mp->m_ail_lock);
3089 3063
3090 lip = xfs_trans_first_ail(mp, &gen); 3064 xfs_trans_ail_cursor_init(mp->m_ail, &cur);
3065 lip = xfs_trans_first_ail(mp, &cur);
3091 while (lip != NULL) { 3066 while (lip != NULL) {
3092 /* 3067 /*
3093 * We're done when we see something other than an EFI. 3068 * We're done when we see something other than an EFI.
3069 * There should be no EFIs left in the AIL now.
3094 */ 3070 */
3095 if (lip->li_type != XFS_LI_EFI) { 3071 if (lip->li_type != XFS_LI_EFI) {
3096 xlog_recover_check_ail(mp, lip, gen); 3072#ifdef DEBUG
3073 for (; lip; lip = xfs_trans_next_ail(mp, &cur))
3074 ASSERT(lip->li_type != XFS_LI_EFI);
3075#endif
3097 break; 3076 break;
3098 } 3077 }
3099 3078
@@ -3102,17 +3081,19 @@ xlog_recover_process_efis(
3102 */ 3081 */
3103 efip = (xfs_efi_log_item_t *)lip; 3082 efip = (xfs_efi_log_item_t *)lip;
3104 if (efip->efi_flags & XFS_EFI_RECOVERED) { 3083 if (efip->efi_flags & XFS_EFI_RECOVERED) {
3105 lip = xfs_trans_next_ail(mp, lip, &gen, NULL); 3084 lip = xfs_trans_next_ail(mp, &cur);
3106 continue; 3085 continue;
3107 } 3086 }
3108 3087
3109 spin_unlock(&mp->m_ail_lock); 3088 spin_unlock(&mp->m_ail_lock);
3110 error = xlog_recover_process_efi(mp, efip); 3089 error = xlog_recover_process_efi(mp, efip);
3111 if (error)
3112 return error;
3113 spin_lock(&mp->m_ail_lock); 3090 spin_lock(&mp->m_ail_lock);
3114 lip = xfs_trans_next_ail(mp, lip, &gen, NULL); 3091 if (error)
3092 goto out;
3093 lip = xfs_trans_next_ail(mp, &cur);
3115 } 3094 }
3095out:
3096 xfs_trans_ail_cursor_done(mp->m_ail, &cur);
3116 spin_unlock(&mp->m_ail_lock); 3097 spin_unlock(&mp->m_ail_lock);
3117 return error; 3098 return error;
3118} 3099}
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index db72b52cd428..7b8bfcf1d3da 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -99,26 +99,137 @@ xfs_trans_push_ail(
99} 99}
100 100
101/* 101/*
102 * AIL traversal cursor initialisation.
103 *
104 * The cursor keeps track of where our current traversal is up
105 * to by tracking the next ƣtem in the list for us. However, for
106 * this to be safe, removing an object from the AIL needs to invalidate
107 * any cursor that points to it. hence the traversal cursor needs to
108 * be linked to the struct xfs_ail so that deletion can search all the
109 * active cursors for invalidation.
110 *
111 * We don't link the push cursor because it is embedded in the struct
112 * xfs_ail and hence easily findable.
113 */
114void
115xfs_trans_ail_cursor_init(
116 struct xfs_ail *ailp,
117 struct xfs_ail_cursor *cur)
118{
119 cur->item = NULL;
120 if (cur == &ailp->xa_cursors)
121 return;
122
123 cur->next = ailp->xa_cursors.next;
124 ailp->xa_cursors.next = cur;
125}
126
127/*
128 * Set the cursor to the next item, because when we look
129 * up the cursor the current item may have been freed.
130 */
131STATIC void
132xfs_trans_ail_cursor_set(
133 struct xfs_ail *ailp,
134 struct xfs_ail_cursor *cur,
135 struct xfs_log_item *lip)
136{
137 if (lip)
138 cur->item = xfs_ail_next(ailp, lip);
139}
140
141/*
142 * Get the next item in the traversal and advance the cursor.
143 * If the cursor was invalidated (inidicated by a lip of 1),
144 * restart the traversal.
145 */
146STATIC struct xfs_log_item *
147xfs_trans_ail_cursor_next(
148 struct xfs_ail *ailp,
149 struct xfs_ail_cursor *cur)
150{
151 struct xfs_log_item *lip = cur->item;
152
153 if ((__psint_t)lip & 1)
154 lip = xfs_ail_min(ailp);
155 xfs_trans_ail_cursor_set(ailp, cur, lip);
156 return lip;
157}
158
159/*
160 * Invalidate any cursor that is pointing to this item. This is
161 * called when an item is removed from the AIL. Any cursor pointing
162 * to this object is now invalid and the traversal needs to be
163 * terminated so it doesn't reference a freed object. We set the
164 * cursor item to a value of 1 so we can distinguish between an
165 * invalidation and the end of the list when getting the next item
166 * from the cursor.
167 */
168STATIC void
169xfs_trans_ail_cursor_clear(
170 struct xfs_ail *ailp,
171 struct xfs_log_item *lip)
172{
173 struct xfs_ail_cursor *cur;
174
175 /* need to search all cursors */
176 for (cur = &ailp->xa_cursors; cur; cur = cur->next) {
177 if (cur->item == lip)
178 cur->item = (struct xfs_log_item *)
179 ((__psint_t)cur->item | 1);
180 }
181}
182
183/*
184 * Now that the traversal is complete, we need to remove the cursor
185 * from the list of traversing cursors. Avoid removing the embedded
186 * push cursor, but use the fact it is alway present to make the
187 * list deletion simple.
188 */
189void
190xfs_trans_ail_cursor_done(
191 struct xfs_ail *ailp,
192 struct xfs_ail_cursor *done)
193{
194 struct xfs_ail_cursor *prev = NULL;
195 struct xfs_ail_cursor *cur;
196
197 done->item = NULL;
198 if (done == &ailp->xa_cursors)
199 return;
200 prev = &ailp->xa_cursors;
201 for (cur = prev->next; cur; prev = cur, cur = prev->next) {
202 if (cur == done) {
203 prev->next = cur->next;
204 break;
205 }
206 }
207 ASSERT(cur);
208}
209
210/*
102 * Return the item in the AIL with the current lsn. 211 * Return the item in the AIL with the current lsn.
103 * Return the current tree generation number for use 212 * Return the current tree generation number for use
104 * in calls to xfs_trans_next_ail(). 213 * in calls to xfs_trans_next_ail().
105 */ 214 */
106STATIC xfs_log_item_t * 215STATIC xfs_log_item_t *
107xfs_trans_first_push_ail( 216xfs_trans_first_push_ail(
108 xfs_mount_t *mp, 217 struct xfs_ail *ailp,
109 int *gen, 218 struct xfs_ail_cursor *cur,
110 xfs_lsn_t lsn) 219 xfs_lsn_t lsn)
111{ 220{
112 xfs_log_item_t *lip; 221 xfs_log_item_t *lip;
113 222
114 lip = xfs_ail_min(mp->m_ail); 223 lip = xfs_ail_min(ailp);
115 *gen = (int)mp->m_ail->xa_gen; 224 xfs_trans_ail_cursor_set(ailp, cur, lip);
116 if (lsn == 0) 225 if (lsn == 0)
117 return lip; 226 return lip;
118 227
119 list_for_each_entry(lip, &mp->m_ail->xa_ail, li_ail) { 228 list_for_each_entry(lip, &ailp->xa_ail, li_ail) {
120 if (XFS_LSN_CMP(lip->li_lsn, lsn) >= 0) 229 if (XFS_LSN_CMP(lip->li_lsn, lsn) >= 0) {
230 xfs_trans_ail_cursor_set(ailp, cur, lip);
121 return lip; 231 return lip;
232 }
122 } 233 }
123 234
124 return NULL; 235 return NULL;
@@ -137,22 +248,21 @@ xfsaild_push(
137 xfs_lsn_t target = ailp->xa_target; 248 xfs_lsn_t target = ailp->xa_target;
138 xfs_lsn_t lsn; 249 xfs_lsn_t lsn;
139 xfs_log_item_t *lip; 250 xfs_log_item_t *lip;
140 int gen;
141 int restarts;
142 int flush_log, count, stuck; 251 int flush_log, count, stuck;
143 xfs_mount_t *mp = ailp->xa_mount; 252 xfs_mount_t *mp = ailp->xa_mount;
144 253 struct xfs_ail_cursor *cur = &ailp->xa_cursors;
145#define XFS_TRANS_PUSH_AIL_RESTARTS 10
146 254
147 spin_lock(&mp->m_ail_lock); 255 spin_lock(&mp->m_ail_lock);
148 lip = xfs_trans_first_push_ail(mp, &gen, *last_lsn); 256 xfs_trans_ail_cursor_init(ailp, cur);
257 lip = xfs_trans_first_push_ail(ailp, cur, *last_lsn);
149 if (!lip || XFS_FORCED_SHUTDOWN(mp)) { 258 if (!lip || XFS_FORCED_SHUTDOWN(mp)) {
150 /* 259 /*
151 * AIL is empty or our push has reached the end. 260 * AIL is empty or our push has reached the end.
152 */ 261 */
262 xfs_trans_ail_cursor_done(ailp, cur);
153 spin_unlock(&mp->m_ail_lock); 263 spin_unlock(&mp->m_ail_lock);
154 last_pushed_lsn = 0; 264 last_pushed_lsn = 0;
155 goto out; 265 return tout;
156 } 266 }
157 267
158 XFS_STATS_INC(xs_push_ail); 268 XFS_STATS_INC(xs_push_ail);
@@ -170,7 +280,7 @@ xfsaild_push(
170 */ 280 */
171 tout = 10; 281 tout = 10;
172 lsn = lip->li_lsn; 282 lsn = lip->li_lsn;
173 flush_log = stuck = count = restarts = 0; 283 flush_log = stuck = count = 0;
174 while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) { 284 while ((XFS_LSN_CMP(lip->li_lsn, target) < 0)) {
175 int lock_result; 285 int lock_result;
176 /* 286 /*
@@ -245,13 +355,12 @@ xfsaild_push(
245 if (stuck > 100) 355 if (stuck > 100)
246 break; 356 break;
247 357
248 lip = xfs_trans_next_ail(mp, lip, &gen, &restarts); 358 lip = xfs_trans_ail_cursor_next(ailp, cur);
249 if (lip == NULL) 359 if (lip == NULL)
250 break; 360 break;
251 if (restarts > XFS_TRANS_PUSH_AIL_RESTARTS)
252 break;
253 lsn = lip->li_lsn; 361 lsn = lip->li_lsn;
254 } 362 }
363 xfs_trans_ail_cursor_done(ailp, cur);
255 spin_unlock(&mp->m_ail_lock); 364 spin_unlock(&mp->m_ail_lock);
256 365
257 if (flush_log) { 366 if (flush_log) {
@@ -275,8 +384,7 @@ xfsaild_push(
275 */ 384 */
276 tout += 20; 385 tout += 20;
277 last_pushed_lsn = 0; 386 last_pushed_lsn = 0;
278 } else if ((restarts > XFS_TRANS_PUSH_AIL_RESTARTS) || 387 } else if ((stuck * 100) / count > 90) {
279 ((stuck * 100) / count > 90)) {
280 /* 388 /*
281 * Either there is a lot of contention on the AIL or we 389 * Either there is a lot of contention on the AIL or we
282 * are stuck due to operations in progress. "Stuck" in this 390 * are stuck due to operations in progress. "Stuck" in this
@@ -288,7 +396,6 @@ xfsaild_push(
288 */ 396 */
289 tout += 10; 397 tout += 10;
290 } 398 }
291out:
292 *last_lsn = last_pushed_lsn; 399 *last_lsn = last_pushed_lsn;
293 return tout; 400 return tout;
294} /* xfsaild_push */ 401} /* xfsaild_push */
@@ -348,9 +455,6 @@ xfs_trans_unlocked_item(
348 * we move in the AIL is the minimum one, update the tail lsn in the 455 * we move in the AIL is the minimum one, update the tail lsn in the
349 * log manager. 456 * log manager.
350 * 457 *
351 * Increment the AIL's generation count to indicate that the tree
352 * has changed.
353 *
354 * This function must be called with the AIL lock held. The lock 458 * This function must be called with the AIL lock held. The lock
355 * is dropped before returning. 459 * is dropped before returning.
356 */ 460 */
@@ -368,14 +472,13 @@ xfs_trans_update_ail(
368 if (lip->li_flags & XFS_LI_IN_AIL) { 472 if (lip->li_flags & XFS_LI_IN_AIL) {
369 dlip = xfs_ail_delete(mp->m_ail, lip); 473 dlip = xfs_ail_delete(mp->m_ail, lip);
370 ASSERT(dlip == lip); 474 ASSERT(dlip == lip);
475 xfs_trans_ail_cursor_clear(mp->m_ail, dlip);
371 } else { 476 } else {
372 lip->li_flags |= XFS_LI_IN_AIL; 477 lip->li_flags |= XFS_LI_IN_AIL;
373 } 478 }
374 479
375 lip->li_lsn = lsn; 480 lip->li_lsn = lsn;
376
377 xfs_ail_insert(mp->m_ail, lip); 481 xfs_ail_insert(mp->m_ail, lip);
378 mp->m_ail->xa_gen++;
379 482
380 if (mlip == dlip) { 483 if (mlip == dlip) {
381 mlip = xfs_ail_min(mp->m_ail); 484 mlip = xfs_ail_min(mp->m_ail);
@@ -415,11 +518,11 @@ xfs_trans_delete_ail(
415 mlip = xfs_ail_min(mp->m_ail); 518 mlip = xfs_ail_min(mp->m_ail);
416 dlip = xfs_ail_delete(mp->m_ail, lip); 519 dlip = xfs_ail_delete(mp->m_ail, lip);
417 ASSERT(dlip == lip); 520 ASSERT(dlip == lip);
521 xfs_trans_ail_cursor_clear(mp->m_ail, dlip);
418 522
419 523
420 lip->li_flags &= ~XFS_LI_IN_AIL; 524 lip->li_flags &= ~XFS_LI_IN_AIL;
421 lip->li_lsn = 0; 525 lip->li_lsn = 0;
422 mp->m_ail->xa_gen++;
423 526
424 if (mlip == dlip) { 527 if (mlip == dlip) {
425 mlip = xfs_ail_min(mp->m_ail); 528 mlip = xfs_ail_min(mp->m_ail);
@@ -455,46 +558,29 @@ xfs_trans_delete_ail(
455 */ 558 */
456xfs_log_item_t * 559xfs_log_item_t *
457xfs_trans_first_ail( 560xfs_trans_first_ail(
458 xfs_mount_t *mp, 561 struct xfs_mount *mp,
459 int *gen) 562 struct xfs_ail_cursor *cur)
460{ 563{
461 xfs_log_item_t *lip; 564 xfs_log_item_t *lip;
565 struct xfs_ail *ailp = mp->m_ail;
462 566
463 lip = xfs_ail_min(mp->m_ail); 567 lip = xfs_ail_min(ailp);
464 *gen = (int)mp->m_ail->xa_gen; 568 xfs_trans_ail_cursor_set(ailp, cur, lip);
465 569
466 return lip; 570 return lip;
467} 571}
468 572
469/* 573/*
470 * If the generation count of the tree has not changed since the 574 * Grab the next item in the AIL from the cursor passed in.
471 * caller last took something from the AIL, then return the elmt
472 * in the tree which follows the one given. If the count has changed,
473 * then return the minimum elmt of the AIL and bump the restarts counter
474 * if one is given.
475 */ 575 */
476xfs_log_item_t * 576xfs_log_item_t *
477xfs_trans_next_ail( 577xfs_trans_next_ail(
478 xfs_mount_t *mp, 578 struct xfs_mount *mp,
479 xfs_log_item_t *lip, 579 struct xfs_ail_cursor *cur)
480 int *gen,
481 int *restarts)
482{ 580{
483 xfs_log_item_t *nlip; 581 struct xfs_ail *ailp = mp->m_ail;
484
485 ASSERT(mp && lip && gen);
486 if (mp->m_ail->xa_gen == *gen) {
487 nlip = xfs_ail_next(mp->m_ail, lip);
488 } else {
489 nlip = xfs_ail_min(mp->m_ail);
490 *gen = (int)mp->m_ail->xa_gen;
491 if (restarts != NULL) {
492 XFS_STATS_INC(xs_push_ail_restarts);
493 (*restarts)++;
494 }
495 }
496 582
497 return (nlip); 583 return xfs_trans_ail_cursor_next(ailp, cur);
498} 584}
499 585
500 586
@@ -517,6 +603,7 @@ xfs_trans_ail_init(
517 xfs_mount_t *mp) 603 xfs_mount_t *mp)
518{ 604{
519 struct xfs_ail *ailp; 605 struct xfs_ail *ailp;
606 int error;
520 607
521 ailp = kmem_zalloc(sizeof(struct xfs_ail), KM_MAYFAIL); 608 ailp = kmem_zalloc(sizeof(struct xfs_ail), KM_MAYFAIL);
522 if (!ailp) 609 if (!ailp)
@@ -524,7 +611,15 @@ xfs_trans_ail_init(
524 611
525 ailp->xa_mount = mp; 612 ailp->xa_mount = mp;
526 INIT_LIST_HEAD(&ailp->xa_ail); 613 INIT_LIST_HEAD(&ailp->xa_ail);
527 return xfsaild_start(ailp); 614 error = xfsaild_start(ailp);
615 if (error)
616 goto out_free_ailp;
617 mp->m_ail = ailp;
618 return 0;
619
620out_free_ailp:
621 kmem_free(ailp);
622 return error;
528} 623}
529 624
530void 625void
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index 98317fdc33b5..f114d388570a 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -44,20 +44,33 @@ xfs_log_busy_slot_t *xfs_trans_add_busy(xfs_trans_t *tp,
44 xfs_extlen_t idx); 44 xfs_extlen_t idx);
45 45
46/* 46/*
47 * From xfs_trans_ail.c 47 * AIL traversal cursor.
48 *
49 * Rather than using a generation number for detecting changes in the ail, use
50 * a cursor that is protected by the ail lock. The aild cursor exists in the
51 * struct xfs_ail, but other traversals can declare it on the stack and link it
52 * to the ail list.
53 *
54 * When an object is deleted from or moved int the AIL, the cursor list is
55 * searched to see if the object is a designated cursor item. If it is, it is
56 * deleted from the cursor so that the next time the cursor is used traversal
57 * will return to the start.
58 *
59 * This means a traversal colliding with a removal will cause a restart of the
60 * list scan, rather than any insertion or deletion anywhere in the list. The
61 * low bit of the item pointer is set if the cursor has been invalidated so
62 * that we can tell the difference between invalidation and reaching the end
63 * of the list to trigger traversal restarts.
48 */ 64 */
49void xfs_trans_update_ail(struct xfs_mount *mp, 65struct xfs_ail_cursor {
50 struct xfs_log_item *lip, xfs_lsn_t lsn) 66 struct xfs_ail_cursor *next;
51 __releases(mp->m_ail_lock); 67 struct xfs_log_item *item;
52void xfs_trans_delete_ail(struct xfs_mount *mp, 68};
53 struct xfs_log_item *lip)
54 __releases(mp->m_ail_lock);
55struct xfs_log_item *xfs_trans_first_ail(struct xfs_mount *, int *);
56struct xfs_log_item *xfs_trans_next_ail(struct xfs_mount *,
57 struct xfs_log_item *, int *, int *);
58 69
59/* 70/*
60 * AIL push thread support 71 * Private AIL structures.
72 *
73 * Eventually we need to drive the locking in here as well.
61 */ 74 */
62struct xfs_ail { 75struct xfs_ail {
63 struct xfs_mount *xa_mount; 76 struct xfs_mount *xa_mount;
@@ -65,8 +78,28 @@ struct xfs_ail {
65 uint xa_gen; 78 uint xa_gen;
66 struct task_struct *xa_task; 79 struct task_struct *xa_task;
67 xfs_lsn_t xa_target; 80 xfs_lsn_t xa_target;
81 struct xfs_ail_cursor xa_cursors;
68}; 82};
69 83
84/*
85 * From xfs_trans_ail.c
86 */
87void xfs_trans_update_ail(struct xfs_mount *mp,
88 struct xfs_log_item *lip, xfs_lsn_t lsn)
89 __releases(mp->m_ail_lock);
90void xfs_trans_delete_ail(struct xfs_mount *mp,
91 struct xfs_log_item *lip)
92 __releases(mp->m_ail_lock);
93struct xfs_log_item *xfs_trans_first_ail(struct xfs_mount *mp,
94 struct xfs_ail_cursor *cur);
95struct xfs_log_item *xfs_trans_next_ail(struct xfs_mount *mp,
96 struct xfs_ail_cursor *cur);
97
98void xfs_trans_ail_cursor_init(struct xfs_ail *ailp,
99 struct xfs_ail_cursor *cur);
100void xfs_trans_ail_cursor_done(struct xfs_ail *ailp,
101 struct xfs_ail_cursor *cur);
102
70long xfsaild_push(struct xfs_ail *, xfs_lsn_t *); 103long xfsaild_push(struct xfs_ail *, xfs_lsn_t *);
71void xfsaild_wakeup(struct xfs_ail *, xfs_lsn_t); 104void xfsaild_wakeup(struct xfs_ail *, xfs_lsn_t);
72int xfsaild_start(struct xfs_ail *); 105int xfsaild_start(struct xfs_ail *);