userfaultfd

USERFAULTFD(2)  Ð ÑководÑÑво пÑогÑаммиÑÑа Linux  USERFAULTFD(2)



ÐÐЯ
       userfaultfd - ÑоздаÑÑ ÑайловÑй деÑкÑипÑÐ¾Ñ Ð´Ð»Ñ
       обÑабоÑки ÑÑÑаниÑнÑÑ Ð¾Ñибок в
       полÑзоваÑелÑÑком пÑоÑÑÑанÑÑве

ÐÐÐÐÐ
       #include <sys/types.h>
       #include <linux/userfaultfd.h>

       int userfaultfd(int flags);

       ÐамеÑание: Ð glibc Ð½ÐµÑ Ð¾Ð±ÑÑÑоÑной ÑÑнкÑии длÑ
       данного ÑиÑÑемного вÑзова; ÑмоÑÑиÑе ÐÐÐÐЧÐÐÐЯ.

ÐÐÐСÐÐÐÐ
       ÐÑзов userfaultfd() ÑоздаÑÑ Ð½Ð¾Ð²Ñй обÑÐµÐºÑ userfaultfd,
       коÑоÑÑй можно иÑполÑзоваÑÑ Ð´Ð»Ñ Ð¿ÐµÑедаÑи
       обÑабоÑки ÑÑÑаниÑнÑÑ Ð¾Ñибок пÑиложениÑ
       полÑзоваÑелÑÑкого пÑоÑÑÑанÑÑва, и возвÑаÑаеÑ
       ÑайловÑй деÑкÑипÑоÑ, ÑÑÑлаÑÑийÑÑ Ð½Ð° новÑй
       обÑекÑ. ÐовÑй обÑÐµÐºÑ userfaultfd наÑÑÑаиваеÑÑÑ Ñ
       помоÑÑÑ ioctl(2).

       ÐоÑле наÑÑÑойки обÑекÑа userfaultfd пÑиложение
       Ð¼Ð¾Ð¶ÐµÑ Ð¸ÑполÑзоваÑÑ Ð²Ñзов read(2) Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑениÑ
       Ñведомлений userfaultfd. ЧÑение из userfaultfd
       Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð±Ð»Ð¾ÐºÐ¸ÑÑÑÑим и не блокиÑÑÑÑим, в
       завиÑимоÑÑи Ð¾Ñ Ð¸ÑполÑзованного пÑи
       Ñоздании userfaultfd знаÑÐµÐ½Ð¸Ñ flags или
       поÑледÑÑÑÐ¸Ñ Ð²Ñзовов fcntl(2).

       ÐÐ»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ userfaultfd() можно
       иÑполÑзоваÑÑ ÑледÑÑÑие знаÑÐµÐ½Ð¸Ñ flags (ÑеÑез OR):

       O_CLOEXEC
              ÐклÑÑиÑÑ Ñлаг close-on-exec Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾
              оÑкÑÑÑого Ñайлового деÑкÑипÑоÑа userfaultfd.
              СмоÑÑиÑе опиÑание Ñлага O_CLOEXEC в open(2).

       O_NONBLOCK
              ÐклÑÑиÑÑ Ð½Ðµ блокиÑÑÑÑÑÑ ÑабоÑÑ Ñ Ð¾Ð±ÑекÑом
              userfaultfd. СмоÑÑиÑе опиÑание Ñлага O_NONBLOCK
              в open(2).

       Ðогда закÑÑваеÑÑÑ Ð¿Ð¾Ñледний ÑÑÑлаÑÑийÑÑ Ð½Ð°
       обÑÐµÐºÑ userfaultfd ÑайловÑй деÑкÑипÑоÑ, Ð´Ð»Ñ Ð²ÑеÑ
       диапазонов памÑÑи, заÑегиÑÑÑиÑованнÑÑ Ð²
       ÑÑом обÑекÑе, ÑнимаеÑÑÑ ÑегиÑÑÑаÑиÑ, а вÑе
       непÑоÑиÑаннÑе ÑобÑÑÐ¸Ñ Ð¾ÑиÑаÑÑÑÑ.

   ÐÑполÑзование
       ÐеÑанизм userfaultfd ÑазÑабоÑан Ð´Ð»Ñ Ñого, ÑÑобÑ
       позволиÑÑ Ð½Ð¸Ñи в многониÑевой пÑогÑамме
       вÑполнÑÑÑ Ð´ÐµÐ»ÐµÐ½Ð¸Ðµ на ÑÑÑаниÑÑ
       полÑзоваÑелÑÑкого пÑоÑÑÑанÑÑва дÑÑÐ³Ð¸Ñ Ð½Ð¸Ñей
       пÑоÑеÑÑа. ÐÑи возникновении ÑÑÑаниÑной
       оÑибки в одной из заÑегиÑÑÑиÑованнÑÑ Ð²
       обÑекÑе userfaultfd облаÑÑей ниÑÑ Ñ Ð¾Ñибкой
       заÑÑÐ¿Ð°ÐµÑ Ð¸ генеÑиÑÑеÑÑÑ ÑобÑÑие, коÑоÑое
       можно пÑоÑиÑаÑÑ ÑеÑез ÑайловÑй деÑкÑипÑоÑ
       userfaultfd. ÐиÑÑ Ð¾Ð±ÑабоÑки ÑÑÑаниÑнÑÑ Ð¾Ñибок
       ÑиÑÐ°ÐµÑ ÑообÑÐµÐ½Ð¸Ñ Ð¸Ð· ÑÑого Ñайлового
       деÑкÑипÑоÑа и обÑлÑÐ¶Ð¸Ð²Ð°ÐµÑ Ð¸Ð· Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ
       опеÑаÑий, опиÑаннÑÑ Ð² ioctl_userfaultfd(2). РвÑемÑ
       ÑÑого ниÑÑ Ð¾Ð±ÑабоÑки ÑÑÑаниÑнÑÑ Ð¾Ñибок можеÑ
       пÑивеÑÑи в дейÑÑвие меÑанизм пÑобÑждениÑ
       ÑпÑÑей ниÑи.

       ÐиÑи Ñ Ð¾Ñибкой и ниÑи обÑабоÑки ÑÑÑаниÑнÑÑ
       оÑибок могÑÑ Ð±ÑÑÑ Ð·Ð°Ð¿ÑÑÐµÐ½Ñ Ð² конÑекÑÑе
       ÑазлиÑнÑÑ Ð¿ÑоÑеÑÑов. Ð ÑÑом ÑлÑÑае даннÑе ниÑи
       могÑÑ Ð¿ÑинадлежаÑÑ ÑазнÑм пÑогÑаммам, а
       пÑогÑаммам, вÑполнÑÑÑим ниÑи Ñ Ð¾Ñибкой, не
       обÑзаÑелÑно взаимодейÑÑвоваÑÑ Ñ
       пÑогÑаммой, обÑабаÑÑваÑÑей ÑÑÑаниÑнÑе
       оÑибки. Ð Ñаком ÑазобÑÑнном Ñежиме пÑоÑеÑÑÑ,
       ÑледÑÑÐµÐ¼Ñ Ð·Ð° userfaultfd и обÑабаÑÑваÑÑемÑ
       ÑÑÑаниÑнÑе оÑибки, необÑодимо знаÑÑ Ð¾Ð±
       изменениÑÑ Ð² ÑаÑкладке виÑÑÑалÑной памÑÑи
       пÑоÑеÑÑа Ñ Ð¾Ñибкой, ÑÑÐ¾Ð±Ñ Ð½Ðµ допÑÑÑиÑÑ
       повÑеждение памÑÑи.

       ÐаÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11, userfaultfd Ñакже ÑведомлÑеÑ
       ниÑи обÑабоÑки ÑÑÑаниÑнÑÑ Ð¾Ñибок об
       изменениÑÑ Ð² ÑаÑкладке виÑÑÑалÑной памÑÑи
       пÑоÑеÑÑа Ñ Ð¾Ñибкой. Также, еÑли пÑоÑеÑÑ Ñ
       оÑибкой вÑзÑÐ²Ð°ÐµÑ fork(2), Ñо Ð´Ð»Ñ Ð¾Ð±ÑекÑа
       userfaultfd, ÑвÑзанного Ñ ÑодиÑелем, в доÑеÑнем
       пÑоÑеÑÑе Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑоздаÑÑ Ð´ÑбликаÑ, и
       оÑÑлеживаÑÑий userfaultfd Ñакже бÑÐ´ÐµÑ ÑведомлÑн
       (ÑмоÑÑиÑе опиÑание UFFD_EVENT_FORK ниже) о
       Ñайловом деÑкÑипÑоÑе, ÑвÑзанном Ñ Ð¾Ð±ÑекÑом
       userfault, коÑоÑÑй бÑл Ñоздан Ð´Ð»Ñ Ð´Ð¾ÑеÑнего
       пÑоÑеÑÑа, ÑÑо позволÑÐµÑ Ð¾ÑÑлеживаÑÑÐµÐ¼Ñ userfaultfd
       вÑполнÑÑÑ Ð´ÐµÐ»ÐµÐ½Ð¸Ðµ на ÑÑÑаниÑÑ
       полÑзоваÑелÑÑкое пÑоÑÑÑанÑÑво доÑеÑнего
       пÑоÑеÑÑа. РоÑлиÑие Ð¾Ñ ÑÑÑаниÑнÑÑ Ð¾Ñибок,
       коÑоÑÑе пÑоиÑÑодÑÑ ÑинÑÑонно и ÑÑебÑÑÑ Ñвного
       или неÑвного пÑобÑждениÑ, вÑе оÑÑалÑнÑе
       ÑобÑÑÐ¸Ñ Ð´Ð¾ÑÑавлÑÑÑÑÑ Ð°ÑинÑÑонно и не
       взаимодейÑÑвÑÑÑий пÑоÑеÑÑ Ð²Ð¾Ð·Ð¾Ð±Ð½Ð¾Ð²Ð»ÑеÑ
       вÑполнение ÑÑÐ°Ð·Ñ Ð¶Ðµ поÑле Ñого как
       оÑÑлеживаÑÑий userfaultfd вÑполнÑÐµÑ read(2).
       ÐÑÑлеживаÑÑий userfaultfd должен коÑÑекÑно
       ÑинÑÑонизиÑоваÑÑ Ð²ÑÐ·Ð¾Ð²Ñ UFFDIO_COPY пÑи
       обÑабоÑке ÑобÑÑий.

       ÐмеÑÑаÑÑÑ Ð°ÑинÑÑÐ¾Ð½Ð½Ð°Ñ Ð¼Ð¾Ð´ÐµÐ»Ñ Ð´Ð¾ÑÑавки ÑобÑÑий
       опÑималÑна Ð´Ð»Ñ ÑеализаÑии однониÑевой не
       взаимодейÑÑвÑÑÑей оÑÑлеживаÑÑей userfaultfd
       пÑогÑаммÑ.

   РабоÑа Ñ userfaultfd
       ÐоÑле ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¾Ð±ÑекÑа userfaultfd Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ
       userfaultfd() пÑиложение должно вклÑÑиÑÑ ÐµÐ³Ð¾ Ñ
       помоÑÑÑ Ð¾Ð¿ÐµÑаÑии UFFDIO_API вÑзова ioctl(2). ÐаннаÑ
       опеÑаÑÐ¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑÐµÑ ÑоглаÑоваÑÑ Ð¼ÐµÐ¶Ð´Ñ ÑдÑом и
       полÑзоваÑелÑÑким пÑоÑÑÑанÑÑвом веÑÑиÑ
       пÑогÑаммного инÑеÑÑейÑа поддеÑживаемÑÑ
       ÑвойÑÑв. ÐÑа опеÑаÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° бÑÑÑ Ð²Ñполнено
       Ñамой пеÑвой ÑÑеди дÑÑÐ³Ð¸Ñ Ð¾Ð¿ÐµÑаÑий ioctl(2),
       опиÑÑваемÑÑ Ð½Ð¸Ð¶Ðµ (в пÑоÑивном ÑлÑÑае ÑÑи
       опеÑаÑии завеÑÑаÑÑÑÑ Ð¾Ñибкой EINVAL).

       ÐоÑле ÑÑпеÑного вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ UFFDIO_API
       пÑиложение должно заÑегиÑÑÑиÑоваÑÑ
       Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ñ Ð°Ð´ÑеÑов памÑÑи Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¾Ð¿ÐµÑаÑии
       UFFDIO_REGISTER вÑзова ioctl(2). ÐоÑле ÑÑпеÑного
       вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ UFFDIO_REGISTER ÑÑÑаниÑÐ½Ð°Ñ Ð¾Ñибка,
       возникаÑÑÐ°Ñ Ð² запÑоÑенном диапазоне и
       ÑдовлеÑвоÑÑÑÑÐ°Ñ ÑежимÑ, опÑеделÑÐ½Ð½Ð¾Ð¼Ñ Ð²
       Ð¼Ð¾Ð¼ÐµÐ½Ñ ÑегиÑÑÑаÑии, бÑÐ´ÐµÑ Ð¿ÐµÑеÑлана ÑдÑом
       пÑÐ¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² полÑзоваÑелÑÑком пÑоÑÑÑанÑÑве.
       ÐÐ»Ñ ÑеÑÐµÐ½Ð¸Ñ ÑÑÑаниÑной оÑибки пÑиложение
       Ð¼Ð¾Ð¶ÐµÑ Ð¸ÑполÑзоваÑÑ Ð¾Ð¿ÐµÑаÑÐ¸Ñ UFFDIO_COPY или
       UFFDIO_ZERO вÑзова ioctl(2).

       ÐаÑÐ¸Ð½Ð°Ñ Ñ Linux 4.14, еÑли пÑиложение
       ÑÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð±Ð¸Ñ ÑвойÑÑва UFFD_FEATURE_SIGBUS Ñ
       помоÑÑÑ UFFDIO_API ioctl(2), Ñо ÑÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾
       ÑÑÑаниÑнÑÑ Ð¾ÑÐ¸Ð±ÐºÐ°Ñ Ð½Ðµ пеÑеÑÑлаÑÑÑÑ Ð²
       полÑзоваÑелÑÑкое пÑоÑÑÑанÑÑво. ÐмеÑÑо ÑÑого в
       оÑибÑийÑÑ Ð¿ÑоÑеÑÑ Ð¿Ð¾ÑÑлаеÑÑÑ Ñигнал SIGBUS. С
       даннÑм ÑвойÑÑвом userfaultfd можно иÑполÑзоваÑÑ
       в ÑелÑÑ Ð½Ð°Ð´ÑжноÑÑи, пÑоÑÑо Ð»Ð¾Ð²Ñ Ð²Ñе попÑÑки
       доÑÑÑпа к облаÑÑÑÑ Ð²Ð½ÑÑÑи заÑегиÑÑÑиÑованного
       адÑеÑного диапазона, в коÑоÑом неÑ
       вÑделеннÑÑ ÑÑÑаниÑ, не ÑлÑÑÐ°Ñ Ð¿Ñи ÑÑом ÑобÑÑиÑ
       userfaultfd. ÐÑи Ñаком доÑÑÑпе к памÑÑи не
       поÑÑебÑеÑÑÑ Ð¿ÑоÑеÑÑ ÑÐ»ÐµÐ¶ÐµÐ½Ð¸Ñ Ð·Ð° userfaultfd.
       ÐапÑимеÑ, данное ÑвойÑÑво Ð¼Ð¾Ð¶ÐµÑ Ð¾ÐºÐ°Ð·Ð°ÑÑÑÑ
       полезнÑм пÑиложениÑм, коÑоÑÑе ÑоÑÑÑ Ð½Ðµ
       даваÑÑ ÑдÑÑ Ð²ÑполнÑÑÑ Ð°Ð²ÑомаÑиÑеÑкое
       вÑделение ÑÑÑÐ°Ð½Ð¸Ñ Ð¸ заполнение дÑÑ Ð²
       ÑазÑеженнÑÑ ÑÐ°Ð¹Ð»Ð°Ñ Ð¿Ñи обÑаÑении к дÑÑе ÑеÑез
       оÑобÑажение в памÑÑи.

       СвойÑÑво UFFD_FEATURE_SIGBUS неÑвно наÑледÑеÑÑÑ Ð¿Ñи
       fork(2), еÑли иÑполÑзÑеÑÑÑ Ð²Ð¼ÐµÑÑе Ñ UFFD_FEATURE_FORK.

       ÐодÑобноÑÑи о ÑазлиÑнÑÑ Ð¾Ð¿ÐµÑаÑиÑÑ ioctl(2) можно
       найÑи в ioctl_userfaultfd(2).

       ÐаÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11 пÑи опеÑаÑии UFFDIO_API можно
       вклÑÑиÑÑ Ð½Ðµ ÑолÑко ÑобÑÑÐ¸Ñ ÑÑÑаниÑной оÑибки.

       Ðо Linux 4.11 обÑÐµÐºÑ userfaultfd мог бÑÑÑ Ð¸ÑполÑзован
       ÑолÑко Ñ Ð°Ð½Ð¾Ð½Ð¸Ð¼Ð½Ñми ÑаÑÑнÑми оÑобÑажениÑми
       памÑÑи. ÐаÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11 обÑÐµÐºÑ userfaultfd можеÑ
       Ñакже иÑполÑзоваÑÑÑÑ Ñ Ð¾ÑобÑажениÑми обÑей
       памÑÑи и hugetlbfs.

   ЧÑение из ÑÑÑÑкÑÑÑÑ userfaultfd
       ÐаждÑй вÑзов read(2) из Ñайлового деÑкÑипÑоÑа
       userfaultfd возвÑаÑÐ°ÐµÑ Ð¾Ð´Ð½Ñ Ð¸Ð»Ð¸ более ÑÑÑÑкÑÑÑ
       uffd_msg, ÐºÐ°Ð¶Ð´Ð°Ñ Ð¸Ð· коÑоÑÑÑ Ð¾Ð¿Ð¸ÑÑÐ²Ð°ÐµÑ ÑобÑÑие
       ÑÑÑаниÑной оÑибки или ÑобÑÑие, ÑÑебÑемое длÑ
       иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ userfaultfd в ÑазобÑÑнном Ñежиме:

           struct uffd_msg {
               __u8  event;            /* Ñип ÑобÑÑÐ¸Ñ */
               ...
               union {
                   struct {
                       __u64 flags;    /* Ñлаги, опиÑÑваÑÑие оÑÐ¸Ð±ÐºÑ */
                       __u64 address;  /* оÑибоÑнÑй адÑÐµÑ */
                   } pagefault;

                   struct {            /* наÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11 */
                       __u32 ufd;      /* ÑайловÑй деÑкÑипÑÐ¾Ñ userfault
                                          доÑеÑнего пÑоÑеÑÑа */
                   } fork;

                   struct {            /* наÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11 */
                       __u64 from;     /* ÑÑаÑÑй адÑÐµÑ Ð¿ÐµÑеоÑобÑажаемой облаÑÑи */
                       __u64 to;       /* новÑй адÑÐµÑ Ð¿ÐµÑеоÑобÑажаемой облаÑÑи */
                       __u64 len;      /* наÑалÑнÑй ÑÐ°Ð·Ð¼ÐµÑ Ð¾ÑобÑÐ°Ð¶ÐµÐ½Ð¸Ñ */
                   } remap;

                   struct {            /* наÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11 */
                       __u64 start;    /* наÑалÑнÑй адÑÐµÑ ÑдалÑемой облаÑÑи */
                       __u64 end;      /* конеÑнÑй адÑÐµÑ ÑдалÑемой облаÑÑи */
                   } remove;
                   ...
               } arg;

               /* полÑ-заполниÑели не Ð¿Ð¾ÐºÐ°Ð·Ð°Ð½Ñ */
           } __packed;

       ÐÑли доÑÑÑпно неÑколÑко ÑобÑÑий и пеÑеданнÑй
       бÑÑÐµÑ Ð´Ð¾ÑÑаÑоÑного ÑазмеÑа, Ñо read(2)
       возвÑаÑÐ°ÐµÑ ÑÑолÑко ÑобÑÑий ÑколÑко Ð²Ð»ÐµÐ·Ð°ÐµÑ Ð²
       бÑÑеÑ. ÐÑли бÑÑеÑ, ÑказаннÑй read(2), менÑÑе
       ÑазмеÑа ÑÑÑÑкÑÑÑÑ uffd_msg, Ñо read(2) завеÑÑаеÑÑÑ
       оÑибкой EINVAL.

       ÐÐ¾Ð»Ñ ÑÑÑÑкÑÑÑÑ uffd_msg:

       event  Тип ÑобÑÑиÑ. Тип ÑобÑÑÐ¸Ñ Ð²Ð»Ð¸ÑÐµÑ Ð½Ð°
              заполнÑемÑе Ð¿Ð¾Ð»Ñ Ð¾Ð±ÑÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ arg,
              пÑедÑÑавлÑÑÑего деÑали, ÑÑебÑемÑе длÑ
              обÑабоÑки ÑобÑÑиÑ. СобÑÑиÑ, не оÑноÑÑÑиеÑÑ
              к ÑÑÑаниÑнÑм оÑибкам, генеÑиÑÑÑÑÑÑ ÑолÑко
              когда вклÑÑено ÑооÑвеÑÑÑвÑÑÑее ÑвойÑÑво
              пÑи ÑоглаÑовании пÑогÑаммного
              инÑеÑÑейÑа Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¾Ð¿ÐµÑаÑии UFFDIO_API
              вÑзова ioctl(2).

              Рполе event могÑÑ Ð¿Ð¾ÑвлÑÑÑÑÑ ÑледÑÑÑие
              знаÑениÑ:

              UFFD_EVENT_PAGEFAULT (наÑÐ¸Ð½Ð°Ñ Ñ Linux 4.3)
                     СобÑÑие ÑÑÑаниÑной оÑибки. ÐеÑали
                     оÑибки доÑÑÑÐ¿Ð½Ñ Ð² поле pagefault.

              UFFD_EVENT_FORK (наÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11)
                     ÐенеÑиÑÑеÑÑÑ, когда пÑоÑеÑÑ Ñ Ð¾Ñибкой
                     вÑзÑÐ²Ð°ÐµÑ fork(2) (или clone(2) без Ñлага
                     CLONE_VM). ÐеÑали оÑибки доÑÑÑÐ¿Ð½Ñ Ð²
                     поле fork.

              UFFD_EVENT_REMAP (наÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11)
                     ÐенеÑиÑÑеÑÑÑ, когда пÑоÑеÑÑ Ñ Ð¾Ñибкой
                     вÑзÑÐ²Ð°ÐµÑ mremap(2). ÐеÑали оÑибки
                     доÑÑÑÐ¿Ð½Ñ Ð² поле remap.

              UFFD_EVENT_REMOVE (наÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11)
                     ÐенеÑиÑÑеÑÑÑ, когда пÑоÑеÑÑ Ñ Ð¾Ñибкой
                     вÑзÑÐ²Ð°ÐµÑ madvise(2) Ñ ÑовеÑом MADV_DONTNEED
                     или MADV_REMOVE. ÐеÑали оÑибки доÑÑÑпнÑ
                     в поле remove.

              UFFD_EVENT_UNMAP (наÑÐ¸Ð½Ð°Ñ Ñ Linux 4.11)
                     ÐенеÑиÑÑеÑÑÑ, когда пÑоÑеÑÑ Ñ Ð¾Ñибкой
                     оÑменÑÐµÑ Ð¿ÑоеÑиÑование диапазона
                     памÑÑи ÑвнÑм обÑазом Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ munmap(2)
                     или неÑвно пÑи вÑзове mmap(2) или
                     mremap(2). ÐеÑали оÑибки доÑÑÑÐ¿Ð½Ñ Ð²
                     поле remove.

       pagefault.address
              ÐдÑеÑ, из-за коÑоÑого возникла
              ÑÑÑаниÑÐ½Ð°Ñ Ð¾Ñибка.

       pagefault.flags
              ÐиÑÐ¾Ð²Ð°Ñ Ð¼Ð°Ñка Ñлагов, опиÑÑваÑÑиÑ
              ÑобÑÑие. ÐÐ»Ñ UFFD_EVENT_PAGEFAULT Ð¼Ð¾Ð¶ÐµÑ Ð¿Ð¾ÑвлÑÑÑÑÑ
              ÑледÑÑÑий Ñлаг:

              UFFD_PAGEFAULT_FLAG_WRITE
                     ÐÑли адÑÐµÑ Ð² диапазоне, коÑоÑÑй бÑл
                     заÑегиÑÑÑиÑован Ñ Ñлагом
                     UFFDIO_REGISTER_MODE_MISSING (ÑмоÑÑиÑе
                     ioctl_userfaultfd(2)) и ÑÑÐ¾Ñ Ñлаг ÑÑÑановлен,
                     Ñо ÑÑо оÑибка запиÑи; в пÑоÑивном
                     ÑлÑÑае ÑÑо оÑибка ÑÑениÑ.

       fork.ufd
              С помоÑÑÑ fork(2) бÑл Ñоздан поÑомок, длÑ
              коÑоÑого бÑл Ñоздан ÑайловÑй
              деÑкÑипÑоÑ, ÑвÑзаннÑй Ñ Ð¾Ð±ÑекÑом userfault.

       remap.from
              ÐеÑвонаÑалÑнÑй адÑÐµÑ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° памÑÑи,
              коÑоÑÑй бÑл пеÑеоÑобÑажÑн Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ
              mremap(2).

       remap.to
              ÐовÑй адÑÐµÑ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° памÑÑи, коÑоÑÑй
              бÑл пеÑеоÑобÑажÑн Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ mremap(2).

       remap.len
              ÐеÑвонаÑалÑнÑй ÑÐ°Ð·Ð¼ÐµÑ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð°
              памÑÑи, коÑоÑÑй бÑл пеÑеоÑобÑажÑн Ñ
              помоÑÑÑ mremap(2).

       remove.start
              ÐаÑалÑнÑй адÑÐµÑ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° памÑÑи,
              коÑоÑÑй бÑл оÑвобождÑн Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ madvise(2)
              или бÑло оÑменено пÑоеÑиÑование.

       remove.end
              ÐонеÑнÑй адÑÐµÑ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð° памÑÑи,
              коÑоÑÑй бÑл оÑвобождÑн Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ madvise(2)
              или бÑло оÑменено пÑоеÑиÑование.

       ÐÑзов read(2) Ñ ÑайловÑм деÑкÑипÑоÑом userfaultfd
       Ð¼Ð¾Ð¶ÐµÑ Ð·Ð°Ð²ÐµÑÑиÑÑÑÑ ÑледÑÑÑими оÑибками:

       EINVAL ÐбÑÐµÐºÑ userfaultfd не бÑл вклÑÑÑн Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ
              опеÑаÑии UFFDIO_API вÑзова ioctl(2).

       ÐÑли в ÑвÑзанном оÑкÑÑÑом Ñайловом опиÑании
       Ñказан Ñлаг O_NONBLOCK, Ñо ÑайловÑй деÑкÑипÑоÑ
       userfaultfd можно оÑÑлеживаÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ poll(2),
       select(2) и epoll(7). ÐÑи возникновении ÑобÑÑий,
       ÑайловÑй деÑкÑипÑÐ¾Ñ Ð¿Ð¾Ð¼ÐµÑаеÑÑÑ ÐºÐ°Ðº доÑÑÑпнÑй
       на ÑÑение. ÐÑли Ñлаг O_NONBLOCK не задан, Ñо poll(2)
       (вÑегда) показÑваеÑ, ÑÑо Ñайл наÑодиÑÑÑ Ð²
       ÑоÑÑоÑнии POLLERR, а select(2) показÑваеÑ, ÑÑо
       ÑайловÑй деÑкÑипÑÐ¾Ñ Ð´Ð¾ÑÑÑпен на ÑÑение и
       запиÑÑ.

