mlock, mlock2, munlock, mlockall, munlockall - Speicher (ent)sperren
Standard-C-Bibliothek (
libc,
-lc)
#include <sys/mman.h>
int mlock(const void Adresse[.len], size_t Länge);
int mlock2(const void Addresse[.len], size_t Länge, unsigned int Schalter);
int munlock(const void Adresse[.len], size_t Länge);
int mlockall(int Schalter);
int munlockall(void);
mlock(),
mlock2() und
mlockall() sperrt den gesamten oder
einen Teil des virtuellen Adressraums des aufrufenden Prozesses im RAM und
verhindern, dass der Speicherinhalt in den Auslagerungsbereich ausgelagert
wird.
munlock() und
munlockall() führen die umgekehrte Aktion
durch, d.h. entsperren den gesamten oder einen Teil des virtuellen Adressraums
des aufrufenden Prozesses, sodass die Seiten im angegebenen virtuellen
Adressbereich wieder ausgelagert werden können, wenn das von der
Kernel-Speicherverwaltung verlangt wird.
(Ent)sperren des Speichers wird für ganze Speicherseiten
durchgeführt.
mlock() sperrt Seiten im Adressbereich, der bei
adr beginnt und
sich über
Länge Byte erstreckt. Alle Seiten, die einen
Teil des angegebenen Adressbereichs enthalten, verbleiben nach einem
erfolgreichen Aufruf garantiert im RAM; die Seiten bleiben garantiert im RAM,
bis sie wieder entsperrt werden.
mlock2() sperrt auch Seiten im Adressbereich, der bei
adr beginnt
und sich über
Länge Byte erstreckt. Der Status der
Seiten, die in dem angegebenen Adressbereichs nach einem erfolgreichen Aufruf
enthalten sind, hängt vom Wert des
Schalter-Arguments ab.
Das Argument
Schalter kann entweder 0 oder die folgende Konstante sein:
- MLOCK_ONFAULT
- Sperrt Seiten, die derzeit im Speicher sind, und markiert
den gesamten Bereich, so dass die verbleibenden, nicht im Speicher
befindlichen Seiten gesperrt sind, wenn Sie durch eine
Seitenausnahmebehandlung befüllt werden.
Wenn
flags 0 ist, verhält sich
mlock2() genau so wie
mlock().
munlock() entsperrt Seiten im Adressbereich, der mit
adr beginnt
und sich über
Länge Byte erstreckt. Nach diesem Aufruf
können alle Seiten, die einen Teil des angegebenen Speicherbereichs
umfassen, erneut vom Kernel in externen Auslagerungsspeicher ausgelagert
werden.
mlockall() sperrt alle Seiten, die in den Adressraum des aufrufenden
Prozesses gemappt sind. Dieses bezieht sich auf die Seiten von Code-, Daten-
und Stacksegment genauso wie auf dynamische Bibliotheken, Kernel-Daten im
Anwendungsraum, Gemeinsamen Speicher und in den Speicher gemappte Dateien. Es
wird garantiert, dass alle gemappten Speicherseiten im RAM sind, wenn der
Aufruf von
mlockall() erfolgreich beendet wird. Es wird darüber
hinaus garantiert, dass die Seiten solange im RAM bleiben, bis sie wieder
entsperrt werden.
Das Argument
Schalter wird mittels logischem bitweisem ODER aus einer
oder mehreren der folgenden Konstanten konstruiert:
- MCL_CURRENT
- sperrt alle Seiten, die momentan in den Adressraum des
Prozesses gemappt sind.
- MCL_FUTURE
- sperrt alle Seiten, die in Zukunft in den Adressraum des
Prozesses gemappt werden. Das könnten zum Beispiel neue
Adress-Seiten sein, die bei einem sich vergrößernden Heap
und Stack benötigt werden, Dateien, die in den Speicher gemappt
werden, oder gemeinsam benutzte Speicherbereiche.
-
MCL_ONFAULT (seit Linux 4.4)
- Wird zusammen mit MCL_CURRENT, MCL_FUTURE
oder beiden verwandt. Markiert alle aktuellen (mit MCL_CURRENT)
oder zukünftigen (mit MCL_FUTURE) Mappings, dass sie Seiten
sperren, wenn diese durch Ausnahmebehandlungen hereingekommen sind. Bei
der Verwendung mit MCL_CURRENT, werden alle vorhandenen Seiten
gesperrt, aber mlockall() wird keine nicht vorhandenen Seiten durch
Ausnahmebehandlungen hereinbringen. Bei der Verwendung mit
MCL_FUTURE werden alle zukünftigen Mappings markiert, dass
sie Seiten sperren, wenn diese durch Ausnahmebehandlungen hereinkommen,
sie werden aber durch die Sperre nicht befüllt, wenn das Mapping
erstellt wird. MCL_ONFAULT muss entweder mit MCL_CURRENT,
MCL_FUTURE oder beiden verwandt werden.
Falls
MCL_FUTURE angegeben wurde, kann ein späterer Systemaufruf
(z. B.
mmap(2),
sbrk(2),
malloc(3)) fehlschlagen,
wenn durch ihn die Zahl gesperrter Bytes das zulässige Maximum
überschreiten würde (siehe unten). Unter den gleichen
Voraussetzungen kann eine Vergrößerung des Stacks ebenfalls
fehlschlagen: der Kernel wird die Stack-Vergrößerung verweigern
und dem Prozess ein
SIGSEGV-Signal schicken.
munlockall() entsperrt alle in den Addressraum des aufrufenden Prozesses
gemappten Seiten.
Bei Erfolg geben diese Systemaufrufe 0 zurück. Bei einem Fehler wird -1
zurückgegeben,
errno gesetzt, um den Fehler anzuzeigen und keine
Änderungen an den Sperren im Adressraum des Prozesses
durchgeführt.
- EAGAIN
- (mlock(), mlock2() und munlock()) Ein
Teil des angegebenen Adressbereichs oder der gesamte Adressbereich konnten
nicht gesperrt werden.
- EINVAL
- (mlock(), mlock2() und munlock()) Das
Ergebnis der Addition adr+Länge war kleiner als
adr (z. B. kann die Addition einen Überlauf
verursacht haben).
- EINVAL
- (mlock2()) Es wurden unbekannte Schalter
angegeben.
- EINVAL
- (mlockall()) Es wurden entweder unbekannte
Schalter angegeben oder MCL_ONFAULT wurde weder mit
MCL_FUTURE noch mit MCL_CURRENT angegeben.
- EINVAL
- (Nicht unter Linux) addr war kein Vielfaches der
Seitengröße.
- ENOMEM
- (mlock(), mlock2() und munlock()) Ein
Teil des angegebenen Adressbereichs entspricht nicht Seiten, die in den
Adressraum des Prozesses gemappt sind.
- ENOMEM
- (mlock(), mlock2() und munlock())
Sperren oder Entsperren eines Bereiches würde dazu führen,
dass die Gesamtanzahl der Mappings mit eindeutigen Attributen (z.B.
gesperrt oder nicht gesperrt) das erlaubte Maximum überschreiten
würde. (Beispielsweise würde das Entsperren eines Bereichs
in der Mitte eines derzeit gesperrten Bereichs zu drei Mappings
führen: zwei gesperrte Mappings an jedem Ende und ein entsperrtes
Mapping in der Mitte.)
- ENOMEM
- (Linux 2.6.9 und neuer) Der Aufrufende hatte eine weiche
Ressourcenbegrenzung RLIMIT_MEMLOCK ungleich null, versuchte aber
über diese Grenze hinaus Speicher zu sperren. Diese Grenze wird
nicht erzwungen, wenn der Prozess privilegiert ist (
CAP_IPC_LOCK).
- ENOMEM
- (Linux 2.4 und älter) Der aufrufende Prozess
versuchte, mehr als die Hälfte des RAMs zu sperren.
- EPERM
- Der Aufrufende ist nicht privilegiert, benötigt aber
zur Durchführung der angeforderten Aktionen Privilegien (
CAP_IPC_LOCK).
- EPERM
- (munlockall()) (Linux 2.6.8 und älter) Der
Aufrufende war nicht privilegiert ( CAP_IPC_LOCK).
mlock2() ist seit Linux 4.4 verfügbar. Glibc-Unterstützung
wurde in Version 2.27 hinzugefügt.
mlock(),
munlock(),
mlockall() und
munlockall():
POSIX.1-2001, POSIX.1-2008, SVr4.
mlock2() ist Linux-spezifisch.
Auf POSIX-Systemen, auf denen
mlock() und
munlock()
verfügbar sind, ist
_POSIX_MEMLOCK_RANGE in
<unistd.h> definiert und die Anzahl der Bytes pro Seite kann der
Konstante
PAGESIZE (wenn sie definiert ist) in
<limits.h>
entnommen werden oder durch einen Aufruf von
sysconf(_SC_PAGESIZE)
bestimmt werden.
Auf POSIX-Systemen, auf denen
mlockall() und
munlockall()
verfügbar sind, ist
_POSIX_MEMLOCK in <unistd.h> als ein
Wert größer als 0 definiert. (Siehe auch
sysconf(3).)
Das Sperren von Speicher hat zwei Hauptanwendungen: Echtzeitalgorithmen und
Hochsicherheits-Datenverarbeitung. Echtzeitanwendungen erfordern
deterministisches Timing, und, wie auch Scheduling, ist Paging einer der
Hauptgründe für unerwartete Verzögerungen in der
Programmausführung. Echtzeitanwendungen werden außerdem
für gewöhnlich mit
sched_setscheduler(2) auf einen
Echtzeit-Scheduler umschalten. Kryptographische Sicherheitssoftware stellt oft
sicherheitskritische Bytes wie Passwörter oder geheime Schlüssel
als Datenstrukturen dar. Durch Paging könnten diese geheimen Daten auf
ein permanentes Auslagerungsspeichermedium übertragen werden, von wo
aus sie auch dann noch Dritten zugänglich sein können, lange
nachdem das Programm die geheimen Daten aus dem RAM gelöscht und sich
beendet hat. (Bedenken Sie bitte, dass der Suspend-Modus von Laptops und
manchen Desktop-Rechnern, unabhängig von Speichersperren, eine Kopie
des RAMs auf der Platte speichern wird.)
Echtzeitprozesse, die mittels
mlockall() Verzögerungen durch
Seitenausnahmebehandlungen vermeiden, sollten ausreichend gesperrte
Stackseiten reservieren, bevor sie in die zeitkritische Phase treten, sodass
durch einen Funktionsaufruf keine Seitenausnahmebehandlung entstehen kann.
Dies kann durch den Aufruf einer Funktion erreicht werden, die eine
ausreichend große automatische Variable (ein Feld) erzeugt und in den
Speicher schreibt, in dem die Variable liegt, um diese Stackseiten zu belegen.
Auf diesem Wege werden genug Seiten für den Stack gemappt und
können im RAM gesperrt werden. Der Schreibvorgang stellt sicher, dass
nicht einmal ein Schreib-Kopier-Seitenausnahmebehandlung in der kritischen
Phase eintreten kann.
Speichersperren werden nicht an mittels
fork(2) erzeugte Kindprozesse
vererbt und durch einen Aufruf von
execve(2) oder das Ende des
Prozesses automatisch entfernt (entsperrt). Die Einstellungen
MCL_FUTURE und
MCL_FUTURE | MCL_ONFAULT in
mlockall()
werden nicht von einem Kindprozess ererbt, der mittels
fork(2) erzeugt
wurde und werden während eines
execve(2) gelöscht.
Beachten Sie, dass
fork(2) den Adressraum für eine
Kopieren-beim-Schreiben-Aktion vorbereiten wird. Die Konsequenz ist, dass
nachfolgende Schreibaktionen zu einer Seitenausnahmebehandlung führen
werden, die wiederum hohe Latenzen für Echtzeitprozesse hervorrufen.
Daher ist es essenziell,
fork(2) nicht nach einer
mlockall()-
oder
mlock()-Aktion auszuführen - selbst nicht aus einem Thread,
der bei niedriger Priorität innerhalb eines Prozesses läuft, der
wiederum einen Thread hat, der mit erhöhter Priorität
läuft.
Die Speichersperrung wird automatisch entfernt, wenn der Adressbereich mittels
munmap(2) entmappt wird.
Speichersperren werden nicht hochgezählt (»gestapelt«), das
heißt, Seiten die mehrmals durch den Aufruf von
mlockall(),
mlock2() oder
mlock() gesperrt wurden werden durch einen
einzigen Aufruf von
munlock() für den entsprechenden Bereich
oder durch
munlockall() sofort wieder freigegeben. Seiten, die an
verschiedene Orte oder für verschiedene Prozesse gemappt wurden,
bleiben solange im RAM gesperrt, wie sie mindestens an einem Ort oder durch
einen Prozess gesperrt sind.
Wenn einem Aufruf von
mlockall(), der den Schalter
MCL_FUTURE
nutzt, ein weiterer Aufruf folgt, der diesen Schalter nicht angibt, gehen die
durch den Aufruf von
MCL_FUTURE erwirkten Änderungen verloren.
Der Schalter
MLOCK_ONFAULT von
mlock2() und der Schalter
MCL_ONFAULT von
mlockall() erlaubt effizientes Speicher-Sperren
für Anwendungen, die mit großen Mappings umgehen, bei denen nur
ein (kleiner) Anteil von Seiten im Mapping berührt werden. In diesen
Fällen würde das Sperren aller Seiten in dem Mapping eine
erhebliche Einbuße für das Speicher-Sperren verursachen.
Unter Linux runden
mlock(),
mlock2() und
munlock()
adr automatisch zur nächsten Seitengrenze ab. Da aber die
POSIX.1-Spezifikation von
mlock() und
munlock()
Implementierungen gestattet, welche die Ausrichtung von
adr an
Seitengrenzen fordern, sollten portable Anwendungen die Ausrichtung
sicherstellen.
Das Feld
VmLck der Linux-spezifischen Datei
/proc/[PID]/status
gibt an, wie viele Kilobyte Speicher der Prozess mit der Kennung
PID
mittels
mlock(),
mlock2(),
mlockall() und
mmap(2)
mit dem Schalter
MAP_LOCKED gesperrt hat.
Bis einschließlich Linux 2.6.8 muss ein Prozess privilegiert sein (
CAP_IPC_LOCK), um Speicher zu sperren. Die weiche Systembegrenzung
RLIMIT_MEMLOCK bestimmt einen Speicher-Schwellwert, den der Prozess
sperren darf.
Seit Linux 2.6.9 kann ein privilegierter Prozess unbegrenzt Speicher sperren.
Die weiche Systembegrenzung
RLIMIT_MEMLOCK legt stattdessen fest,
wieviel Speicher ein nicht privilegierter Prozess sperren darf.
In Linux 4.8 und älter bedeutete ein Fehler in der Bilanzierung des
Kernels für gesperrten Speicher von unprivilegierten Prozessen (d.h.
solchen ohne
CAP_IPC_LOCK), das die gesperrten Bytes, die einer
überlappenden (falls vorhanden) und durch
adr und
Länge festgelegte Region liegen, beim Prüfen gegen die
Begrenzung doppelt zählten. Solche Doppelbilanzierung konnte zu einem
inkorrekten Wert für den »total locked memory« für
den Prozess, der die Begrenzung
RLIMIT_MEMLOCK überschritt,
führen. Damit konnten dann
mlock() und
mlock2()
fehlschlagen, obwohl die Anfragen hätten erfolgreich sein sollen.
Dieser Fehler wurde in Linux 4.9 behoben.
In Linux 2.4.x bis einschließlich 2.4.17 bewirkte ein Fehler, dass der
Schalter
MCL_FUTURE von
mlockall() über einen Aufruf von
fork(2) vererbt wurde. Dies wurde in Linux 2.4.18 behoben.
Seit Linux 2.6.9 werden, falls ein privilegierter Prozess
mlockall(MCL_FUTURE) aufruft und anschließend Privilegien
aufgibt (die Capability
CAP_IPC_LOCK verliert, weil er beispielsweise
seine effektive UID auf einen von null verschiedenen Wert setzt), nachfolgende
Speicherzuordnungen (z.B.
mmap(2),
brk(2)) fehlschlagen, wenn
die Ressourcengrenze
RLIMIT_MEMLOCK angetroffen wird.
mincore(2),
mmap(2),
setrlimit(2),
shmctl(2),
sysconf(3),
proc(5),
capabilities(7)
Die deutsche Übersetzung dieser Handbuchseite wurde von Hanno Wagner
<
[email protected]>, Martin Schulze
<
[email protected]>, Michaela Hohenner
<
[email protected]>, Martin Eberhard Schauer
<
[email protected]>, Mario Blättermann
<
[email protected]> und Helge Kreutzmann
<
[email protected]> erstellt.
Diese Übersetzung ist Freie Dokumentation; lesen Sie die
GNU
General Public License Version 3 oder neuer bezüglich der
Copyright-Bedingungen. Es wird KEINE HAFTUNG übernommen.
Wenn Sie Fehler in der Übersetzung dieser Handbuchseite finden, schicken
Sie bitte eine E-Mail an die
Mailingliste
der Übersetzer