Linux
2019-03-06
man-pages-ru
Russian man pages from the Linux Documentation Project
manpages-dev
Manual pages about using GNU/Linux for development
man-pages
Linux kernel and C library user-space interface documentation
ИМЯ
ioctl_userfaultfd - создаёт файловый дескриптор для обработки страничных ошибок в пользовательском пространстве
ОБЗОР
#include <sys/ioctl.h>
int ioctl(int fd, int cmd, ...);
ОПИСАНИЕ
Над объектом userfaultfd (созданным вызовом userfaultfd(2)) можно выполнять различные операции ioctl(2) используя вызовы вида:
ioctl(fd, cmd, argp); Здесь fd — файловый дескриптор, ссылающийся на объект userfaultfd, cmd — одна из команд, перечисленных ниже, а argp — указатель на структуру данных, используемую командой cmd.
Операции ioctl(2) описаны ниже. Операции UFFDIO_API, UFFDIO_REGISTER и UFFDIO_UNREGISTER используются для настройки поведения userfaultfd. Они позволяют вызывающему выбрать какие свойства нужно включить и какие типы событий будут доставляться приложению. Остальные операции являются операциями над диапазоном. Эти операции позволяют вызывающему приложению воспринимать события страничных ошибок.
UFFDIO_API
(начиная с Linux 4.3) Включить работу с userfaultfd и выполнить согласование программного интерфейса.
В аргументе argp содержится указатель на структуру uffdio_api, определённую следующим образом:
struct uffdio_api {
__u64 api; /* запрашиваемая версия API (входные данные) */
__u64 features; /* запрашиваемые свойства (входные/выходные) */
__u64 ioctls; /* доступные операции ioctl() (выходные данные) */ };
__u64 api; /* запрашиваемая версия API (входные данные) */
__u64 features; /* запрашиваемые свойства (входные/выходные) */
__u64 ioctls; /* доступные операции ioctl() (выходные данные) */ };
В поле api задаётся версия программного интерфейса, запрашиваемого приложением.
Ядро проверяет, что поддерживает запрашиваемую версию программного интерфейса и изменять поля features и ioctls в битовой маске, представляющей все доступные свойства и общие операции ioctl(2).
В ядрах Linux до версии 4.11 полю features должен быть присвоен ноль перед вызовом UFFDIO_API, и при возврате из ioctl(2) ядро помещает ноль (т. е., нет бит свойств) в поле features.
Начиная с Linux 4.11 поле features можно использовать для запроса поддержки определённых свойств и явно включить свойства userfaultfd, которые по умолчанию выключены. Ядро всегда сообщает о всех доступных свойствах через поле features.
Чтобы включить свойство userfaultfd приложение должно установить соответствующий бит в поле features. Если ядро поддерживает все запрошенные свойств, то он включит их. В противном случае оно обнулит возвращаемую структуру uffdio_api и вернёт EINVAL.
Могут устанавливаться следующие биты свойств:
UFFD_FEATURE_EVENT_FORK (начиная с Linux 4.11) | |
Если это свойство включено, то объекты userfaultfd, связанные с родительским процессом, дублируются в дочернем процессе при вызове fork(2), а событие UFFD_EVENT_FORK доставляется отслеживающему userfaultfd. | |
UFFD_FEATURE_EVENT_REMAP (начиная с Linux 4.11) | |
Если это свойство включено, то при вызове mremap(2) процессом с ошибкой отслеживающий userfaultfd будет получать событие с типом UFFD_EVENT_REMAP. | |
UFFD_FEATURE_EVENT_REMOVE (начиная с Linux 4.11) | |
Если это свойство включено, то при вызове madvise(2)со значением совета MADV_DONTNEED или MADV_REMOVE для освобождения области виртуальной памяти процессом с ошибкой отслеживающий userfaultfd будет получать событие с типом UFFD_EVENT_REMOVE. | |
UFFD_FEATURE_EVENT_UNMAP (начиная с Linux 4.11) | |
Если это свойство включено, то при явном вызове mremap(2) или неявном вызове mmap(2) или mremap(2) процессом с ошибкой отслеживающий userfaultfd будет получать событие с типом UFFD_EVENT_UNMAP. | |
UFFD_FEATURE_MISSING_HUGETLBFS (начиная с Linux 4.11) | |
Если этот бит установлен, то ядро включает поддержку регистрации диапазонов userfaultfd для областей виртуальной памяти hugetlbfs. | |
UFFD_FEATURE_MISSING_SHMEM (начиная с Linux 4.11) | |
Если этот бит установлен, то ядро включает поддержку регистрации диапазонов userfaultfd для общих областей виртуальной памяти. К ним относятся все программные интерфейсы общей памяти ядра: общая память System V, tmpfs(5), общие отображения /dev/zero, mmap(2) с флагом MAP_SHARED, memfd_create(2) и т. д. | |
UFFD_FEATURE_SIGBUS (начиная с 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 | Дескриптор userfaultfd уже включён предыдущей операцией UFFDIO_API. |
EINVAL | Версия программного интерфейса, запрошенная в поле 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; /* начало диапазона */
__u64 len; /* длина диапазона (в байтах) */ };
__u64 start; /* начало диапазона */
__u64 len; /* длина диапазона (в байтах) */ };
struct uffdio_register {
struct uffdio_range range;
__u64 mode; /* желаемый режим операции (входные данные) */
__u64 ioctls; /* доступные операции ioctl() (результат) */ };
struct uffdio_range range;
__u64 mode; /* желаемый режим операции (входные данные) */
__u64 ioctls; /* доступные операции ioctl() (результат) */ };
В поле range задаётся диапазон памяти (начинающийся с start и длиной len байт), который должен обрабатываться userfaultfd.
В поле mode задаётся режим операции на этим диапазоном памяти. У режима 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 | В поле mode указан некорректный или неподдерживаемый бит или поле mode равно нулю. |
EINVAL | Отображение в указанном адресном диапазоне отсутствует. |
EINVAL | Значение range.start или range.len не кратно размеру системной страницы или значение range.len равно или эти поля содержат другие некорректные значения. |
EINVAL | В указанном адресном диапазоне имеется несовместимое отображение. |
UFFDIO_UNREGISTER
(начиная с Linux 4.3) Снять регистрацию диапазона адресов памяти в userfaultfd. Страницы в диапазоне должны быть «совместимыми» (смотрите описание UFFDIO_REGISTER).
Снимаемый с регистрации диапазон адресов задаётся в структуре uffdio_range, которая указывается в argp.
При успешном выполнении операции ioctl(2) возвращается 0. При ошибке возвращается -1 и в errno записывается причина ошибки. Возможные значения:
EINVAL | Поле start или len структуры ufdio_range не кратно размеру системной страницы или поле len равно нулю или эти поля содержат другие некорректные значения. |
EINVAL | В указанном адресном диапазоне имеется несовместимое отображение. |
EINVAL | Отображение в указанном адресном диапазоне отсутствует. |
UFFDIO_COPY
(начиная с Linux 4.3) Атомарно копировать непрерывный участок памяти в зарегистрированный в userfault диапазон и разбудить заблокированную нить (не обязательно). Адреса источника и назначения и количество копируемых байт задаётся в полях src, dst и len структуры uffdio_copy, на которую указывает argp:
struct uffdio_copy {
__u64 dst; /* источник копирования */
__u64 src; /* назначение копирования */
__u64 len; /* количество копируемых байт */
__u64 mode; /* флаги, управляющие поведением копирования */
__s64 copy; /* количество скопированных байт или отрицательная ошибка */ };
__u64 dst; /* источник копирования */
__u64 src; /* назначение копирования */
__u64 len; /* количество копируемых байт */
__u64 mode; /* флаги, управляющие поведением копирования */
__s64 copy; /* количество скопированных байт или отрицательная ошибка */ };
Для изменения поведения операции UFFDIO_COPY можно использовать следующие значения mode (побитовое ИЛИ):
UFFDIO_COPY_MODE_DONTWAKE | |
Не будить нить, которая ждёт решения страничной ошибки | |
Поле copy используется ядром для возврата количества байт, которые были скопированы, или ошибки (отрицательное значение, подобное errno). Если значение, возвращённое в copy, не совпадает со значением, указанным в len, то операция завершается ошибкой EAGAIN. Поле copy используется только для результата; оно не читается операцией UFFDIO_COPY. | |
При успешном выполнении операции ioctl(2) возвращается 0. В этом случае была скопирована область целиком. При ошибке возвращается -1 и в errno записывается причина ошибки. Возможные значения: | |
EAGAIN | Количество скопированных байт (т. е., значение, возвращаемое в поле copy) не равно значению, указанному в поле len. |
EINVAL | Значение dst или len не кратно размеру системной страницы или диапазон, заданный в src и len или dst и len является неправильным. |
EINVAL | В поле mode установлен недопустимый бит. |
ENOENT (начиная с Linux 4.11) | |
Процесс с ошибкой изменил раскладку своей виртуальной памяти одновременно имея незавершённую операцию UFFDIO_COPY. | |
ENOSPC (в Linux 4.11 по Linux 4.13) | |
Процесс с ошибкой завершил работу в момент выполнения операции UFFDIO_COPY. | |
ESRCH (начиная с Linux 4.13) | |
Процесс с ошибкой завершил работу в момент выполнения операции UFFDIO_COPY. |
UFFDIO_ZEROPAGE
(начиная с Linux 4.3) Обнулить диапазон памяти, зарегистрированный в userfaultfd.
Запрашиваемый диапазон указывается в поле range структуры uffdio_zeropage, на которую указывает argp:
struct uffdio_zeropage {
struct uffdio_range range;
__u64 mode; /* флаги, определяющие поведение копирования */
__s64 zeropage; /* количество обнуляемых байт или отрицательная ошибка */ };
struct uffdio_range range;
__u64 mode; /* флаги, определяющие поведение копирования */
__s64 zeropage; /* количество обнуляемых байт или отрицательная ошибка */ };
Для изменения поведения операции UFFDIO_ZEROPAGE можно использовать следующие значения mode (побитовое ИЛИ):
UFFDIO_ZEROPAGE_MODE_DONTWAKE | |
Не будить нить, которая ждёт решения страничной ошибки. | |
Поле zeropage используется ядром для возврата количества байт, которые были обнулены, или ошибки (также, как для UFFDIO_COPY). Если значение, возвращённое в zeropage, не совпадает со значением, указанным в range.len, то операция завершается ошибкой EAGAIN. Поле zeropage используется только для результата; оно не читается операцией UFFDIO_ZEROPAGE. | |
При успешном выполнении операции ioctl(2) возвращается 0. В этом случае была обнулена вся область. При ошибке возвращается -1 и в errno записывается причина ошибки. Возможные значения: | |
EAGAIN | Количество обнулённых байт (т. е., значение, возвращаемое в поле zeropage) не равно значению, указанному в поле range.len. |
EINVAL | Значение range.start или range.len не кратно размеру системной страницы, значение range.len равно нулю, указанный диапазон является неправильным. |
EINVAL | В поле mode установлен недопустимый бит. |
ESRCH (начиная с Linux 4.13) | |
Процесс с ошибкой завершил работу в момент выполнения операции UFFDIO_ZEROPAGE. |
UFFDIO_WAKE
(начиная с Linux 4.3) Разбудить нить, которая ждёт решения страничной ошибки в указанном диапазоне адресов памяти.
Операция UFFDIO_WAKE используется вместе с UFFDIO_COPY и UFFDIO_ZEROPAGE, у которых установлен бит UFFDIO_COPY_MODE_DONTWAKE или UFFDIO_ZEROPAGE_MODE_DONTWAKE в поле mode. При отслеживании userfault можно выполнять несколько операций UFFDIO_COPY и UFFDIO_ZEROPAGE вместе и затем явно будить нить с ошибкой с помощью UFFDIO_WAKE.
В аргументе argp содержится указатель на структуру uffdio_range (показана выше), в которой задаётся диапазон адресов.
При успешном выполнении операции ioctl(2) возвращается 0. При ошибке возвращается -1 и в errno записывается причина ошибки. Возможные значения:
EINVAL | Поле start или len структуры ufdio_range не кратно размеру системной страницы или поле len равно нулю или указанный диапазон является неправильным. |
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Смотрите описание приведённое выше для каждой операции.
ОШИБКИ
Смотрите описание приведённое выше для каждой операции. Также для всех описанных выше операций могут возникать общие ошибки:
EFAULT | Значение argp указывает на некорректный адрес памяти. |
EINVAL | (для все операций кроме UFFDIO_API) Объект userfaultfd пока не включён (с помощью операции UFFDIO_API). |
СООТВЕТСТВИЕ СТАНДАРТАМ
Данные операции ioctl(2) есть только в Linux.
ДЕФЕКТЫ
Чтобы определить доступные свойства userfault и включить некоторые из них нужно закрыть файловый дескриптор userfaultfd после первой операции UFFDIO_API, которая запрашивает доступность свойств, и повторно открыть его перед второй операцией UFFDIO_API, которая теперь включит желаемый свойства.
ПРИМЕР
Смотрите userfaultfd(2).
СМОТРИТЕ ТАКЖЕ
ioctl(2), mmap(2), userfaultfd(2)
Файл Documentation/admin-guide/mm/userfaultfd.rst из дерева исходного кода ядра Linux