mremap - Modifier une projection de la mémoire virtuelle
Bibliothèque C standard (
libc,
-lc)
#define _GNU_SOURCE /* Consultez feature_test_macros(7) */
#include <sys/mman.h>
void *mremap(void old_address[.old_size], size_t old_size,
size_t new_size, int flags, ... /* void *new_address */);
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).
old_address est l'ancienne adresse du bloc de mémoire virtuelle
à agrandir (ou à diminuer). Veuillez noter que
old_address doit être alignée sur une frontière de
page.
old_size est l'ancienne taille du bloc de mémoire
virtuelle.
new_size est la taille désirée pour le nouveau
bloc de mémoire. Un cinquième argument,
new_address, peut
éventuellement être fourni ; voyez la description de
MREMAP_FIXED ci-dessous.
Si la valeur de
old_size est de zéro et si
old_address
renvoie à une projection partageable (voir
MAP_SHARED de
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é.
-
MREMAP_DONTUNMAP (depuis Linux 5.7)
- Cet attribut, qui doit être utilisé avec
MREMAP_MAYMOVE, refait une projection vers une nouvelle adresse
mais il ne supprime pas celle à old_address.
- L'attribut MREMAP_DONTUNMAP ne peut être
utilisé qu'avec des projections privées anonymes (voir la
description de MAP_PRIVATE et de MAP_ANONYMOUS dans
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.
Si le segment de mémoire indiqué par
old_address et
old_size est verrouillé (par
mlock(2) ou similaire), ce
verrou est maintenu quand le segment est modifié et/ou
déplacé. Par conséquent, la quantité de
mémoire verrouillée par le processus peut changer.
mremap() renvoie un pointeur sur la nouvelle zone de mémoire
virtuelle s'il réussit. En cas d'échec, la valeur
MAP_FAILED (c'est-à-dire
(void *) -1) est
renvoyée et
errno est défini pour indiquer l'erreur.
- 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
- Une adresse dans l'intervalle entre old_address et
old_address+old_size n'est pas une adresse virtuelle valable
pour ce processus. On peut également obtenir EFAULT
même s'il existe des projections recouvrant la zone complète
demandée, mais que ces projections sont de types
différents.
- 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.
Cet appel système est spécifique à Linux et ne devrait pas
être employé dans des programmes destinés à
être portables.
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.
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.
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.
Avant Linux 4.14, si
old_size valait zéro et si la
projection à laquelle renvoyait
old_address était une
projection privée (
MAP_PRIVATE de
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.
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)
La traduction française de cette page de manuel a été
créée par Christophe Blaess
<
https://www.blaess.fr/christophe/>, Stéphan Rafin
<
[email protected]>, Thierry Vignaud
<
[email protected]>, François Micaux, Alain Portal
<
[email protected]>, Jean-Philippe Guérard
<
[email protected]>, Jean-Luc Coulon (f5ibh)
<
[email protected]>, Julien Cristau
<
[email protected]>, Thomas Huriaux <
[email protected]>,
Nicolas François <
[email protected]>, Florentin
Duneau <
[email protected]>, Simon Paillard
<
[email protected]>, Denis Barbier
<
[email protected]>, David Prévot <
[email protected]> et
Jean-Philippe MENGUAL <
[email protected]>
Cette traduction est une documentation libre ; veuillez vous reporter
à la
GNU
General Public License version 3 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 à
[email protected]