IOCTL_USERFAULTFD - Linux手册页
Linux程序员手册 第2部分
更新日期: 2020-06-09
名称
ioctl_userfaultfd-创建文件描述符以处理用户空间中的页面错误
语法
#include <sys/ioctl.h> int ioctl(int fd, int cmd, ...);
说明
可以使用以下形式的调用对userfaultfd对象(通过调用userfaultfd(2)创建)执行各种ioctl(2)操作:
ioctl(fd, cmd, argp);
In the above,
fd
is a file descriptor referring to a userfaultfd object,
cmd
is one of the commands listed below, and
argp
is a pointer to a data structure that is specific to
cmd.
下面介绍了各种ioctl(2)操作。 UFFDIO_API,UFFDIO_REGISTER和UFFDIO_UNREGISTER操作用于配置userfaultfd行为。这些操作使调用者可以选择要启用哪些功能以及将哪些类型的事件传递给应用程序。其余操作是范围操作。这些操作使调用应用程序可以解决页面错误事件。
UFFDIO_API
(从Linux 4.3开始。)启用userfaultfd的操作并执行API握手。
argp参数是指向uffdio_api结构的指针,该结构定义为:
struct uffdio_api { __u64 api; /* Requested API version (input) */ __u64 features; /* Requested features (input/output) */ __u64 ioctls; /* Available ioctl() operations (output) */ };
api字段表示应用程序请求的API版本。
内核将验证它可以支持所请求的API版本,并将功能和ioctls字段设置为代表所有可用功能和可用的通用ioctl(2)操作的位掩码。
对于4.11之前的Linux内核版本,必须在调用UFFDIO_API之前将features字段初始化为零,并且从ioctl(2)返回时内核将零(即无功能位)放入内核。
从Linux 4.11开始,features字段可用于询问是否支持特定功能,并显式启用默认情况下禁用的userfaultfd功能。内核始终在功能字段中报告所有可用功能。
要启用userfaultfd功能,应用程序应在功能字段中设置与要启用的每个功能相对应的位。如果内核支持所有请求的功能,它将启用它们。否则,它将归零返回的uffdio_api结构并返回EINVAL。
可以设置以下功能位:
- UFFD_FEATURE_EVENT_FORK(since Linux 4.11)
- 启用此功能后,在fork(2)期间,与父进程关联的userfaultfd对象将复制到子进程中,并且UFFD_EVENT_FORK事件将传递到userfaultfd监视器
- UFFD_FEATURE_EVENT_REMAP(since Linux 4.11)
- 如果启用了此功能,则当故障进程调用mremap(2)时,userfaultfd监视器将收到类型为UFFD_EVENT_REMAP的事件。
- UFFD_FEATURE_EVENT_REMOVE(since Linux 4.11)
- 如果启用了此功能,则当故障进程使用MADV_DONTNEED或MADV_REMOVE建议值调用madvise(2)释放虚拟内存区域时,userfaultfd监视器将收到UFFD_EVENT_REMOVE类型的事件。
- UFFD_FEATURE_EVENT_UNMAP(since Linux 4.11)
- 如果启用了此功能,则当故障进程使用munmap(2)显式取消虚拟内存的映射时,或者在mmap(2)或mremap(2)期间隐式取消虚拟内存的映射。 userfaultfd监视器将收到UFFD_EVENT_UNMAP类型的事件。
- UFFD_FEATURE_MISSING_HUGETLBFS(since Linux 4.11)
- 如果设置了此功能位,则内核支持在hugetlbfs虚拟内存区域上注册userfaultfd范围
- UFFD_FEATURE_MISSING_SHMEM(since Linux 4.11)
- 如果设置了此功能位,则内核支持在共享内存区域上注册userfaultfd范围。这包括所有内核共享内存API:System V共享内存,tmpfs(5),/ dev / zero的共享映射,设置了MAP_SHARED标志的mmap(2),memfd_create(2)等。
- UFFD_FEATURE_SIGBUS(since Linux 4.14)
- 如果设置了此功能位,则不会传递任何页面错误事件(UFFD_EVENT_PAGEFAULT)。而是将SIGBUS信号发送到故障过程。使用此功能的应用程序将不需要使用userfaultfd监视器来处理对用户userfaultfd注册的区域的内存访问。
返回的ioctls字段可以包含以下位:
- 1 << _UFFDIO_API
- 支持UFFDIO_API操作。
- 1 << _UFFDIO_REGISTER
- 支持UFFDIO_REGISTER操作。
- 1 << _UFFDIO_UNREGISTER
- 支持UFFDIO_UNREGISTER操作。
此ioctl(2)操作成功返回0。发生错误时,将返回-1并将errno设置为指示错误原因。可能的错误包括:
- EFAULT
- argp是指调用过程的可访问地址空间之外的地址。
- EINVAL
- 先前的UFFDIO_API操作已经启用了userfaultfd。
- EINVAL
- 该内核不支持api字段中请求的API版本,或者传递给内核的features字段包含当前内核版本不支持的功能位。
UFFDIO_REGISTER
(从Linux 4.3开始。)向userfaultfd对象注册一个内存地址范围。范围内的页面必须"兼容"。
在Linux内核4.11之前,只有私有匿名范围才可以与UFFDIO_REGISTER注册。
从Linux 4.11开始,hugetlbfs和共享内存范围也与UFFDIO_REGISTER兼容。
argp参数是指向uffdio_register结构的指针,该结构定义为:
struct uffdio_range { __u64 start; /* Start of range */ __u64 len; /* Length of range (bytes) */ }; struct uffdio_register { struct uffdio_range range; __u64 mode; /* Desired mode of operation (input) */ __u64 ioctls; /* Available ioctl() operations (output) */ };
范围字段定义了一个内存范围,该范围从开始一直到应由userfaultfd处理的len个字节继续。
模式字段定义了该存储区域所需的操作模式。以下值可以按位或以将userfaultfd模式设置为指定范围:
- UFFDIO_REGISTER_MODE_MISSING
- 跟踪丢失页面上的页面错误。
- UFFDIO_REGISTER_MODE_WP
- 在受写保护的页面上跟踪页面错误。
当前,唯一受支持的模式是UFFDIO_REGISTER_MODE_MISSING。
如果操作成功,则内核会修改ioctls位掩码字段,以指示哪些ioctl(2)操作可用于指定范围。返回的位掩码与UFFDIO_API相同。
此ioctl(2)操作成功返回0。发生错误时,将返回-1并将errno设置为指示错误原因。可能的错误包括:
- EBUSY
- 指定范围内的映射已向另一个userfaultfd对象注册。
- EFAULT
- argp是指调用过程的可访问地址空间之外的地址。
- EINVAL
- 在模式字段中指定了无效或不受支持的位;或模式字段为零。
- EINVAL
- 在指定的地址范围内没有映射。
- EINVAL
- range.start或range.len不是系统页面大小的倍数;或者,range.len为零;否则这些字段无效。
- EINVAL
- 在指定的地址范围内存在不兼容的映射。
UFFDIO_UNREGISTER
(从Linux 4.3开始。)从userfaultfd注销内存地址范围。范围中的页面必须是"兼容的"(请参阅UFFDIO_REGISTER的说明。)
要注销的地址范围在argp指向的uffdio_range结构中指定。
此ioctl(2)操作成功返回0。发生错误时,将返回-1并将errno设置为指示错误原因。可能的错误包括:
- EINVAL
- ufdio_range结构的start或len字段不是系统页面大小的倍数;或len字段为零;否则这些字段无效。
- EINVAL
- 在指定的地址范围内存在不兼容的映射。
- EINVAL
- 在指定的地址范围内没有映射。
UFFDIO_COPY
(从Linux 4.3开始。)以原子方式将连续的内存块复制到userfault注册的范围内,并有选择地唤醒被阻塞的线程。源地址和目标地址以及要复制的字节数由argp指向的uffdio_copy结构的src,dst和len字段指定:
struct uffdio_copy { __u64 dst; /* Destination of copy */ __u64 src; /* Source of copy */ __u64 len; /* Number of bytes to copy */ __u64 mode; /* Flags controlling behavior of copy */ __s64 copy; /* Number of bytes copied, or negated error */ };
以下值可以在模式下按位或,以更改UFFDIO_COPY操作的行为:
- UFFDIO_COPY_MODE_DONTWAKE
- 不要唤醒等待页面错误解决的线程
内核使用copy字段来返回实际复制的字节数或错误(错误的errno样式值)。如果copy中返回的值与len中指定的值不匹配,则操作失败,并显示错误EAGAIN。复制字段仅用于输出; UFFDIO_COPY操作不会读取它。
此ioctl(2)操作成功返回0。在这种情况下,将复制整个区域。发生错误时,将返回-1并将errno设置为指示错误原因。可能的错误包括:
- EAGAIN
- 复制的字节数(即在复制字段中返回的值)不等于在len字段中指定的值。
- EINVAL
- dst或len不是系统页面大小的倍数,或者src和len或dst和len指定的范围无效。
- EINVAL
- 在模式字段中指定了无效的位。
- ENOENT(since Linux 4.11)
- 故障处理已通过出色的UFFDIO_COPY操作同时更改了其虚拟内存布局。
- ENOSPC(from Linux 4.11 until Linux 4.13)
- UFFDIO_COPY操作时,故障过程已退出。
- ESRCH(since Linux 4.13)
- UFFDIO_COPY操作时,故障过程已退出。
UFFDIO_ZEROPAGE
(从Linux 4.3开始。)清零在userfaultfd中注册的内存范围。
所需范围由argp指向的uffdio_zeropage结构的范围字段指定:
struct uffdio_zeropage { struct uffdio_range range; __u64 mode; /* Flags controlling behavior of copy */ __s64 zeropage; /* Number of bytes zeroed, or negated error */ };
以下值可以在模式下按位或,以更改UFFDIO_ZEROPAGE操作的行为:
- UFFDIO_ZEROPAGE_MODE_DONTWAKE
- 不要唤醒等待页面错误解决的线程。
内核使用Zeropage字段返回实际被清零的字节数,或者以与UFFDIO_COPY相同的方式返回错误。如果零页字段中返回的值与range.len中指定的值不匹配,则操作将失败,并显示错误EAGAIN。零页字段仅用于输出; UFFDIO_ZEROPAGE操作不会读取它。
此ioctl(2)操作成功返回0。在这种情况下,整个区域被清零。发生错误时,将返回-1并将errno设置为指示错误原因。可能的错误包括:
- EAGAIN
- 调零的字节数(即,在zeropage字段中返回的值)不等于range.len字段中指定的值。
- EINVAL
- range.start或range.len都不是系统页面大小的倍数;或range.len为零;或指定的范围无效。
- EINVAL
- 在模式字段中指定了无效的位。
- ESRCH(since Linux 4.13)
- UFFDIO_ZEROPAGE操作时,故障过程已退出。
UFFDIO_WAKE
(从Linux 4.3开始。)唤醒线程,等待指定内存地址范围内的页面错误解决。
UFFDIO_WAKE操作与在模式字段中设置了UFFDIO_COPY_MODE_DONTWAKE或UFFDIO_ZEROPAGE_MODE_DONTWAKE位的UFFDIO_COPY和UFFDIO_ZEROPAGE操作结合使用。用户故障监视器可以批量执行几个UFFDIO_COPY和UFFDIO_ZEROPAGE操作,然后使用UFFDIO_WAKE显式唤醒故障线程。
argp参数是指向uffdio_range结构的指针(如上所示),该结构指定地址范围。
此ioctl(2)操作成功返回0。发生错误时,将返回-1并将errno设置为指示错误原因。可能的错误包括:
- EINVAL
- ufdio_range结构的start或len字段不是系统页面大小的倍数;或len为零;否则指定的范围无效。
返回值
请参阅上面的各个操作说明。
错误说明
请参阅上面的各个操作说明。此外,上述所有操作都可能发生以下一般错误:
- EFAULT
- argp没有指向有效的内存地址。
- EINVAL
- (对于除UFFDIO_API之外的所有操作。)尚未启用userfaultfd对象(通过UFFDIO_API操作)。
遵循规范
这些ioctl(2)操作特定于Linux。
BUGS
为了检测可用的用户故障功能并启用这些功能的某些子集,必须在查询功能可用性的第一个UFFDIO_API操作之后关闭userfaultfd文件描述符,并在实际启用所需功能的第二个UFFDIO_API操作之前重新打开该文件描述符。
示例
请参阅userfaultfd(2)。
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。