Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

user_driver: use ramfs to allocate DMA buffers #537

Closed
wants to merge 2 commits into from

Conversation

jstarks
Copy link
Member

@jstarks jstarks commented Dec 18, 2024

When allocating DMA buffers for noiommu VFIO devices, we need to ensure that the kernel will not move the buffers in physical memory. In some cases, we achieve that by managing the memory entirely in user mode. In others, we allocate memory from the kernel on demand and then lock it with mlock.

The mlock approach apparently does not always work--since we are locking pages allocated for an anonymous mapping, the kernel is still free to move the allocation between physical pages. mlock's only guarantee seems to be that the kernel will not swap the page out to the swap file (which doesn't exist in the OpenHCL environment anyway). It looks like pages are indeed being moved with the ARM64 kernel for a reason that is not yet completely understood.

To fix this, switch to using a temporary file in ramfs instead of using an anonymous mapping. This should guarantee the allocation does not move between physical pages since ramfs pages are allocated as immovable in the kernel.

Also, update the init process to mount ramfs. This has no resource usage effect by itself--ramfs allocates memory only as required.

When allocating DMA buffers for noiommu VFIO devices, we need to ensure
that the kernel will not move the buffers in physical memory. In some
cases, we achieve that by managing the memory entirely in user mode. In
others, we allocate memory from the kernel on demand and then lock it
with `mlock`.

The `mlock` approach apparently does not always work--since we are
locking pages allocated for an anonymous mapping, the kernel is still
free to _move_ the allocation between physical pages. `mlock`'s only
guarantee seems to be that the kernel will not swap the page out to the
swap file (which doesn't exist in the OpenHCL environment anyway). It
looks like pages are indeed being moved with the ARM64 kernel for a
reason that is not yet completely understood.

To fix this, switch to using a temporary file in ramfs instead of using
an anonymous mapping. This should guarantee the allocation does not move
between physical pages since ramfs pages are allocated as unmovable in
the kernel.

Also, update the init process to mount ramfs. This has no resource usage
effect by itself--ramfs allocates memory only as required.
@jstarks jstarks requested a review from a team as a code owner December 18, 2024 22:53
// SAFETY: No file descriptor or address is being passed.
// The result is being validated.
let addr = unsafe {
libc::mmap(
std::ptr::null_mut(),
len,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_LOCKED,
-1,
libc::MAP_SHARED | libc::MAP_LOCKED,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAP_ANONYMOUS should zeroinit pages according to the documentation but MAP_SHARED should not. LockMem::new should zeroinit pages anyway, do we know if all cases are covered? (assuming the doc is correct about this).

@jstarks jstarks marked this pull request as draft December 18, 2024 23:23
@mattkur
Copy link
Contributor

mattkur commented Dec 19, 2024

Unfortunately, testing shows that this doesn't seem to resolve the underlying issue.

@jstarks jstarks closed this Jan 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants