@@ -3,6 +3,11 @@ use crate::raw;
33use crate :: { IoctlFlags , Uffd } ;
44use bitflags:: bitflags;
55use nix:: errno:: Errno ;
6+ use std:: fs:: { File , OpenOptions } ;
7+ use std:: io:: ErrorKind ;
8+ use std:: os:: fd:: AsRawFd ;
9+
10+ const UFFD_DEVICE_PATH : & str = "/dev/userfaultfd" ;
611
712cfg_if:: cfg_if! {
813 if #[ cfg( any( feature = "linux5_7" , feature = "linux4_14" ) ) ] {
@@ -115,6 +120,47 @@ impl UffdBuilder {
115120 self
116121 }
117122
123+ fn uffd_from_dev ( & self , file : & mut File , flags : i32 ) -> Result < Uffd > {
124+ match unsafe { raw:: new_uffd ( file. as_raw_fd ( ) , flags) } {
125+ Err ( err) => Err ( err. into ( ) ) ,
126+ Ok ( fd) => Ok ( Uffd { fd } ) ,
127+ }
128+ }
129+
130+ fn uffd_from_syscall ( & self , flags : i32 ) -> Result < Uffd > {
131+ let fd = match Errno :: result ( unsafe { raw:: userfaultfd ( flags) } ) {
132+ Ok ( fd) => fd,
133+ // setting the USER_MODE_ONLY flag on kernel pre-5.11 causes it to return EINVAL.
134+ // If the user asks for the flag, we first try with it set, and if kernel gives
135+ // EINVAL we try again without the flag set.
136+ Err ( Errno :: EINVAL ) if self . user_mode_only => Errno :: result ( unsafe {
137+ raw:: userfaultfd ( flags & !raw:: UFFD_USER_MODE_ONLY as i32 )
138+ } ) ?,
139+ Err ( e) => return Err ( e. into ( ) ) ,
140+ } ;
141+
142+ // Wrap the fd up so that a failure in this function body closes it with the drop.
143+ Ok ( Uffd { fd } )
144+ }
145+
146+ // Try to get a UFFD file descriptor using `/dev/userfaultfd`. If that fails
147+ // fall back to calling the system call.
148+ fn open_file_descriptor ( & self , flags : i32 ) -> Result < Uffd > {
149+ // If `/dev/userfaultfd` exists we'll try to get the file descriptor from it. If the file
150+ // doesn't exist we will fall back to calling the system call. This means, that if the
151+ // device exists but the calling process does not have access rights to it, this will fail,
152+ // i.e. we will not fall back to calling the system call.
153+ match OpenOptions :: new ( )
154+ . read ( true )
155+ . write ( true )
156+ . open ( UFFD_DEVICE_PATH )
157+ {
158+ Ok ( mut file) => self . uffd_from_dev ( & mut file, flags) ,
159+ Err ( err) if err. kind ( ) == ErrorKind :: NotFound => self . uffd_from_syscall ( flags) ,
160+ Err ( err) => Err ( Error :: OpenDevUserfaultfd ( err) ) ,
161+ }
162+ }
163+
118164 /// Create a `Uffd` object with the current settings of this builder.
119165 pub fn create ( & self ) -> Result < Uffd > {
120166 // first do the syscall to get the file descriptor
@@ -130,19 +176,7 @@ impl UffdBuilder {
130176 flags |= raw:: UFFD_USER_MODE_ONLY as i32 ;
131177 }
132178
133- let fd = match Errno :: result ( unsafe { raw:: userfaultfd ( flags) } ) {
134- Ok ( fd) => fd,
135- // setting the USER_MODE_ONLY flag on kernel pre-5.11 causes it to return EINVAL.
136- // If the user asks for the flag, we first try with it set, and if kernel gives
137- // EINVAL we try again without the flag set.
138- Err ( Errno :: EINVAL ) if self . user_mode_only => Errno :: result ( unsafe {
139- raw:: userfaultfd ( flags & !raw:: UFFD_USER_MODE_ONLY as i32 )
140- } ) ?,
141- Err ( e) => return Err ( e. into ( ) ) ,
142- } ;
143-
144- // Wrap the fd up so that a failure in this function body closes it with the drop.
145- let uffd = Uffd { fd } ;
179+ let uffd = self . open_file_descriptor ( flags) ?;
146180
147181 // then do the UFFDIO_API ioctl to set up and ensure features and other ioctls are available
148182 let mut api = raw:: uffdio_api {
0 commit comments