** Also affects: linux (Ubuntu Noble)
Importance: Undecided
Status: New
** Also affects: linux-nvidia (Ubuntu Noble)
Importance: Undecided
Status: New
** Also affects: linux-nvidia-bos (Ubuntu Noble)
Importance: Undecided
Status: New
** Description changed:
+ SRU Justification
+
+ [Impact]
+
+ There is a performance regression seen for calls to get_user_pages() on
+ single-page NULL-mapping folios, introduced by commit f002882ca369 ("mm: merge
+ folio_is_secretmem() and folio_fast_pin_allowed() into
+ gup_fast_folio_allowed()").
+
+ When either CONFIG_SECRETMEM=y, or when the folio is a long-term writable pin,
+ the current implementation requires that the mapping be checked as either a
+ secretmem mapping or a file-backed one. If it is either, or if the mapping is
+ NULL, the slow path is forced.
+
+ However, when the mapping is NULL, the folio cannot be a secretmem mapping.
+ Thus, as long as the folio is NOT a long-term writable pin, the fast path can
+ still be used.
+
+ This performance regression was initially observed during GPU Direct Storage
+ (GDS) workloads.
+
+ [Fix]
+
+ The upstream commit c494788faffe ("mm/gup: fix GUP-fast fallback for
+ NULL-mapping order-0 folios") resolves the performance regression by changing
+ gup_fast_folio_allowed() to allow the fast path for the case described above,
+ where the folio is NOT a long-term writable pin and its mapping field is NULL.
+
+ [Test Plan]
+
+ Build and boot tested.
+
+ The performance regression and subsequent fix can be verified with a GDS
+ workload. The original bug report also describes a test kernel module that
uses
+ the `alloc_page` + `vm_insert_page` + `pin_user_pages_fast(..., FOLL_WRITE,
+ ...)` functions to emulate GDS behavior, and using
`get_user_pages_fast_only()`
+ on that to validate that the fast path is now allowed in this scenario.
+
+ [Where problems could occur]
+
+ The fix affects the get_user_pages*() path of the mm subsystem, which is used
+ heavily. The fix has been reviewed and applied in upstream Linux.
+
+ -------------------------------------------------------
+
+ Original report:
+
Clean cherry-pick from linux-next:
```
(cherry picked from commit ae75e88d8c258fd849de594e7d468b5263e7b3e3
linux-next)
```
John Hubbard, Acked-by David Hildenbrand, applied by Andrew Morton.
[Lore
thread](https://lore.kernel.org/all/[email protected]/).
## Problem
`f002882ca369` (present on this branch) made `gup_fast_folio_allowed()` bail
to the
slow path for *any* order-0 folio with a NULL `->mapping` when
`CONFIG_SECRETMEM=y`.
Pages from `alloc_page()` + `vm_insert_page()` legitimately have a NULL
mapping, so
every `pin_user_pages_fast()` over such a range misses the fast path —
nvidia-fs
(GPUDirect Storage) allocates its shadow buffers exactly this way.
The NULL check was meant to catch truncated file-backed pages, not secretmem.
Secretmem folios are published via `filemap_add_folio()`, which always sets
`->mapping`, so a NULL mapping proves the folio is *not* secretmem. Returning
`!reject_file_backed` keeps long-term writable pins on the slow path and
restores
the fast path otherwise — exactly the pre-`f002882ca369` behaviour.
`CONFIG_SECRETMEM=y` on amd64 and arm64, so this is live on every
flavour we ship.
## Measurement (GH200, 288 cores)
A module reproducing the nvidia-fs pattern (`alloc_page` + `vm_insert_page`,
then
`pin_user_pages_fast(..., FOLL_WRITE, ...)`), with an anonymous-memory
control the
patch cannot affect. `get_user_pages_fast_only()` gives the GUP-fast verdict
directly: **0/N unpatched, N/N patched**.
Median ns/page, 512 pages/thread, 5 reps:
| threads | 4K unpatched → patched | 64K unpatched → patched |
|--------:|-----------------------:|------------------------:|
| 1 | 34 → 34 (1.0x) | 33 → 30 (1.1x) |
| 8 | 74 → 33 (**2.2x**) | 1920 → 31 (**62x**) |
| 32 | 95 → 33 (**2.9x**) | 4792 → 33 (**145x**) |
| 128 | 500 → 218 (noisy) | 16673 → 76 (**219x**) |
The anon control held at 30-35 ns/page across all four kernels, so only the
affected
range moved. Stock `7.0.0-1015-nvidia-64k` independently reproduces the
unpatched 64K
numbers (8 threads: 1176 vs 37), so this isn't a test-config artefact.
Single-threaded it's a wash; the win is under concurrency. `perf` on the
unpatched
64K kernel shows the slow path is ~90% lock contention
(`queued_spin_lock_slowpath`
72%), gone entirely once patched — contention that scales with thread count,
not a
fixed per-page cost.
## Risk
Low. One line in a static function with three callers, all in GUP-fast. Only
`reject_file_backed == false && check_secretmem && mapping == NULL` changes
behaviour; long-term writable pins are untouched.
A secretmem folio caught mid-truncate can't happen here: `secretmem_setattr()`
refuses to shrink, there's no `.fallocate` (so no punch-hole), and
`secretmem_migrate_folio()` returns `-EBUSY`. Only inode eviction remains,
which
requires every VMA gone — no VMA, no PTE for GUP-fast to walk. Raised by David
Hildenbrand on v1 and resolved before he Acked.
## Testing
Applies cleanly; built arm64 4K/64K and x86_64, no new warnings; verified in
the
binary (unpatched `mov w0, #0x0` vs patched `eor w0, w0, #0x1`); benchmarked
as above.
** Changed in: linux (Ubuntu Noble)
Status: New => In Progress
** Changed in: linux (Ubuntu Noble)
Assignee: (unassigned) => Jacob Martin (jacobmartin)
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2162917
Title:
Backport: "mm/gup: fix GUP-fast fallback for NULL-mapping order-0
folios"
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2162917/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs