Struct userfaultfd::UffdBuilder
source · pub struct UffdBuilder { /* private fields */ }Expand description
A builder for initializing Uffd objects.
use userfaultfd::UffdBuilder;
let uffd = UffdBuilder::new()
.close_on_exec(true)
.non_blocking(true)
.user_mode_only(true)
.create();
assert!(uffd.is_ok());Implementations§
source§impl UffdBuilder
impl UffdBuilder
sourcepub fn new() -> UffdBuilder
pub fn new() -> UffdBuilder
Create a new builder with no required features or ioctls, close_on_exec and
non_blocking both set to false, and user_mode_only set to true.
Examples found in repository?
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
fn main() {
let num_pages = env::args()
.nth(1)
.expect("Usage: manpage <num_pages>")
.parse::<usize>()
.unwrap();
let page_size = sysconf(SysconfVar::PAGE_SIZE).unwrap().unwrap() as usize;
let len = num_pages * page_size;
// Create and enable userfaultfd object
let uffd = UffdBuilder::new()
.close_on_exec(true)
.non_blocking(true)
.user_mode_only(true)
.create()
.expect("uffd creation");
// Create a private anonymous mapping. The memory will be demand-zero paged--that is, not yet
// allocated. When we actually touch the memory, it will be allocated via the userfaultfd.
let addr = unsafe {
mmap(
None,
len.try_into().unwrap(),
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
-1,
0,
)
.expect("mmap")
};
println!("Address returned by mmap() = {:p}", addr);
// Register the memory range of the mapping we just created for handling by the userfaultfd
// object. In mode, we request to track missing pages (i.e., pages that have not yet been
// faulted in).
uffd.register(addr, len).expect("uffd.register()");
// Create a thread that will process the userfaultfd events
let _s = std::thread::spawn(move || fault_handler_thread(uffd));
// Main thread now touches memory in the mapping, touching locations 1024 bytes apart. This will
// trigger userfaultfd events for all pages in the region.
// Ensure that faulting address is not on a page boundary, in order to test that we correctly
// handle that case in fault_handling_thread()
let mut l = 0xf;
while l < len {
let ptr = (addr as usize + l) as *mut u8;
let c = unsafe { *ptr };
println!("Read address {:p} in main(): {:?}", ptr, c as char);
l += 1024;
std::thread::sleep(std::time::Duration::from_micros(100000));
}
}sourcepub fn close_on_exec(&mut self, close_on_exec: bool) -> &mut Self
pub fn close_on_exec(&mut self, close_on_exec: bool) -> &mut Self
Enable the close-on-exec flag for the new userfaultfd object (see the description of
O_CLOEXEC in open(2)).
Examples found in repository?
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
fn main() {
let num_pages = env::args()
.nth(1)
.expect("Usage: manpage <num_pages>")
.parse::<usize>()
.unwrap();
let page_size = sysconf(SysconfVar::PAGE_SIZE).unwrap().unwrap() as usize;
let len = num_pages * page_size;
// Create and enable userfaultfd object
let uffd = UffdBuilder::new()
.close_on_exec(true)
.non_blocking(true)
.user_mode_only(true)
.create()
.expect("uffd creation");
// Create a private anonymous mapping. The memory will be demand-zero paged--that is, not yet
// allocated. When we actually touch the memory, it will be allocated via the userfaultfd.
let addr = unsafe {
mmap(
None,
len.try_into().unwrap(),
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
-1,
0,
)
.expect("mmap")
};
println!("Address returned by mmap() = {:p}", addr);
// Register the memory range of the mapping we just created for handling by the userfaultfd
// object. In mode, we request to track missing pages (i.e., pages that have not yet been
// faulted in).
uffd.register(addr, len).expect("uffd.register()");
// Create a thread that will process the userfaultfd events
let _s = std::thread::spawn(move || fault_handler_thread(uffd));
// Main thread now touches memory in the mapping, touching locations 1024 bytes apart. This will
// trigger userfaultfd events for all pages in the region.
// Ensure that faulting address is not on a page boundary, in order to test that we correctly
// handle that case in fault_handling_thread()
let mut l = 0xf;
while l < len {
let ptr = (addr as usize + l) as *mut u8;
let c = unsafe { *ptr };
println!("Read address {:p} in main(): {:?}", ptr, c as char);
l += 1024;
std::thread::sleep(std::time::Duration::from_micros(100000));
}
}sourcepub fn non_blocking(&mut self, non_blocking: bool) -> &mut Self
pub fn non_blocking(&mut self, non_blocking: bool) -> &mut Self
Enable non-blocking operation for the userfaultfd object.
If this is set to false, Uffd::read_event() will block until an event is available to
read. Otherwise, it will immediately return None if no event is available.
Examples found in repository?
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
fn main() {
let num_pages = env::args()
.nth(1)
.expect("Usage: manpage <num_pages>")
.parse::<usize>()
.unwrap();
let page_size = sysconf(SysconfVar::PAGE_SIZE).unwrap().unwrap() as usize;
let len = num_pages * page_size;
// Create and enable userfaultfd object
let uffd = UffdBuilder::new()
.close_on_exec(true)
.non_blocking(true)
.user_mode_only(true)
.create()
.expect("uffd creation");
// Create a private anonymous mapping. The memory will be demand-zero paged--that is, not yet
// allocated. When we actually touch the memory, it will be allocated via the userfaultfd.
let addr = unsafe {
mmap(
None,
len.try_into().unwrap(),
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
-1,
0,
)
.expect("mmap")
};
println!("Address returned by mmap() = {:p}", addr);
// Register the memory range of the mapping we just created for handling by the userfaultfd
// object. In mode, we request to track missing pages (i.e., pages that have not yet been
// faulted in).
uffd.register(addr, len).expect("uffd.register()");
// Create a thread that will process the userfaultfd events
let _s = std::thread::spawn(move || fault_handler_thread(uffd));
// Main thread now touches memory in the mapping, touching locations 1024 bytes apart. This will
// trigger userfaultfd events for all pages in the region.
// Ensure that faulting address is not on a page boundary, in order to test that we correctly
// handle that case in fault_handling_thread()
let mut l = 0xf;
while l < len {
let ptr = (addr as usize + l) as *mut u8;
let c = unsafe { *ptr };
println!("Read address {:p} in main(): {:?}", ptr, c as char);
l += 1024;
std::thread::sleep(std::time::Duration::from_micros(100000));
}
}sourcepub fn user_mode_only(&mut self, user_mode_only: bool) -> &mut Self
pub fn user_mode_only(&mut self, user_mode_only: bool) -> &mut Self
Enable user-mode only flag for the userfaultfd object.
If set to false, the process must have the CAP_SYS_PTRACE capability starting with Linux 5.11
or object creation will fail with EPERM. When set to true, userfaultfd can’t be used
to handle kernel-mode page faults such as when kernel tries copying data to userspace.
When used with kernels older than 5.11, this has no effect; the process doesn’t need
CAP_SYS_PTRACE and can handle kernel-mode page faults.
Examples found in repository?
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
fn main() {
let num_pages = env::args()
.nth(1)
.expect("Usage: manpage <num_pages>")
.parse::<usize>()
.unwrap();
let page_size = sysconf(SysconfVar::PAGE_SIZE).unwrap().unwrap() as usize;
let len = num_pages * page_size;
// Create and enable userfaultfd object
let uffd = UffdBuilder::new()
.close_on_exec(true)
.non_blocking(true)
.user_mode_only(true)
.create()
.expect("uffd creation");
// Create a private anonymous mapping. The memory will be demand-zero paged--that is, not yet
// allocated. When we actually touch the memory, it will be allocated via the userfaultfd.
let addr = unsafe {
mmap(
None,
len.try_into().unwrap(),
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
-1,
0,
)
.expect("mmap")
};
println!("Address returned by mmap() = {:p}", addr);
// Register the memory range of the mapping we just created for handling by the userfaultfd
// object. In mode, we request to track missing pages (i.e., pages that have not yet been
// faulted in).
uffd.register(addr, len).expect("uffd.register()");
// Create a thread that will process the userfaultfd events
let _s = std::thread::spawn(move || fault_handler_thread(uffd));
// Main thread now touches memory in the mapping, touching locations 1024 bytes apart. This will
// trigger userfaultfd events for all pages in the region.
// Ensure that faulting address is not on a page boundary, in order to test that we correctly
// handle that case in fault_handling_thread()
let mut l = 0xf;
while l < len {
let ptr = (addr as usize + l) as *mut u8;
let c = unsafe { *ptr };
println!("Read address {:p} in main(): {:?}", ptr, c as char);
l += 1024;
std::thread::sleep(std::time::Duration::from_micros(100000));
}
}sourcepub fn require_features(&mut self, feature: FeatureFlags) -> &mut Self
pub fn require_features(&mut self, feature: FeatureFlags) -> &mut Self
Add a requirement that a particular feature or set of features is available.
If a required feature is unavailable, UffdBuilder.create() will return an error.
sourcepub fn require_ioctls(&mut self, ioctls: IoctlFlags) -> &mut Self
pub fn require_ioctls(&mut self, ioctls: IoctlFlags) -> &mut Self
Add a requirement that a particular ioctl or set of ioctls is available.
If a required ioctl is unavailable, UffdBuilder.create() will return an error.
sourcepub fn create(&self) -> Result<Uffd>
pub fn create(&self) -> Result<Uffd>
Create a Uffd object with the current settings of this builder.
Examples found in repository?
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
fn main() {
let num_pages = env::args()
.nth(1)
.expect("Usage: manpage <num_pages>")
.parse::<usize>()
.unwrap();
let page_size = sysconf(SysconfVar::PAGE_SIZE).unwrap().unwrap() as usize;
let len = num_pages * page_size;
// Create and enable userfaultfd object
let uffd = UffdBuilder::new()
.close_on_exec(true)
.non_blocking(true)
.user_mode_only(true)
.create()
.expect("uffd creation");
// Create a private anonymous mapping. The memory will be demand-zero paged--that is, not yet
// allocated. When we actually touch the memory, it will be allocated via the userfaultfd.
let addr = unsafe {
mmap(
None,
len.try_into().unwrap(),
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS,
-1,
0,
)
.expect("mmap")
};
println!("Address returned by mmap() = {:p}", addr);
// Register the memory range of the mapping we just created for handling by the userfaultfd
// object. In mode, we request to track missing pages (i.e., pages that have not yet been
// faulted in).
uffd.register(addr, len).expect("uffd.register()");
// Create a thread that will process the userfaultfd events
let _s = std::thread::spawn(move || fault_handler_thread(uffd));
// Main thread now touches memory in the mapping, touching locations 1024 bytes apart. This will
// trigger userfaultfd events for all pages in the region.
// Ensure that faulting address is not on a page boundary, in order to test that we correctly
// handle that case in fault_handling_thread()
let mut l = 0xf;
while l < len {
let ptr = (addr as usize + l) as *mut u8;
let c = unsafe { *ptr };
println!("Read address {:p} in main(): {:?}", ptr, c as char);
l += 1024;
std::thread::sleep(std::time::Duration::from_micros(100000));
}
}