mremap(2)

NOM
mremap - Modifier une projection de la mémoire virtuelle

BIBLIOTHÈQUE
Bibliothèque C standard (libc, -lc)

SYNOPSIS
#define _GNU_SOURCE         /* Consultez feature_test_macros(7) */
#include <sys/mman.h>

void *mremap(size_t old_size;
             void old_address[old_size], size_t old_size,
             size_t new_size, int flags, ...  /* void *new_address */);

DESCRIPTION
mremap() agrandit (ou diminue) une projection (Ndt : mapping) de mémoire virtuelle en mémoire réelle, en la déplaçant éventuellement (sous contrôle de l'argument flags et de la place disponible dans l'espace d'adressage virtuel).

Mappings can also simply be moved (without any resizing) by specifying equal old_size and new_size and using the MREMAP_FIXED flag (see below). Since Linux 6.17, while old_address must be mapped, old_size may span multiple mappings including unmapped areas between them when performing a simple move. The MREMAP_DONTUNMAP flag may also be specified.

Similarly, if the operation performs a shrink, that is, if old_size is greater than new_size, then old_size may also span multiple mappings, which do not have to be adjacent to one another. If this shrink is performed in-place, that is, neither MREMAP_FIXED, nor MREMAP_DONTUNMAP are specified, new_size may also span multiple VMAs. However, if the range is moved, then new_size must span only a single mapping.

If the operation is neither a MREMAP_FIXED move nor a shrink, then old_size must span only a single mapping.

old_address is the old address of the first virtual memory block that you want to expand, shrink, and/or move. Note that old_address has to be page aligned. old_size is the size of the range containing virtual memory blocks to be manipulated. new_size is the requested size of the virtual memory blocks after the resize. An optional fifth argument, new_address, may be provided; see the description of MREMAP_FIXED below.

Si la valeur de old_size est de zéro et si old_address renvoie à une projection partageable (voir la description de MAP_SHARED dans mmap(2)), mremap() créera une nouvelle projection des mêmes pages. new_size sera la taille de la nouvelle projection et l'emplacement de la nouvelle projection peut être indiqué avec new_address ; voir la description de MREMAP_FIXED ci-dessous. Si une nouvelle projection est demandée à l'aide de cette méthode, l'attribut MREMAP_MAYMOVE doit être indiqué également.

L'argument de masquage flags est soit 0, soit un des attributs suivants :

MREMAP_MAYMOVE
    Par défaut, s'il n'y a pas suffisamment d'espace pour agrandir une projection à son emplacement actuel, mremap() échoue. Si ce drapeau est utilisé, le noyau est autorisé à déplacer la projection à une autre adresse virtuelle si nécessaire. Si la projection est déplacée, les pointeurs absolus vers l'ancienne projection deviennent caduques (il faut utiliser des décalages par rapport à l'adresse de début de la projection).

MREMAP_FIXED (depuis Linux 2.3.31)
    Ce drapeau a un but similaire à MAP_FIXED pour mmap(2). S'il est utilisé, mremap() prend un cinquième argument void *new_address qui contient une adresse alignée sur un début de page vers laquelle la projection doit être déplacée. Toute projection existant précédemment dans la zone entre new_address et new_size est supprimée.

    Si MREMAP_FIXED est indiqué, MREMAP_MAYMOVE doit également être indiqué.

    Since Linux 6.17, if old_size is equal to new_size and MREMAP_FIXED is specified, then old_size may span beyond the mapping in which old_address resides. In this case, gaps between mappings in the original range are maintained in the new range. The whole operation is performed atomically unless an error arises, in which case the operation may be partially completed, that is, some mappings may be moved and others not.

    Moving multiple mappings is not permitted if any of those mappings have either been registered with userfaultfd(2), or map drivers that specify their own custom address mapping logic.

MREMAP_DONTUNMAP (depuis Linux 5.7)
    This flag, which must be used in conjunction with MREMAP_MAYMOVE, remaps mappings to a new address but does not unmap them from their original address.

    The MREMAP_DONTUNMAP flag can be used only with mappings that are not VM_DONTEXPAND or VM_PFNMAP. Before Linux 5.13, the MREMAP_DONTUNMAP flag could be used only with private anonymous mappings (see the description of MAP_PRIVATE and MAP_ANONYMOUS in mmap(2)).

    À la fin, tous les accès à la plage indiquée par old_address et old_size donneront une erreur de pagination. Elle sera gérée par un gestionnaire userfaultfd(2) si l'adresse se situe dans une plage précédemment enregistrée avec userfaultfd(2). Sinon, le noyau alloue une page remplie de zéros pour gérer cette erreur.

    L'attribut MREMAP_DONTUNMAP peut être utilisé pour déplacer de manière atomique une projection tout en laissant la source associée. Voir les NOTES pour des applications possibles de MREMAP_DONTUNMAP.

If the memory segments specified by old_address and old_size are locked (using mlock(2) or similar), then this lock is maintained when the segments are resized and/or relocated. As a consequence, the amount of memory locked by the process may change.

VALEUR RENVOYÉE
On success mremap() returns a pointer to the new virtual memory area. On error, the value MAP_FAILED (that is, (void *) -1) is returned, and errno is set to indicate the error.

ERREURS

EAGAIN
    L'appelant a tenté d'agrandir un segment de mémoire verrouillé, mais c'est impossible sans dépasser la limite RLIMIT_MEMLOCK.

EFAULT
    Some address in the range old_address to old_address+old_size is an invalid virtual memory address for this process. You can also get EFAULT even if there exist mappings that cover the whole address space requested, but those mappings are of different types, and the mremap() operation being performed does not support this.

EINVAL
    Un paramètre non valable a été donné. Parmi les causes possibles :

    -   old_address n'était pas aligné sur une page ;

    -   une autre valeur que MREMAP_MAYMOVE, MREMAP_FIXED ou MREMAP_DONTUNMAP a été indiquée dans flags ;

    -   new_size était zéro ;

    -   new_size ou new_address n'était pas valable ;

    -   la nouvelle plage d'adresses indiquée par new_address et new_size chevauche l'ancienne plage d'adresses indiquée par old_address et old_size ;

    -   MREMAP_FIXED ou MREMAP_DONTUNMAP était indiqué sans MREMAP_MAYMOVE ;

    -   MREMAP_DONTUNMAP était indiqué mais une ou plusieurs pages de la plage indiquée par old_address et old_size n'étaient pas privées et anonymes ;

    -   MREMAP_DONTUNMAP était indiqué et old_size n'était pas égal à new_size ;

    -   old_size était de zéro et old_address ne renvoie pas à une projection partageable (mais voir BOGUES) ;

    -   old_size valait zéro et l'attribut MREMAP_MAYMOVE n'était pas indiqué.

ENOMEM
    Pas assez de mémoire disponible pour terminer l'opération. Les causes possibles sont :

    -   La zone de mémoire ne peut pas être agrandie à l'emplacement virtuel actuel, et l'option MREMAP_MAYMOVE n'a pas été fournie dans flags. Ou encore, il n'y a plus assez de mémoire (virtuelle) disponible.

    -   MREMAP_DONTUNMAP a été utilisé, provoquant la création d'une nouvelle projection qui dépasserait la mémoire (virtuelle) disponible. Ou alors elle excéderait le nombre maximal de projections autorisées.

NORMES
Linux.

HISTORIQUE
Avant la glibc 2.4, glibc ne fournissait pas la définition de MREMAP_FIXED et le prototype de mremap() ne permettait pas de passer le paramètre new_address.

NOTES
mremap() modifie la correspondance entre les adresses virtuelles et les pages de mémoire. Ce mécanisme peut être utilisé pour implémenter un realloc(3) très efficace.

Sous Linux, la mémoire est divisée en pages. Un processus utilisateur dispose d'un ou plusieurs segments linéaires de mémoire virtuelle. À chaque segment correspond une ou plusieurs projections dans les pages de mémoire réelle (dans la table des pages). Chaque segment de mémoire virtuelle dispose de ses propres droits d'accès (sa protection), ce qui peut déclencher des fautes de segmentation (SIGSEGV) si l'accès à la mémoire est mal géré (par exemple, en écrivant dans un segment en lecture seule). De même, une tentative d'accès à la mémoire en dehors des segments déclenche une faute de segmentation.

Si mremap() est utilisé pour déplacer ou étendre une zone verrouillée avec mlock(2) ou équivalent, l'appel mremap() fera le maximum pour remplir la nouvelle zone mais il n'échouera pas avec ENOMEM si la zone ne peut pas être remplie.

  Cas d'utilisation de MREMAP_DONTUNMAP
Parmi les applications possibles de MREMAP_DONTUNMAP :

-   userfaultfd(2) non coopératif : une application peut retirer une plage d'adresses virtuelles en utilisant MREMAP_DONTUNMAP, puis utiliser un gestionnaire userfaultfd(2) pour gérer les erreurs de pagination qui arrivent ensuite lorsque d'autres threads du processus créent des pages dans la plage retirée.

-   Récupérateur de mémoire : MREMAP_DONTUNMAP peut être utilisé avec userfaultfd(2) pour implémenter des algorithmes de ramasse-miettes (garbage collection) (par exemple, dans une machine virtuelle Java). Une telle implémentation peut être moins coûteuse (et plus simple) que les techniques de collecte traditionnelles qui impliquent de marquer des pages avec une protection PROT_NONE ainsi que l'utilisation d'un gestionnaire SIGSEGV pour capter les accès à ces pages.

BOGUES
Avant Linux 4.14, si old_size valait zéro et si la projection à laquelle renvoyait old_address était une projection privée (voir la description de MAP_PRIVATE dans mmap(2)), mremap() créait une nouvelle projection privée sans lien avec celle d'origine. Ce comportement était intentionnel et probablement non prévu dans des applications de l'espace utilisateur (l'intention de mremap() étant de créer une nouvelle projection à partir de celle d'origine). Depuis Linux 4.14, mremap() échoue avec l'erreur EINVAL dans ce scénario.

VOIR AUSSI
brk(2), getpagesize(2), getrlimit(2), mlock(2), mmap(2), sbrk(2), malloc(3), realloc(3)

Votre manuel favori à propos de systèmes d'exploitation, pour des informations supplémentaires sur la mémoire paginée (par exemple Modern Operating Systems de Andrew S. Tanenbaum, Inside Linux par Randolf Bentson, The Design of the UNIX Operating System par Maurice J. Bach)

TRADUCTION
La traduction française de cette page de manuel a été créée par Christophe Blaess <https://www.blaess.fr/christophe/>, Stéphan Rafin <stephan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org>, David Prévot <david@tilapin.org> et Jean-Philippe MENGUAL <jpmengual@debian.org>

Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 (https://www.gnu.org/licenses/gpl-3.0.html) concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.

Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à debian-l10n-french@lists.debian.org.