IOCTL_USERFAULTFD(2) | Руководство программиста Linux | IOCTL_USERFAULTFD(2) |
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. Они позволяют вызывающему выбрать какие свойства нужно включить и какие типы событий будут доставляться приложению. Остальные операции являются операциями над диапазоном. Эти операции позволяют вызывающему приложению воспринимать события страничных ошибок.
(начиная с Linux 4.3) Включить работу с userfaultfd и выполнить согласование программного интерфейса.
В аргументе argp содержится указатель на структуру uffdio_api, определённую следующим образом:
struct uffdio_api { __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.
Могут устанавливаться следующие биты свойств:
Возвращаемое поле ioctls можно содержать следующие биты:
При успешном выполнении операции ioctl(2) возвращается 0. При ошибке возвращается -1 и в errno записывается причина ошибки. Возможные значения:
(начиная с 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; /* длина диапазона (в байтах) */ }; struct uffdio_register { struct uffdio_range range; __u64 mode; /* желаемый режим операции (входные данные) */ __u64 ioctls; /* доступные операции ioctl() (результат) */ };
В поле range задаётся диапазон памяти (начинающийся с start и длиной len байт), который должен обрабатываться userfaultfd.
В поле mode задаётся режим операции на этим диапазоном памяти. У режима userfaultfd могут быть указаны следующие значения (через операцию ИЛИ) для задаваемого диапазона:
В настоящее время поддерживается только режим UFFDIO_REGISTER_MODE_MISSING.
При успешном выполнении ядро изменяет битовую маску ioctls показывая какие операции ioctl(2) доступны для задаваемого диапазона. Здесь возвращается битовая маска как для UFFDIO_API.
При успешном выполнении операции ioctl(2) возвращается 0. При ошибке возвращается -1 и в errno записывается причина ошибки. Возможные значения:
(начиная с Linux 4.3) Снять регистрацию диапазона адресов памяти в userfaultfd. Страницы в диапазоне должны быть «совместимыми» (смотрите описание UFFDIO_REGISTER).
Снимаемый с регистрации диапазон адресов задаётся в структуре uffdio_range, которая указывается в argp.
При успешном выполнении операции ioctl(2) возвращается 0. При ошибке возвращается -1 и в errno записывается причина ошибки. Возможные значения:
(начиная с Linux 4.3) Атомарно копировать непрерывный участок памяти в зарегистрированный в userfault диапазон и разбудить заблокированную нить (не обязательно). Адреса источника и назначения и количество копируемых байт задаётся в полях src, dst и len структуры uffdio_copy, на которую указывает argp:
struct uffdio_copy { __u64 dst; /* источник копирования */ __u64 src; /* назначение копирования */ __u64 len; /* количество копируемых байт */ __u64 mode; /* флаги, управляющие поведением копирования */ __s64 copy; /* количество скопированных байт или отрицательная ошибка */ };
Для изменения поведения операции UFFDIO_COPY можно использовать следующие значения mode (побитовое ИЛИ):
Поле copy используется ядром для возврата количества байт, которые были скопированы, или ошибки (отрицательное значение, подобное errno). Если значение, возвращённое в copy, не совпадает со значением, указанным в len, то операция завершается ошибкой EAGAIN. Поле copy используется только для результата; оно не читается операцией UFFDIO_COPY.
При успешном выполнении операции ioctl(2) возвращается 0. В этом случае была скопирована область целиком. При ошибке возвращается -1 и в errno записывается причина ошибки. Возможные значения:
(начиная с Linux 4.3) Обнулить диапазон памяти, зарегистрированный в userfaultfd.
Запрашиваемый диапазон указывается в поле range структуры uffdio_zeropage, на которую указывает argp:
struct uffdio_zeropage { struct uffdio_range range; __u64 mode; /* флаги, определяющие поведение копирования */ __s64 zeropage; /* количество обнуляемых байт или отрицательная ошибка */ };
Для изменения поведения операции UFFDIO_ZEROPAGE можно использовать следующие значения mode (побитовое ИЛИ):
Поле zeropage используется ядром для возврата количества байт, которые были обнулены, или ошибки (также, как для UFFDIO_COPY). Если значение, возвращённое в zeropage, не совпадает со значением, указанным в range.len, то операция завершается ошибкой EAGAIN. Поле zeropage используется только для результата; оно не читается операцией UFFDIO_ZEROPAGE.
При успешном выполнении операции ioctl(2) возвращается 0. В этом случае была обнулена вся область. При ошибке возвращается -1 и в errno записывается причина ошибки. Возможные значения:
(начиная с 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 записывается причина ошибки. Возможные значения:
Смотрите описание приведённое выше для каждой операции.
Смотрите описание приведённое выше для каждой операции. Также для всех описанных выше операций могут возникать общие ошибки:
Данные операции ioctl(2) есть только в Linux.
Чтобы определить доступные свойства userfault и включить некоторые из них нужно закрыть файловый дескриптор userfaultfd после первой операции UFFDIO_API, которая запрашивает доступность свойств, и повторно открыть его перед второй операцией UFFDIO_API, которая теперь включит желаемый свойства.
Смотрите userfaultfd(2).
ioctl(2), mmap(2), userfaultfd(2)
Файл Documentation/admin-guide/mm/userfaultfd.rst из дерева исходного кода ядра Linux
2019-03-06 | Linux |