.\" -*- coding: UTF-8 -*- .\" Copyright (c) 2016, IBM Corporation. .\" Written by Mike Rapoport .\" and Copyright (C) 2017 Michael Kerrisk .\" .\" SPDX-License-Identifier: Linux-man-pages-copyleft .\" .\"******************************************************************* .\" .\" This file was generated with po4a. Translate the source file. .\" .\"******************************************************************* .TH userfaultfd 2 "12 février 2024" "Pages du manuel de Linux 6.06" .SH NOM userfaultfd \- Créer un descripteur de fichier pour gérer les erreurs de page en espace utilisateur .SH BIBLIOTHÈQUE Bibliothèque C standard (\fIlibc\fP, \fI\-lc\fP) .SH SYNOPSIS .nf \fB#include \fP /* Définition des constantes \fBO_*\fP */ \fB#include \fP /* Définition des constantes \fBSYS_*\fP */ \fB#include \fP /* Définition des constantes \fBUFFD_*\fP */ \fB#include \fP .P \fBint syscall(SYS_userfaultfd, int \fP\fIflags\fP\fB);\fP .fi .P \fINote\fP : la glibc ne fournit pas d'enveloppe pour \fBuserfaultfd\fP(), imposant l'utilisation de \fBsyscall\fP(2). .SH DESCRIPTION \fBuserfaultfd\fP() crée un nouvel objet userfaultfd qui peut être utilisé pour la délégation de la gestion des erreurs de page à une application de l'espace utilisateur et renvoie un descripteur de fichier qui fait référence au nouvel objet. Le nouvel objet userfaultfd est configuré en utilisant \fBioctl\fP(2). .P Une fois l'objet userfaultfd configuré, l'application peut utiliser \fBread\fP(2) pour recevoir des notification d'userfaultfd. Les lectures à partir d'userfaultfd peuvent être bloquantes ou non bloquantes en fonction de la valeur des attributs (\fIflags\fP) utilisés pour la création de l'userfaultfd ou des appels suivants à \fBfcntl\fP(2). .P Les valeurs suivantes peuvent être combinées dans \fIflags\fP par un OU binaire pour modifier le comportement d'\fBuserfaultfd\fP() : .TP \fBO_CLOEXEC\fP Activer l'attribut close\-on\-exec pour le nouveau descripteur de fichier userfaultfd. Consultez la description de l'attribut \fBO_CLOEXEC\fP dans \fBopen\fP(2). .TP \fBO_NONBLOCK\fP Permettre une opération non bloquante pour l'objet userfaultfd. Voir la description de l'attribut \fBO_NONBLOCK\fP dans \fBopen\fP(2). .TP \fBUFFD_USER_MODE_ONLY\fP C'est un attribut spécifique à userfaultfd qui a été introduit dans Linux\ 5.11. Quand il est défini, l'objet userfaultfd ne pourra gérer que les erreurs de page provenant de l'espace utilisateur dans les régions enregistrées. Quand une erreur provenant du noyau est déclenchée dans l'intervalle enregistré avec cet userfaultfd, un signal \fBSIGBUS\fP sera envoyé. .P .\" Quand le dernier descripteur de fichier faisant référence à un objet userfaultfd est fermé, tous les intervalles de mémoire qui ont été enregistrés avec l'objet sont désenregistrés et les événements non lus sont vidés. .P Userfaultfd gère trois modes d'enregistrement : .TP \fBUFFDIO_REGISTER_MODE_MISSING\fP (depuis Linux 4.10) Quand il est enregistré avec le mode \fBUFFDIO_REGISTER_MODE_MISSING\fP, l'espace utilisateur recevra une notification d'erreur de page lors de l'accès à une page manquante. L'exécution du thread fautif sera arrêtée jusqu'à ce que l'erreur de page soit résolue à partir de l'espace utilisateur par un ioctl \fBUFFDIO_COPY\fP ou \fBUFFDIO_ZEROPAGE\fP. .TP \fBUFFDIO_REGISTER_MODE_MINOR\fP (depuis Linux 5.13) Quand il est enregistré avec le mode \fBUFFDIO_REGISTER_MODE_MINOR\fP, l'espace utilisateur recevra une notification d'erreur de page lorsqu'une erreur de page mineure survient. C'est\-à\-dire quand une page de sauvegarde est dans le cache de page, mais les entrées dans la table de pages n'existent pas encore. L'exécution du thread fautif sera arrêtée jusqu'à ce que l'erreur de page soit résolue à partir de l'espace utilisateur par un ioctl \fBUFFDIO_CONTINUE\fP. .TP \fBUFFDIO_REGISTER_MODE_WP\fP (depuis Linux 5.7) Quand il est enregistré avec le mode \fBUFFDIO_REGISTER_MODE_WP\fP, l'espace utilisateur recevra une notification d'erreur de page lors d'une écriture sur une page protégée en écriture. L'exécution du thread fautif sera arrêtée jusqu'à ce que l'espace utilisateur supprime la protection de la page en utilisant un ioctl \fBUFFDIO_WRITEPROTECT\fP. .P Plusieurs modes peuvent être activés en même temps pour le même intervalle de mémoire. .P Depuis Linux 4.14, une notification d'erreur de page d'userfaultfd peut incorporer de façon sélective des informations d'identifiant des threads en erreur dans une notification. Il est nécessaire d'activer cette fonctionnalité explicitement en utilisant le bit de fonction \fBUFFD_FEATURE_THREAD_ID\fP lors de l'initialisation du contexte d'userfaultfd. Par défaut, la déclaration de l'identifiant du thread est désactivée. .SS Utilisation Le mécanisme d'userfaultfd est conçu pour permettre à un thread dans un programme multi\-thread de réaliser la pagination en espace utilisateur pour d'autres threads dans le processus. Lorsqu'un erreur de page survient pour une des régions enregistrées dans l'objet userfaultfd, le thread en erreur est mis en sommeil et un événement est généré qui peut être lu au moyen du descripteur de fichier userfaultfd. Le thread de gestion d'erreur lit les événements à partir de ce descripteur de fichier et les corrige en utilisant les opérations décrites dans \fBioctl_userfaultfd\fP(2). Lors de l'intervention sur les événements d'erreur de page, le thread de gestion d'erreur peut déclencher le réveil d'un thread endormi. .P Il est possible que les threads en erreur et les threads traitant les erreurs soient exécutés dans le contexte de processus différents. Dans ce cas, ces threads peuvent appartenir à différents programmes, et le programme qui exécute les threads en erreur ne collaborera pas nécessairement avec le programme qui gère les erreurs de page. Dans ce mode non coopératif, le processus qui contrôle userfaultfd et gère les erreurs de page a besoin d'avoir connaissance des modifications dans la disposition de la mémoire virtuelle du processus en erreur pour éviter une corruption de mémoire.' .P Depuis Linux 4.11, userfaultfd peut aussi informer les threads gérant les erreurs des modifications dans la disposition de la mémoire virtuelle du processus en erreur. De plus, si le processus en erreur invoque \fBfork\fP(2), les objets userfaultfd associés au parent peuvent être dupliqués dans le processus enfant et le contrôleur d'userfaultfd sera informé (au moyen de \fBUFFD_EVENT_FORK\fP décrit plus bas) sur le descripteur de fichier associé aux objets userfault créés pour le processus enfant, ce qui permet au contrôleur d'userfaultfd de réaliser la pagination de l'espace utilisateur pour le processus enfant. À la différence des erreurs de page qui doivent être synchrones et réclament un réveil explicite ou explicite, tous les autres événements sont envoyés de façon asynchrone et le processus non coopératif reprend son exécution dès que le gestionnaire d'userfaultfd exécute \fBread\fP(2). Le gestionnaire d'userfaultfd doit soigneusement synchroniser les appels à \fBUFFDIO_COPY\fP avec le traitement des événements. .P .\" Regarding the preceding sentence, Mike Rapoport says: .\" The major point here is that current events delivery model could be .\" problematic for multi-threaded monitor. I even suspect that it would be .\" impossible to ensure synchronization between page faults and non-page .\" fault events in multi-threaded monitor. .\" .P .\" FIXME elaborate about non-cooperating mode, describe its limitations .\" for kernels before Linux 4.11, features added in Linux 4.11 .\" and limitations remaining in Linux 4.11 .\" Maybe it's worth adding a dedicated sub-section... .\" Le modèle asynchrone actuel d'envoi d'événement est optimal pour des implémentations de gestionnaire userfaultfd non coopératif à thread unique. .P .\" Depuis Linux 5.7, userfaultfd peut effectuer le suivi synchrone de page sale en utilisant le nouveau mode d'enregistrement de page protégée en écriture. Il faut vérifier le bit de fonction \fBUFFD_FEATURE_PAGEFAULT_FLAG_WP\fP avant d'utiliser cette fonctionnalité. Le mode protection en écriture, similaire au mode d'origine page manquante d'userfaultfd, génère une notification d'userfaultfd quand la page protégée en écriture est écrite. L'utilisateur doit résoudre l'erreur de page en déprotégeant la page fautive et en forçant le thread fautif à continuer. Pour plus d'informations, consultez la section «\ Mode protection d'écriture d'userfaultfd\ » .SS "Fonctionnement d'userfaultfd" After the userfaultfd object is created with \fBuserfaultfd\fP(), the application must enable it using the \fBUFFDIO_API\fP \fBioctl\fP(2) operation. This operation allows a two\-step handshake between the kernel and user space to determine what API version and features the kernel supports, and then to enable those features user space wants. This operation must be performed before any of the other \fBioctl\fP(2) operations described below (or those operations fail with the \fBEINVAL\fP error). .P After a successful \fBUFFDIO_API\fP operation, the application then registers memory address ranges using the \fBUFFDIO_REGISTER\fP \fBioctl\fP(2) operation. After successful completion of a \fBUFFDIO_REGISTER\fP operation, a page fault occurring in the requested memory range, and satisfying the mode defined at the registration time, will be forwarded by the kernel to the user\-space application. The application can then use various (e.g., \fBUFFDIO_COPY\fP, \fBUFFDIO_ZEROPAGE\fP, or \fBUFFDIO_CONTINUE\fP) \fBioctl\fP(2) operations to resolve the page fault. .P Depuis Linux 4.4, si l'application définit le bit de la fonction \fBUFFD_FEATURE_SIGBUS\fP en utilisant l'\fBioctl\fP(2) \fBUFFDIO_API\fP, aucune notification d'erreur d page ne sera transmise à l'espace utilisateur. Un signal est envoyé à la place au processus en erreur. Avec cette fonction, userfaultfd peut être utilisé à des fins de robustesse pour capturer simplement tout accès aux zones dans l'intervalle d'adresses enregistré qui n'ont pas de pages allouées sans avoir à écouter les événements d'userfaultfd. Aucun contrôleur d'userfaultfd ne sera requis pour traiter ce type d'accès mémoire. Par exemple, cette fonction peut être utile à des applications qui désirent empêcher le noyau d'allouer des pages automatiquement et de remplir des trous dans des fichiers creux quand c'est un mappage mémoire qui permet l'accès aux trous. .P La fonction \fBUFFD_FEATURE_SIGBUS\fP est héritée de façon implicite avec \fBfork\fP(2) si elle est utilisée en combinaison avec \fBUFFD_FEATURE_FORK\fP. .P Des détails sur les différentes opérations d'\fBioctl\fP(2) sont disponibles dans \fBioctl_userfaultfd\fP(2). .P Depuis Linux 4.11, les événements autres que les erreurs de page peuvent être activés pendant l'opération \fBUFFDIO_API\fP. .P .\" Jusqu'à Linux 4.11, userfaultfd ne peut être utilisé qu'avec des mappages de mémoire privée anonyme. Depuis Linux 4.11, userfaultfd peut aussi être utilisé avec des mappages de mémoire hugelbfs et partagée. .SS "Mode protection d'écriture d'userfaultfd (depuis Linux 5.7)" Depuis Linux 5.7, userfaultfd prend en charge le mode protection d'écriture pour la mémoire anonyme. L'utilisateur doit d'abord vérifier la disponibilité de cette fonctionnalité en utilisant l'ioctl \fBUFFDIO_API\fP sur le bit de fonction \fBUFFD_FEATURE_PAGEFAULT_FLAG_WP\fP avant d'utiliser cette fonctionnalité. .P Depuis Linux 5.19, le mode protection d'écriture est aussi pris en charge sur la mémoire de type shmem ou hugetlbfs. Il peut être détecté avec le bit de fonction \fBUFFD_FEATURE_WP_HUGETLBFS_SHMEM\fP. .P Pour enregistrer avec le mode page protégée en écriture de userfaultfd, l'utilisateur doit initier l'ioctl \fBUFFDIO_REGISTER\fP avec le mode \fBUFFDIO_REGISTER_MODE_WP\fP défini. Notez qu'il est permis de surveiller le même intervalle de mémoire avec plusieurs modes. Par exemple, un utilisateur peut effectuer \fBUFFDIO_REGISTER\fP avec le mode défini à \fBUFFDIO_REGISTER_MODE_MISSING | UFFDIO_REGISTER_MODE_WP\fP. Quand seul le mode \fBUFFDIO_REGISTER_MODE_WP\fP est enregistré, l'espace utilisateur ne recevra \fIaucune\fP notification quand une page manquante est écrite. À la place, l'espace utilisateur ne recevra une notification d'erreur de page protégée en écriture que quand une page existante et protégée en écriture est écrite. .P Après que l'ioctl \fBUFFDIO_REGISTER\fP s'est terminé avec le mode \fBUFFDIO_REGISTER_MODE_WP\fP défini, l'utilisateur peut protéger en écriture toute mémoire dans l'intervalle en utilisant l'ioctl \fBUFFDIO_WRITEPROTECT\fP où \fIuffdio_writeprotect.mode\fP devrait être défini à \fBUFFDIO_WRITEPROTECT_MODE_WP\fP. .P Quand un événement de protection en écriture survient, l'espace utilisateur recevra une notification d'erreur de page dont l'\fIuffd_msg.pagefault.flags\fP aura l'attribut \fBUFFD_PAGEFAULT_FLAG_WP\fP défini. Notez : dans la mesure où seulement les écritures peuvent déclencher ce genre d'erreur, les notifications de protection en écriture auront toujours le bit \fBUFFD_PAGEFAULT_FLAG_WRITE\fP défini en même temps que le bit \fBUFFD_PAGEFAULT_FLAG_WP\fP. .P .\" Pour résoudre une erreur de page de protection d'écriture, l'utilisateur doit initier un autre ioctl \fBUFFDIO_WRITEPROTECT\fP dont l'\fIuffd_msg.pagefault.flags\fP doit avoir l'attribut \fBUFFDIO_WRITEPROTECT_MODE_WP\fP effacé après la page ou l'intervalle fautif. .SS "Mode erreur mineure d'userfaultfd (depuis Linux 5.13)" Depuis Linux 5.13, userfaultfd prend en charge le mode erreur mineure. Dans ce mode, les messages d’erreur ne sont pas produits pour des erreurs majeures (où les pages étaient absentes), mais plutôt pour des erreurs mineures où une page existe dans le cache de page, mais où les entrées de la table de pages ne sont pas encore présentes. L'utilisateur doit d'abord vérifier la disponibilité de cette fonctionnalité en utilisant l'ioctl \fBUFFDIO_API\fP avec les bits de fonction appropriés avant d'utiliser cette fonctionnalité : \fBUFFD_FEATURE_MINOR_HUGETLBFS\fP depuis Linux 5.13 ou \fBUFFD_FEATURE_MINOR_SHMEM\fP depuis Linux 5.14. .P Pour enregistrer avec le mode erreur mineure d'userfaultfd, l'utilisateur doit initier l'ioctl \fBUFFDIO_REGISTER\fP avec le mode \fBUFFD_REGISTER_MODE_MINOR\fP défini. .P Quand une erreur mineure survient, l'espace utilisateur recevra une notification d'erreur de page dont l'\fIuffd_msg.pagefault.flags\fP aura l'attribut \fBUFFD_PAGEFAULT_FLAG_MINOR\fP défini. .P Pour résoudre une erreur de page mineure, le gestionnaire doit décider si le contenu de la page existante doit être modifiée d'abord, ou non. Si c'est le cas, cela doit être fait à son emplacement au moyen d'un second mappage non enregistré par userfaultfd vers la même page de sauvegarde (par exemple en mappant deux fois le fichier shmem ou hugetlbfs). Une fois que la page est considérée « à jour », l'erreur peut être résolue en initiant un ioctl \fBUFFDIO_CONTINUE\fP qui installe les entrées de la table de pages et (par défaut) réveille le ou les threads en erreur. .P .\" Le mode erreur mineure ne prend en charge que la mémoire s'appuyant sur hugetlbfs (depuis Linux 5.13) et sur shmem (depuis Linux 5.14). .SS "Lire à partir de la structure userfaultfd" Chaque \fBread\fP(2) à partir du descripteur de fichier userfaultfd renvoie une ou plusieurs structures \fIuffd_msg\fP, chacune d'elles décrit un événement d'erreur de page ou un événement requis pour l'utilisation non coopérative d'userfaultfd : .P .in +4n .EX struct uffd_msg { __u8 event; /* Type d'événement */ ... union { struct { __u64 flags; /* Attributs décrivant l'erreur */ __u64 address; /* Adresse fautive */ union { __u32 ptid; /* ID du thread de l'erreur */ } feat; } pagefault; \& struct { /* Depuis Linux 4.11 */ __u32 ufd; /* Descripteur de ficher d'userfault du processus enfant */ } fork; \& struct { /* Depuis Linux 4.11 */ __u64 from; /* Ancienne adresse de la zone remappée */ __u64 to; /* Nouvelle adresse de la zone remappée */ __u64 len; /* Taille originale du mappage */ } remap; \& struct { /* Depuis Linux 4.11 */ __u64 start; /* Adresse de début de la zone supprimée */ __u64 end; /* Adresse de fin de la zone supprimée */ } remove; ... } arg; \& /* Remplissage des champs omis */ } __packed; .EE .in .P Si plusieurs événements sont disponibles et si le tampon fourni est suffisamment grand, \fBread\fP(2) renvoie autant d'événements qu'il en tient dans le tampon fourni. Si le tampon fourni à \fBread\fP(2) est plus petit que la taille de la structure \fIuffd_msg\fP, \fBread\fP(2) échoue avec l'erreur \fBEINVAL\fP. .P Les champs définis dans la structure \fIuffd_msg\fP sont les suivants : .TP \fIevent\fP Le type d'événement. Selon le type d'événement, différents champs de l'union \fIarg\fP représentent les détails nécessaires au traitement de l'événement. Les événements qui ne sont pas des erreurs de page ne sont générés que quand la fonctionnalité appropriée est activée durant la connexion de l'API à l'\fBioctl\fP(2) \fBUFFDIO_API\fP. .IP Les valeurs suivantes peuvent apparaître dans le champ \fIevent\fP : .RS .TP \fBUFFD_EVENT_PAGEFAULT\fP (depuis Linux 4.3) Un événement d'erreur de page. Les détails de l'erreur de page sont disponibles dans le champ \fIpagefault\fP. .TP \fBUFFD_EVENT_FORK\fP (depuis Linux 4.11) .\" FIXME describe duplication of userfault file descriptor during fork Généré lorsque le processus en erreur invoque \fBfork\fP(2) (ou \fBclone\fP(2) sans l'attribut \fBCLONE_VM\fP). Les détails de l'événement sont disponibles dans le champ \fIfork\fP. .TP \fBUFFD_EVENT_REMAP\fP (depuis Linux 4.11) Généré lorsque le processus en erreur invoque \fBmremap\fP(2). Les détails de l'événement sont disponibles dans le champ \fIremap\fP. .TP \fBUFFD_EVENT_REMOVE\fP (depuis Linux 4.11) Généré lorsque le processus en erreur invoque \fBmadvise\fP(2) avec les conseils \fBMADV_DONTNEED\fP ou \fBMADV_REMOVE\fP. Les détails de l'événement sont disponibles dans le champ \fIremove\fP. .TP \fBUFFD_EVENT_UNMAP\fP (depuis Linux 4.11) Généré lorsque le processus en erreur supprime le mappage d'un intervalle de mémoire soit explicitement avec \fBmunmap\fP(2), soit implicitement durant l'exécution de \fBmmap\fP(2) ou \fBmremap\fP(2). Les détails de l'événement sont disponibles dans le champ \fIremove\fP. .RE .TP \fIpagefault.address\fP L'adresse qui a déclenché l'erreur de page. .TP \fIpagefault.flags\fP Un masque de bits qui décrit l'événement. Pour \fBUFFD_EVENT_PAGEFAULT\fP, les attributs suivants peuvent apparaître : .RS .TP \fBUFFD_PAGEFAULT_FLAG_WP\fP Si cet attribut est défini, alors l'erreur était une erreur de protection en écriture. .TP \fBUFFD_PAGEFAULT_FLAG_MINOR\fP Si cet attribut est défini, alors l'erreur était une erreur mineure. .TP \fBUFFD_PAGEFAULT_FLAG_WRITE\fP Si cet attribut est défini, alors l'erreur était une erreur d'écriture. .P Si ni \fBUFFD_PAGEFAULT_FLAG_WP\fP ni \fBUFFD_PAGEFAULT_FLAG_MINOR\fP ne sont définis, l'erreur était une erreur d'absence. .RE .TP \fIpagefault.feat.pid\fP L'identifiant du thread qui a déclenché l'erreur de page. .TP \fIfork.ufd\fP Le descripteur de fichier associé à l'objet userfault créé pour l'enfant créé par \fBfork\fP(2). .TP \fIremap.from\fP L'adresse d'origine de la plage de mémoire dont le mappage a été modifié en utilisant \fBmadvise\fP(2). .TP \fIremap.to\fP La nouvelle adresse de la plage de mémoire dont le mappage a été modifié en utilisant \fBmadvise\fP(2). .TP \fIremap.len\fP La taille d'origine de la plage de mémoire dont le mappage a été modifié en utilisant \fBmadvise\fP(2). .TP \fIremove.start\fP L'adresse de début de la plage de mémoire qui a été libérée en utilisant \fBmadvise\fP(2) ou dont le mappage a été supprimé. .TP \fIremove.end\fP L'adresse terminale de la plage de mémoire qui a été libérée en utilisant \fBmadvise\fP(2) ou dont le mappage a été supprimé. .P \fBread\fP(2) sur un descripteur de fichier userfaultfd peut échouer pour les raisons suivantes : .TP \fBEINVAL\fP L'objet userfaultfd n'a pas encore été activé avec l'opération d'\fBioctl\fP(2) \fBUFFDIO_API\fP. .P .\" FIXME What is the reason for this seemingly odd behavior with respect .\" to the O_NONBLOCK flag? (see userfaultfd_poll() in fs/userfaultfd.c). .\" Something needs to be said about this. Si l'attribut \fBO_NONBLOCK\fP est activé dans la description de fichier ouvert associée, le descripteur de fichier userfaultfd peut être surveillé avec \fBpoll\fP(2), \fBselect\fP(2) et \fBepoll\fP(7). Quand les événements sont disponibles, le descripteur de fichier l'indique comme lisible. Si l'attribut \fBO_NONBLOCK\fP n'est pas activé, alors \fBpoll\fP(2) indique (toujours) que le fichier comme ayant une condition \fBPOLLERR\fP et \fBselect\fP(2) indique que le descripteur de fichier est à la fois accessible en lecture et en écriture. .SH "VALEUR RENVOYÉE" En cas de succès, \fBuserfaultfd\fP() renvoie un nouveau descripteur de fichier qui fait référence à l'objet userfaultfd. En cas d'erreur, la fonction renvoie \fB\-1\fP et \fIerrno\fP est défini pour indiquer l'erreur. .SH ERREURS .TP \fBEINVAL\fP Une valeur non prise en compte a été spécifiée dans \fIflags\fP. .TP \fBEMFILE\fP La limite par processus du nombre de descripteurs de fichier ouverts a été atteinte. .TP \fBENFILE\fP La limite du nombre total de fichiers ouverts pour le système entier a été atteinte. .TP \fBENOMEM\fP La mémoire disponible du noyau n'était pas suffisante. .TP \fBEPERM\fP (depuis Linux 5.2) .\" cefdca0a86be517bc390fc4541e3674b8e7803b0 L'appelant n'est pas privilégié (il n'a pas la capacité \fBCAP_SYS_PTRACE\fP dans l'espace de noms initial) et \fI/proc/sys/vm/unprivileged_userfaultfd\fP a la valeur \fB0\fP. .SH STANDARDS Linux. .SH HISTORIQUE Linux 4.3. .P La prise en charge des zones de mémoire hugetlbfs et partagée et des événements qui ne sont pas des erreurs de page a été ajoutée dans Linux 4.11 .SH NOTES Le mécanisme d'userfaultfd peut être utilisé comme une alternative aux techniques traditionnelles de pagination de l'espace utilisateur basées sur l'utilisation du signal \fBSIGSEGV\fP et de \fBmmap\fP(2). Il peut aussi être utilisé pour implémenter la restauration en mode paresseux (« lazy restore ») pour les mécanismes de la fonctionnalité de gel des applications (checkpoint/restore), aussi bien que la migration après copie pour permettre une exécution (presque) ininterrompue lors du transfert de machines virtuelles et de conteneurs Linux d'un hôte à un autre. .SH BOGUES Si \fBUFFD_FEATURE_EVENT_FORK\fP est activé et si un appel système issu de la famille de \fBfork\fP(2) est interrompu par un signal ou échoue, un descripteur périmé d'userfaultfd peut être créé. Dans ce cas, un faux \fBUFFD_EVENT_FORK\fP sera fourni au surveillant d'userfaultfd. .SH EXEMPLES Le programme ci\-dessous démontre l'utilisation du mécanisme userfaultfd. Le programme crée deux threads, un qui agit comme gestionnaire d'erreur de page pour le processus, pour les pages dans une région sans demande de page en utilisant \fBmmap\fP(2). .P Le programme prend un argument en ligne de commande, qui est le nombre de pages qui seront créées dans un mappage dont les erreurs de pages seront gérées au moyen d'userfaultfd. Après la création d'un objet userfaultfd, le programme crée alors un mappage privé anonyme de la taille spécifiée et enregistre l'intervalle d'adresses de ce mappage en utilisant l'opération d'\fBioctl\fP(2) \fBUFFDIO_REGISTER\fP. Le programme crée alors un second thread qui exécutera la tâche de gestion des erreurs de page. .P Le thread principal parcourt les pages du mappage à la recherche des octets des pages successives. Comme il n'y a pas eu encore d'accès aux pages, le premier accès à un octet de chaque page déclenchera un événement d'erreur de page sur le descripteur de fichier userfaultfd. .P Chaque événement d'erreur de page est géré par le second thread qui s'installe dans une boucle traitant l'entrée du descripteur de fichier userfaultfd. À chaque itération de la boucle, le second thread appelle \fBpoll\fP(2) pour vérifier l'état du descripteur de fichier puis lit un événement à partir de ce descripteur de fichier. Tout ce type d'événements doit être un événement \fBUFFD_EVENT_PAGEFAULT\fP que le thread traite en copiant un page de données dans la région en erreur en utilisant l'opération d'\fBioctl\fP(2) \fBUFFDIO_COPY\fP. .P La suite est un exemple de ce qui est observé lors de l'exécution du programme : .P .in +4n .EX $ \fB./userfaultfd_demo 3\fP Address returned by mmap() = 0x7fd30106c000 \& fault_handler_thread(): poll() returns: nready = 1; POLLIN = 1; POLLERR = 0 UFFD_EVENT_PAGEFAULT event: flags = 0; address = 7fd30106c00f (uffdio_copy.copy returned 4096) Read address 0x7fd30106c00f in main(): A Read address 0x7fd30106c40f in main(): A Read address 0x7fd30106c80f in main(): A Read address 0x7fd30106cc0f in main(): A \& fault_handler_thread(): poll() returns: nready = 1; POLLIN = 1; POLLERR = 0 UFFD_EVENT_PAGEFAULT event: flags = 0; address = 7fd30106d00f (uffdio_copy.copy returned 4096) Read address 0x7fd30106d00f in main(): B Read address 0x7fd30106d40f in main(): B Read address 0x7fd30106d80f in main(): B Read address 0x7fd30106dc0f in main(): B \& fault_handler_thread(): poll() returns: nready = 1; POLLIN = 1; POLLERR = 0 UFFD_EVENT_PAGEFAULT event: flags = 0; address = 7fd30106e00f (uffdio_copy.copy returned 4096) Read address 0x7fd30106e00f in main(): C Read address 0x7fd30106e40f in main(): C Read address 0x7fd30106e80f in main(): C Read address 0x7fd30106ec0f in main(): C .EE .in .SS "Source du programme" .\" SRC BEGIN (userfaultfd.c) \& .EX /* userfaultfd_demo.c \& Licensed under the GNU General Public License version 2 or later. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include \& static int page_size; \& static void * fault_handler_thread(void *arg) { int nready; long uffd; /* userfaultfd file descriptor */ ssize_t nread; struct pollfd pollfd; struct uffdio_copy uffdio_copy; \& static int fault_cnt = 0; /* Number of faults so far handled */ static char *page = NULL; static struct uffd_msg msg; /* Data read from userfaultfd */ \& uffd = (long) arg; \& /* Create a page that will be copied into the faulting region. */ \& if (page == NULL) { page = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, \-1, 0); if (page == MAP_FAILED) err(EXIT_FAILURE, "mmap"); } \& /* Loop, handling incoming events on the userfaultfd file descriptor. */ \& for (;;) { \& /* See what poll() tells us about the userfaultfd. */ \& pollfd.fd = uffd; pollfd.events = POLLIN; nready = poll(&pollfd, 1, \-1); if (nready == \-1) err(EXIT_FAILURE, "poll"); \& printf("\enfault_handler_thread():\en"); printf(" poll() returns: nready = %d; " "POLLIN = %d; POLLERR = %d\en", nready, (pollfd.revents & POLLIN) != 0, (pollfd.revents & POLLERR) != 0); \& /* Read an event from the userfaultfd. */ \& nread = read(uffd, &msg, sizeof(msg)); if (nread == 0) { printf("EOF on userfaultfd!\en"); exit(EXIT_FAILURE); } \& if (nread == \-1) err(EXIT_FAILURE, "read"); \& /* We expect only one kind of event; verify that assumption. */ \& if (msg.event != UFFD_EVENT_PAGEFAULT) { fprintf(stderr, "Unexpected event on userfaultfd\en"); exit(EXIT_FAILURE); } \& /* Display info about the page\-fault event. */ \& printf(" UFFD_EVENT_PAGEFAULT event: "); printf("flags = %"PRIx64"; ", msg.arg.pagefault.flags); printf("address = %"PRIx64"\en", msg.arg.pagefault.address); \& /* Copy the page pointed to by \[aq]page\[aq] into the faulting region. Vary the contents that are copied in, so that it is more obvious that each fault is handled separately. */ \& memset(page, \[aq]A\[aq] + fault_cnt % 20, page_size); fault_cnt++; \& uffdio_copy.src = (unsigned long) page; \& /* We need to handle page faults in units of pages(!). So, round faulting address down to page boundary. */ \& uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address & \[ti](page_size \- 1); uffdio_copy.len = page_size; uffdio_copy.mode = 0; uffdio_copy.copy = 0; if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) == \-1) err(EXIT_FAILURE, "ioctl\-UFFDIO_COPY"); \& printf(" (uffdio_copy.copy returned %"PRId64")\en", uffdio_copy.copy); } } \& int main(int argc, char *argv[]) { int s; char c; char *addr; /* Start of region handled by userfaultfd */ long uffd; /* userfaultfd file descriptor */ size_t len, l; /* Length of region handled by userfaultfd */ pthread_t thr; /* ID of thread that handles page faults */ struct uffdio_api uffdio_api; struct uffdio_register uffdio_register; \& if (argc != 2) { fprintf(stderr, "Usage: %s num\-pages\en", argv[0]); exit(EXIT_FAILURE); } \& page_size = sysconf(_SC_PAGE_SIZE); len = strtoull(argv[1], NULL, 0) * page_size; \& /* Create and enable userfaultfd object. */ \& uffd = syscall(SYS_userfaultfd, O_CLOEXEC | O_NONBLOCK); if (uffd == \-1) err(EXIT_FAILURE, "userfaultfd"); \& /* NOTE: Two\-step feature handshake is not needed here, since this example doesn't require any specific features. \& Programs that *do* should call UFFDIO_API twice: once with `features = 0` to detect features supported by this kernel, and again with the subset of features the program actually wants to enable. */ uffdio_api.api = UFFD_API; uffdio_api.features = 0; if (ioctl(uffd, UFFDIO_API, &uffdio_api) == \-1) err(EXIT_FAILURE, "ioctl\-UFFDIO_API"); \& /* Create a private anonymous mapping. The memory will be demand\-zero paged\-\-that is, not yet allocated. When we actually touch the memory, it will be allocated via the userfaultfd. */ \& addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, \-1, 0); if (addr == MAP_FAILED) err(EXIT_FAILURE, "mmap"); \& printf("Address returned by mmap() = %p\en", addr); \& /* Register the memory range of the mapping we just created for handling by the userfaultfd object. In mode, we request to track missing pages (i.e., pages that have not yet been faulted in). */ \& 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) err(EXIT_FAILURE, "ioctl\-UFFDIO_REGISTER"); \& /* Create a thread that will process the userfaultfd events. */ \& s = pthread_create(&thr, NULL, fault_handler_thread, (void *) uffd); if (s != 0) { errc(EXIT_FAILURE, s, "pthread_create"); } \& /* Main thread now touches memory in the mapping, touching locations 1024 bytes apart. This will trigger userfaultfd events for all pages in the region. */ \& l = 0xf; /* Ensure that faulting address is not on a page boundary, in order to test that we correctly handle that case in fault_handling_thread(). */ while (l < len) { c = addr[l]; printf("Read address %p in %s(): ", addr + l, __func__); printf("%c\en", c); l += 1024; usleep(100000); /* Slow things down a little */ } \& exit(EXIT_SUCCESS); } .EE .\" SRC END .SH "VOIR AUSSI" \fBfcntl\fP(2), \fBioctl\fP(2), \fBioctl_userfaultfd\fP(2), \fBmadvise\fP(2), \fBmmap\fP(2) .P \fIDocumentation/admin\-guide/mm/userfaultfd.rst\fP dans l'arborescence des sources du noyau Linux .PP .SH TRADUCTION La traduction française de cette page de manuel a été créée par Christophe Blaess , Stéphan Rafin , Thierry Vignaud , François Micaux, Alain Portal , Jean-Philippe Guérard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas François , Florentin Duneau , Simon Paillard , Denis Barbier , David Prévot et Jean-Pierre Giraud . .PP Cette traduction est une documentation libre ; veuillez vous reporter à la .UR https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License version 3 .UE concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE. .PP Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à .MT debian-l10n-french@lists.debian.org .ME .