ÐÐÐÐÐ ÐЩÐÐÐÐÐ ÐÐÐЧÐÐÐÐ
       ÐÑи ÑÑпеÑном вÑполнении userfaultfd() возвÑаÑаеÑ
       новÑй ÑайловÑй деÑкÑипÑоÑ, коÑоÑÑй ÑÑÑлаеÑÑÑ
       на обÑÐµÐºÑ userfaultfd. ÐÑи оÑибке возвÑаÑаеÑÑÑ -1,
       и errno изменÑеÑÑÑ ÑооÑвеÑÑÑвÑÑÑим обÑазом.

ÐШÐÐÐÐ
       EINVAL Ð flags Ñказано неподдеÑживаемое
              знаÑение.

       EMFILE ÐÑло доÑÑигнÑÑо огÑаниÑение по
              колиÑеÑÑÐ²Ñ Ð¾ÑкÑÑÑÑÑ ÑайловÑÑ Ð´ÐµÑкÑипÑоÑов
              на пÑоÑеÑÑ.

       ENFILE ÐоÑÑигнÑÑо макÑималÑное колиÑеÑÑво
              оÑкÑÑÑÑÑ Ñайлов в ÑиÑÑеме.

       ENOMEM ÐедоÑÑаÑоÑное колиÑеÑÑво памÑÑи ÑдÑа.

