Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm/migrate_device.c: refactor migrate_vma and migrate_deivce_coherent_page()

migrate_device_coherent_page() reuses the existing migrate_vma family of
functions to migrate a specific page without providing a valid mapping or
vma. This looks a bit odd because it means we are calling migrate_vma_*()
without setting a valid vma, however it was considered acceptable at the
time because the details were internal to migrate_device.c and there was
only a single user.

One of the reasons the details could be kept internal was that this was
strictly for migrating device coherent memory. Such memory can be copied
directly by the CPU without intervention from a driver. However this
isn't true for device private memory, and a future change requires similar
functionality for device private memory. So refactor the code into
something more sensible for migrating device memory without a vma.

Link: https://lkml.kernel.org/r/c7b2ff84e9b33d022cf4a40f87d051f281a16d8f.1664366292.git-series.apopple@nvidia.com
Signed-off-by: Alistair Popple <apopple@nvidia.com>
Cc: "Huang, Ying" <ying.huang@intel.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Yang Shi <shy828301@gmail.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Ralph Campbell <rcampbell@nvidia.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Alex Sierra <alex.sierra@amd.com>
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Felix Kuehling <Felix.Kuehling@amd.com>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Lyude Paul <lyude@redhat.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Alistair Popple and committed by
Andrew Morton
241f6885 0dc45ca1

