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

source

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?
examples/manpage.rs (line 88)
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));
    }
}
source

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?
examples/manpage.rs (line 89)
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));
    }
}
source

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?
examples/manpage.rs (line 90)
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));
    }
}
source

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?
examples/manpage.rs (line 91)
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));
    }
}
source

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.

source

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.

source

pub fn create(&self) -> Result<Uffd>

Create a Uffd object with the current settings of this builder.

Examples found in repository?
examples/manpage.rs (line 92)
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));
    }
}

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

const: unstable · source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

const: unstable · source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

const: unstable · source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

const: unstable · source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
const: unstable · source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
const: unstable · source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.