ÐÐРСÐÐ
       СиÑÑемнÑй вÑзов userfaultfd() впеÑвÑе поÑвилÑÑ Ð²
       Linux 4.3.

       ÐоддеÑжка hugetlbfs и обÑÐ¸Ñ Ð¾Ð±Ð»Ð°ÑÑей памÑÑи, а
       Ñакже ÑобÑÑий, не оÑноÑÑÑиÑÑÑ Ðº ÑÑÑаниÑнÑм
       оÑибкам, бÑла добавлена в Linux 4.11.

СÐÐТÐÐТСТÐÐРСТÐÐÐÐРТÐÐ
       ÐÑзов userfaultfd() еÑÑÑ ÑолÑко в Linux и поÑÑÐ¾Ð¼Ñ Ð½Ðµ
       должен иÑполÑзоваÑÑÑÑ Ð² пÑогÑаммаÑ,
       пÑедназнаÑеннÑÑ Ð´Ð»Ñ Ð¿ÐµÑеноÑа на дÑÑгие
       плаÑÑоÑмÑ.

ÐÐÐÐЧÐÐÐЯ
       Ð glibc Ð½ÐµÑ Ð¾Ð±ÑÑÑки Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ ÑиÑÑемного
       вÑзова; запÑÑкайÑе его Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ syscall(2).

       ÐеÑанизм userfaultfd Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ÑполÑзован как
       алÑÑеÑнаÑива обÑÑÐ½Ð¾Ð¼Ñ ÑÑÑаниÑÐ½Ð¾Ð¼Ñ Ð´ÐµÐ»ÐµÐ½Ð¸Ñ
       полÑзоваÑелÑÑкого пÑоÑÑÑанÑÑва на оÑнове
       иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñигнала SIGSEGV и mmap(2). Также
       он Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð¸ÑполÑзован Ð´Ð»Ñ ÑеализаÑии
       оÑложенного (lazy) воÑÑÑановлениÑ
       checkpoint/restore mechanisms, as well as post-copy migration to allow
       (поÑÑи) не пÑеÑÑваемого вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¿Ñи
       пеÑеноÑе виÑÑÑалÑнÑÑ Ð¼Ð°Ñин и конÑейнеÑов Linux
       Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ Ñзла на дÑÑгой.

