diff options
-rw-r--r-- | fs/xfs/xfs_trans_ail.c | 79 | ||||
-rw-r--r-- | fs/xfs/xfs_trans_priv.h | 4 |
2 files changed, 28 insertions, 55 deletions
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 7908c798a02b..43233e92f0f6 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c | |||
@@ -163,17 +163,11 @@ xfs_ail_max_lsn( | |||
163 | } | 163 | } |
164 | 164 | ||
165 | /* | 165 | /* |
166 | * AIL traversal cursor initialisation. | 166 | * The cursor keeps track of where our current traversal is up to by tracking |
167 | * | 167 | * the next item in the list for us. However, for this to be safe, removing an |
168 | * The cursor keeps track of where our current traversal is up | 168 | * object from the AIL needs to invalidate any cursor that points to it. hence |
169 | * to by tracking the next ƣtem in the list for us. However, for | 169 | * the traversal cursor needs to be linked to the struct xfs_ail so that |
170 | * this to be safe, removing an object from the AIL needs to invalidate | 170 | * deletion can search all the active cursors for invalidation. |
171 | * any cursor that points to it. hence the traversal cursor needs to | ||
172 | * be linked to the struct xfs_ail so that deletion can search all the | ||
173 | * active cursors for invalidation. | ||
174 | * | ||
175 | * We don't link the push cursor because it is embedded in the struct | ||
176 | * xfs_ail and hence easily findable. | ||
177 | */ | 171 | */ |
178 | STATIC void | 172 | STATIC void |
179 | xfs_trans_ail_cursor_init( | 173 | xfs_trans_ail_cursor_init( |
@@ -181,17 +175,12 @@ xfs_trans_ail_cursor_init( | |||
181 | struct xfs_ail_cursor *cur) | 175 | struct xfs_ail_cursor *cur) |
182 | { | 176 | { |
183 | cur->item = NULL; | 177 | cur->item = NULL; |
184 | if (cur == &ailp->xa_cursors) | 178 | list_add_tail(&cur->list, &ailp->xa_cursors); |
185 | return; | ||
186 | |||
187 | cur->next = ailp->xa_cursors.next; | ||
188 | ailp->xa_cursors.next = cur; | ||
189 | } | 179 | } |
190 | 180 | ||
191 | /* | 181 | /* |
192 | * Get the next item in the traversal and advance the cursor. | 182 | * Get the next item in the traversal and advance the cursor. If the cursor |
193 | * If the cursor was invalidated (inidicated by a lip of 1), | 183 | * was invalidated (indicated by a lip of 1), restart the traversal. |
194 | * restart the traversal. | ||
195 | */ | 184 | */ |
196 | struct xfs_log_item * | 185 | struct xfs_log_item * |
197 | xfs_trans_ail_cursor_next( | 186 | xfs_trans_ail_cursor_next( |
@@ -208,40 +197,25 @@ xfs_trans_ail_cursor_next( | |||
208 | } | 197 | } |
209 | 198 | ||
210 | /* | 199 | /* |
211 | * Now that the traversal is complete, we need to remove the cursor | 200 | * When the traversal is complete, we need to remove the cursor from the list |
212 | * from the list of traversing cursors. Avoid removing the embedded | 201 | * of traversing cursors. |
213 | * push cursor, but use the fact it is always present to make the | ||
214 | * list deletion simple. | ||
215 | */ | 202 | */ |
216 | void | 203 | void |
217 | xfs_trans_ail_cursor_done( | 204 | xfs_trans_ail_cursor_done( |
218 | struct xfs_ail *ailp, | 205 | struct xfs_ail *ailp, |
219 | struct xfs_ail_cursor *done) | 206 | struct xfs_ail_cursor *cur) |
220 | { | 207 | { |
221 | struct xfs_ail_cursor *prev = NULL; | 208 | cur->item = NULL; |
222 | struct xfs_ail_cursor *cur; | 209 | list_del_init(&cur->list); |
223 | |||
224 | done->item = NULL; | ||
225 | if (done == &ailp->xa_cursors) | ||
226 | return; | ||
227 | prev = &ailp->xa_cursors; | ||
228 | for (cur = prev->next; cur; prev = cur, cur = prev->next) { | ||
229 | if (cur == done) { | ||
230 | prev->next = cur->next; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | ASSERT(cur); | ||
235 | } | 210 | } |
236 | 211 | ||
237 | /* | 212 | /* |
238 | * Invalidate any cursor that is pointing to this item. This is | 213 | * Invalidate any cursor that is pointing to this item. This is called when an |
239 | * called when an item is removed from the AIL. Any cursor pointing | 214 | * item is removed from the AIL. Any cursor pointing to this object is now |
240 | * to this object is now invalid and the traversal needs to be | 215 | * invalid and the traversal needs to be terminated so it doesn't reference a |
241 | * terminated so it doesn't reference a freed object. We set the | 216 | * freed object. We set the low bit of the cursor item pointer so we can |
242 | * cursor item to a value of 1 so we can distinguish between an | 217 | * distinguish between an invalidation and the end of the list when getting the |
243 | * invalidation and the end of the list when getting the next item | 218 | * next item from the cursor. |
244 | * from the cursor. | ||
245 | */ | 219 | */ |
246 | STATIC void | 220 | STATIC void |
247 | xfs_trans_ail_cursor_clear( | 221 | xfs_trans_ail_cursor_clear( |
@@ -250,8 +224,7 @@ xfs_trans_ail_cursor_clear( | |||
250 | { | 224 | { |
251 | struct xfs_ail_cursor *cur; | 225 | struct xfs_ail_cursor *cur; |
252 | 226 | ||
253 | /* need to search all cursors */ | 227 | list_for_each_entry(cur, &ailp->xa_cursors, list) { |
254 | for (cur = &ailp->xa_cursors; cur; cur = cur->next) { | ||
255 | if (cur->item == lip) | 228 | if (cur->item == lip) |
256 | cur->item = (struct xfs_log_item *) | 229 | cur->item = (struct xfs_log_item *) |
257 | ((__psint_t)cur->item | 1); | 230 | ((__psint_t)cur->item | 1); |
@@ -405,7 +378,7 @@ xfs_ail_worker( | |||
405 | struct xfs_ail *ailp = container_of(to_delayed_work(work), | 378 | struct xfs_ail *ailp = container_of(to_delayed_work(work), |
406 | struct xfs_ail, xa_work); | 379 | struct xfs_ail, xa_work); |
407 | xfs_mount_t *mp = ailp->xa_mount; | 380 | xfs_mount_t *mp = ailp->xa_mount; |
408 | struct xfs_ail_cursor *cur = &ailp->xa_cursors; | 381 | struct xfs_ail_cursor cur; |
409 | xfs_log_item_t *lip; | 382 | xfs_log_item_t *lip; |
410 | xfs_lsn_t lsn; | 383 | xfs_lsn_t lsn; |
411 | xfs_lsn_t target; | 384 | xfs_lsn_t target; |
@@ -417,13 +390,12 @@ xfs_ail_worker( | |||
417 | 390 | ||
418 | spin_lock(&ailp->xa_lock); | 391 | spin_lock(&ailp->xa_lock); |
419 | target = ailp->xa_target; | 392 | target = ailp->xa_target; |
420 | xfs_trans_ail_cursor_init(ailp, cur); | 393 | lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn); |
421 | lip = xfs_trans_ail_cursor_first(ailp, cur, ailp->xa_last_pushed_lsn); | ||
422 | if (!lip || XFS_FORCED_SHUTDOWN(mp)) { | 394 | if (!lip || XFS_FORCED_SHUTDOWN(mp)) { |
423 | /* | 395 | /* |
424 | * AIL is empty or our push has reached the end. | 396 | * AIL is empty or our push has reached the end. |
425 | */ | 397 | */ |
426 | xfs_trans_ail_cursor_done(ailp, cur); | 398 | xfs_trans_ail_cursor_done(ailp, &cur); |
427 | spin_unlock(&ailp->xa_lock); | 399 | spin_unlock(&ailp->xa_lock); |
428 | goto out_done; | 400 | goto out_done; |
429 | } | 401 | } |
@@ -511,12 +483,12 @@ xfs_ail_worker( | |||
511 | if (stuck > 100) | 483 | if (stuck > 100) |
512 | break; | 484 | break; |
513 | 485 | ||
514 | lip = xfs_trans_ail_cursor_next(ailp, cur); | 486 | lip = xfs_trans_ail_cursor_next(ailp, &cur); |
515 | if (lip == NULL) | 487 | if (lip == NULL) |
516 | break; | 488 | break; |
517 | lsn = lip->li_lsn; | 489 | lsn = lip->li_lsn; |
518 | } | 490 | } |
519 | xfs_trans_ail_cursor_done(ailp, cur); | 491 | xfs_trans_ail_cursor_done(ailp, &cur); |
520 | spin_unlock(&ailp->xa_lock); | 492 | spin_unlock(&ailp->xa_lock); |
521 | 493 | ||
522 | if (flush_log) { | 494 | if (flush_log) { |
@@ -848,6 +820,7 @@ xfs_trans_ail_init( | |||
848 | 820 | ||
849 | ailp->xa_mount = mp; | 821 | ailp->xa_mount = mp; |
850 | INIT_LIST_HEAD(&ailp->xa_ail); | 822 | INIT_LIST_HEAD(&ailp->xa_ail); |
823 | INIT_LIST_HEAD(&ailp->xa_cursors); | ||
851 | spin_lock_init(&ailp->xa_lock); | 824 | spin_lock_init(&ailp->xa_lock); |
852 | INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker); | 825 | INIT_DELAYED_WORK(&ailp->xa_work, xfs_ail_worker); |
853 | mp->m_ail = ailp; | 826 | mp->m_ail = ailp; |
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h index c0cb40890329..212946b97239 100644 --- a/fs/xfs/xfs_trans_priv.h +++ b/fs/xfs/xfs_trans_priv.h | |||
@@ -53,7 +53,7 @@ void xfs_trans_committed_bulk(struct xfs_ail *ailp, struct xfs_log_vec *lv, | |||
53 | * of the list to trigger traversal restarts. | 53 | * of the list to trigger traversal restarts. |
54 | */ | 54 | */ |
55 | struct xfs_ail_cursor { | 55 | struct xfs_ail_cursor { |
56 | struct xfs_ail_cursor *next; | 56 | struct list_head list; |
57 | struct xfs_log_item *item; | 57 | struct xfs_log_item *item; |
58 | }; | 58 | }; |
59 | 59 | ||
@@ -66,7 +66,7 @@ struct xfs_ail { | |||
66 | struct xfs_mount *xa_mount; | 66 | struct xfs_mount *xa_mount; |
67 | struct list_head xa_ail; | 67 | struct list_head xa_ail; |
68 | xfs_lsn_t xa_target; | 68 | xfs_lsn_t xa_target; |
69 | struct xfs_ail_cursor xa_cursors; | 69 | struct list_head xa_cursors; |
70 | spinlock_t xa_lock; | 70 | spinlock_t xa_lock; |
71 | struct delayed_work xa_work; | 71 | struct delayed_work xa_work; |
72 | xfs_lsn_t xa_last_pushed_lsn; | 72 | xfs_lsn_t xa_last_pushed_lsn; |