1
2
3
4
5
6
7#include "xfs.h"
8#include "xfs_fs.h"
9#include "xfs_shared.h"
10#include "xfs_format.h"
11#include "xfs_log_format.h"
12#include "xfs_trans_resv.h"
13#include "xfs_mount.h"
14#include "xfs_trans.h"
15#include "xfs_trans_priv.h"
16#include "xfs_trace.h"
17#include "xfs_errortag.h"
18#include "xfs_error.h"
19#include "xfs_log.h"
20
21#ifdef DEBUG
22
23
24
25
26
27
28
29
30
31STATIC void
32xfs_ail_check(
33 struct xfs_ail *ailp,
34 struct xfs_log_item *lip)
35{
36 struct xfs_log_item *prev_lip;
37 struct xfs_log_item *next_lip;
38 xfs_lsn_t prev_lsn = NULLCOMMITLSN;
39 xfs_lsn_t next_lsn = NULLCOMMITLSN;
40 xfs_lsn_t lsn;
41 bool in_ail;
42
43
44 if (list_empty(&ailp->ail_head))
45 return;
46
47
48
49
50 in_ail = test_bit(XFS_LI_IN_AIL, &lip->li_flags);
51 prev_lip = list_entry(lip->li_ail.prev, struct xfs_log_item, li_ail);
52 if (&prev_lip->li_ail != &ailp->ail_head)
53 prev_lsn = prev_lip->li_lsn;
54 next_lip = list_entry(lip->li_ail.next, struct xfs_log_item, li_ail);
55 if (&next_lip->li_ail != &ailp->ail_head)
56 next_lsn = next_lip->li_lsn;
57 lsn = lip->li_lsn;
58
59 if (in_ail &&
60 (prev_lsn == NULLCOMMITLSN || XFS_LSN_CMP(prev_lsn, lsn) <= 0) &&
61 (next_lsn == NULLCOMMITLSN || XFS_LSN_CMP(next_lsn, lsn) >= 0))
62 return;
63
64 spin_unlock(&ailp->ail_lock);
65 ASSERT(in_ail);
66 ASSERT(prev_lsn == NULLCOMMITLSN || XFS_LSN_CMP(prev_lsn, lsn) <= 0);
67 ASSERT(next_lsn == NULLCOMMITLSN || XFS_LSN_CMP(next_lsn, lsn) >= 0);
68 spin_lock(&ailp->ail_lock);
69}
70#else
71#define xfs_ail_check(a,l)
72#endif
73
74
75
76
77
78static struct xfs_log_item *
79xfs_ail_max(
80 struct xfs_ail *ailp)
81{
82 if (list_empty(&ailp->ail_head))
83 return NULL;
84
85 return list_entry(ailp->ail_head.prev, struct xfs_log_item, li_ail);
86}
87
88
89
90
91
92static struct xfs_log_item *
93xfs_ail_next(
94 struct xfs_ail *ailp,
95 struct xfs_log_item *lip)
96{
97 if (lip->li_ail.next == &ailp->ail_head)
98 return NULL;
99
100 return list_first_entry(&lip->li_ail, struct xfs_log_item, li_ail);
101}
102
103
104
105
106
107
108
109
110
111xfs_lsn_t
112xfs_ail_min_lsn(
113 struct xfs_ail *ailp)
114{
115 xfs_lsn_t lsn = 0;
116 struct xfs_log_item *lip;
117
118 spin_lock(&ailp->ail_lock);
119 lip = xfs_ail_min(ailp);
120 if (lip)
121 lsn = lip->li_lsn;
122 spin_unlock(&ailp->ail_lock);
123
124 return lsn;
125}
126
127
128
129
130static xfs_lsn_t
131xfs_ail_max_lsn(
132 struct xfs_ail *ailp)
133{
134 xfs_lsn_t lsn = 0;
135 struct xfs_log_item *lip;
136
137 spin_lock(&ailp->ail_lock);
138 lip = xfs_ail_max(ailp);
139 if (lip)
140 lsn = lip->li_lsn;
141 spin_unlock(&ailp->ail_lock);
142
143 return lsn;
144}
145
146
147
148
149
150
151
152
153STATIC void
154xfs_trans_ail_cursor_init(
155 struct xfs_ail *ailp,
156 struct xfs_ail_cursor *cur)
157{
158 cur->item = NULL;
159 list_add_tail(&cur->list, &ailp->ail_cursors);
160}
161
162
163
164
165
166struct xfs_log_item *
167xfs_trans_ail_cursor_next(
168 struct xfs_ail *ailp,
169 struct xfs_ail_cursor *cur)
170{
171 struct xfs_log_item *lip = cur->item;
172
173 if ((uintptr_t)lip & 1)
174 lip = xfs_ail_min(ailp);
175 if (lip)
176 cur->item = xfs_ail_next(ailp, lip);
177 return lip;
178}
179
180
181
182
183
184void
185xfs_trans_ail_cursor_done(
186 struct xfs_ail_cursor *cur)
187{
188 cur->item = NULL;
189 list_del_init(&cur->list);
190}
191
192
193
194
195
196
197
198
199
200STATIC void
201xfs_trans_ail_cursor_clear(
202 struct xfs_ail *ailp,
203 struct xfs_log_item *lip)
204{
205 struct xfs_ail_cursor *cur;
206
207 list_for_each_entry(cur, &ailp->ail_cursors, list) {
208 if (cur->item == lip)
209 cur->item = (struct xfs_log_item *)
210 ((uintptr_t)cur->item | 1);
211 }
212}
213
214
215
216
217
218
219
220struct xfs_log_item *
221xfs_trans_ail_cursor_first(
222 struct xfs_ail *ailp,
223 struct xfs_ail_cursor *cur,
224 xfs_lsn_t lsn)
225{
226 struct xfs_log_item *lip;
227
228 xfs_trans_ail_cursor_init(ailp, cur);
229
230 if (lsn == 0) {
231 lip = xfs_ail_min(ailp);
232 goto out;
233 }
234
235 list_for_each_entry(lip, &ailp->ail_head, li_ail) {
236 if (XFS_LSN_CMP(lip->li_lsn, lsn) >= 0)
237 goto out;
238 }
239 return NULL;
240
241out:
242 if (lip)
243 cur->item = xfs_ail_next(ailp, lip);
244 return lip;
245}
246
247static struct xfs_log_item *
248__xfs_trans_ail_cursor_last(
249 struct xfs_ail *ailp,
250 xfs_lsn_t lsn)
251{
252 struct xfs_log_item *lip;
253
254 list_for_each_entry_reverse(lip, &ailp->ail_head, li_ail) {
255 if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0)
256 return lip;
257 }
258 return NULL;
259}
260
261
262
263
264
265
266
267struct xfs_log_item *
268xfs_trans_ail_cursor_last(
269 struct xfs_ail *ailp,
270 struct xfs_ail_cursor *cur,
271 xfs_lsn_t lsn)
272{
273 xfs_trans_ail_cursor_init(ailp, cur);
274 cur->item = __xfs_trans_ail_cursor_last(ailp, lsn);
275 return cur->item;
276}
277
278
279
280
281
282
283
284static void
285xfs_ail_splice(
286 struct xfs_ail *ailp,
287 struct xfs_ail_cursor *cur,
288 struct list_head *list,
289 xfs_lsn_t lsn)
290{
291 struct xfs_log_item *lip;
292
293 ASSERT(!list_empty(list));
294
295
296
297
298
299
300 lip = cur ? cur->item : NULL;
301 if (!lip || (uintptr_t)lip & 1)
302 lip = __xfs_trans_ail_cursor_last(ailp, lsn);
303
304
305
306
307
308
309
310
311 if (cur)
312 cur->item = list_entry(list->prev, struct xfs_log_item, li_ail);
313
314
315
316
317
318
319
320 if (lip)
321 list_splice(list, &lip->li_ail);
322 else
323 list_splice(list, &ailp->ail_head);
324}
325
326
327
328
329static void
330xfs_ail_delete(
331 struct xfs_ail *ailp,
332 struct xfs_log_item *lip)
333{
334 xfs_ail_check(ailp, lip);
335 list_del(&lip->li_ail);
336 xfs_trans_ail_cursor_clear(ailp, lip);
337}
338
339static inline uint
340xfsaild_push_item(
341 struct xfs_ail *ailp,
342 struct xfs_log_item *lip)
343{
344
345
346
347
348 if (XFS_TEST_ERROR(false, ailp->ail_mount, XFS_ERRTAG_LOG_ITEM_PIN))
349 return XFS_ITEM_PINNED;
350
351
352
353
354
355
356
357 if (!lip->li_ops->iop_push)
358 return XFS_ITEM_PINNED;
359 return lip->li_ops->iop_push(lip, &ailp->ail_buf_list);
360}
361
362static long
363xfsaild_push(
364 struct xfs_ail *ailp)
365{
366 xfs_mount_t *mp = ailp->ail_mount;
367 struct xfs_ail_cursor cur;
368 struct xfs_log_item *lip;
369 xfs_lsn_t lsn;
370 xfs_lsn_t target;
371 long tout;
372 int stuck = 0;
373 int flushing = 0;
374 int count = 0;
375
376
377
378
379
380
381 if (ailp->ail_log_flush && ailp->ail_last_pushed_lsn == 0 &&
382 (!list_empty_careful(&ailp->ail_buf_list) ||
383 xfs_ail_min_lsn(ailp))) {
384 ailp->ail_log_flush = 0;
385
386 XFS_STATS_INC(mp, xs_push_ail_flush);
387 xfs_log_force(mp, XFS_LOG_SYNC);
388 }
389
390 spin_lock(&ailp->ail_lock);
391
392
393 smp_rmb();
394 target = ailp->ail_target;
395 ailp->ail_target_prev = target;
396
397 lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->ail_last_pushed_lsn);
398 if (!lip) {
399
400
401
402
403 xfs_trans_ail_cursor_done(&cur);
404 spin_unlock(&ailp->ail_lock);
405 goto out_done;
406 }
407
408 XFS_STATS_INC(mp, xs_push_ail);
409
410 lsn = lip->li_lsn;
411 while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) {
412 int lock_result;
413
414
415
416
417
418
419 lock_result = xfsaild_push_item(ailp, lip);
420 switch (lock_result) {
421 case XFS_ITEM_SUCCESS:
422 XFS_STATS_INC(mp, xs_push_ail_success);
423 trace_xfs_ail_push(lip);
424
425 ailp->ail_last_pushed_lsn = lsn;
426 break;
427
428 case XFS_ITEM_FLUSHING:
429
430
431
432
433
434
435
436
437
438
439
440 XFS_STATS_INC(mp, xs_push_ail_flushing);
441 trace_xfs_ail_flushing(lip);
442
443 flushing++;
444 ailp->ail_last_pushed_lsn = lsn;
445 break;
446
447 case XFS_ITEM_PINNED:
448 XFS_STATS_INC(mp, xs_push_ail_pinned);
449 trace_xfs_ail_pinned(lip);
450
451 stuck++;
452 ailp->ail_log_flush++;
453 break;
454 case XFS_ITEM_LOCKED:
455 XFS_STATS_INC(mp, xs_push_ail_locked);
456 trace_xfs_ail_locked(lip);
457
458 stuck++;
459 break;
460 default:
461 ASSERT(0);
462 break;
463 }
464
465 count++;
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480 if (stuck > 100)
481 break;
482
483 lip = xfs_trans_ail_cursor_next(ailp, &cur);
484 if (lip == NULL)
485 break;
486 lsn = lip->li_lsn;
487 }
488 xfs_trans_ail_cursor_done(&cur);
489 spin_unlock(&ailp->ail_lock);
490
491 if (xfs_buf_delwri_submit_nowait(&ailp->ail_buf_list))
492 ailp->ail_log_flush++;
493
494 if (!count || XFS_LSN_CMP(lsn, target) >= 0) {
495out_done:
496
497
498
499
500
501 tout = 50;
502 ailp->ail_last_pushed_lsn = 0;
503 } else if (((stuck + flushing) * 100) / count > 90) {
504
505
506
507
508
509
510
511
512
513
514 tout = 20;
515 ailp->ail_last_pushed_lsn = 0;
516 } else {
517
518
519
520 tout = 10;
521 }
522
523 return tout;
524}
525
526static int
527xfsaild(
528 void *data)
529{
530 struct xfs_ail *ailp = data;
531 long tout = 0;
532
533 current->flags |= PF_MEMALLOC;
534 set_freezable();
535
536 while (1) {
537 if (tout && tout <= 20)
538 set_current_state(TASK_KILLABLE);
539 else
540 set_current_state(TASK_INTERRUPTIBLE);
541
542
543
544
545
546
547
548
549
550 if (kthread_should_stop()) {
551 __set_current_state(TASK_RUNNING);
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567 ASSERT(list_empty(&ailp->ail_buf_list) ||
568 XFS_FORCED_SHUTDOWN(ailp->ail_mount));
569 xfs_buf_delwri_cancel(&ailp->ail_buf_list);
570 break;
571 }
572
573 spin_lock(&ailp->ail_lock);
574
575
576
577
578
579
580
581
582
583
584 smp_rmb();
585 if (!xfs_ail_min(ailp) &&
586 ailp->ail_target == ailp->ail_target_prev) {
587 spin_unlock(&ailp->ail_lock);
588 freezable_schedule();
589 tout = 0;
590 continue;
591 }
592 spin_unlock(&ailp->ail_lock);
593
594 if (tout)
595 freezable_schedule_timeout(msecs_to_jiffies(tout));
596
597 __set_current_state(TASK_RUNNING);
598
599 try_to_freeze();
600
601 tout = xfsaild_push(ailp);
602 }
603
604 return 0;
605}
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621void
622xfs_ail_push(
623 struct xfs_ail *ailp,
624 xfs_lsn_t threshold_lsn)
625{
626 struct xfs_log_item *lip;
627
628 lip = xfs_ail_min(ailp);
629 if (!lip || XFS_FORCED_SHUTDOWN(ailp->ail_mount) ||
630 XFS_LSN_CMP(threshold_lsn, ailp->ail_target) <= 0)
631 return;
632
633
634
635
636
637 smp_wmb();
638 xfs_trans_ail_copy_lsn(ailp, &ailp->ail_target, &threshold_lsn);
639 smp_wmb();
640
641 wake_up_process(ailp->ail_task);
642}
643
644
645
646
647void
648xfs_ail_push_all(
649 struct xfs_ail *ailp)
650{
651 xfs_lsn_t threshold_lsn = xfs_ail_max_lsn(ailp);
652
653 if (threshold_lsn)
654 xfs_ail_push(ailp, threshold_lsn);
655}
656
657
658
659
660void
661xfs_ail_push_all_sync(
662 struct xfs_ail *ailp)
663{
664 struct xfs_log_item *lip;
665 DEFINE_WAIT(wait);
666
667 spin_lock(&ailp->ail_lock);
668 while ((lip = xfs_ail_max(ailp)) != NULL) {
669 prepare_to_wait(&ailp->ail_empty, &wait, TASK_UNINTERRUPTIBLE);
670 ailp->ail_target = lip->li_lsn;
671 wake_up_process(ailp->ail_task);
672 spin_unlock(&ailp->ail_lock);
673 schedule();
674 spin_lock(&ailp->ail_lock);
675 }
676 spin_unlock(&ailp->ail_lock);
677
678 finish_wait(&ailp->ail_empty, &wait);
679}
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703void
704xfs_trans_ail_update_bulk(
705 struct xfs_ail *ailp,
706 struct xfs_ail_cursor *cur,
707 struct xfs_log_item **log_items,
708 int nr_items,
709 xfs_lsn_t lsn) __releases(ailp->ail_lock)
710{
711 struct xfs_log_item *mlip;
712 int mlip_changed = 0;
713 int i;
714 LIST_HEAD(tmp);
715
716 ASSERT(nr_items > 0);
717 mlip = xfs_ail_min(ailp);
718
719 for (i = 0; i < nr_items; i++) {
720 struct xfs_log_item *lip = log_items[i];
721 if (test_and_set_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
722
723 if (XFS_LSN_CMP(lsn, lip->li_lsn) <= 0)
724 continue;
725
726 trace_xfs_ail_move(lip, lip->li_lsn, lsn);
727 xfs_ail_delete(ailp, lip);
728 if (mlip == lip)
729 mlip_changed = 1;
730 } else {
731 trace_xfs_ail_insert(lip, 0, lsn);
732 }
733 lip->li_lsn = lsn;
734 list_add(&lip->li_ail, &tmp);
735 }
736
737 if (!list_empty(&tmp))
738 xfs_ail_splice(ailp, cur, &tmp, lsn);
739
740 if (mlip_changed) {
741 if (!XFS_FORCED_SHUTDOWN(ailp->ail_mount))
742 xlog_assign_tail_lsn_locked(ailp->ail_mount);
743 spin_unlock(&ailp->ail_lock);
744
745 xfs_log_space_wake(ailp->ail_mount);
746 } else {
747 spin_unlock(&ailp->ail_lock);
748 }
749}
750
751bool
752xfs_ail_delete_one(
753 struct xfs_ail *ailp,
754 struct xfs_log_item *lip)
755{
756 struct xfs_log_item *mlip = xfs_ail_min(ailp);
757
758 trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn);
759 xfs_ail_delete(ailp, lip);
760 xfs_clear_li_failed(lip);
761 clear_bit(XFS_LI_IN_AIL, &lip->li_flags);
762 lip->li_lsn = 0;
763
764 return mlip == lip;
765}
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788void
789xfs_trans_ail_delete(
790 struct xfs_ail *ailp,
791 struct xfs_log_item *lip,
792 int shutdown_type) __releases(ailp->ail_lock)
793{
794 struct xfs_mount *mp = ailp->ail_mount;
795 bool mlip_changed;
796
797 if (!test_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
798 spin_unlock(&ailp->ail_lock);
799 if (!XFS_FORCED_SHUTDOWN(mp)) {
800 xfs_alert_tag(mp, XFS_PTAG_AILDELETE,
801 "%s: attempting to delete a log item that is not in the AIL",
802 __func__);
803 xfs_force_shutdown(mp, shutdown_type);
804 }
805 return;
806 }
807
808 mlip_changed = xfs_ail_delete_one(ailp, lip);
809 if (mlip_changed) {
810 if (!XFS_FORCED_SHUTDOWN(mp))
811 xlog_assign_tail_lsn_locked(mp);
812 if (list_empty(&ailp->ail_head))
813 wake_up_all(&ailp->ail_empty);
814 }
815
816 spin_unlock(&ailp->ail_lock);
817 if (mlip_changed)
818 xfs_log_space_wake(ailp->ail_mount);
819}
820
821int
822xfs_trans_ail_init(
823 xfs_mount_t *mp)
824{
825 struct xfs_ail *ailp;
826
827 ailp = kmem_zalloc(sizeof(struct xfs_ail), KM_MAYFAIL);
828 if (!ailp)
829 return -ENOMEM;
830
831 ailp->ail_mount = mp;
832 INIT_LIST_HEAD(&ailp->ail_head);
833 INIT_LIST_HEAD(&ailp->ail_cursors);
834 spin_lock_init(&ailp->ail_lock);
835 INIT_LIST_HEAD(&ailp->ail_buf_list);
836 init_waitqueue_head(&ailp->ail_empty);
837
838 ailp->ail_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
839 ailp->ail_mount->m_fsname);
840 if (IS_ERR(ailp->ail_task))
841 goto out_free_ailp;
842
843 mp->m_ail = ailp;
844 return 0;
845
846out_free_ailp:
847 kmem_free(ailp);
848 return -ENOMEM;
849}
850
851void
852xfs_trans_ail_destroy(
853 xfs_mount_t *mp)
854{
855 struct xfs_ail *ailp = mp->m_ail;
856
857 kthread_stop(ailp->ail_task);
858 kmem_free(ailp);
859}
860