fcntl(2) | System Calls Manual | fcntl(2) |
fcntl - Dateideskriptoren manipulieren
Standard-C-Bibliothek (libc, -lc)
#include <fcntl.h>
int fcntl(int dd, int Bef, … /* arg */ );
fcntl() führt eine der unten beschriebenen Aktionen auf dem offenen Dateideskriptor dd aus. Die Aktion wird durch Bef festgelegt.
fcntl() kann ein optionales drittes Argument akzeptieren. Ob dieses Argument notwendig ist, ergibt sich durch Bef. Der benötigte Argumenttyp wird nach jedem Bef-Namen in Klammern angedeutet (in den meisten Fällen ist der benötigte Typ int und der Argumenttyp wird mit dem Namen arg identifiziert). Falls das Argument nicht notwendig ist, wird void angegeben.
Bestimmte der unten aufgeführten Aktionen werden nur seit einer bestimmten Linux-Kernelversion unterstützt. Die bevorzugte Methode, um herauszufinden, ob der Gastkernel eine bestimmte Aktion unterstützt, ist der Aufruf von fcntl() mit dem gewünschten Wert von Bef und dem anschließenden Test, ob der Aufruf mit EINVAL fehlschlug, wodurch angezeigt wird, dass der Kernel diesen Wert nicht unterstützt.
Die folgenden Befehle verändern die einem Dateideskriptor zugeordneten Schalter. Derzeit ist nur ein solcher Schalter definiert: FD_CLOEXEC, der »close-on-exec«-Schalter. Falls das FD_CLOEXEC-Bit gesetzt ist, wird der Dateideskriptor automatisch bei einem erfolgreichen execve(2) geschlossen. (Falls der execve(2) fehlschlägt, bleibt der Dateideskriptor offen.) Falls das Bit FD_CLOEXEC nicht gesetzt ist, wird der Dateideskriptor über ein execve(2) hinweg offen bleiben.
In Programmen mit mehreren Threads ist die Verwendung von fcntl() F_SETFD, um den Schalter »close-on-exec« zum gleichen Zeitpunkt zu setzen, zu dem ein anderer Thread ein fork(2) mit einem execve(2) ausführt, anfällig für einen Ressourcenwettlauf, der unbeabsichtigterweise den Dateideskriptor an das Programm, das im Kindprozess läuft, durchsickern lässt. Siehe die Diskussion des Schalters O_CLOEXEC in open(2) für Details und wie dem Problem abgeholfen werden kann.
Jede offene Dateideskription hat bestimmte zugeordnete Statusschalter, die durch open(2) initialisiert und möglicherweise durch fcntl() verändert werden. Duplizierte Dateideskriptoren (mit dup(2), fcntl(F_DUPFD), fork(2) usw. erstellte) beziehen sich auf die gleiche offene Dateideskription und teilen sich daher die gleichen Dateistatusschalter.
Die Dateistatusschalter und deren Bedeutung sind in open(2) beschrieben.
Linux implementiert traditionelle (»Prozess-orientierte«) UNIX-Datensatz-Sperren, wie durch POSIX standardisiert. Für eine Linux-spezifische Alternative mit besserer Semantik lesen Sie die Diskussion über offene Dateideskriptions-Sperren unten.
F_SETLK, F_SETLKW und F_GETLK werden dazu verwandt, Datensatzsperren (auch bekannt als Byte-Bereichs-, Dateisegment- oder Dateiregionsperren) zu erlangen, abzugeben oder auf deren Existenz zu prüfen. Das dritte Argument, lock, ist ein Zeiger auf eine Struktur, die mindestens die folgende Felder (in einer nicht festgelegten Reihenfolge) enthält:
struct flock { … short l_type; /* Art der Sperre: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* Wie l_start interpretiert wird: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* Anfangsversatz für Sperre */ off_t l_len; /* Anzahl von zu sperrenden Bytes */ pid_t l_pid; /* PID des Prozesses, der unsere Sperre blockiert (gesetzt durch F_GETLK und F_OFD_GETLK) */ … };
Die Felder l_whence, l_start und l_len dieser Struktur legen den Bereich der Bytes, die gesperrt werden sollen, fest. Bytes hinter dem Ende der Datei können gesperrt sein, aber Bytes vor dem Anfang der Datei sind es nicht.
l_start ist der Startversatz für die Sperre und wird relativ zu einem der folgenden interpretiert: Dem Anfang der Datei (falls l_whence SEEK_SET ist), dem aktuellen Dateiversatz (falls l_whence SEEK_CUR ist) oder dem Ende der Datei (falls l_whence SEEK_END ist). In den abschließenden zwei Fällen kann l_start eine negative Zahl sein, vorausgesetzt, der Versatz liegt nicht vor dem Anfang der Datei.
l_len legt die Anzahl der zu sperrenden Bytes fest. Falls l_len positiv ist, wird der zu sperrende Bereich die Bytes l_start bis einschließlich l_start+l_len-1 umfassen. Die Angabe von 0 für l_len hat eine besondere Bedeutung: Alle Bytes beginnend bei l_whence und l_start bis zum Ende der Datei sperren, unabhängig davon, wie groß die Datei anwächst.
POSIX.1-2001 erlaubt (verlangt es aber nicht), dass eine Implementierung einen negativen Wert für l_len unterstützt. Falls l_len negativ ist, deckt das durch lock beschriebene Intervall die Bytes l_start+l_len bis zu einschließlich l_start-1 ab. Dies wird durch Linux seit 2.4.21 und 2.5.49 unterstützt.
Das Feld l_type kann dazu verwandt werden, eine Lese- (F_RDLCK) oder Schreibsperre (F_WRLCK) auf eine Datei zu setzen. Eine beliebige Anzahl an Prozessen kann eine Lesesperre auf eine Dateiregion halten (gemeinsame Sperre), aber nur ein Prozess kann eine Schreibsperre (exklusive Sperre) halten. Eine exklusive Sperre sperrt alle anderen Sperren aus, sowohl exklusive als auch gemeinsame. Ein einzelner Prozess kann nur eine Art von Sperre auf eine Dateiregion halten. Falls eine neue Sperre auf eine bereits gesperrte Region angewandt wird, wird die existierende Sperre in den Typ der neuen Sperre umgewandelt. (Solche Umwandlungen können das Teilen, Verkleinern, Vereinigen mit bestehenden Sperren beinhalten, falls der durch die neue Sperre festgelegte Byte-Bereiche nicht genau mit dem Bereich der bereits existierenden Sperre zusammenfällt.)
Um eine Lesesperre zu setzen, muss dd zum Lesen offen sein. Um eine Schreibsperre zu setzen, muss dd zum Schreiben offen sein. Um beide Typen setzen zu können, öffnen Sie eine Datei lese- und schreibbar.
Wenn Sperren mit F_SETLKW gesetzt werden, erkennt der Kernel Verklemmungen, bei denen zwei oder mehr Prozesse ihre Sperr-Anfragen gegenseitig durch Sperren, die von anderen Prozessen gehalten werden, blockieren. Nehmen Sie beispielsweise an, Prozess A hält eine Schreibsperre auf Byte 100 einer Datei und Prozess B hält eine Schreibsperre auf Byte 200. Falls jeder Prozess dann versucht, mit F_SETLKW die vom anderen Prozess bereits gesperrten Bytes zu sperren, würden ohne Erkennung von Verklemmungen beide Prozesse unbegrenzt blockiert bleiben. Wenn der Kernel solche Verklemmungen erkennt, sorgt er dafür, dass eine der blockierenden Sperranfragen sofort mit dem Fehler EDEADLK fehlschlägt. Eine Anwendung, die auf einen solchen Fehler trifft, sollte einige ihrer Sperren freigeben, um anderen Anwendungen das Fortfahren zu erlauben, bevor sie erneut versucht, die von ihr benötigten Sperren zu erlangen. Zirkuläre Verklemmungen mit mehr als zwei Prozessen werden auch erkannt. Beachten Sie aber, dass es eine Begrenzung der Erkennung von Verklemmungen im Kernel gibt; siehe FEHLER.
Datensatzsperren werden durch ein explizites F_UNLCK entfernt und auch freigegeben, wenn der Prozess sich beendet.
Datensatzsperren werden nicht von einem durch fork(2) erstellten Kind geerbt, aber über ein execve(2) hinweg erhalten.
Aufgrund des durch die stdio(3)-Bibliothek durchgeführten Pufferns sollte die Verwendung von Datensatzsperren mit Routinen aus diesem Paket vermieden werden; verwenden Sie stattdessen read(2) und write(2).
Die weiter oben beschriebenen Datensatzsperren werden dem Prozess zugeordnet (anders als die weiter unten beschriebenen Dateideskriptionssperren). Dies hat einige unglückliche Konsequenzen:
Offene Dateideskriptionssperren lösen beide Probleme.
Offene Dateideskriptionsperren sind empfohlene Byte-Bereichssperren, deren Funktionsweise in den meisten Aspekten den herkömmlichen, oben beschriebenen Datensatzsperren entspricht. Dieser Sperrtyp ist Linux-spezifisch und seit Linux 3.15 verfügbar. (Es gibt einen Vorschlag der Austin-Gruppe, diesen Sperrtyp in die nächste Überarbeitung von POSIX.1 aufzunehmen.) Eine Erklärung offener Dateideskriptionen finden Sie in open(2).
Der Hauptunterschied zwischen den beiden Sperrtypen besteht darin, dass die herkömmlichen Datensatzsperren mit einem Prozess verbunden sind, während Sperren offener Dateideskriptionen mit der offenen Dateideskription verbunden sind, für die sie erlangt wurden, ähnlich wie Sperren, die mit flock(2) erlangt wurden. Konsequenterweise (und anders als herkömmliche empfohlene Datensatzsperren) werden Sperren offener Dateideskriptionen über fork(2) (und clone(2) mit CLONE_FILES) geerbt und werden nur automatisch durch das Schließen der letzten offenen Dateideskription freigegeben, statt bei jedem Schließen der Datei.
Im Konflikt stehende Kombinationen von Sperren (d.h. eine Lese-Sperre und eine Schreib-Sperre oder zwei Schreib-Sperren), wobei eine Sperre eine offene Dateideskriptionssperre und die andere eine traditionelle Datensatzsperre ist, sind selbst dann im Konflikt, wenn sie vom gleichen Prozess auf dem gleichen Dateideskriptor aufgenommen wurden.
Offene Dateideskriptionssperren, die über die gleichen offenen Dateideskriptionen (d.h. über den gleichen Dateideskriptor oder über durch fork(2), dup(2), fcntl() F_DUPFD und so weiter erstellte Duplikate des Dateideskriptors) gesetzt werden, sind immer kompatibel: Falls auf einen bereits gesperrten Bereich eine neue Sperre gesetzt wird, wird die existierende Sperre in den neuen Sperrtyp umgewandelt. (Solche Umwandlungen können wie oben beschrieben zum Teilen, Verkleinern oder Verschmelzen mit einer existierenden Sperre führen.)
Auf der anderen Seite können offene Dateideskriptionssperren zueinander im Konflikt stehen, wenn sie über verschiedene offene Dateideskriptionen erlangt wurden. Daher können die Threads in einem Programm mit mehreren Threads offene Dateideskriptionssperren dazu verwenden, um den Zugriff auf Dateiregionen zu koordinieren, indem jeder Thread sein eigenes open(2) auf der Datei durchführt und die Sperren über den entstehenden Dateideskriptor anwendet.
Wie bei herkömmlichen empfohlenen Sperren ist das dritte Argument für fcntl(), lock, ein Zeiger auf eine flock-Struktur. Im Gegensatz zu herkömmlichen Datensatzsperren muss das Feld l_pid dieser Struktur bei Verwendung der unterhalb beschriebenen Befehle auf Null gesetzt werden.
Die Befehle für den Umgang mit offenen Dateideskriptionssperren sind analog zu denen, die mit traditionellen Sperren verwandt werden:
In der aktuellen Implementierung wird nicht auf Verklemmungen für offene Dateideskriptionssperren geprüft. (Dies steht im Gegensatz zu den prozessorientierten Datensatzsperren, bei denen der Kernel eine Erkennung von Verklemmungen durchführt.)
Warnung: Die Linux-Implementierung der Pflichtsperren ist unzuverlässig. Siehe FEHLER unten. Aufgrund dieser Fehler und der Tatsache, dass davon ausgegangen wird, dass diese Funktionalität wenig genutzt wird, sind die Pflichtsperren seit Linux 4.5 eine optionale Funktionalität, die durch eine Konfigurationsoption (CONFIG_MANDATORY_FILE_LOCKING) gesteuert werden. In Linux 5.15 und neuer wird diese Funktionalität nicht mehr unterstützt.
Standardmäßig sind herkömmliche (prozessorientierte) und Sperren offener Dateideskriptionsdatensätze empfohlene Sperren. Empfohlene Sperren werden nicht erzwungen und sind nur bei der Zusammenarbeit von Prozessen nützlich.
Beide Sperrtypen können auch verpflichtend sein. Verpflichtende Sperren werden für alle Prozesse durchgesetzt. Falls ein Prozess einen inkompatiblen Zugriff auf einen Dateibereich versucht (z.B. read(2) oder write(2)), der eine inkompatible verpflichtende Sperre hat, dann hängt das Ergebnis davon ab, ob der Schalter O_NONBLOCK für seine offene Dateideskription aktiviert ist. Falls der Schalter O_NONBLOCK nicht aktiviert ist, wird der Systemaufruf blockiert, bis die Sperre entfernt oder in einen Modus umgewandelt wurde, der mit dem Zugriff kompatibel ist. Falls der Schalter O_NONBLOCK aktiviert ist, wird der Systemaufruf mit dem Fehler EAGAIN fehlschlagen.
Um verpflichtende Sperren zu verwenden, müssen verpflichtende Sperren sowohl auf dem Dateisystem, das die zu sperrende Datei enthält, aktiviert werden als auch auf der Datei selbst. Verpflichtende Sperren werden auf Dateisystemen mit der Option »-o mand« von mount(8) oder dem Schalter MS_MANDLOCK für mount(2) aktiviert. Verpflichtende Sperren werden für eine Datei aktiviert, indem das Ausführrecht für die Datei entfernt und das »set-group-ID«-Rechte-Bit aktiviert wird (siehe chmod(1) und chmod(2)).
Verpflichtende Sperren werden nicht durch POSIX spezifiziert. Einige andere Systeme unterstützen auch verpflichtende Sperren, allerdings unterscheiden sich die Details zur Aktivierung zwischen den Systemen.
Wenn eine empfohlene Sperre auf einem Netzwerkdateisystem wie NFS erlangt wird, ist es möglich, dass die Sperre verloren geht. Die kann aufgrund administrativer Aktionen auf dem Server oder aufgrund einer Netzwerkeinteilung (d.h. einem Verlust der Netzverbindung mit dem Server) passieren, die so lange dauert, dass der Server annimmt, dass der Client nicht mehr funktioniert.
Wenn das Dateisystem ermittelt, dass eine Sperre verloren gegangen ist, können zukünftige read(2)- oder write(2)-Anfragen mit dem Fehler EIO fehlschlagen. Dieser Fehler wird beibehalten, bis die Sperre entfernt oder der Dateideskriptor geschlossen wird. Seit Linux 3.12 passiert dies zumindest auf NFSv4 (einschließlich aller Unterversionen).
Einige UNIX-Versionen senden in diesen Fällen ein Signal (SIGLOST). Linux definiert dieses Signal nicht und stellt keine asynchrone Benachrichtigung über verlorene Sperren bereit.
F_GETOWN, F_SETOWN, F_GETOWN_EX, F_SETOWN_EX, F_GETSIG und F_SETSIG werden zur Verwaltung der E/A-Verfügbarkeitssignale verwandt:
struct f_owner_ex { int type; pid_t pid; };
Mittels dieser Mechanismen kann ein Programm eine komplett asynchrone E/A implementieren, ohne (in den meisten Fällen) select(2) oder poll(2) zu verwenden.
Die Verwendung von O_ASYNC ist für BSD und Linux spezifisch. Die einzige in POSIX.1 spezifizierte Verwendung von F_GETOWN and F_SETOWN ist im Zusammenhang mit der Verwendung des Signals SIGURG bei Sockets. (POSIX spezifiziert das Signal SIGIO nicht). POSIX enthält asynchrone E/A und auch die Struktur aio_sigevent, um ähnliche Dinge zu erreichen; diese sind unter Linux auch als Teil der GNU-C-Bibliothek (Glibc) verfügbar.
F_SETLEASE und F_GETLEASE (Linux 2.4 und neuer) werden dazu verwandt, für die offene Dateideskription, auf den der Dateideskriptor dd verweist, eine Ausleihe (»lease«) zu etablieren und die aktuelle Ausleihe zu ermitteln. Ein Datei-Ausleihe stellt einen Mechanismus bereit, durch den ein Prozess, der die Ausleihe hält (der »Ausleiher«) über die Auslieferung eines Signals benachrichtigt wird, wenn ein Prozess (der »Ausleihe-Brecher«) versucht, die von diesem Dateideskriptor referenzierte Datei mit open(2) zu öffen oder mit truncate(2) zu verkleinern/vergrößern.
Ausleihen sind einem offenen Dateideskriptor zugeordnet (siehe open(2)). Das bedeutet, dass ein duplizierter Dateideskriptor (zum Beispiel durch fork(2) oder dup(2) erstellt) sich auf die gleiche Ausleihe bezieht und dass diese Ausleihe durch jeden dieser Deskriptoren verändert oder freigegeben werden kann. Desweiteren werden Ausleihen durch eine explizite Aktion F_UNLCK auf einem dieser duplizierten Dateideskriptoren freigegeben oder wenn alle solchen Dateideskriptoren geschlossen wurden.
Ausleihen dürfen nur für reguläre Dateien herausgenommen werden. Ein nicht privilegierter Prozess darf eine Ausleihe nur für Dateien herausnehmen, deren UID (Eigentümer) auf die Dateisystem-UID des Prozesses passt. Ein Prozess mit der Capability CAP_LEASE darf Ausleihen für beliebige Dateien herausnehmen.
Wenn ein Prozess (der »Ausleihe-Brecher«) ein open(2) oder truncate(2) durchführt, der mit einer mittels F_SETLEASE etablierten Ausleihe in Konflikt steht, wird der Systemaufruf durch den Kernel blockiert und der Kernel informiert den Ausleihenden, indem er ihm ein Signal (standardmäßig SIGIO) sendet. Der Ausleihende sollte reagieren, indem er alle notwendigen Aufräumarbeiten durchführt, um den Zugriff des anderen Prozesses auf die Datei vorzubereiten (z.B. das Rausschreiben von zwischengespeicherten Puffern). Danach sollte er entweder seine Ausleihe entfernen oder runterstufen. Eine Ausleihe wird durch Ausführung des Befehls F_SETLEASE mit der Angabe von arg als F_UNLCK entfernt. Falls der Ausleihende derzeit eine Schreib-Ausleihe auf die Datei hält und der Ausleih-Brecher die Datei zum Lesen öffnet, dann reicht es aus, wenn der Ausleihende seine Ausleihe auf eine Lese-Ausleihe herunterstuft. Dies erfolgt durch Ausführung des Befehls F_SETLEASE mit der Angabe von arg als F_RDLCK.
Falls der Ausleihende nicht innerhalb der in /proc/sys/fs/lease-break-time festgelegten Anzahl von Sekunden seine Ausleihe herunterstuft oder entfernt, entfernt der Kernel die Ausleihe des Ausleihenden zwangsweise oder stuft sie zwangsweise herunter.
Sobald ein Ausleih-Brechen eingeleitet wurde, liefert F_GETLEASE den Ziel-Ausleihtyp (entweder F_RDLCK oder F_UNLCK, abhängig davon, was zum Ausleih-Brecher kompatibel wäre) zurück, bis der Ausleihende freiwillig seine Ausleihe herunterstuft oder entfernt oder der Kernel dies zwangsweise tut, nachdem der Ausleih-Brech-Timer abgelaufen ist.
Sobald die Ausleihe freiwillig oder zwangsweise entfernt oder heruntergestuft wurde und unter der Annahme, dass der Ausleih-Brecher nicht den Systemaufruf entblockiert hat, erlaubt der Kernel dem Systemaufruf des Ausleih-Brechers fortzufahren.
Falls das vom Ausleih-Brecher blockierte open(2) oder truncate(2) durch einen Signal-Handler unterbrochen wird, schlägt der Systemaufruf mit dem Fehler EINTR fehl, aber die anderen Schritte erfolgen dennoch wie oben beschrieben. Falls der Ausleih-Brecher durch ein Signal getötet wird, während er in open(2) oder truncate(2) blockiert ist, erfolgen die anderen Schritte dennoch wie oben beschrieben. Falls der Ausleih-Brecher den Schalter O_NONBLOCK beim Aufruf von open(2) angegeben hat, schlägt der Aufruf sofort mit dem Fehler EWOULDBLOCK fehl, aber die anderen Schritte erfolgen dennoch wie oben beschrieben.
Standardmäßig wird das Signal SIGIO zur Information des Ausleihenden verwandt, dies kann aber mit dem Befehl F_SETSIG von fcntl() geändert werden. Falls ein Befehl F_SETSIG ausgeführt wird (selbst einer, der SIGIO festlegt) und der Singal-Handler mittels SA_SIGINFO etabliert wurde, dann wird der Handler eine Struktur siginfo_t als sein zweites Argument erhalten und das Feld si_fd dieses Argumentes wird den Dateideskriptor der Datei mit der Ausleihe, auf die ein anderer Prozess zugegriffen hat, enthalten. (Dies ist nützlich, falls der Aufrufende Ausleihen für mehrere Dateien hält.)
Dateisiegel begrenzen die Menge der erlaubten Aktionen für eine bestimmte Datei. Für jedes auf eine Datei angebrachte Siegel wird von jetzt an eine bestimmte Gruppe an Aktionen auf dieser Datei mit dem Fehler EPERM fehlschlagen. Die Datei wird als versiegelt bezeichnet. Die Vorgabemenge der Siegel hängt von der Art der unterliegenden Datei und dem Dateisystem ab. Für einen Überblick über Dateiversiegelung, einer Diskussion ihres Zwecks und Code-Beispiele siehe memfd_create(2).
Derzeit können Dateisiegel nur auf durch memfd_create(2) zurückgelieferte Dateideskriptoren angewandt werden (falls MFD_ALLOW_SEALING eingesetzt wurde). Auf anderen Dateisystemen werden alle fcntl()-Aktionen zur Versiegelung EINVAL zurückliefern.
Siegel sind eine Eigenschaft eines Inodes. Daher verfügen alle offenen Dateideskriptoren, die auf den gleichen Inode verweisen, über die gleiche Gruppe an Siegeln. Desweiteren können Siegel nie entfernt, nur hinzugefügt werden.
Die folgenden Versiegelungen sind verfügbar:
Der Kernel kann mit Schreib-Lebenszeithinweisen über die erwartete relative Lebenszeit von Schreibaktionen an einer benannten Inode oder über eine bestimmte offene Dateideskription informiert werden (Siehe open(2) für eine Erläuterung von offenen Dateideskriptoren.). In diesem Kontext bedeutet der Ausdruck »Schreib-Lebenszeit«, die erwartete Zeit, die die Daten auf dem Medium verbleiben, bevor sie überschrieben oder gelöscht werden.
Eine Anwendung darf die unten angegebenen verschiedenen Hinweisewerte verwenden, um die Schreibaktionen in verschiedene Schreibklassen zu trennen, so dass mehrere Benutzer oder Anwendungen, die mit dem gleichen Speicher-Backend arbeiten, ihre E/A-Muster in einer konsistenten Art zusammenfassen können. Allerdings implizieren diese Schalter keine funktionalen Semantiken und verschiedene E/A-Klassen können die Schreib-Lebenszeithinweise in beliebigen Arten benutzen, so lange die Hinweise konsistent benutzt werden.
Die folgenden Aktionen können auf den Dateideskriptor dd angewandt werden:
Falls einer offenen Dateideskription noch kein Lese-/Schreibhinweis zugeordnet wurde, dann soll der der Inode zugeordnete Wert verwandt werden, falls vorhanden.
Die folgenden Lese-/Schreibhinweise sind seit Linux 4.13 gültig:
Alle schreibspezifischen Hinweise sind relativ zueinander und ihnen sollte keine individuelle absolute Bedeutung beigemessen werden.
Für einen erfolgreichen Aufruf hängt der Rückgabewert von der Aktion ab:
Bei einem Fehler wird -1 zurückgegeben und errno wird gesetzt, um den Fehler anzuzeigen.
SVr4, 4.3BSD, POSIX.1-2001. Nur die Aktionen F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK, F_SETLK und F_SETLKW sind in POSIX.1-2001 spezifiziert.
F_GETOWN und F_SETOWN sind in POSIX.1-2001 spezifiziert. (Um Ihre Definitionen zu erhalten, definieren Sie entweder _XOPEN_SOURCE mit einem Wert größer oder gleich 500 oder definieren Sie _POSIX_C_SOURCE mit einem Wert größer oder gleich 200809L.)
F_DUPFD_CLOEXEC ist in POSIX.1-2001 spezifiziert. (Um diese Definitionen zu erhalten, definieren Sie _POSIX_C_SOURCE mit einem Wert größer oder gleich 200809L oder _XOPEN_SOURCE mit einem Wert größer oder gleich 700.)
F_GETOWN_EX, F_SETOWN_EX, F_SETPIPE_SZ, F_GETPIPE_SZ, F_GETSIG, F_SETSIG, F_NOTIFY, F_GETLEASE und F_SETLEASE sind Linux-spezifisch. (Definieren Sie das Makro _GNU_SOURCE, um diese Definitionen zu erhalten.)
F_OFD_SETLK, F_OFD_SETLKW und F_OFD_GETLK sind Linux-spezifisch (und _GNU_SOURCE muss definiert werden, um ihre Definitionen zu erhalten). Es wird aber daran gearbeitet, dass sie in der nächsten Version von POSIX.1 enthalten sind.
F_ADD_SEALS und F_GET_SEALS sind Linux-spezifisch.
Die Fehler, die von dup2(2) zurückgegeben werden, sind anders als die von F_DUPFD.
Der ursprüngliche Systemaufruf fcntl() von Linux war nicht dafür konstruiert, große Dateiversätze (in der Struktur flock) zu handhaben. Konsequenterweise wurde ein Systemaufruf fcntl64() in Linux 2.4 hinzugefügt. Dieser neuere Systemaufruf setzt eine andere Struktur zum Sperren von Dateien ein, flock64, und entsprechende Befehle F_GETLK64, F_SETLK64 und F_SETLKW64. Diese Details können allerdings von Anwendungen, die Glibc einsetzen, ignoriert werden, da dessen Wrapperfunktion fcntl() transparent den neueren Systemaufruf einsetzt, wo er verfügbar ist.
Seit Linux 2.0 gibt es keine Wechselwirkung zwischen den durch flock(2) und fcntl() gesetzten Sperrtypen.
Bei einer Reihe von Systemen gibt es in struct flock weitere Felder wie z.B. l_sysid (zur Identifizierung der Maschine, auf der die Sperre gehalten wird). Es ist klar, dass l_pid alleine nicht sehr nützlich ist, falls der Prozess, der die Sperre hält, auf einer anderen Maschine existiert. Unter Linux wird dieses Feld, auch wenn es auf einigen Architekturen (wie MIPS32) vorhanden ist, nicht verwandt.
Der ursprüngliche Systemaufruf fcntl() von Linux war nicht dafür konstruiert, große Dateiversätze (in der Struktur flock) zu handhaben. Konsequenterweise wurde ein Systemaufruf fcntl64() in Linux 2.4 hinzugefügt. Dieser neuere Systemaufruf setzt eine andere Struktur zum Sperren von Dateien ein, flock64, und entsprechende Befehle F_GETLK64, F_SETLK64 und F_SETLKW64. Diese Details können allerdings von Anwendungen, die Glibc einsetzen, ignoriert werden, da dessen Wrapperfunktion fcntl() transparent den neueren Systemaufruf einsetzt, wo er verfügbar ist.
Falls ein NFSv4-Client vor Linux 3.12 den Kontakt mit dem Server für eine bestimmte Zeitperiode (definiert als mehr als 90 Sekunden ohne Kommunikation) verlor, konnte er eine Sperre verlieren und wieder erlangen, ohne von dieser Tatsache Kenntnis zu erhalten. (Die Zeitperiode, nach der der Kontakt als verloren angesehen wird, ist als NFSv4-Ausleihzeit bekannt. Auf einem Linux-NFS-Server kann diese durch einen Blick in /proc/fs/nfsd/nfsv4leasetime, die diese Periode in Sekunden ausdrückt, bestimmt werden. Der Vorgabewert für diese Datei ist 90.) In diesem Szenario sind potenziell Datenbeschädigungen möglich, da ein anderer Prozess in der Zwischenzeit eine Sperre erlangen und Datei-E/A durchführen könnte.
Wenn seit Linux 3.12 ein NFSv4-Client den Kontakt mit dem Server verliert, wird jede E/A des Prozesses, der »glaubt«, er halte eine Sperre, fehlschlagen, bis dieser Prozess die Datei schließt und erneut öffnet. Ein Kernelparameter (nfs.recover_lost_locks) kann auf 1 gesetzt werden, um das pre-3.12-Verhalten zu erreichen, bei dem ein Client versuchen wird, verloren gegangene Sperren wiederherzustellen, wenn der Kontakt mit dem Server wieder etabliert ist. Aufgrund des vorhandenen Risikos der Datenverfälschung ist die Vorgabe für diesen Parameter 0 (deaktiviert).
Es ist nicht möglich, F_SETFL zum Ändern des Zustands der Schalter O_DSYNC und O_SYNC zu verwenden. Versuche, den Zustand dieser Schalter zu ändern, werden ohne Meldung ignoriert.
Eine Begrenzung der Linux-Systemaufrufkonventionen auf einigen Architekturen (insbesondere i386) bedeutet, dass, falls eine von F_GETOWN zurückgelieferte (negative) Prozessgruppenkennung in den Bereich -1 bis -4095 fällt, dies von Glibc fälschlicherweise als Fehler im Systemaufruf interpretiert wird. Dann wird der Rückgabewert von fcntl() -1 sein und errno wird die (positive) Prozessgruppenkennung enthalten. Die Linux-spezifische Aktion F_GETOWN_EX vermeidet dieses Problem. Seit Glibc 2.11 versteckt Glibc das Kernelproblem F_GETOWN, indem F_GETOWN mittels F_GETOWN_EX implementiert wird.
Unter Linux 2.4 und älter gibt es einen Fehler, der auftreten kann, wenn ein unprivilegierter Prozess statt einem Aufrufenden F_SETOWN verwendet, um den Eigentümer eines Socket-Dateideskriptors als Prozess(gruppe) festzulegen. In diesem Fall kann fcntl() -1 mit errno auf EPERM gesetzt zurückliefern, selbst wenn der/die Eigentümerprozess(gruppe) dergestalt ist, dass der Aufrufende Rechte hat, ihr/ihm Signale zu senden. Trotz dieses zurückgelieferten Fehlers wird der Dateieigentümer gesetzt und Signale werden zum Eigentümer gesandt.
Der vom Kernel eingesetzte Algorithmus zur Erkennung von Verklemmungen beim Umgang mit F_SETLKW kann sowohl falsch-negative (keine Erkennung von Verklemmungen, eine Gruppe von verklemmten Prozessen bleibt unbegrenzt blockiert) als auch falsch-positive (EDEADLK-Fehler obwohl keine Verklemmung vorliegt) liefern. Beispielsweise begrenzt der Kernel die Sperrtiefe seiner Abhängigkeitssuche auf 10 Schritte, was bedeutet, dass zirkulare Verklemmungsketten, die diese Größe überschreiten, nicht erkannt werden. Zusätzlich kann der Kernel fälschlicherweise eine Verklemmung erkennen, wenn zwei oder mehr Prozesse, die mit dem Schalter CLONE_FILES von clone(2) Sperren setzen, die (dem Kernel) als im Konflikt stehend erscheinen.
Die Linux-Implementierung von Pflichtsperren ist Gegenstand von Ressourcenwettläufen, die sie unzuverlässig machen: Ein write(2)-Aufruf, der sich mit einer Sperre überschneidet, kann Daten verändern, nachdem die Pflichtsperre erlangt wurde. Ein read(2)-Aufruf, der sich mit einer Sperre überschneidet, kann Änderungen an Daten entdecken, die nur vorgenommen wurden, nachdem eine Schreibsperre erlangt wurde. Ähnliche Wettläufe gibt es zwischen Pflichtsperren und mmap(2). Daher ist es nicht zu empfehlen, sich auf Pflichtsperren zu verlassen.
dup2(2), flock(2), open(2), socket(2), lockf(3), capabilities(7), feature_test_macros(7), lslocks(8)
locks.txt, mandatory-locking.txt und dnotify.txt in dem Linux-Kernelquelldateiverzeichnis Documentation/filesystems/. (Bei älteren Kerneln befinden sich diese Dateien direkt unter dem Verzeichnis Documentation/ und mandatory-locking.txt heißt mandatory.txt.)
Die deutsche Übersetzung dieser Handbuchseite wurde von Martin Schulze <joey@infodrom.org>, Chris Leick <c.leick@vollbio.de>, Helge Kreutzmann <debian@helgefjell.de> und Mario Blättermann <mario.blaettermann@gmail.com> 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.
5. Februar 2023 | Linux man-pages 6.03 |