ÐÐФÐÐТЫ
       ÐÑли Ñказано UFFD_FEATURE_EVENT_FORK и ÑиÑÑемнÑй
       вÑзов из ÑемейÑÑва fork(2) пÑеÑÑваеÑÑÑ Ð¿Ð¾
       ÑÐ¸Ð³Ð½Ð°Ð»Ñ Ð¸Ð»Ð¸ завеÑÑаеÑÑÑ Ð¾Ñибкой, Ñо можеÑ
       бÑÑÑ Ñоздан повиÑÑий деÑкÑипÑÐ¾Ñ userfaultfd. Ð ÑÑом
       ÑлÑÑае пÑогÑамме ÑÐ»ÐµÐ¶ÐµÐ½Ð¸Ñ Ð·Ð° userfaultfd можеÑ
       бÑÑÑ Ð´Ð¾ÑÑавлен ложнÑй UFFD_EVENT_FORK.

ÐÐ ÐÐÐÐ
       ÐÑогÑамма, пÑедÑÑÐ°Ð²Ð»ÐµÐ½Ð½Ð°Ñ Ð´Ð°Ð»ÐµÐµ,
       показÑÐ²Ð°ÐµÑ Ð¸ÑполÑзование меÑанизма
       userfaultfd. Ðна ÑоздаÑÑ Ð´Ð²Ðµ ниÑи, одна ÑлÑжиÑ
       обÑабоÑÑиком ÑÑÑаниÑнÑÑ Ð¾Ñибок пÑоÑеÑÑа длÑ
       ÑÑÑÐ°Ð½Ð¸Ñ Ð² Ñежиме вÑÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿Ñи
       необÑодимоÑÑи, ÑозданнÑÑ mmap(2).

       ÐÑогÑамма Ð¸Ð¼ÐµÐµÑ Ð¾Ð´Ð¸Ð½ паÑамеÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð½Ð¾Ð¹
       ÑÑÑоки, опÑеделÑÑÑий колиÑеÑÑво ÑÑÑаниÑ,
       коÑоÑÑе бÑдÑÑ ÑÐ¾Ð·Ð´Ð°Ð½Ñ Ð² оÑобÑажении, ÑÑи
       ÑÑÑаниÑнÑе оÑибки бÑдÑÑ Ð¾Ð±ÑабоÑÐ°Ð½Ñ userfaultfd.
       ÐоÑле ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¾Ð±ÑекÑа userfaultfd пÑогÑамма
       ÑоздаÑÑ Ð°Ð½Ð¾Ð½Ð¸Ð¼Ð½Ð¾Ðµ ÑаÑÑное оÑобÑажение
       Ñказанного ÑазмеÑа и ÑегиÑÑÑиÑÑÐµÑ Ð°Ð´ÑеÑнÑй
       диапазон оÑобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ð¾Ð¿ÐµÑаÑии
       UFFDIO_REGISTER вÑзовом ioctl(2). ÐоÑле ÑÑого
       пÑогÑамма ÑоздаÑÑ Ð²ÑоÑÑÑ Ð½Ð¸ÑÑ, коÑоÑÐ°Ñ Ð±ÑдеÑ
       вÑполнÑÑÑ Ð·Ð°Ð´Ð°ÑÑ Ð¿Ð¾ обÑабоÑке ÑÑÑаниÑнÑÑ
       оÑибок.

       ÐоÑле ÑÑого Ð³Ð»Ð°Ð²Ð½Ð°Ñ Ð½Ð¸ÑÑ Ð¾Ð±ÑÐ¾Ð´Ð¸Ñ ÑÑÑаниÑÑ
       оÑобÑÐ°Ð¶ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿ÑаÑÐ¸Ð²Ð°Ñ Ð±Ð°Ð¹ÑÑ ÑледÑÑÑей
       ÑÑÑаниÑÑ. Так как к ÑÑÑаниÑам еÑÑ Ð½Ðµ
       обÑаÑалиÑÑ, пеÑвÑй доÑÑÑп к байÑÑ Ð² каждой
       ÑÑÑаниÑе бÑÐ´ÐµÑ Ð²ÑзÑваÑÑ ÑобÑÑие ÑÑÑаниÑной
       оÑибки в Ñайловом деÑкÑипÑоÑе userfaultfd.

       Ðаждое ÑобÑÑие ÑÑÑаниÑной оÑибки
       обÑабаÑÑваеÑÑÑ Ð²ÑоÑой ниÑÑÑ, коÑоÑÐ°Ñ Ð²ÑполнÑеÑ
       Ñикл обÑабоÑки ввода из Ñайлового
       деÑкÑипÑоÑа userfaultfd. ÐÑи каждом пÑоÑоде
       Ñикла вÑоÑÐ°Ñ Ð½Ð¸ÑÑ ÑнаÑала вÑзÑÐ²Ð°ÐµÑ poll(2) длÑ
       пÑовеÑки ÑоÑÑоÑÐ½Ð¸Ñ Ñайлового деÑкÑипÑоÑа,
       заÑем ÑиÑÐ°ÐµÑ ÑобÑÑие из Ñайлового
       деÑкÑипÑоÑа. ÐÑе ÑобÑÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ
       UFFD_EVENT_PAGEFAULT, Ð´Ð»Ñ Ð¸Ñ Ð¾Ð±ÑабоÑки ниÑÑ ÐºÐ¾Ð¿Ð¸ÑÑеÑ
       ÑÑÑаниÑÑ Ð´Ð°Ð½Ð½ÑÑ Ð² оÑибоÑнÑÑ Ð¾Ð±Ð»Ð°ÑÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ
       опеÑаÑии UFFDIO_COPY вÑзова ioctl(2).

       РезÑлÑÑÐ°Ñ ÑабоÑÑ Ð¿ÑогÑаммÑ:

           $ ./userfaultfd_demo 3
           ÐдÑеÑ, возвÑаÑÑннÑй mmap() = 0x7fd30106c000

           fault_handler_thread():
               poll() веÑнÑл: nready = 1; POLLIN = 1; POLLERR = 0
               ÑобÑÑие UFFD_EVENT_PAGEFAULT: Ñлаги = 0; адÑÐµÑ = 7fd30106c00f
                   (uffdio_copy.copy Ñавно 4096)
           ЧÑение по адÑеÑÑ 0x7fd30106c00f в main(): A
           ЧÑение по адÑеÑÑ 0x7fd30106c40f в main(): A
           ЧÑение по адÑеÑÑ 0x7fd30106c80f в main(): A
           ЧÑение по адÑеÑÑ 0x7fd30106cc0f в main(): A

           fault_handler_thread():
               poll() веÑнÑл: nready = 1; POLLIN = 1; POLLERR = 0
               ÑобÑÑие UFFD_EVENT_PAGEFAULT: Ñлаги = 0; адÑÐµÑ = 7fd30106d00f
                   (uffdio_copy.copy Ñавно 4096)
           ЧÑение по адÑеÑÑ 0x7fd30106d00f в main(): B
           ЧÑение по адÑеÑÑ 0x7fd30106d40f в main(): B
           ЧÑение по адÑеÑÑ 0x7fd30106d80f в main(): B
           ЧÑение по адÑеÑÑ 0x7fd30106dc0f в main(): B

           fault_handler_thread():
               poll() веÑнÑл: nready = 1; POLLIN = 1; POLLERR = 0
               ÑобÑÑие UFFD_EVENT_PAGEFAULT: Ñлаги = 0; адÑÐµÑ = 7fd30106e00f
                   (uffdio_copy.copy Ñавно 4096)
           ЧÑение по адÑеÑÑ 0x7fd30106e00f в main(): C
           ЧÑение по адÑеÑÑ 0x7fd30106e40f в main(): C
           ЧÑение по адÑеÑÑ 0x7fd30106e80f в main(): C
           ЧÑение по адÑеÑÑ 0x7fd30106ec0f в main(): C

   ÐÑÑоднÑй код пÑогÑаммÑ

       /* userfaultfd_demo.c

          ÑаÑпÑоÑÑÑанÑеÑÑÑ Ð¿Ð¾ лиÑензии GNU General Public License version 2 и новее.
       */
       #define _GNU_SOURCE
       #include <sys/types.h>
       #include <stdio.h>
       #include <linux/userfaultfd.h>
       #include <pthread.h>
       #include <errno.h>
       #include <unistd.h>
       #include <stdlib.h>
       #include <fcntl.h>
       #include <signal.h>
       #include <poll.h>
       #include <string.h>
       #include <sys/mman.h>
       #include <sys/syscall.h>
       #include <sys/ioctl.h>
       #include <poll.h>

       #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                               } while (0)

       static int page_size;

       static void *
       fault_handler_thread(void *arg)
       {
           static struct uffd_msg msg;   /* даннÑе, пÑоÑиÑаннÑе из userfaultfd */
           static int fault_cnt = 0;     /* колиÑеÑÑво обÑабоÑаннÑÑ Ð¾Ñибок */
           long uffd;                    /* ÑайловÑй деÑкÑипÑÐ¾Ñ userfaultfd */
           static char *page = NULL;
           struct uffdio_copy uffdio_copy;
           ssize_t nread;

           uffd = (long) arg;

           /* ÑоздаÑм ÑÑÑаниÑÑ, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ ÐºÐ¾Ð¿Ð¸ÑоваÑÑÑÑ Ð² оÑибоÑнÑÑ Ð¾Ð±Ð»Ð°ÑÑÑ */

           if (page == NULL) {
               page = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
                           MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
               if (page == MAP_FAILED)
                   errExit("mmap");
           }

           /* ÑиклиÑеÑки обÑабаÑÑваем вÑоднÑе ÑообÑÐµÐ½Ð¸Ñ Ð²
              Ñайловом деÑкÑипÑоÑе userfaultfd */

           for (;;) {

               /* С помоÑÑÑ poll() пÑовеÑÑем userfaultfd */

               struct pollfd pollfd;
               int nready;
               pollfd.fd = uffd;
               pollfd.events = POLLIN;
               nready = poll(&pollfd, 1, -1);
               if (nready == -1)
                   errExit("poll");

               printf("\nfault_handler_thread():\n");
               printf("    poll() веÑнÑл: nready = %d; "
                       "POLLIN = %d; POLLERR = %d\n", nready,
                       (pollfd.revents & POLLIN) != 0,
                       (pollfd.revents & POLLERR) != 0);

               /* ÑиÑаем ÑобÑÑие из userfaultfd */

               nread = read(uffd, &msg, sizeof(msg));
               if (nread == 0) {
                   printf("EOF в userfaultfd!\n");
                   exit(EXIT_FAILURE);
               }

               if (nread == -1)
                   errExit("read");

               /* ожидаем ÑолÑко один Ñип ÑобÑÑий; пÑовеÑÑем, ÑÑо ÑÑо Ñак */

               if (msg.event != UFFD_EVENT_PAGEFAULT) {
                   fprintf(stderr, "ÐеожидаемÑй Ñип ÑобÑÑÐ¸Ñ Ð² userfaultfd\n");
                   exit(EXIT_FAILURE);
               }

               /* показÑваем инÑоÑмаÑÐ¸Ñ Ð¾ ÑобÑÑии ÑÑÑаниÑной оÑибки */

               printf("    ÑобÑÑие UFFD_EVENT_PAGEFAULT: ");
               printf("Ñлаги = %llx; ", msg.arg.pagefault.flags);
               printf("адÑÐµÑ = %llx\n", msg.arg.pagefault.address);

               /* копиÑÑем ÑÑÑаниÑÑ, на коÑоÑÑÑ ÑказÑÐ²Ð°ÐµÑ 'page', в оÑибоÑнÑÑ
                  облаÑÑÑ. ÐенÑем ÑодеÑжимое, коÑоÑое копиÑÑем Ð´Ð»Ñ Ñого, ÑÑобÑ
                  бÑло более оÑевидно, ÑÑо ÐºÐ°Ð¶Ð´Ð°Ñ Ð¾Ñибка обÑабаÑÑваеÑÑÑ Ð¾ÑделÑно. */

               memset(page, 'A' + fault_cnt % 20, page_size);
               fault_cnt++;

               uffdio_copy.src = (unsigned long) page;

               /* Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¾Ð±ÑабаÑÑваÑÑ ÑÑÑаниÑнÑе оÑибки в единиÑÐ°Ñ ÑÑÑаниÑ(!).
                  поÑÑÐ¾Ð¼Ñ Ð¾ÐºÑÑглÑем адÑÐµÑ Ð¾Ñибки по нижней гÑаниÑÑ ÑÑÑаниÑÑ */

               uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address &
                                                  ~(page_size - 1);
               uffdio_copy.len = page_size;
               uffdio_copy.mode = 0;
               uffdio_copy.copy = 0;
               if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) == -1)
                   errExit("ioctl-UFFDIO_COPY");

               printf("        (uffdio_copy.copy Ñавно %lld)\n",
                       uffdio_copy.copy);
           }
       }

       int
       main(int argc, char *argv[])
       {
           long uffd;          /* ÑайловÑй деÑкÑипÑÐ¾Ñ userfaultfd */
           char *addr;         /* ÐаÑало облаÑÑи, обÑабаÑÑваемое userfaultfd */
           unsigned long len;  /* Ð Ð°Ð·Ð¼ÐµÑ Ð¾Ð±Ð»Ð°ÑÑи, обÑабаÑÑваемой userfaultfd */
           pthread_t thr;      /* ID ниÑи, обÑабаÑÑваÑÑей ÑÑÑаниÑнÑе оÑибки */
           struct uffdio_api uffdio_api;
           struct uffdio_register uffdio_register;
           int s;

           if (argc != 2) {
               fprintf(stderr, "ÐÑполÑзование: %s колиÑеÑÑво-ÑÑÑаниÑ\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           page_size = sysconf(_SC_PAGE_SIZE);
           len = strtoul(argv[1], NULL, 0) * page_size;

           /* ÑоздаÑм и вклÑÑаем обÑÐµÐºÑ userfaultfd */

           uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
           if (uffd == -1)
               errExit("userfaultfd");

           uffdio_api.api = UFFD_API;
           uffdio_api.features = 0;
           if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
               errExit("ioctl-UFFDIO_API");

           /* ÐопиÑÑем ÑаÑÑное анонимное оÑобÑажение. ÐамÑÑÑ Ð±ÑдеÑ
              вÑделена по ÑÑебованиÑ, Ñо еÑÑÑ ÑеалÑно не вÑделÑеÑÑÑ. Ðогда мÑ
              обÑаÑимÑÑ Ðº памÑÑи, она бÑÐ´ÐµÑ Ð²Ñделена Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ
              userfaultfd. */

           addr = mmap(NULL, len, PROT_READ | PROT_WRITE,
                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
           if (addr == MAP_FAILED)
               errExit("mmap");

           printf("ÐдÑеÑ, возвÑаÑÑннÑй mmap() = %p\n", addr);

           /* РегиÑÑÑиÑÑем в обÑекÑе userfaultfd облаÑÑÑ Ð¿Ð°Ð¼ÑÑи оÑобÑажениÑ
              коÑоÑое Ð¼Ñ ÑолÑко ÑÑо Ñоздали. ÐапÑаÑиваем Ñежим ÑлежениÑ
              за оÑÑÑÑÑÑвÑÑÑими ÑÑÑаниÑами (Ñ. е., коÑоÑÑе пока не
              бÑли заполненÑ). */

           uffdio_register.range.start = (unsigned long) addr;
           uffdio_register.range.len = len;
           uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
           if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1)
               errExit("ioctl-UFFDIO_REGISTER");

           /* СоздаÑм ниÑÑ, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð¾Ð±ÑабаÑÑваÑÑ ÑобÑÑÐ¸Ñ  userfaultfd */

           s = pthread_create(&thr, NULL, fault_handler_thread, (void *) uffd);
           if (s != 0) {
               errno = s;
               errExit("pthread_create");
           }

           /* ТепеÑÑ Ð³Ð»Ð°Ð²Ð½Ð°Ñ Ð½Ð¸ÑÑ Ð¾Ð±ÑаÑаеÑÑÑ Ðº памÑÑи в оÑобÑажении c
              инÑеÑвалом в 1024 байÑа. ÐÑо ÑоздаÑÑ ÑобÑÑÐ¸Ñ Ð² userfaultfd
              Ð´Ð»Ñ Ð²ÑÐµÑ ÑÑÑÐ°Ð½Ð¸Ñ Ð² облаÑÑи. */

           int l;
           l = 0xf;    /* ÐаÑанÑиÑÑем, ÑÑо оÑибоÑнÑй адÑÐµÑ Ð½Ðµ на гÑаниÑе
                          ÑÑÑаниÑÑ, ÑÑÐ¾Ð±Ñ Ð¿ÑоÑеÑÑиÑоваÑÑ ÑÑо, Ð¼Ñ Ð¿ÑавилÑно
                          обÑабаÑÑваем ÑÑÐ¾Ñ ÑлÑÑай в fault_handling_thread() */
           while (l < len) {
               char c = addr[l];
               printf("ЧÑение по адÑеÑÑ %p в main(): ", addr + l);
               printf("%c\n", c);
               l += 1024;
               usleep(100000);         /* замедлим пÑогÑÐ°Ð¼Ð¼Ñ */
           }

           exit(EXIT_SUCCESS);
       }

СÐÐТРÐТРТÐÐÐÐ
       fcntl(2), ioctl(2), ioctl_userfaultfd(2), madvise(2), mmap(2)

       Файл Documentation/vm/userfaultfd.txt в деÑеве
       иÑÑодного кода ÑдÑа Linux

Linux                             2017-09-15                    USERFAULTFD(2)