io_uring/net: fail zc sendmsg when unsupported by socket
[platform/kernel/linux-starfive.git] / mm / migrate_device.c
index 5ab6ab9..6fa682e 100644 (file)
@@ -325,14 +325,14 @@ static void migrate_vma_collect(struct migrate_vma *migrate)
  * folio_migrate_mapping(), except that here we allow migration of a
  * ZONE_DEVICE page.
  */
-static bool migrate_vma_check_page(struct page *page)
+static bool migrate_vma_check_page(struct page *page, struct page *fault_page)
 {
        /*
         * One extra ref because caller holds an extra reference, either from
         * isolate_lru_page() for a regular page, or migrate_vma_collect() for
         * a device page.
         */
-       int extra = 1;
+       int extra = 1 + (page == fault_page);
 
        /*
         * FIXME support THP (transparent huge page), it is bit more complex to
@@ -357,26 +357,20 @@ static bool migrate_vma_check_page(struct page *page)
 }
 
 /*
- * migrate_vma_unmap() - replace page mapping with special migration pte entry
- * @migrate: migrate struct containing all migration information
- *
- * Isolate pages from the LRU and replace mappings (CPU page table pte) with a
- * special migration pte entry and check if it has been pinned. Pinned pages are
- * restored because we cannot migrate them.
- *
- * This is the last step before we call the device driver callback to allocate
- * destination memory and copy contents of original page over to new page.
+ * Unmaps pages for migration. Returns number of unmapped pages.
  */
-static void migrate_vma_unmap(struct migrate_vma *migrate)
+static unsigned long migrate_device_unmap(unsigned long *src_pfns,
+                                         unsigned long npages,
+                                         struct page *fault_page)
 {
-       const unsigned long npages = migrate->npages;
        unsigned long i, restore = 0;
        bool allow_drain = true;
+       unsigned long unmapped = 0;
 
        lru_add_drain();
 
        for (i = 0; i < npages; i++) {
-               struct page *page = migrate_pfn_to_page(migrate->src[i]);
+               struct page *page = migrate_pfn_to_page(src_pfns[i]);
                struct folio *folio;
 
                if (!page)
@@ -391,8 +385,7 @@ static void migrate_vma_unmap(struct migrate_vma *migrate)
                        }
 
                        if (isolate_lru_page(page)) {
-                               migrate->src[i] &= ~MIGRATE_PFN_MIGRATE;
-                               migrate->cpages--;
+                               src_pfns[i] &= ~MIGRATE_PFN_MIGRATE;
                                restore++;
                                continue;
                        }
@@ -405,34 +398,55 @@ static void migrate_vma_unmap(struct migrate_vma *migrate)
                if (folio_mapped(folio))
                        try_to_migrate(folio, 0);
 
-               if (page_mapped(page) || !migrate_vma_check_page(page)) {
+               if (page_mapped(page) ||
+                   !migrate_vma_check_page(page, fault_page)) {
                        if (!is_zone_device_page(page)) {
                                get_page(page);
                                putback_lru_page(page);
                        }
 
-                       migrate->src[i] &= ~MIGRATE_PFN_MIGRATE;
-                       migrate->cpages--;
+                       src_pfns[i] &= ~MIGRATE_PFN_MIGRATE;
                        restore++;
                        continue;
                }
+
+               unmapped++;
        }
 
        for (i = 0; i < npages && restore; i++) {
-               struct page *page = migrate_pfn_to_page(migrate->src[i]);
+               struct page *page = migrate_pfn_to_page(src_pfns[i]);
                struct folio *folio;
 
-               if (!page || (migrate->src[i] & MIGRATE_PFN_MIGRATE))
+               if (!page || (src_pfns[i] & MIGRATE_PFN_MIGRATE))
                        continue;
 
                folio = page_folio(page);
                remove_migration_ptes(folio, folio, false);
 
-               migrate->src[i] = 0;
+               src_pfns[i] = 0;
                folio_unlock(folio);
                folio_put(folio);
                restore--;
        }
+
+       return unmapped;
+}
+
+/*
+ * migrate_vma_unmap() - replace page mapping with special migration pte entry
+ * @migrate: migrate struct containing all migration information
+ *
+ * Isolate pages from the LRU and replace mappings (CPU page table pte) with a
+ * special migration pte entry and check if it has been pinned. Pinned pages are
+ * restored because we cannot migrate them.
+ *
+ * This is the last step before we call the device driver callback to allocate
+ * destination memory and copy contents of original page over to new page.
+ */
+static void migrate_vma_unmap(struct migrate_vma *migrate)
+{
+       migrate->cpages = migrate_device_unmap(migrate->src, migrate->npages,
+                                       migrate->fault_page);
 }
 
 /**
@@ -517,6 +531,8 @@ int migrate_vma_setup(struct migrate_vma *args)
                return -EINVAL;
        if (!args->src || !args->dst)
                return -EINVAL;
+       if (args->fault_page && !is_device_private_page(args->fault_page))
+               return -EINVAL;
 
        memset(args->src, 0, sizeof(*args->src) * nr_pages);
        args->cpages = 0;
@@ -677,42 +693,38 @@ abort:
        *src &= ~MIGRATE_PFN_MIGRATE;
 }
 
-/**
- * migrate_vma_pages() - migrate meta-data from src page to dst page
- * @migrate: migrate struct containing all migration information
- *
- * This migrates struct page meta-data from source struct page to destination
- * struct page. This effectively finishes the migration from source page to the
- * destination page.
- */
-void migrate_vma_pages(struct migrate_vma *migrate)
+static void __migrate_device_pages(unsigned long *src_pfns,
+                               unsigned long *dst_pfns, unsigned long npages,
+                               struct migrate_vma *migrate)
 {
-       const unsigned long npages = migrate->npages;
-       const unsigned long start = migrate->start;
        struct mmu_notifier_range range;
-       unsigned long addr, i;
+       unsigned long i;
        bool notified = false;
 
-       for (i = 0, addr = start; i < npages; addr += PAGE_SIZE, i++) {
-               struct page *newpage = migrate_pfn_to_page(migrate->dst[i]);
-               struct page *page = migrate_pfn_to_page(migrate->src[i]);
+       for (i = 0; i < npages; i++) {
+               struct page *newpage = migrate_pfn_to_page(dst_pfns[i]);
+               struct page *page = migrate_pfn_to_page(src_pfns[i]);
                struct address_space *mapping;
                int r;
 
                if (!newpage) {
-                       migrate->src[i] &= ~MIGRATE_PFN_MIGRATE;
+                       src_pfns[i] &= ~MIGRATE_PFN_MIGRATE;
                        continue;
                }
 
                if (!page) {
+                       unsigned long addr;
+
+                       if (!(src_pfns[i] & MIGRATE_PFN_MIGRATE))
+                               continue;
+
                        /*
                         * The only time there is no vma is when called from
                         * migrate_device_coherent_page(). However this isn't
                         * called if the page could not be unmapped.
                         */
-                       VM_BUG_ON(!migrate->vma);
-                       if (!(migrate->src[i] & MIGRATE_PFN_MIGRATE))
-                               continue;
+                       VM_BUG_ON(!migrate);
+                       addr = migrate->start + i*PAGE_SIZE;
                        if (!notified) {
                                notified = true;
 
@@ -723,7 +735,7 @@ void migrate_vma_pages(struct migrate_vma *migrate)
                                mmu_notifier_invalidate_range_start(&range);
                        }
                        migrate_vma_insert_page(migrate, addr, newpage,
-                                               &migrate->src[i]);
+                                               &src_pfns[i]);
                        continue;
                }
 
@@ -736,21 +748,26 @@ void migrate_vma_pages(struct migrate_vma *migrate)
                         * device private or coherent memory.
                         */
                        if (mapping) {
-                               migrate->src[i] &= ~MIGRATE_PFN_MIGRATE;
+                               src_pfns[i] &= ~MIGRATE_PFN_MIGRATE;
                                continue;
                        }
                } else if (is_zone_device_page(newpage)) {
                        /*
                         * Other types of ZONE_DEVICE page are not supported.
                         */
-                       migrate->src[i] &= ~MIGRATE_PFN_MIGRATE;
+                       src_pfns[i] &= ~MIGRATE_PFN_MIGRATE;
                        continue;
                }
 
-               r = migrate_folio(mapping, page_folio(newpage),
-                               page_folio(page), MIGRATE_SYNC_NO_COPY);
+               if (migrate && migrate->fault_page == page)
+                       r = migrate_folio_extra(mapping, page_folio(newpage),
+                                               page_folio(page),
+                                               MIGRATE_SYNC_NO_COPY, 1);
+               else
+                       r = migrate_folio(mapping, page_folio(newpage),
+                                       page_folio(page), MIGRATE_SYNC_NO_COPY);
                if (r != MIGRATEPAGE_SUCCESS)
-                       migrate->src[i] &= ~MIGRATE_PFN_MIGRATE;
+                       src_pfns[i] &= ~MIGRATE_PFN_MIGRATE;
        }
 
        /*
@@ -761,28 +778,56 @@ void migrate_vma_pages(struct migrate_vma *migrate)
        if (notified)
                mmu_notifier_invalidate_range_only_end(&range);
 }
-EXPORT_SYMBOL(migrate_vma_pages);
 
 /**
- * migrate_vma_finalize() - restore CPU page table entry
+ * migrate_device_pages() - migrate meta-data from src page to dst page
+ * @src_pfns: src_pfns returned from migrate_device_range()
+ * @dst_pfns: array of pfns allocated by the driver to migrate memory to
+ * @npages: number of pages in the range
+ *
+ * Equivalent to migrate_vma_pages(). This is called to migrate struct page
+ * meta-data from source struct page to destination.
+ */
+void migrate_device_pages(unsigned long *src_pfns, unsigned long *dst_pfns,
+                       unsigned long npages)
+{
+       __migrate_device_pages(src_pfns, dst_pfns, npages, NULL);
+}
+EXPORT_SYMBOL(migrate_device_pages);
+
+/**
+ * migrate_vma_pages() - migrate meta-data from src page to dst page
  * @migrate: migrate struct containing all migration information
  *
- * This replaces the special migration pte entry with either a mapping to the
- * new page if migration was successful for that page, or to the original page
- * otherwise.
+ * This migrates struct page meta-data from source struct page to destination
+ * struct page. This effectively finishes the migration from source page to the
+ * destination page.
+ */
+void migrate_vma_pages(struct migrate_vma *migrate)
+{
+       __migrate_device_pages(migrate->src, migrate->dst, migrate->npages, migrate);
+}
+EXPORT_SYMBOL(migrate_vma_pages);
+
+/*
+ * migrate_device_finalize() - complete page migration
+ * @src_pfns: src_pfns returned from migrate_device_range()
+ * @dst_pfns: array of pfns allocated by the driver to migrate memory to
+ * @npages: number of pages in the range
  *
- * This also unlocks the pages and puts them back on the lru, or drops the extra
- * refcount, for device pages.
+ * Completes migration of the page by removing special migration entries.
+ * Drivers must ensure copying of page data is complete and visible to the CPU
+ * before calling this.
  */
-void migrate_vma_finalize(struct migrate_vma *migrate)
+void migrate_device_finalize(unsigned long *src_pfns,
+                       unsigned long *dst_pfns, unsigned long npages)
 {
-       const unsigned long npages = migrate->npages;
        unsigned long i;
 
        for (i = 0; i < npages; i++) {
                struct folio *dst, *src;
-               struct page *newpage = migrate_pfn_to_page(migrate->dst[i]);
-               struct page *page = migrate_pfn_to_page(migrate->src[i]);
+               struct page *newpage = migrate_pfn_to_page(dst_pfns[i]);
+               struct page *page = migrate_pfn_to_page(src_pfns[i]);
 
                if (!page) {
                        if (newpage) {
@@ -792,7 +837,7 @@ void migrate_vma_finalize(struct migrate_vma *migrate)
                        continue;
                }
 
-               if (!(migrate->src[i] & MIGRATE_PFN_MIGRATE) || !newpage) {
+               if (!(src_pfns[i] & MIGRATE_PFN_MIGRATE) || !newpage) {
                        if (newpage) {
                                unlock_page(newpage);
                                put_page(newpage);
@@ -819,8 +864,72 @@ void migrate_vma_finalize(struct migrate_vma *migrate)
                }
        }
 }
+EXPORT_SYMBOL(migrate_device_finalize);
+
+/**
+ * migrate_vma_finalize() - restore CPU page table entry
+ * @migrate: migrate struct containing all migration information
+ *
+ * This replaces the special migration pte entry with either a mapping to the
+ * new page if migration was successful for that page, or to the original page
+ * otherwise.
+ *
+ * This also unlocks the pages and puts them back on the lru, or drops the extra
+ * refcount, for device pages.
+ */
+void migrate_vma_finalize(struct migrate_vma *migrate)
+{
+       migrate_device_finalize(migrate->src, migrate->dst, migrate->npages);
+}
 EXPORT_SYMBOL(migrate_vma_finalize);
 
+/**
+ * migrate_device_range() - migrate device private pfns to normal memory.
+ * @src_pfns: array large enough to hold migrating source device private pfns.
+ * @start: starting pfn in the range to migrate.
+ * @npages: number of pages to migrate.
+ *
+ * migrate_vma_setup() is similar in concept to migrate_vma_setup() except that
+ * instead of looking up pages based on virtual address mappings a range of
+ * device pfns that should be migrated to system memory is used instead.
+ *
+ * This is useful when a driver needs to free device memory but doesn't know the
+ * virtual mappings of every page that may be in device memory. For example this
+ * is often the case when a driver is being unloaded or unbound from a device.
+ *
+ * Like migrate_vma_setup() this function will take a reference and lock any
+ * migrating pages that aren't free before unmapping them. Drivers may then
+ * allocate destination pages and start copying data from the device to CPU
+ * memory before calling migrate_device_pages().
+ */
+int migrate_device_range(unsigned long *src_pfns, unsigned long start,
+                       unsigned long npages)
+{
+       unsigned long i, pfn;
+
+       for (pfn = start, i = 0; i < npages; pfn++, i++) {
+               struct page *page = pfn_to_page(pfn);
+
+               if (!get_page_unless_zero(page)) {
+                       src_pfns[i] = 0;
+                       continue;
+               }
+
+               if (!trylock_page(page)) {
+                       src_pfns[i] = 0;
+                       put_page(page);
+                       continue;
+               }
+
+               src_pfns[i] = migrate_pfn(pfn) | MIGRATE_PFN_MIGRATE;
+       }
+
+       migrate_device_unmap(src_pfns, npages, NULL);
+
+       return 0;
+}
+EXPORT_SYMBOL(migrate_device_range);
+
 /*
  * Migrate a device coherent page back to normal memory. The caller should have
  * a reference on page which will be copied to the new page if migration is
@@ -829,25 +938,19 @@ EXPORT_SYMBOL(migrate_vma_finalize);
 int migrate_device_coherent_page(struct page *page)
 {
        unsigned long src_pfn, dst_pfn = 0;
-       struct migrate_vma args;
        struct page *dpage;
 
        WARN_ON_ONCE(PageCompound(page));
 
        lock_page(page);
        src_pfn = migrate_pfn(page_to_pfn(page)) | MIGRATE_PFN_MIGRATE;
-       args.src = &src_pfn;
-       args.dst = &dst_pfn;
-       args.cpages = 1;
-       args.npages = 1;
-       args.vma = NULL;
 
        /*
         * We don't have a VMA and don't need to walk the page tables to find
         * the source page. So call migrate_vma_unmap() directly to unmap the
         * page as migrate_vma_setup() will fail if args.vma == NULL.
         */
-       migrate_vma_unmap(&args);
+       migrate_device_unmap(&src_pfn, 1, NULL);
        if (!(src_pfn & MIGRATE_PFN_MIGRATE))
                return -EBUSY;
 
@@ -857,10 +960,10 @@ int migrate_device_coherent_page(struct page *page)
                dst_pfn = migrate_pfn(page_to_pfn(dpage));
        }
 
-       migrate_vma_pages(&args);
+       migrate_device_pages(&src_pfn, &dst_pfn, 1);
        if (src_pfn & MIGRATE_PFN_MIGRATE)
                copy_highpage(dpage, page);
-       migrate_vma_finalize(&args);
+       migrate_device_finalize(&src_pfn, &dst_pfn, 1);
 
        if (src_pfn & MIGRATE_PFN_MIGRATE)
                return 0;