+85 -65
+85 -65
mm/migrate_device.c
··· 357 357 } 358 358 359 359 /* 360 - * migrate_vma_unmap() - replace page mapping with special migration pte entry 361 - * @migrate: migrate struct containing all migration information 362 - * 363 - * Isolate pages from the LRU and replace mappings (CPU page table pte) with a 364 - * special migration pte entry and check if it has been pinned. Pinned pages are 365 - * restored because we cannot migrate them. 366 - * 367 - * This is the last step before we call the device driver callback to allocate 368 - * destination memory and copy contents of original page over to new page. 360 + * Unmaps pages for migration. Returns number of unmapped pages. 369 361 */ 370 - static void migrate_vma_unmap(struct migrate_vma *migrate) 362 + static unsigned long migrate_device_unmap(unsigned long *src_pfns, 363 + unsigned long npages, 364 + struct page *fault_page) 371 365 { 372 - const unsigned long npages = migrate->npages; 373 366 unsigned long i, restore = 0; 374 367 bool allow_drain = true; 368 + unsigned long unmapped = 0; 375 369 376 370 lru_add_drain(); 377 371 378 372 for (i = 0; i < npages; i++) { 379 - struct page *page = migrate_pfn_to_page(migrate->src[i]); 373 + struct page *page = migrate_pfn_to_page(src_pfns[i]); 380 374 struct folio *folio; 381 375 382 376 if (!page) ··· 385 391 } 386 392 387 393 if (isolate_lru_page(page)) { 388 - migrate->src[i] &= ~MIGRATE_PFN_MIGRATE; 389 - migrate->cpages--; 394 + src_pfns[i] &= ~MIGRATE_PFN_MIGRATE; 390 395 restore++; 391 396 continue; 392 397 } ··· 399 406 try_to_migrate(folio, 0); 400 407 401 408 if (page_mapped(page) || 402 - !migrate_vma_check_page(page, migrate->fault_page)) { 409 + !migrate_vma_check_page(page, fault_page)) { 403 410 if (!is_zone_device_page(page)) { 404 411 get_page(page); 405 412 putback_lru_page(page); 406 413 } 407 414 408 - migrate->src[i] &= ~MIGRATE_PFN_MIGRATE; 409 - migrate->cpages--; 415 + src_pfns[i] &= ~MIGRATE_PFN_MIGRATE; 410 416 restore++; 411 417 continue; 412 418 } 419 + 420 + unmapped++; 413 421 } 414 422 415 423 for (i = 0; i < npages && restore; i++) { 416 - struct page *page = migrate_pfn_to_page(migrate->src[i]); 424 + struct page *page = migrate_pfn_to_page(src_pfns[i]); 417 425 struct folio *folio; 418 426 419 - if (!page || (migrate->src[i] & MIGRATE_PFN_MIGRATE)) 427 + if (!page || (src_pfns[i] & MIGRATE_PFN_MIGRATE)) 420 428 continue; 421 429 422 430 folio = page_folio(page); 423 431 remove_migration_ptes(folio, folio, false); 424 432 425 - migrate->src[i] = 0; 433 + src_pfns[i] = 0; 426 434 folio_unlock(folio); 427 435 folio_put(folio); 428 436 restore--; 429 437 } 438 + 439 + return unmapped; 440 + } 441 + 442 + /* 443 + * migrate_vma_unmap() - replace page mapping with special migration pte entry 444 + * @migrate: migrate struct containing all migration information 445 + * 446 + * Isolate pages from the LRU and replace mappings (CPU page table pte) with a 447 + * special migration pte entry and check if it has been pinned. Pinned pages are 448 + * restored because we cannot migrate them. 449 + * 450 + * This is the last step before we call the device driver callback to allocate 451 + * destination memory and copy contents of original page over to new page. 452 + */ 453 + static void migrate_vma_unmap(struct migrate_vma *migrate) 454 + { 455 + migrate->cpages = migrate_device_unmap(migrate->src, migrate->npages, 456 + migrate->fault_page); 430 457 } 431 458 432 459 /** ··· 693 680 *src &= ~MIGRATE_PFN_MIGRATE; 694 681 } 695 682 696 - /** 697 - * migrate_vma_pages() - migrate meta-data from src page to dst page 698 - * @migrate: migrate struct containing all migration information 699 - * 700 - * This migrates struct page meta-data from source struct page to destination 701 - * struct page. This effectively finishes the migration from source page to the 702 - * destination page. 703 - */ 704 - void migrate_vma_pages(struct migrate_vma *migrate) 683 + static void migrate_device_pages(unsigned long *src_pfns, 684 + unsigned long *dst_pfns, unsigned long npages, 685 + struct migrate_vma *migrate) 705 686 { 706 - const unsigned long npages = migrate->npages; 707 - const unsigned long start = migrate->start; 708 687 struct mmu_notifier_range range; 709 - unsigned long addr, i; 688 + unsigned long i; 710 689 bool notified = false; 711 690 712 - for (i = 0, addr = start; i < npages; addr += PAGE_SIZE, i++) { 713 - struct page *newpage = migrate_pfn_to_page(migrate->dst[i]); 714 - struct page *page = migrate_pfn_to_page(migrate->src[i]); 691 + for (i = 0; i < npages; i++) { 692 + struct page *newpage = migrate_pfn_to_page(dst_pfns[i]); 693 + struct page *page = migrate_pfn_to_page(src_pfns[i]); 715 694 struct address_space *mapping; 716 695 int r; 717 696 718 697 if (!newpage) { 719 - migrate->src[i] &= ~MIGRATE_PFN_MIGRATE; 698 + src_pfns[i] &= ~MIGRATE_PFN_MIGRATE; 720 699 continue; 721 700 } 722 701 723 702 if (!page) { 703 + unsigned long addr; 704 + 724 705 /* 725 706 * The only time there is no vma is when called from 726 707 * migrate_device_coherent_page(). However this isn't 727 708 * called if the page could not be unmapped. 728 709 */ 729 - VM_BUG_ON(!migrate->vma); 730 - if (!(migrate->src[i] & MIGRATE_PFN_MIGRATE)) 710 + VM_BUG_ON(!migrate); 711 + addr = migrate->start + i*PAGE_SIZE; 712 + if (!(src_pfns[i] & MIGRATE_PFN_MIGRATE)) 731 713 continue; 732 714 if (!notified) { 733 715 notified = true; ··· 734 726 mmu_notifier_invalidate_range_start(&range); 735 727 } 736 728 migrate_vma_insert_page(migrate, addr, newpage, 737 - &migrate->src[i]); 729 + &src_pfns[i]); 738 730 continue; 739 731 } 740 732 ··· 747 739 * device private or coherent memory. 748 740 */ 749 741 if (mapping) { 750 - migrate->src[i] &= ~MIGRATE_PFN_MIGRATE; 742 + src_pfns[i] &= ~MIGRATE_PFN_MIGRATE; 751 743 continue; 752 744 } 753 745 } else if (is_zone_device_page(newpage)) { 754 746 /* 755 747 * Other types of ZONE_DEVICE page are not supported. 756 748 */ 757 - migrate->src[i] &= ~MIGRATE_PFN_MIGRATE; 749 + src_pfns[i] &= ~MIGRATE_PFN_MIGRATE; 758 750 continue; 759 751 } 760 752 761 - if (migrate->fault_page == page) 753 + if (migrate && migrate->fault_page == page) 762 754 r = migrate_folio_extra(mapping, page_folio(newpage), 763 755 page_folio(page), 764 756 MIGRATE_SYNC_NO_COPY, 1); ··· 766 758 r = migrate_folio(mapping, page_folio(newpage), 767 759 page_folio(page), MIGRATE_SYNC_NO_COPY); 768 760 if (r != MIGRATEPAGE_SUCCESS) 769 - migrate->src[i] &= ~MIGRATE_PFN_MIGRATE; 761 + src_pfns[i] &= ~MIGRATE_PFN_MIGRATE; 770 762 } 771 763 772 764 /* ··· 777 769 if (notified) 778 770 mmu_notifier_invalidate_range_only_end(&range); 779 771 } 780 - EXPORT_SYMBOL(migrate_vma_pages); 781 772 782 773 /** 783 - * migrate_vma_finalize() - restore CPU page table entry 774 + * migrate_vma_pages() - migrate meta-data from src page to dst page 784 775 * @migrate: migrate struct containing all migration information 785 776 * 786 - * This replaces the special migration pte entry with either a mapping to the 787 - * new page if migration was successful for that page, or to the original page 788 - * otherwise. 789 - * 790 - * This also unlocks the pages and puts them back on the lru, or drops the extra 791 - * refcount, for device pages. 777 + * This migrates struct page meta-data from source struct page to destination 778 + * struct page. This effectively finishes the migration from source page to the 779 + * destination page. 792 780 */ 793 - void migrate_vma_finalize(struct migrate_vma *migrate) 781 + void migrate_vma_pages(struct migrate_vma *migrate) 794 782 { 795 - const unsigned long npages = migrate->npages; 783 + migrate_device_pages(migrate->src, migrate->dst, migrate->npages, migrate); 784 + } 785 + EXPORT_SYMBOL(migrate_vma_pages); 786 + 787 + static void migrate_device_finalize(unsigned long *src_pfns, 788 + unsigned long *dst_pfns, unsigned long npages) 789 + { 796 790 unsigned long i; 797 791 798 792 for (i = 0; i < npages; i++) { 799 793 struct folio *dst, *src; 800 - struct page *newpage = migrate_pfn_to_page(migrate->dst[i]); 801 - struct page *page = migrate_pfn_to_page(migrate->src[i]); 794 + struct page *newpage = migrate_pfn_to_page(dst_pfns[i]); 795 + struct page *page = migrate_pfn_to_page(src_pfns[i]); 802 796 803 797 if (!page) { 804 798 if (newpage) { ··· 810 800 continue; 811 801 } 812 802 813 - if (!(migrate->src[i] & MIGRATE_PFN_MIGRATE) || !newpage) { 803 + if (!(src_pfns[i] & MIGRATE_PFN_MIGRATE) || !newpage) { 814 804 if (newpage) { 815 805 unlock_page(newpage); 816 806 put_page(newpage); ··· 837 827 } 838 828 } 839 829 } 830 + 831 + /** 832 + * migrate_vma_finalize() - restore CPU page table entry 833 + * @migrate: migrate struct containing all migration information 834 + * 835 + * This replaces the special migration pte entry with either a mapping to the 836 + * new page if migration was successful for that page, or to the original page 837 + * otherwise. 838 + * 839 + * This also unlocks the pages and puts them back on the lru, or drops the extra 840 + * refcount, for device pages. 841 + */ 842 + void migrate_vma_finalize(struct migrate_vma *migrate) 843 + { 844 + migrate_device_finalize(migrate->src, migrate->dst, migrate->npages); 845 + } 840 846 EXPORT_SYMBOL(migrate_vma_finalize); 841 847 842 848 /* ··· 863 837 int migrate_device_coherent_page(struct page *page) 864 838 { 865 839 unsigned long src_pfn, dst_pfn = 0; 866 - struct migrate_vma args; 867 840 struct page *dpage; 868 841 869 842 WARN_ON_ONCE(PageCompound(page)); 870 843 871 844 lock_page(page); 872 845 src_pfn = migrate_pfn(page_to_pfn(page)) | MIGRATE_PFN_MIGRATE; 873 - args.src = &src_pfn; 874 - args.dst = &dst_pfn; 875 - args.cpages = 1; 876 - args.npages = 1; 877 - args.vma = NULL; 878 846 879 847 /* 880 848 * We don't have a VMA and don't need to walk the page tables to find 881 849 * the source page. So call migrate_vma_unmap() directly to unmap the 882 850 * page as migrate_vma_setup() will fail if args.vma == NULL. 883 851 */ 884 - migrate_vma_unmap(&args); 852 + migrate_device_unmap(&src_pfn, 1, NULL); 885 853 if (!(src_pfn & MIGRATE_PFN_MIGRATE)) 886 854 return -EBUSY; 887 855 ··· 885 865 dst_pfn = migrate_pfn(page_to_pfn(dpage)); 886 866 } 887 867 888 - migrate_vma_pages(&args); 868 + migrate_device_pages(&src_pfn, &dst_pfn, 1, NULL); 889 869 if (src_pfn & MIGRATE_PFN_MIGRATE) 890 870 copy_highpage(dpage, page); 891 - migrate_vma_finalize(&args); 871 + migrate_device_finalize(&src_pfn, &dst_pfn, 1); 892 872 893 873 if (src_pfn & MIGRATE_PFN_MIGRATE) 894 874 return 0;