Re: [PATCH 2/2] mm: fs: Invalidate BH LRU during page migration

From: kernel test robot
Date: Wed Mar 03 2021 - 13:26:01 EST


Hi Minchan,

I love your patch! Yet something to improve:

[auto build test ERROR on block/for-next]
[also build test ERROR on linux/master linus/master v5.12-rc1 next-20210303]
[cannot apply to hnaz-linux-mm/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Minchan-Kim/mm-disable-LRU-pagevec-during-the-migration-temporarily/20210303-191809
base: https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git for-next
config: powerpc64-randconfig-r006-20210303 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project a7cad6680b4087eff8994f1f99ac40c661a6621f)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install powerpc64 cross compiling tool for clang build
# apt-get install binutils-powerpc64-linux-gnu
# https://github.com/0day-ci/linux/commit/a1c74fba81d1258e320ef52bc995cb0333e3e083
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Minchan-Kim/mm-disable-LRU-pagevec-during-the-migration-temporarily/20210303-191809
git checkout a1c74fba81d1258e320ef52bc995cb0333e3e083
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=powerpc64

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@xxxxxxxxx>

All errors (new ones prefixed by >>):

>> mm/swap.c:671:2: error: implicit declaration of function 'invalidate_bh_lru' [-Werror,-Wimplicit-function-declaration]
invalidate_bh_lru(NULL);
^
mm/swap.c:671:2: note: did you mean 'invalidate_bdev'?
include/linux/blkdev.h:2021:20: note: 'invalidate_bdev' declared here
static inline void invalidate_bdev(struct block_device *bdev)
^
>> mm/swap.c:860:7: error: implicit declaration of function 'has_bh_in_lru' [-Werror,-Wimplicit-function-declaration]
has_bh_in_lru(cpu, NULL)) {
^
2 errors generated.


vim +/invalidate_bh_lru +671 mm/swap.c

634
635 /*
636 * Drain pages out of the cpu's pagevecs.
637 * Either "cpu" is the current CPU, and preemption has already been
638 * disabled; or "cpu" is being hot-unplugged, and is already dead.
639 */
640 void lru_add_drain_cpu(int cpu)
641 {
642 struct pagevec *pvec = &per_cpu(lru_pvecs.lru_add, cpu);
643
644 if (pagevec_count(pvec))
645 __pagevec_lru_add(pvec);
646
647 pvec = &per_cpu(lru_rotate.pvec, cpu);
648 /* Disabling interrupts below acts as a compiler barrier. */
649 if (data_race(pagevec_count(pvec))) {
650 unsigned long flags;
651
652 /* No harm done if a racing interrupt already did this */
653 local_lock_irqsave(&lru_rotate.lock, flags);
654 pagevec_lru_move_fn(pvec, pagevec_move_tail_fn);
655 local_unlock_irqrestore(&lru_rotate.lock, flags);
656 }
657
658 pvec = &per_cpu(lru_pvecs.lru_deactivate_file, cpu);
659 if (pagevec_count(pvec))
660 pagevec_lru_move_fn(pvec, lru_deactivate_file_fn);
661
662 pvec = &per_cpu(lru_pvecs.lru_deactivate, cpu);
663 if (pagevec_count(pvec))
664 pagevec_lru_move_fn(pvec, lru_deactivate_fn);
665
666 pvec = &per_cpu(lru_pvecs.lru_lazyfree, cpu);
667 if (pagevec_count(pvec))
668 pagevec_lru_move_fn(pvec, lru_lazyfree_fn);
669
670 activate_page_drain(cpu);
> 671 invalidate_bh_lru(NULL);
672 }
673
674 /**
675 * deactivate_file_page - forcefully deactivate a file page
676 * @page: page to deactivate
677 *
678 * This function hints the VM that @page is a good reclaim candidate,
679 * for example if its invalidation fails due to the page being dirty
680 * or under writeback.
681 */
682 void deactivate_file_page(struct page *page)
683 {
684 /*
685 * In a workload with many unevictable page such as mprotect,
686 * unevictable page deactivation for accelerating reclaim is pointless.
687 */
688 if (PageUnevictable(page))
689 return;
690
691 if (likely(get_page_unless_zero(page))) {
692 struct pagevec *pvec;
693
694 local_lock(&lru_pvecs.lock);
695 pvec = this_cpu_ptr(&lru_pvecs.lru_deactivate_file);
696
697 if (pagevec_add_and_need_flush(pvec, page))
698 pagevec_lru_move_fn(pvec, lru_deactivate_file_fn);
699 local_unlock(&lru_pvecs.lock);
700 }
701 }
702
703 /*
704 * deactivate_page - deactivate a page
705 * @page: page to deactivate
706 *
707 * deactivate_page() moves @page to the inactive list if @page was on the active
708 * list and was not an unevictable page. This is done to accelerate the reclaim
709 * of @page.
710 */
711 void deactivate_page(struct page *page)
712 {
713 if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) {
714 struct pagevec *pvec;
715
716 local_lock(&lru_pvecs.lock);
717 pvec = this_cpu_ptr(&lru_pvecs.lru_deactivate);
718 get_page(page);
719 if (pagevec_add_and_need_flush(pvec, page))
720 pagevec_lru_move_fn(pvec, lru_deactivate_fn);
721 local_unlock(&lru_pvecs.lock);
722 }
723 }
724
725 /**
726 * mark_page_lazyfree - make an anon page lazyfree
727 * @page: page to deactivate
728 *
729 * mark_page_lazyfree() moves @page to the inactive file list.
730 * This is done to accelerate the reclaim of @page.
731 */
732 void mark_page_lazyfree(struct page *page)
733 {
734 if (PageLRU(page) && PageAnon(page) && PageSwapBacked(page) &&
735 !PageSwapCache(page) && !PageUnevictable(page)) {
736 struct pagevec *pvec;
737
738 local_lock(&lru_pvecs.lock);
739 pvec = this_cpu_ptr(&lru_pvecs.lru_lazyfree);
740 get_page(page);
741 if (pagevec_add_and_need_flush(pvec, page))
742 pagevec_lru_move_fn(pvec, lru_lazyfree_fn);
743 local_unlock(&lru_pvecs.lock);
744 }
745 }
746
747 void lru_add_drain(void)
748 {
749 local_lock(&lru_pvecs.lock);
750 lru_add_drain_cpu(smp_processor_id());
751 local_unlock(&lru_pvecs.lock);
752 }
753
754 void lru_add_drain_cpu_zone(struct zone *zone)
755 {
756 local_lock(&lru_pvecs.lock);
757 lru_add_drain_cpu(smp_processor_id());
758 drain_local_pages(zone);
759 local_unlock(&lru_pvecs.lock);
760 }
761
762 #ifdef CONFIG_SMP
763
764 static DEFINE_PER_CPU(struct work_struct, lru_add_drain_work);
765
766 static void lru_add_drain_per_cpu(struct work_struct *dummy)
767 {
768 lru_add_drain();
769 }
770
771 /*
772 * Doesn't need any cpu hotplug locking because we do rely on per-cpu
773 * kworkers being shut down before our page_alloc_cpu_dead callback is
774 * executed on the offlined cpu.
775 * Calling this function with cpu hotplug locks held can actually lead
776 * to obscure indirect dependencies via WQ context.
777 */
778 void lru_add_drain_all(bool force_all_cpus)
779 {
780 /*
781 * lru_drain_gen - Global pages generation number
782 *
783 * (A) Definition: global lru_drain_gen = x implies that all generations
784 * 0 < n <= x are already *scheduled* for draining.
785 *
786 * This is an optimization for the highly-contended use case where a
787 * user space workload keeps constantly generating a flow of pages for
788 * each CPU.
789 */
790 static unsigned int lru_drain_gen;
791 static struct cpumask has_work;
792 static DEFINE_MUTEX(lock);
793 unsigned cpu, this_gen;
794
795 /*
796 * Make sure nobody triggers this path before mm_percpu_wq is fully
797 * initialized.
798 */
799 if (WARN_ON(!mm_percpu_wq))
800 return;
801
802 /*
803 * Guarantee pagevec counter stores visible by this CPU are visible to
804 * other CPUs before loading the current drain generation.
805 */
806 smp_mb();
807
808 /*
809 * (B) Locally cache global LRU draining generation number
810 *
811 * The read barrier ensures that the counter is loaded before the mutex
812 * is taken. It pairs with smp_mb() inside the mutex critical section
813 * at (D).
814 */
815 this_gen = smp_load_acquire(&lru_drain_gen);
816
817 mutex_lock(&lock);
818
819 /*
820 * (C) Exit the draining operation if a newer generation, from another
821 * lru_add_drain_all(), was already scheduled for draining. Check (A).
822 */
823 if (unlikely(this_gen != lru_drain_gen))
824 goto done;
825
826 /*
827 * (D) Increment global generation number
828 *
829 * Pairs with smp_load_acquire() at (B), outside of the critical
830 * section. Use a full memory barrier to guarantee that the new global
831 * drain generation number is stored before loading pagevec counters.
832 *
833 * This pairing must be done here, before the for_each_online_cpu loop
834 * below which drains the page vectors.
835 *
836 * Let x, y, and z represent some system CPU numbers, where x < y < z.
837 * Assume CPU #z is is in the middle of the for_each_online_cpu loop
838 * below and has already reached CPU #y's per-cpu data. CPU #x comes
839 * along, adds some pages to its per-cpu vectors, then calls
840 * lru_add_drain_all().
841 *
842 * If the paired barrier is done at any later step, e.g. after the
843 * loop, CPU #x will just exit at (C) and miss flushing out all of its
844 * added pages.
845 */
846 WRITE_ONCE(lru_drain_gen, lru_drain_gen + 1);
847 smp_mb();
848
849 cpumask_clear(&has_work);
850 for_each_online_cpu(cpu) {
851 struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
852
853 if (force_all_cpus ||
854 pagevec_count(&per_cpu(lru_pvecs.lru_add, cpu)) ||
855 data_race(pagevec_count(&per_cpu(lru_rotate.pvec, cpu))) ||
856 pagevec_count(&per_cpu(lru_pvecs.lru_deactivate_file, cpu)) ||
857 pagevec_count(&per_cpu(lru_pvecs.lru_deactivate, cpu)) ||
858 pagevec_count(&per_cpu(lru_pvecs.lru_lazyfree, cpu)) ||
859 need_activate_page_drain(cpu) ||
> 860 has_bh_in_lru(cpu, NULL)) {
861 INIT_WORK(work, lru_add_drain_per_cpu);
862 queue_work_on(cpu, mm_percpu_wq, work);
863 __cpumask_set_cpu(cpu, &has_work);
864 }
865 }
866
867 for_each_cpu(cpu, &has_work)
868 flush_work(&per_cpu(lru_add_drain_work, cpu));
869
870 done:
871 mutex_unlock(&lock);
872 }
873 #else
874 void lru_add_drain_all(void)
875 {
876 lru_add_drain();
877 }
878 #endif /* CONFIG_SMP */
879

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@xxxxxxxxxxxx

Attachment: .config.gz
Description: application/gzip