diff options
-rw-r--r-- | fs/xfs/xfs_log.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 61 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_ail.c | 207 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_priv.h | 55 |
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, | |||
900 | int | 900 | int |
901 | xfs_log_need_covered(xfs_mount_t *mp) | 901 | xfs_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) |
56 | STATIC void xlog_recover_check_summary(xlog_t *); | 56 | STATIC void xlog_recover_check_summary(xlog_t *); |
57 | STATIC 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) | ||
3037 | STATIC void | ||
3038 | xlog_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 | } |
3095 | out: | ||
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 | */ | ||
114 | void | ||
115 | xfs_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 | */ | ||
131 | STATIC void | ||
132 | xfs_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 | */ | ||
146 | STATIC struct xfs_log_item * | ||
147 | xfs_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 | */ | ||
168 | STATIC void | ||
169 | xfs_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 | */ | ||
189 | void | ||
190 | xfs_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 | */ |
106 | STATIC xfs_log_item_t * | 215 | STATIC xfs_log_item_t * |
107 | xfs_trans_first_push_ail( | 216 | xfs_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 | } |
291 | out: | ||
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 | */ |
456 | xfs_log_item_t * | 559 | xfs_log_item_t * |
457 | xfs_trans_first_ail( | 560 | xfs_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 | */ |
476 | xfs_log_item_t * | 576 | xfs_log_item_t * |
477 | xfs_trans_next_ail( | 577 | xfs_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 | |||
620 | out_free_ailp: | ||
621 | kmem_free(ailp); | ||
622 | return error; | ||
528 | } | 623 | } |
529 | 624 | ||
530 | void | 625 | void |
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 | */ |
49 | void xfs_trans_update_ail(struct xfs_mount *mp, | 65 | struct 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; |
52 | void xfs_trans_delete_ail(struct xfs_mount *mp, | 68 | }; |
53 | struct xfs_log_item *lip) | ||
54 | __releases(mp->m_ail_lock); | ||
55 | struct xfs_log_item *xfs_trans_first_ail(struct xfs_mount *, int *); | ||
56 | struct 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 | */ |
62 | struct xfs_ail { | 75 | struct 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 | */ | ||
87 | void xfs_trans_update_ail(struct xfs_mount *mp, | ||
88 | struct xfs_log_item *lip, xfs_lsn_t lsn) | ||
89 | __releases(mp->m_ail_lock); | ||
90 | void xfs_trans_delete_ail(struct xfs_mount *mp, | ||
91 | struct xfs_log_item *lip) | ||
92 | __releases(mp->m_ail_lock); | ||
93 | struct xfs_log_item *xfs_trans_first_ail(struct xfs_mount *mp, | ||
94 | struct xfs_ail_cursor *cur); | ||
95 | struct xfs_log_item *xfs_trans_next_ail(struct xfs_mount *mp, | ||
96 | struct xfs_ail_cursor *cur); | ||
97 | |||
98 | void xfs_trans_ail_cursor_init(struct xfs_ail *ailp, | ||
99 | struct xfs_ail_cursor *cur); | ||
100 | void xfs_trans_ail_cursor_done(struct xfs_ail *ailp, | ||
101 | struct xfs_ail_cursor *cur); | ||
102 | |||
70 | long xfsaild_push(struct xfs_ail *, xfs_lsn_t *); | 103 | long xfsaild_push(struct xfs_ail *, xfs_lsn_t *); |
71 | void xfsaild_wakeup(struct xfs_ail *, xfs_lsn_t); | 104 | void xfsaild_wakeup(struct xfs_ail *, xfs_lsn_t); |
72 | int xfsaild_start(struct xfs_ail *); | 105 | int xfsaild_start(struct xfs_ail *); |