table of contents
fcntl(2) | System Calls Manual | fcntl(2) |
NAZWA¶
fcntl - manipuluje deskryptorem pliku
BIBLIOTEKA¶
Standardowa biblioteka C (libc, -lc)
SKŁADNIA¶
#include <fcntl.h>
int fcntl(int fd, int op, ... /* arg */ );
OPIS¶
fcntl dokonuje jednej z operacji opisanych poniżej na otwartym deskryptorze pliku fd. Wykonywana operacja jest określona przez op.
fcntl() opcjonalnie może przyjąć trzeci argument. To, czy argument ten jest wymagany, zależy od op. Wymagany typ argumentu jest wskazany w nawiasie po każdej nazwie op (zwykle wymaganym typem jest int, a argument jest identyfikowany określeniem arg) lub podane jest void, gdy argument nie jest wymagany.
Niektóre z poniższych operacji są obsługiwane jedynie w określonej wersji jądra Linux. Preferowaną metodą sprawdzenia, czy działające aktualnie jądro obsługuje daną operację, jest przywołanie fcntl() z daną wartością op i sprawdzenie, czy wywołanie zawiedzie z błędem EINVAL wskazując, że jądro nie rozpoznało tej wartości.
Duplikowanie deskryptora pliku¶
- F_DUPFD (int)
- Duplikuje deskryptor pliku fd za pomocą najniższego dostępnego numeru deskryptora pliku większego lub równego arg. Różni się to od dup2(2), korzystającego z konkretnego, zadanego deskryptora.
- Po pomyślnym zakończeniu zwracany jest nowy deskryptor pliku.
- Więcej informacji znajduje się w podręczniku dup(2).
- F_DUPFD_CLOEXEC (int; od Linuksa 2.6.24)
- Jak w przypadku F_DUPFD, lecz dodatkowo ustawia znacznik zamknięcia-przy-wykonaniu dla duplikowanego deskryptora pliku. Podanie tego znacznika umożliwia programowi na uniknięcie dodatkowej operacji F_SETFD fcntl(), w celu ustawienia znacznika FD_CLOEXEC. Wyjaśnienie powodu, dla którego znacznik ten jest przydatny, znajduje się w opisie O_CLOEXEC w podręczniku open(2).
Znaczniki deskryptora pliku¶
Następujące operacje kontrolują znaczniki powiązane z deskryptorem pliku. Obecnie zdefiniowano jedynie jeden taki znacznik: FD_CLOEXEC, znacznik zamknięcia-przy-wykonaniu. Jeśli ustawiony jest bit FD_CLOEXEC, to deskryptor pliku zostanie automatycznie zamknięty podczas pomyślnego wykonania execve(2) (jeśli execve(2) zawiedzie, deskryptor pliku jest pozostawiany otwarty). Jeśli bit FD_CLOEXEC nie jest ustawiony, deskryptor pliku pozostanie otwarty podczas wykonania execve(2).
- F_GETFD (void)
- Zwraca (jako wynik funkcji) znaczniki deskryptora pliku; argument arg jest ignorowany.
- F_SETFD (int)
- Ustawia znaczniki deskryptora pliku na wartość określoną w arg.
W programach wielowątkowych, użycie F_SETFD fcntl() do ustawienia znacznika zamknięcia przy uruchomieniu w tym samym czasie, w którym inny wątek wykonuje fork(2) i execve(2) jest narażone na wystąpienie sytuacji wyścigu, która może niezamierzenie prowadzić do wycieku deskryptora pliku do programu wykonującego proces potomny. Szczegóły i sposób na uniknięcie tego problemu opisano przy znaczniku O_CLOEXEC, w podręczniku open(2).
Znaczniki stanu pliku¶
Z każdym opisem otwartego pliku stowarzyszonych jest kilka znaczników inicjowanych przez open(2), które mogą ewentualnie być modyfikowane przez fcntl(2). Zduplikowane deskryptory pliku (utworzone za pomocą dup(2), fork(2), itp.) odnoszą się do tego samego opisu otwartego pliku, dzieląc zatem te same znaczniki stanu pliku.
Znaczniki stanu pliku i ich znaczenie są opisane w open(2).
- F_GETFL (void)
- Zwraca (jako wynik funkcji) tryb dostępu do pliku i znaczniki stanu pliku, arg jest ignorowany.
- F_SETFL (int)
- Ustawia znaczniki stanu pliku na wartości określone przez arg. W arg ignorowane są: tryb dostępu do pliku (O_RDONLY, O_WRONLY, O_RDWR) oraz znaczniki tworzenia pliku (tj. O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC). W Linuksie, operacja ta może zmienić jedynie znaczniki O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME i O_NONBLOCK. Nie da się zmienić znaczników O_DSYNC i O_SYNC; zob. USTERKI niżej.
Blokowanie doradcze rekordów¶
Linux implementuje tradycyjne („powiązane z procesem”) blokady rekordów UNIX, zgodnie ze standardem POSIX. Istnieje również typowo linuksowa alternatywa używająca lepszej semantyki — blokady opisów otwartego pliku, które są opisane nieco niżej.
F_SETLK, F_SETLKW i F_GETLK służą do zakładania, zwalniania i sprawdzania obecności blokad rekordów (znanych również jako blokady zakresu bajtów, segmentów pliku lub obszarów pliku). Trzeci argument, lock, jest wskaźnikiem do struktury zawierającej co najmniej następujące pola (kolejność nie jest określona).
struct flock {
...
short l_type; /* Rodzaj blokady: F_RDLCK,
F_WRLCK, F_UNLCK */
short l_whence; /* Sposób interpretacji l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Początek (przesunięcie) blokady */
off_t l_len; /* Liczba blokowanych bajtów */
pid_t l_pid; /* PID procesu uniemożliwiającego blokadę
(ustawiane przez F_GETLK i F_OFD_GETLK) */
... };
Pola l_whence, l_start i l_len w tej strukturze określają zakres bajtów, które mają ulec zablokowaniu. Bajty po końcu pliku mogą być blokowane, nie mogą to być natomiast bajty przed jego początkiem.
l_start jest początkowym przesunięciem blokady i jest interpretowane w odniesieniu do: początku pliku (gdy l_whence wynosi SEEK_SET), bieżącego przesunięcia pliku (gdy l_whence wynosi SEEK_CUR) albo końca pliku (gdy l_whence wynosi SEEK_END). W ostatnich dwóch przypadkach, l_start może być liczbą ujemną zakładając, że przesunięcie nie prowadzi przed początek pliku.
l_len określa liczbę bajtów do zablokowania. Jeśli l_len jest dodatnie, to przedział do zablokowania pokrywa bajty od l_start do l_start+l_len-1 włącznie. Podanie 0 w l_len ma specjalne znaczenie: blokowane są wszystkie bajty od położenia określonego przez l_whence i l_start, aż do końca pliku, niezależnie od tego, jak duży staje się plik.
POSIX.1-2001 zezwala implementacji (lecz tego nie wymaga) na obsługę ujemnych wartości l_len; jeśli l_len jest ujemna, to przedział, którego dotyczy lock obejmuje bajty od l_start+l_len do l_start-1 włącznie. Jest to obsługiwane od Linuksa 2.4.21 i Linuksa 2.5.49.
Pole l_type może służyć do założenia blokady dla odczytu (F_RDLCK) lub dla zapisu (F_WRLCK) do pliku. Dowolna liczba procesów może utrzymywać blokadę dla odczytu pliku (blokada wspólna) w pewnym jego obszarze, ale tylko jeden proces może utrzymywać blokadę dla zapisu do pliku (blokada wyłączna). Blokada wyłączna wyklucza wszelkie inne blokady, zarówno wspólne, jak i wyłączne. Pojedynczy proces może w danym obszarze pliku utrzymywać blokadę tylko jednego rodzaju; gdy w aktualnie zablokowanym obszarze zakładana jest nowa blokada, to istniejąca blokada jest przekształcana w blokadę nowego typu (takie przekształcenie może pociągać za sobą podział, skrócenie lub połączenie z istniejącą blokadą, gdy zakres bajtów podany dla nowej blokady nie pokrywa się dokładnie z zakresem istniejącej blokady).
- F_SETLK (struct flock *)
- Ustawienie blokady dla zakresu bajtów określonego przez pola l_whence, l_start i l_len lock (gdy l_type jest równe F_RDLCK lub F_WRLCK) albo jej zwolnienie (gdy l_type jest równe F_UNLCK). Jeśli kolidująca blokada jest utrzymywana przez inny proces, funkcja ta zwraca -1 i ustawia errno na EACCES lub EAGAIN (zwracany w tym przypadku błąd różni się pomiędzy implementacjami, dlatego POSIX wymaga sprawdzania przez przenośne aplikacje obu wartości błędów).
- F_SETLKW (struct flock *)
- Podobne do F_SETLK, lecz w sytuacji, gdy na pliku założona jest kolidująca blokada czeka na zwolnienie tej blokady. Jeśli podczas oczekiwania zostanie przechwycony sygnał, funkcja jest przerywana i (po powrocie z funkcji obsługi sygnału) powraca natychmiast (zwracając wartość -1 i ustawiając errno na EINTR; zob. signal(7)).
- F_GETLK (struct flock *)
- Jako argument lock tej funkcji określa blokadę, jaką chcielibyśmy założyć na pliku. Gdy założenie blokady jest możliwe, fcntl() w rzeczywistości jej nie zakłada, lecz zwraca F_UNLCK w polu l_type struktury lock pozostawiając inne pola tej struktury niezmienione.
- Jeśli jedna lub więcej niezgodnych blokad zapobiegłoby umieszczeniu tej blokady, to fcntl() zwróci szczegóły o jednej z tych blokad w polach l_type, l_whence, l_start i l_len w lock. Jeśli niezgodna blokada jest tradycyjną (związaną z procesem) blokadą rekordu, to pole l_pid jest ustawiane na PID procesu utrzymującego tę blokadę. Jeśli niezgodna blokada jest blokadą opisu otwartego pliku (OFD), to l_pid jest ustawiane na -1. Proszę zauważyć, że w momencie sprawdzenia zwracanych informacji przez wywołującego, mogą być już one nieaktualne.
Aby założyć blokadę do odczytu, deskryptor fd musi być otwarty do odczytu. Aby założyć blokadę do zapisu, deskryptor fd musi być otwarty do zapisu. Aby założyć obydwa rodzaje blokad, należy otworzyć plik do odczytu i zapisu.
Przy umieszczaniu blokady z F_SETLKW, jądra wykrywa zakleszczenia, gdy żądania blokad dwóch lub więcej procesów są wzajemnie zablokowane przez blokady utrzymywane przez inne procesy. Przykładowo, przypuśćmy, że proces A utrzymuje blokadę zapisu na bajcie 100. pliku, a proces B utrzymuje blokadę zapisu na bajcie 200. Jeśli każdy z procesów spróbuje następnie zablokować bajt już zablokowany przez drugie proces za pomocą F_SETLKW, to — bez wykrywania zakleszczeń — oba procesy pozostałyby stale zablokowane. Jeśli jądro wykryje takie zakleszczenie, to spowoduje natychmiastowe niepowodzenie jednego z żądań blokady, z błędem EDEADLK; aplikacja napotykająca na taki błąd powinna zwolnić niektóre ze swoich blokad, aby pozwolić działać inny aplikacjom, przed ponowną próbą odzyskania wymaganych blokad. Wykrywane są również koliste zakleszczenia, z więcej niż dwoma procesami. Proszę jednak zauważyć, że algorytm wykrywania zakleszczeń jądra ma swoje ograniczenia, zob. USTERKI.
Oprócz usunięcia za pomocą wyraźnego F_UNLCK, blokady rekordów są zwalniane automatycznie po zakończeniu procesu.
Blokady rekordów nie są dziedziczone przez procesy potomne poprzez fork(2), ale są zachowywane poprzez execve(2).
Ze względu na wykonywane przez bibliotekę stdio(3) buforowanie, należy unikać blokowania rekordów w połączeniu z funkcjami z tego pakietu; zamiast tego należy używać read(2) i write(2).
Opisane wyżej blokady rekordów są związane z procesem (w przeciwieństwie do blokad opisu otwartego pliku, opisanych niżej). Ma to pewne niefortunne konsekwencje:
- •
- Jeśli proces zamknie dowolny deskryptor odnoszący się do pliku, to zwalniane są wszystkie blokady, niezależnie od tego, na którym z deskryptorów pliku blokady te uzyskano. Jest to złe: oznacza, że proces może utracić swe blokady na pliku takim jak /etc/passwd lub /etc/mtab gdy jakaś funkcja biblioteczna zdecyduje się z jakiegoś powodu otworzyć, odczytać i zamknąć ten sam plik.
- •
- Wątki procesu dzielą blokady. Innymi słowy, program wielowątkowy nie może korzystać z blokad rekordów, aby uniemożliwić jednoczesny dostęp do tego samego miejsca pliku przez swoje wątki.
Blokady opisu otwartego pliku rozwiązują oba te problemy.
Blokady opisu otwartego pliku (spoza POSIX)¶
Blokady opisu otwartego pliku są blokadami doradczymi, definiowanymi w zakresie bajtów, których działanie jest w większości identyczne do tradycyjnych blokad rekordów opisanych wyżej. Ten typ blokad jest typowo linuksowy i jest dostępny od Linuksa 3.15 (w Austin Group istnieje propozycja włączenia tego typu blokady do następnej rewizji POSIX.1). Wyjaśnienie opisu otwartego pliku znajduje się w podręczniku open(2).
Podstawową różnicą, pomiędzy dwoma typami blokad jest fakt, że o ile tradycyjne blokady rekordów są związane z procesem, to blokady opisu otwartego pliku są związane z opisem otwartego pliku, na którym je uzyskano, podobnie jak to wygląda w przypadku blokad uzyskanych za pomocą flock(2). W efekcie (inaczej niż przy tradycyjnych blokadach doradczych rekordów) blokady opisu otwartego pliku są dziedziczone przy fork(2) (i clone(2) ze znacznikiem CLONE_FILES), a także są automatycznie zwalniane po ostatnim zamknięciu opisu otwartego pliku, zamiast zwalniania przy jakimkolwiek zamknięciu pliku.
Kolidujące kombinacje blokad (tj. blokada odczytu z blokadą zapisu lub dwie blokady zapisu) gdy jedna blokada jest blokadą opisu otwartego pliku, a druga jest tradycyjną blokadą rekordu prowadzą do konfliktu nawet wówczas, gdy są uzyskane przez ten sam proces na tym samym deskryptorze pliku.
Blokady opisu otwartego pliku umieszczone na tym samym opisie otwartego pliku (tj. za pomocą tego samego deskryptora pliku lub za pomocą duplikatu deskryptora pliku utworzonego przez fork(2), dup(2), F_DUPFD z fcntl() itp.) są zawsze kompatybilne: jeśli nowa blokada jest umieszczona na już zablokowanym rejonie pliku, to istniejące blokada jest konwertowana na nowy typ blokady (takie konwersje mogą prowadzić to podziału, zmniejszenia lub złączenia z dotychczasową blokadą, jak opisano to wyżej)
Z drugiej strony, blokady opisu otwartego pliku mogą być w konflikcie, gdy są uzyskane przez różne opisy otwartego pliku. Z tego względu, program wielowątkowy może korzystać z blokad opisu otwartego pliku do synchronizowania dostępu do jakiegoś miejsca w pliku, otwierając (open(2)) plik z różnych wątków i zakładając blokady za pomocą wynikowego deskryptora pliku.
Podobnie jak w przypadku tradycyjnych blokad doradczych, trzeci argument do fcntl() — lock, jest wskaźnikiem do struktury flock. W odróżnieniu do tradycyjnych blokad rekordów, pole l_pid tej struktury musi być ustawione na zero za pomocą operacji opisanych niżej.
Operacje działające z blokadami opisu otwartego pliku są analogiczne do tych używanych z tradycyjnymi blokadami:
- F_OFD_SETLK (struct flock *)
- Ustawia blokadę opisu otwartego pliku (gdy l_type jest równe F_RDLCK lub F_WRLCK) albo zwalnia blokadę opisu otwartego pliku (gdy l_type jest równe F_UNLCK) dla zakresu bajtów określonego przez pola l_whence, l_start i l_len lock. Jeśli kolidująca blokada jest utrzymywana przez inny proces, funkcja ta zwraca -1 i ustawia errno na EAGAIN.
- F_OFD_SETLKW (struct flock *)
- Podobne do F_SETLK, lecz w sytuacji, gdy na pliku założona jest kolidująca blokada, czeka na zwolnienie tej blokady. Jeśli podczas oczekiwania zostanie przechwycony sygnał, funkcja jest przerywana i (po powrocie z funkcji obsługi sygnału) powraca natychmiast (zwracając wartość -1 i ustawiając errno na EINTR; zob. signal(7)).
- F_OFD_GETLK (struct flock *)
- Jako argument lock tej funkcji określa blokadę opisu otwartego pliku, jaką chcielibyśmy założyć na pliku. Gdy założenie blokady jest możliwe, fcntl() w rzeczywistości jej nie zakłada, lecz zwraca F_UNLCK w polu l_type struktury lock pozostawiając inne pola tej struktury niezmienione. Jeśli co najmniej jedna niezgodna blokada uniemożliwiłaby założenie zadanej blokady, to informacje o jednej z tych blokad są zwracane za pomocą lock, jak to opisano powyżej dla F_GETLK.
W bieżącej implementacji, dla blokad opisu otwartego pliku nie zachodzi wykrywanie zakleszczeń (w odróżnieniu od blokad rekordów związanych z procesem, dla których jądro wykonuje wykrywanie zakleszczeń).
Blokowanie obowiązujące (przymusowe)¶
Ostrzeżenie: linuksowa implementacja blokowania obowiązującego jest zawodna (zob. USTERKI poniżej). Z powodu opisanych błędów i faktu, że funkcjonalność ta nie była często wykorzystywana, od Linuksa 4.5, tego typu blokowanie stało się opcjonalne i zależy od ustawienia opcji konfiguracyjnej (CONFIG_MANDATORY_FILE_LOCKING). Od Linuksa 5.15 blokowanie obowiązujące (przymusowe) nie jest już w ogólne obsługiwane.
Domyślnie, zarówno tradycyjne blokady (związane z procesem) jak i blokady opisu otwartego pliku (OFD) są doradcze. Blokady doradcze nie są wymuszane i są przydatne tylko w przypadku współdziałających procesów.
Oba te typy mogą być również obowiązujące. Blokady obowiązujące są wymuszane dla wszystkich procesów. Jeśli proces spróbuje uzyskać niezgodny dostęp (tj. odczyt — read(2) lub zapis — write(2)) w obszarze pliku, który posiada niezgodną blokadę obowiązującą, to wynik zależy od tego, czy dla jego opisu otwartego pliku włączono znacznik O_NONBLOCK. Jeśli znacznik O_NONBLOCK nie jest włączony, to dane wywołanie systemowe jest blokowane do momentu usunięcia blokady lub jej przekształcenia w tryb, który jest zgodny z uzyskiwanym dostępem. Jeśli znacznik O_NONBLOCK jest włączony, to wywołanie systemowe zawodzi z błędem EAGAIN.
Aby skorzystać z obowiązujących blokad, blokowanie obowiązujące musi być włączone zarówno na systemie plików zawierającym blokowany plik, jak i na samym pliku. Blokowanie obowiązujące w systemie plików włącza się za pomocą opcji „-o mand” programu mount(8) lub za pomocą znacznika MS_MANDLOCK do mount(8). Blokowanie obowiązujące na pliku włącza się poprzez wyłączenie prawa uruchamiania dla grupy i włączenie bitu set-group-ID (zob. chmod(1) i chmod(2)).
Blokowanie obowiązujące nie jest określone normą POSIX. Niektóre inne systemy również obsługują blokowanie obowiązujące, choć szczegóły ich włączenia również się między systemami.
Zagubione blokady¶
Gdy blokada doradcza jest uzyskiwana na sieciowym systemie plików, takim jak NFS, możliwe jest zagubienie blokady. Może się tak stać ze względu na działanie administracyjne na serwerze lub z powodu podziału sieci (tzn. utraty połączenie z serwerem), które będzie trwało na tyle długo, że serwer może przyjąć brak dalszego funkcjonowania przez klienta.
Gdy system plików stwierdzi, że blokada została zagubiona, przyszły odczyt (read(2)) lub zapis (write(2)) może zawieść z błędem EIO. Błąd ten będzie występował do momentu usunięcia blokady lub zamknięcia deskryptora pliku. Od Linuksa 3.12, dzieje się tak przynajmniej w NFSv4 (we wszystkich jego pomniejszych wydaniach).
Niektóre wersje Uniksa wysyłają w takiej sytuacji sygnał (SIGLOST). Linux nie definiuje tego sygnału i nie zapewnia żadnego asynchronicznego powiadamiania o zagubionych blokadach.
Zarządzanie sygnałami¶
F_GETOWN, F_SETOWN, F_GETOWN_EX, F_SETOWN_EX, F_GETSIG i F_SETSIG służą do zarządzania sygnałami dostępności wejścia/wyjścia:
- F_GETOWN (void)
- Zwraca (jako wynik funkcji) identyfikator procesu lub identyfikator grupy procesów aktualnie otrzymujących sygnały SIGIO i SIGURG dla zdarzeń na deskryptorze plików fd. Identyfikatory procesów są zwracane jako wartości dodatnie, identyfikatory grupy procesów są zwracane jako wartości ujemne (lecz zob. USTERKI poniżej). arg jest ignorowane.
- F_SETOWN (int)
- Ustawia identyfikator procesu lub identyfikator grupy procesów aktualnie otrzymujących sygnały SIGIO i SIGURG dla zdarzeń na deskryptorze plików fd. Docelowy identyfikator procesu lub grupy procesów podaje się jako arg. Identyfikator procesu jest określany jako liczba dodatnia; identyfikator grupy procesów jest określany za pomocą wartości ujemnych. Najczęściej, proces wywołujący określa się jako właściciel (tj. arg jest podawany jak przez getpid(2)).
- Oprócz ustawiania właściciela deskryptora pliku, konieczne jest również włączenie generowania sygnałów na deskryptorze plików. Można to uczynić za pomocą operacji F_SETFL fcntl(), ustawiając znacznik stanu pliku O_ASYNC na deskryptorze pliku. Co za tym idzie, gdy tylko na deskryptorze pliku możliwe stanie się wejście lub wyjście, zostanie wysłany sygnał SIGIO. Operację F_SETSIG fcntl() można wykorzystać do uzyskania dostarczenia sygnału innego niż SIGIO.
- Wysłanie sygnału do właściciela procesu (grupy) podanego w F_SETOWN, podlega takim samym sprawdzeniom uprawnień jak opisano w przypadku kill(2), gdy proces wysyłający jest tym, który używa F_SETOWN (lecz zob. USTERKI poniżej). Jeśli sprawdzenie uprawnień się nie powiedzie, to sygnał jest po cichu odrzucany. Uwaga: Operacja F_SETOWN sprawdza poświadczenia wywołującego w chwili wywołania fcntl() i to te zapisane poświadczenia są używane do sprawdzenia uprawnień.
- Jeśli deskryptor pliku fd odnosi się do gniazda, F_SETOWN określa również odbiorcę sygnałów SIGURG dostarczanych gdy poprzez gniazdo przybędą dane autonomiczne (SIGURG jest wysyłany w sytuacjach, w których select(2) zgłosiłby „stan wyjątkowy”).
- Następujący akapit był prawdziwy w Linuksie 2.6.x do Linuksa 2.6.11 włącznie:
- Jeśli F_SETSIG przekaże się wartość niezerową w procesie wielowątkowym, działającym z biblioteką wątkowania obsługującą grupy wątków (np. NPTL), to wartość pozytywna przekazana F_SETOWN ma inne znaczenie: zamiast byciem identyfikatorem całego procesu, jest identyfikatorem wątku, który identyfikuje dany wątek procesu. W efekcie, może być konieczne podanie F_SETOWN wyniku gettid(2), zamiast wyniku getpid(2), aby uzyskać rozsądne wyniki, gdy korzysta się z F_SETSIG (w bieżącej, linuksowej implementacji wątkowania, identyfikator głównego wątku jest taki sam jak jego identyfikator procesu; oznacza to, że programy jednowątkowe mogą w tym scenariuszu korzystać z gettid(2) lub getpid(2)). Proszę jednak zauważyć, że stwierdzenie w tym akapicie nie dotyczy sygnału SIGURG, wygenerowanego dla danych spoza pasma (ang. out-of-band data) na gnieździe: ten sygnał zawsze trafia albo do procesu albo do grupy procesu, w zależności od wartości przekazanej F_SETOWN.
- Powyższe zachowanie przypadkowo porzucono w Linuksie 2.6.12 i nie zostanie przywrócone. Od Linuksa 2.6.32, należy użyć F_SETOWN_EX, aby przeznaczyć sygnały SIGIO do określonego wątku.
- F_GETOWN_EX (struct f_owner_ex *) (od Linuksa 2.6.32)
- Zwraca ustawienia aktualnego właściciela deskryptora pliku, jak zdefiniowane poprzednią operacją F_SETOWN_EX. Informacja ta jest zwracana przez strukturę na którą wskazuje arg, która ma postać:
-
struct f_owner_ex {
int type;
pid_t pid; };
- Pole type będzie miało jedną z wartości: F_OWNER_TID, F_OWNER_PID lub F_OWNER_PGRP. Pole pid jest liczbą dodatnią, reprezentującą identyfikator, odpowiednio, wątku, procesu lub grupy procesu. Więcej informacji przy F_SETOWN_EX.
- F_SETOWN_EX (struct f_owner_ex *) (od Linuksa 2.6.32)
- Operacja przeprowadza podobne zadanie do F_SETOWN. Pozwala wywołującemu, na kierowanie sygnałów o dostępności wejścia/wyjścia do określonego wątku, procesu lub grupy procesu. Wywołujący określa cel sygnału za pomocą arg, wskaźnika do struktury f_owner_ex. Pole type ma jedną z następujących wartości, definiujących sposób interpretacji pid:
- F_OWNER_TID
- Wysyła sygnał do wątku, którego identyfikator wątku (taki, jak zwracany przez wywołanie clone(2) lub gettid(2)) podano w pid.
- F_OWNER_PID
- Wysyła sygnał do procesu, którego identyfikator podano w pid.
- F_OWNER_PGRP
- Wysyła sygnał do grupy procesu, której identyfikator podano w pid (proszę zauważyć, że w przeciwieństwie do F_SETOWN, identyfikator grupy procesu jest tu podawany jako wartość dodatnia).
- F_GETSIG (void)
- Zwraca (jako wynik funkcji) sygnał wysyłany, gdy wejście lub wyjście stanie się możliwe. Wartość zerowa oznacza wysyłanie SIGIO. Dowolna inna wartość (łącznie z SIGIO) stanowi numer sygnału wysyłanego zamiast niego. W tych sytuacjach dodatkowe informacje mogą być dostępne dla programu obsługi sygnału, o ile zostały zainstalowane z użyciem SA_SIGINFO. arg jest ignorowane.
- F_SETSIG (int)
- Ustawia sygnał wysyłany, gdy wejście lub wyjście stanie się możliwe na wartość podaną w arg. Wartość zerowa oznacza wysyłanie sygnału domyślnego, czyli SIGIO. Dowolna inna wartość (łącznie z SIGIO) stanowi numer sygnału wysyłanego zamiast niego. W tych sytuacjach dodatkowe informacje mogą być dostępne dla programu obsługi sygnału, o ile zostały zainstalowane z użyciem SA_SIGINFO.
- Za pomocą F_SETSIG z niezerową wartością i przy ustawionym SA_SIGINFO dla programu obsługi sygnału (patrz sigaction(2)), można przekazać do programu obsługi sygnału w strukturze siginfo_t dodatkowe informacje o zdarzeniach wejścia/wyjścia. Jeśli pole si_code wskazuje, że źródłem jest SI_SIGIO, to pole si_fd zawiera deskryptor pliku związany ze zdarzeniem. W przeciwnym przypadku, brak jest wskazania, które deskryptory plików oczekują i do określenia dostępnych dla wejścia/wyjścia deskryptorów plików należy używać zwykłych mechanizmów (select (2), poll(2), read(2) z ustawionym O_NONBLOCK itd.).
- Proszę zauważyć, że deskryptor pliku udostępniony w si_fd jest tym samym, który podano podczas operacji F_SETSIG. To może prowadzić do nietypowej sytuacji. Gdy deskryptor pliku jest duplikowany (dup(2) lub podobne), a pierwotny deskryptor pliku jest zamykany, to zdarzenie wejście/wyjścia wciąż będzie tworzone, lecz pole si_fd będzie zawierać deskryptor już zamkniętego pliku.
- Wybierając sygnał czasu rzeczywistego (wartość >= SIGRTMIN), można, używając tych samych numerów sygnałów, spowodować umieszczenie w kolejce wielu zdarzeń wejścia/wyjścia (kolejkowanie zależy od dostępnej pamięci). Jak powyżej, dodatkowe informacje są dostępne, gdy programy obsługi sygnałów zostały zainstalowane z ustawionym SA_SIGINFO.
- Proszę zauważyć, że Linux narzuca limit liczby sygnałów czasu rzeczywistego, które mogą oczekiwać w kolejce na proces (zob. getrlimit(2) i signal(7)) i jeśli limit ten zostanie osiągnięty, to jądro powraca do dostarczania SIGIO, a sygnał ten jest dostarczany do całego procesu, zamiast to konkretnego wątku.
Za pomocą tych mechanizmów program może zaimplementować w pełni asynchroniczne wejście/wyjście, nie używając przez większość czasu select(2) i poll(2).
Opisane powyżej korzystanie z O_ASYNC jest specyficzne dla BSD i Linuksa. Jedynym użyciem F_GETOWN i F_SETOWN podanym w POSIX.1 jest użycie ich w połączeniu z sygnałem SIGURG na gniazdach (POSIX nie określa sygnału SIGIO). F_GETOWN_EX, F_SETOWN_EX, F_GETSIG i F_SETSIG są typowo linuksowe. POSIX posiada asynchroniczne wejście/wyjście i strukturę aio_sigevent służącą do podobnych celów; w Linuksie są one również dostępne jako część biblioteki GNU C (glibc).
Dzierżawy¶
F_SETLEASE i F_GETLEASE (od Linuksa 2.4 wzwyż) służą do ustanowienia nowe dzierżawy i pobrania aktualnej dzierżawy na opisie otwartego pliku, do którego odnosi się deskryptor pliku fd. Dzierżawa pliku zapewnia mechanizm, w którym proces utrzymujący dzierżawę („dzierżawca”) jest zawiadamiany (poprzez dostarczenie sygnału) o tym, że inny proces („zrywający dzierżawę”) próbuje wykonać open(2) lub truncate(2) na pliku, do którego odnosi się dany deskryptor pliku.
- F_SETLEASE (int)
- Ustawia lub usuwa dzierżawę pliku w zależności od tego, która z następujących wartości zostanie podana jako argument arg typu integer :
- F_RDLCK
- Ustanawia dzierżawę odczytu. Spowoduje to zawiadamianie procesu wywołującego o otwarciu pliku do zapisu lub o obcinaniu go. Dzierżawa odczytu może zostać nałożona na deskryptor pliku tylko wtedy, gdy jest on otwarty tylko do odczytu.
- F_WRLCK
- Ustanawia dzierżawę zapisu. Spowoduje to zawiadamianie wywołującego o otwarciu pliku do odczytu lub do zapisu, lub o obcinaniu go. Dzierżawa zapisu może zostać nałożona na plik tylko wtedy, gdy plik nie posiada żadnych innych otwartych deskryptorów pliku.
- F_UNLCK
- Zdejmuje własną dzierżawę z pliku.
Dzierżawy są związane z opisem otwartego pliku (zob. open(2)). Oznacza to, że zduplikowane deskryptory pliku (utworzone np. za pomocą fork(2) lub dup(2)) odnoszą się do tej samem dzierżawy i można ją zmodyfikować lub zwolnić za pomocą dowolnego z tych deskryptorów. Co więcej, dzierżawa jest zwalniana przez operację F_UNLCK na dowolnym z tych zduplikowanych deskryptorów plików albo gdy wszystkie takie deskryptory pliku zostaną zamknięte.
Dzierżawy można ustanawiać tylko na zwykłych plikach. Proces nieuprzywilejowany może ustanawiać jedynie dzierżawy na plikach, których UID (właściciela) odpowiada UID-owi systemu plików dla danego procesu. Proces z przywilejem CAP_LEASE (ang. capability) może ustanawiać dzierżawy na dowolnych plikach.
- F_GETLEASE (void)
- Wskazuje rodzaj dzierżawy związanej z deskryptorem pliku fd, zwracając F_RDLCK, F_WRLCK, albo F_UNLCK, wskazując (odpowiednio) dzierżawę: odczytu, zapisu lub brak dzierżawy. arg jest ignorowane.
Gdy proces („zrywający dzierżawę”) wykona operację open(2) lub truncate(2) kolidującą z dzierżawą ustanowioną poprzez F_SETLEASE, wywołanie funkcji systemowej jest blokowane przez jądro, a jądro zawiadamia dzierżawcę poprzez wysłanie sygnału (domyślnie SIGIO). Dzierżawca powinien odpowiedzieć na otrzymanie tego sygnału wykonując porządki niezbędne dla przygotowania pliku do dostępu przez inny proces (np. zrzucenie buforów) a następnie usunięcie lub zmniejszenie swojej dzierżawy. Dzierżawa jest usuwana poprzez wykonanie operacji F_SETLEASE podając jako arg F_UNLCK. Jeśli dzierżawca aktualnie utrzymuje dzierżawę zapisu na pliku, a zrywający dzierżawę otwiera plik do odczytu, to wystarczające jest zmniejszenie dzierżawy przez dzierżawcę do dzierżawy odczytu. Dokonuje się tego poprzez wykonanie operacji F_SETLEASE podając jako arg F_RDLCK.
Jeśli dzierżawca nie zmniejszy lub nie zwolni dzierżawy w ciągu podanej w /proc/sys/fs/lease-break-time liczby sekund, to jądro przymusowo usunie lub zmniejszy dzierżawę dzierżawcy.
Po zainicjowaniu zerwania dzierżawy, F_GETLEASE zwraca docelowy typ dzierżawy (F_RDLCK albo F_UNLCK, w zależności od tego, co byłoby zgodne ze zrywającym dzierżawę) do momentu, gdy dzierżawca dobrowolnie nie zmniejszy lub nie zwolni dzierżawy albo do momentu, gdy jądro tego nie wymusi po upłynięciu czasu zerwania dzierżawy.
Po dobrowolnym lub wymuszonym usunięciu lub zmniejszeniu dzierżawy, przy założeniu, że wywołanie funkcji systemowej przez zrywającego dzierżawę nie jest nieblokujące, jądro pozwala na kontynuację funkcji systemowej wywołanej przez zrywającego dzierżawę.
Jeśli zablokowane wywołanie open(2) lub truncate(2) zrywającego dzierżawę zostanie przerwane przez procedurę obsługi sygnału, to wywołanie systemowe zawiedzie z błędem EINTR, lecz inne kroki opisane wyżej, wciąż zostaną przeprowadzone. Jeśli zrywający dzierżawę zostanie zabity sygnałem w trakcie blokowania open(2) lub truncate(2), to inne kroki opisane wyżej, wciąż zostaną przeprowadzone. Jeśli zrywający dzierżawę poda znacznik O_NONBLOCK przy wywoływaniu open(2), to wywołanie zawiedzie natychmiast z błędem EWOULDBLOCK, lecz inne kroki opisane wyżej, wciąż zostaną przeprowadzone.
Domyślnym sygnałem stosowanym do zawiadamiania dzierżawcy jest SIGIO, lecz można go zmienić za pomocą operacji F_SETSIG w fcntl(). Jeśli wydano operację F_SETSIG (nawet podając SIGIO), a funkcja obsługi sygnału została określona za pomocą SA_SIGINFO, to ta funkcja obsługi otrzyma jako drugi argument strukturę siginfo_t, której pole si_fd będzie zawierać deskryptor pliku dzierżawionego pliku, do którego uzyskuje dostęp inny proces (jest to przydatne, gdy wywołujący utrzymuje dzierżawy na wielu plikach).
Powiadamianie o zmianach pliku lub katalogu (dnotify)¶
- F_NOTIFY (int)
- (od Linuksa 2.4 wzwyż) Zapewnia powiadamianie o modyfikacji katalogu, do którego odnosi się fd lub o modyfikacji któregokolwiek z plików w tym katalogu. Zdarzenia, powiadamianie o których ma nastąpić, są określone w arg, będącym maską bitową utworzoną jako suma logiczna (OR) zera lub więcej spośród następujących bitów:
- DN_ACCESS
- Uzyskano dostęp do pliku (read(2), pread(2), readv(2) i podobne)
- DN_MODIFY
- Plik został zmodyfikowany (write(2), pwrite(2), writev(2), truncate(2), ftruncate(2) i podobne).
- DN_CREATE
- Utworzono plik (open(2), creat(2), mknod(2), mkdir(2), link(2), symlink(2), rename(2) w tym katalogu).
- DN_DELETE
- Usunięto pliku (unlink(2), rename(2) do innego katalogu, rmdir(2)).
- DN_RENAME
- Zmieniono nazwę w obrębie katalogu (rename(2)).
- DN_ATTRIB
- Zmieniono atrybuty pliku (chown(2), chmod(2), utime(2), utimensat(2) i podobne).
- (Uzyskanie tych definicji wymaga zdefiniowania makra sprawdzania cech _GNU_SOURCE przed włączeniem jakichkolwiek plików nagłówkowych).
- Powiadomienia dotyczące katalogów są zazwyczaj jednorazowe, więc aplikacja musi się ponownie zarejestrować, aby otrzymać dalsze powiadomienia. Alternatywnie, jeśli w arg włączono DN_MULTISHOT, to powiadomienia będą dokonywane aż do ich jawnego usunięcia.
- Szereg wywołań podających DN_MULTISHOT kumuluje się, przy czym zdarzenia w arg są dodawane logicznie do już monitorowanych. Aby wyłączyć powiadamianie o jakichkolwiek zdarzeniach, należy w wywołaniu F_NOTIFY podać arg równe 0.
- Powiadamianie odbywa się poprzez dostarczenie sygnału. Domyślnym sygnałem jest SIGIO, ale można go zmienić za pomocą operacji F_SETSIG w fcntl() (proszę zauważyć, że SIGIO jest jednym z sygnałów standardowych niepodlegających kolejkowaniu; przełączenie się na sygnały czasu rzeczywistego oznacza, że do procesu może być kolejkowane wiele zawiadomień). W tym drugim przypadku, funkcja obsługi sygnału otrzymuje jako swój drugi argument strukturę siginfo_t (gdy funkcja obsługi sygnału została określona za pomocą SA_SIGINFO) a pole si_fd tej struktury zawiera deskryptor pliku, który spowodował powiadomienie (przydatne, gdy utrzymywane są dzierżawy na wielu katalogach).
- W szczególności, gdy używa się DN_MULTISHOT, do zawiadamiania powinien być stosowany sygnał czasu rzeczywistego, tak aby można było kolejkować wiele zmian.
- UWAGA: Nowe aplikacje powinny korzystać z interfejsu inotify (dostępnego od Linuksa 2.6.13), który zapewnia o wiele lepszy interfejs do uzyskiwania powiadomień o zdarzeniach w systemie plików. Zob. inotify(7).
Zmiana pojemności potoku¶
- F_SETPIPE_SZ (int; od Linuksa 2.6.35)
- Zmienia pojemność potoku, do którego odnosi się fd na co najmniej arg bajtów. Proces nieuprzywilejowany może dostosować pojemność potoku na dowolną wartość pomiędzy systemowym rozmiarem strony i limitem zdefiniowanym w /proc/sys/fs/pipe-max-size (zob. proc(5)). Próby ustawienia pojemności potoku poniżej rozmiaru strony są po cichu zaokrąglane w górę, do rozmiaru strony. Próby ustawienia przez proces nieuprzywilejowany rozmiaru potoku powyżej limitu /proc/sys/fs/pipe-max-size prowadzą do błędu EPERM; proces uprzywilejowany (CAP_SYS_RESOURCE) może przesłonić ten limit.
- Przy przydzielaniu bufora dla potoku, jądro może użyć pojemności większej niż arg, gdy jest to wygodne ze względu na implementację (w bieżącej implementacji, przydzielanie następuje do następnej wielokrotności będącej potęgą dwójki, w stosunku do żądanego rozmiaru). Rzeczywista ustawiona pojemność (w bajtach) jest zwracana jako wynik funkcji.
- Próby ustawienia pojemności potoku poniżej aktualnie używanego rozmiaru bufora, używanego do przechowywania jego danych, poskutkuje błędem EBUSY.
- Proszę zauważyć, że ze względu na sposób, w jaki wykorzystywane są strony bufora potoku, przy zapisywaniu danych do potoku, liczba możliwych do zapisanych bajtów może być mniejsza, niż jego nominalny rozmiar, zależnie od rozmiaru zapisów.
- F_GETPIPE_SZ (void; od Linuksa 2.6.35)
- Zwraca (jako wynik funkcji) rozmiar potoku, do którego odnosi się fd.
Pieczętowanie pliku (ang. file sealing)¶
Pieczęcie pliku ograniczają zestaw dozwolonych operacji na danym pliku. Od momentu ustawienia pieczęci na pliku, określony zestaw operacji na tym pliku zawiedzie z błędem EPERM. Taki plik określany jest jako zapieczętowany (ang. sealed). Domyślny zestaw pieczęci zależy od typu pliku i systemu plików. Przegląd pieczętowania plików, opis celowości i nieco przykładów kodu zawarto w podręczniku memfd_create(2).
Obecnie, pieczęcie pliku można zastosować tylko na deskryptorze pliku zwróconym przez memfd_create(2) (jeśli użyto MFD_ALLOW_SEALING). W innych systemach plików, wszystkie operacje fcntl() działające na pieczęciach zwrócą EINVAL.
Pieczęcie są właściwością i-węzła. Z tego powodu, wszystkie opisy otwartego pliku (OFD) odnoszące się do tego samego i-węzła dzielą ten sam zestaw pieczęci. Co więcej, pieczęci nigdy nie można usunąć, można je jedynie dodawać.
- F_ADD_SEALS (int; od Linuksa 3.17)
- Dodaje pieczęcie przekazane w argumencie arg, będącym maską bitową, do zestawu pieczęci i-węzła, do którego odnosi się deskryptor pliku fd. Pieczęci nie można usunąć. Jeśli wywołanie się powiedzie, pieczęcie są natychmiast stosowane przez jądro. Jeśli aktualny zestaw pieczęci obejmuje F_SEAL_SEAL (zob. niżej), to wywołanie to zostanie odrzucone z błędem EPERM. Dodanie pieczęci, która jest już ustawiona nie ma skutku, o ile nie ustawiono F_SEAL_SEAL. Do umieszczenia pieczęci, deskryptor pliku fd musi być zapisywalny.
- F_GET_SEALS (void; od Linuksa 3.17)
- Zwraca (jako wynik funkcji) bieżący zestaw pieczęci i-węzła, do którego odnosi się fd. Jeśli nie ma ustawionych pieczęci, zwracane jest 0. Jeśli plik nie obsługuje pieczętowania, zwracane jest -1, a errno jest ustawiane na EINVAL.
Dostępne są następujące pieczęcie:
- F_SEAL_SEAL
- Jeśli ta pieczęć jest ustawiona, każde kolejne wywołanie fcntl() z F_ADD_SEALS zawiedzie z błędem EPERM. Ta pieczęć zapobiega zatem wszelkim modyfikacjom samego zestawu pieczęci. Jeśli początkowy zestaw pieczęci pliku obejmuje F_SEAL_SEAL, to powoduje to efektywne ustawienie stałego i zablokowanego zestawu pieczęci.
- F_SEAL_SHRINK
- Jeśli ta pieczęć jest ustawiona, rozmiar przedmiotowego pliku nie może ulec zmniejszeniu. Dotyczy to open(2) ze znacznikiem O_TRUNC, jak również truncate(2) i ftruncate(2). Jeśli spróbuje się zmniejszyć zapieczętowany w ten sposób plik, wywołania te zawiodą z błędem EPERM. Zwiększenie rozmiaru pliku jest wciąż możliwe.
- F_SEAL_GROW
- Jeśli ta pieczęć jest ustawiona, rozmiar przedmiotowego pliku nie może ulec zwiększeniu. Dotyczy to zapisu za pomocą write(2) poza koniec pliku, truncate(2), ftruncate(2) oraz fallocate(2). Jeśli spróbuje się zwiększyć zapieczętowany w ten sposób plik, wywołania te zawiodą z błędem EPERM. Jeśli rozmiar pliku nie zmieni się lub ulegnie zmniejszeniu, opisywane wywołania będą działać zgodnie z oczekiwaniami.
- F_SEAL_WRITE
- Jeśli ta pieczęć jest ustawiona, nie można modyfikować zawartości pliku. Proszę zwrócić uwagę, że zmniejszenie lub zwiększenie rozmiaru pliku jest wciąż możliwe i dozwolone. Z tego względu, pieczęć ta jest zwykle używana w połączeniu z innymi pieczęciami. Pieczęć wpływa na write(2) i fallocate(2) (tylko w połączeniu ze znacznikiem FALLOC_FL_PUNCH_HOLE). Jeśli pieczęć jest ustawiona, wywołania te zawiodą z błędem EPERM. Co więcej, utworzenie nowego wspólnego, zapisywalnego przypisania pamięci za pomocą mmap(2) również zawiedzie z błędem EPERM.
- Użycie operacji F_ADD_SEALS do ustawienia pieczęci F_SEAL_WRITE zawiedzie z błędem EBUSY, jeśli istnieją zapisywalne, wspólne przypisania pamięci. Przed dodaniem tej pieczęci konieczne jest ich odmapowanie. Ponadto, jeśli wobec pliku istnieją jakieś oczekujące asynchroniczne operacje wejścia/wyjścia (io_submit(2)), to wszystkie pozostałe zapisy zostaną odrzucone.
- F_SEAL_FUTURE_WRITE (od Linuksa 5.1)
- Skutek zastosowania tej pieczęci jest podobny do F_SEAL_WRITE, lecz zawartość pliku można wciąż zmodyfikować za pomocą wspólnych, zapisywalnych przypisań pamięci, które utworzono przed ustawieniem pieczęci. Próba utworzenia nowego zapisywalnego przypisania na pliku za pomocą mmap(2), zawiedzie z błędem EPERM. Podobnie, próba zapisu do pliku za pomocą write(2) również zawiedzie z błędem EPERM.
- Korzystając z tej pieczęci, proces może utworzyć bufor pamięci, który będzie mógł wciąż modyfikować, dzieląc go jednocześnie na zasadzie „tylko do odczytu” z innymi procesami.
Wskazówki odczytu/zapisu pliku¶
Do poinformowania jądra o oczekiwanym, względnym czasie istnienia zapisów do danego i-węzła lub za pomocą opisu otwartego pliku (OFD; więcej informacji o opisach otwartego pliku w podręczniku open(2)) można użyć wskazówek czasu istnienia zapisu. W tym kontekście, pojęcie „czas istnienia zapisu” oznacza oczekiwany czas, jaki dane będą istniały na nośniku, przed ich nadpisaniem lub usunięciem.
Aplikacja może korzystać z różnych, podanych niżej, wartości wskazówek, aby podzielić zapisy na różne klasy zapisów, dzięki czemu wielu użytkowników lub aplikacji działających na stacji z pojedynczym nośnikiem może zbierać swoje wejścia/wyjścia w spójny sposób. Jednak znaczniki te nie udostępniają żadnego funkcjonalnego zachowania, a różne klasy wejścia/wyjścia mogą używać wskazówek o czasie trwania zapisu w arbitralny sposób dopóki tylko wskazówki są stosowane konsekwentnie.
Do deskryptora fd można zastosować następujące operacje:
- F_GET_RW_HINT (uint64_t *; od Linuksa 4.13)
- Zwraca wartość wskazówki odczytu/zapisu powiązanej z i-węzłem, do którego odnosi się fd.
- F_SET_RW_HINT (uint64_t *; od Linuksa 4.13)
- Ustawia wartość wskazówki odczytu/zapisu powiązanej z i-węzłem, do którego odnosi się fd. Wskazówka ta będzie istniała do momentu jej jawnej modyfikacji lub do momentu odmontowania przedmiotowego systemu plików.
- F_GET_FILE_RW_HINT (uint64_t *; od Linuksa 4.13)
- Zwraca wartość wskazówki odczytu/zapisu powiązanej z opisem otwartego pliku (OFD), do którego odnosi się fd.
- F_SET_FILE_RW_HINT (uint64_t *; od Linuksa 4.13)
- Ustawia wartość wskazówki odczytu/zapisu powiązanej z opisem otwartego pliku (OFD), do którego odnosi się fd.
Jeśli opisowi otwartego pliku nie przypisano wskazówki odczytu/zapisu, powinien on użyć wartości przypisanej i-węzłowi, jeśli taka istnieje.
Od Linuksa 4.13 prawidłowe są następujące wskazówki odczytu/zapisu:
- RWH_WRITE_LIFE_NOT_SET
- Nie ustawiono żadnej wskazówki. Jest to wartość domyślna.
- RWH_WRITE_LIFE_NONE
- Nie ustawiono wskazówki zapisu z danym plikiem lub i-węzłem.
- RWH_WRITE_LIFE_SHORT
- Oczekuje się, że dane zapisane do tego i-węzła lub za pomocą tego opisu otwartego pliku, będą istniały krótko.
- RWH_WRITE_LIFE_MEDIUM
- Oczekuje się, że dane zapisane do tego i-węzła lub za pomocą tego opisu otwartego pliku, będą istniały dłużej, niż dane zapisane ze wskazówką RWH_WRITE_LIFE_SHORT.
- RWH_WRITE_LIFE_LONG
- Oczekuje się, że dane zapisane do tego i-węzła lub za pomocą tego opisu otwartego pliku, będą istniały dłużej, niż dane zapisane ze wskazówką RWH_WRITE_LIFE_MEDIUM.
- RWH_WRITE_LIFE_EXTREME
- Oczekuje się, że dane zapisane do tego i-węzła lub za pomocą tego opisu otwartego pliku, będą istniały dłużej, niż dane zapisane ze wskazówką RWH_WRITE_LIFE_LONG.
Wszystkie wskazówki dotyczące zapisu są jedynie relatywne względem siebie i nie należy przypisywać im bezwzględnego znaczenia.
WARTOŚĆ ZWRACANA¶
Wartość zwracana po pomyślnym zakończeniu funkcji zależy od operacji:
- F_DUPFD
- Nowy deskryptor pliku.
- F_GETFD
- Wartość znaczników deskryptora pliku.
- F_GETFL
- Wartość znaczników stanu pliku
- F_GETLEASE
- Typ dzierżawy ustanowionej na deskryptorze pliku.
- F_GETOWN
- Wartość właściciela deskryptora pliku.
- F_GETSIG
- Wartość sygnału wysłanego, gdy odczyt lub zapis staną się możliwe, lub zero, dla tradycyjnego zachowania SIGIO.
- F_GETPIPE_SZ
- F_SETPIPE_SZ
- Pojemność potoku.
- F_GET_SEALS
- Mapa bitowa identyfikująca pieczęcie, które ustawiono dla i-węzła, do którego odnosi się fd.
- Wszystkie pozostałe operacje
- Zero.
W razie wystąpienia błędu zwracane jest -1 i ustawiane errno wskazując błąd.
BŁĘDY¶
- EACCES lub EAGAIN
- Operacja uniemożliwiona przez blokady utrzymywane przez inne procesy.
- EAGAIN
- Operacja jest zabroniona, gdyż plik został odwzorowany w pamięci przez inny proces.
- EBADF
- fd nie jest deskryptorem otwartego pliku.
- EBADF
- op wynosi F_SETLK lub F_SETLKW a tryb otwarcia deskryptora pliku nie odpowiada rodzajowi żądanej blokady.
- EBUSY
- op wynosi F_SETPIPE_SZ, a nowa pojemność potoku określona w arg jest mniejsza, niż przestrzeń bufora aktualnie zajęta do przechowywania danych w potoku.
- EBUSY
- op wynosi F_ADD_SEALS, arg zawiera F_SEAL_WRITE i istnieje zapisywalne, dzielone przypisanie pliku, do którego odnosi się fd.
- EDEADLK
- Stwierdzono, że podana operacja F_SETLKW spowodowałoby zakleszczenie blokad.
- EFAULT
- lock znajduje się poza dostępną dla użytkownika przestrzenią adresową.
- EINTR
- op wynosi F_SETLKW lub F_OFD_SETLKW i operacja została przerwana sygnałem; zob. signal(7).
- EINTR
- op wynosi F_GETLK, F_SETLK, F_OFD_GETLK lub F_OFD_SETLK, a operacja została przerwana przez sygnał, zanim blokada została sprawdzona lub ustawiona. Najbardziej prawdopodobne podczas blokowania zdalnego pliku (np. blokowanie przez NFS), ale czasami zdarza się lokalnie.
- EINVAL
- Wartość podana w op nie jest rozpoznawana przez to jądro.
- EINVAL
- op wynosi F_ADD_SEALS, a arg obejmuje nierozpoznany bit pieczęci.
- EINVAL
- op wynosi F_ADD_SEALS lub F_GET_SEALS, a system plików zawierający i-węzeł, do którego odnosi się fd, nie obsługuje pieczętowania.
- EINVAL
- op wynosi F_DUPFD, a arg jest ujemny lub większy od maksymalnej dozwolonej wartości (więcej informacji w opisie RLIMIT_NOFILE w podręczniku getrlimit(2)).
- EINVAL
- op wynosi F_SETSIG, a arg nie jest dozwolonym numerem sygnału.
- EINVAL
- op wynosi F_OFD_SETLK, F_OFD_SETLKW lub F_OFD_GETLK, a l_pid nie podano jako zero.
- EMFILE
- op wynosi F_DUPFD, a osiągnięto już maksymalną liczbę otwartych deskryptorów plików na proces.
- ENOLCK
- Zbyt wiele otwartych blokad segmentowych, tablica blokad jest pełna lub zawiódł protokół blokowania zdalnego (np. dla blokad przez NFS).
- ENOTDIR
- W op podano F_NOTIFY, lecz fd nie odnosi się do katalogu.
- EPERM
- op wynosi F_SETPIPE_SZ i osiągnięto miękki lub sztywny limit potoku; zob. pipe(7).
- EPERM
- Próbowano wyzerować znacznik O_APPEND na pliku posiadającym ustawiony atrybut „append-only”.
- EPERM
- op wynosiło F_ADD_SEALS, lecz fd nie był otwarty do zapisu albo bieżący zestaw pieczęci już obejmuje F_SEAL_SEAL.
STANDARDY¶
POSIX.1-2008.
F_GETOWN_EX, F_SETOWN_EX, F_SETPIPE_SZ, F_GETPIPE_SZ, F_GETSIG, F_SETSIG, F_NOTIFY, F_GETLEASE i F_SETLEASE są typowo linuksowe (należy zdefiniować makro _GNU_SOURCE aby pozyskać te definicje).
F_OFD_SETLK, F_OFD_SETLKW i F_OFD_GETLK są typowo linuksowe (i konieczne jest zdefiniowanie _GNU_SOURCE do pozyskania ich definicji), lecz trwają prace nad włączeniem ich do następnej wersji POSIX.1.
F_ADD_SEALS i F_GET_SEALS są typowo linuksowe.
HISTORIA¶
SVr4, 4.3BSD, POSIX.1-2001.
Jedynie operacje F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK, F_SETLK i F_SETLKW są określone w POSIX.1-2001.
F_GETOWN i F_SETOWN są określone w POSIX.1-2001 (do pozyskania ich definicji konieczne jest zdefiniowanie _XOPEN_SOURCE z wartością 500 lub większą albo _POSIX_C_SOURCE z wartością 200809L lub większą).
F_DUPFD_CLOEXEC jest określone w POSIX.1-2008 (do pozyskania jego definicji konieczne jest zdefiniowanie _POSIX_C_SOURCE z wartością 200809L lub większą albo _XOPEN_SOURCE z wartością 700 lub większą).
UWAGI¶
Błędy zwracane przez dup2(2) są inne niż zwracane przez F_DUPFD.
Blokowanie plików¶
Pierwotne linuksowe wywołanie systemowego fcntl() nie było zaprojektowane do obsługi dużych przesunięć plików (w strukturze flock). W konsekwencji, Linux 2.4 dodał wywołanie systemowe fcntl64(). Nowsze wywołanie systemowe korzysta z odmiennej struktury do blokowania plików, flock64 i odpowiadających operacji, F_GETLK64, F_SETLK64 i F_SETLKW64. Detale te mogą być jednak zignorowane przez aplikacje używające glibc, ponieważ jej funkcja opakowująca fcntl() obsługuje nowsze wywołanie systemowe, gdy tylko jest dostępne, w sposób przezroczysty.
Blokady rekordów¶
Od Linuksa 2.0, nie ma oddziaływania pomiędzy typami blokad zakładanych przez flock(2) i przez fcntl().
W niektórych systemach struktura struct flock zawiera dodatkowe pola, takie jak np. l_sysid (do identyfikacji komputera, na którym utrzymywana jest blokada). Oczywiście, samo l_pid jest mało przydatne, gdy proces utrzymujący blokadę może działać na innym komputerze; w Linuksie, choć pole to jest obecne na niektórych architekturach (np. MIPS32), to jednak nie jest używane.
Pierwotne linuksowe wywołanie systemowego fcntl() nie było zaprojektowane do obsługi dużych przesunięć plików (w strukturze flock). W konsekwencji, Linux 2.4 dodał wywołanie systemowe fcntl64(). Nowsze wywołanie systemowe korzysta z odmiennej struktury do blokowania plików, flock64 i odpowiadających operacji, F_GETLK64, F_SETLK64 i F_SETLKW64. Detale te mogą być jednak zignorowane przez aplikacje używające glibc, ponieważ jej funkcja opakowująca fcntl() obsługuje nowsze wywołanie systemowe, gdy tylko jest dostępne, w sposób przezroczysty.
Blokowanie rekordów i NFS¶
Przed Linuksem 3.12, jeśli klient NFSv4 utraci kontakt z serwerem na pewien czas (zdefiniowany jako ponad 90 sekund bez żadnej komunikacji), to może utracić i odzyskać blokadę bez uświadamiania sobie tego faktu (czas, po którym przyjmuje się utratę połączenia jest znany jako czas dzierżawy NFSv4 (leasetime); na serwerze NFS można go sprawdzić w pliku /proc/fs/nfsd/nfsv4leasetime, który podaje go w sekundach; domyślną wartością w pliku jest 90). Ten scenariusz grozi uszkodzeniem danych, ponieważ inny proces mógł w międzyczasie posiąść blokadę i dokonać operacji wejścia/wyjścia na pliku.
Od Linuksa 3.12, jeśli klient NFSv4 utraci połączenie z serwerem, każda operacja wejścia/wyjścia na pliku, przez proces który „sądzi”, że utrzymuje blokadę zawiedzie, dopóki ten proces nie zamknie i nie otworzy pliku ponownie. Można ustawić parametr jądra nfs.recover_lost_locks na 1, aby powrócić do zachowania sprzed wersji 3.12, gdy klient próbuje odzyskać zagubione blokady po odzyskaniu połączenia z serwerem. Ze względu na towarzyszące temu ryzyko uszkodzenia danych, domyślnie parametr ten wynosi 0 (jest wyłączony).
USTERKI¶
F_SETFL¶
Nie da się użyć F_SETFL do zmiany statusu znaczników O_DSYNC i O_SYNC. Takie próby zostaną po cichu zignorowane.
F_GETOWN¶
Ograniczenie konwencji linuksowego wywołania systemowego na niektórych architekturach (przede wszystkim i386) oznacza, że jeśli (ujemny) identyfikator grupy procesu mający być zwrócony przez F_GETOWN znajduje się w przedziale od -1 do -4095, to zwracana wartość jest przez glibc nieprawidłowo interpretowana jako błąd w wywołaniu systemowym; to jest zwrócona przez fcntl() wartość będzie wynosiła -1, a errno będzie zawierać (dodatni) identyfikator grupy procesu. Typowo linuksowa operacja F_GETOWN_EX unika tego problemu. Od glibc 2.11, glibc czyni problem jądra F_GETOWN niewidzialnym, przez zaimplementowanie F_GETOWN za pomocą F_GETOWN_EX.
F_SETOWN¶
W Linuksie 2.4 i wcześniejszych istnieje błąd, który może się ujawnić, gdy proces nieuprzywilejowany używa F_SETOWN do podania właściciela deskryptora pliku gniazda, będące procesem (grupą) inną niż wywołujący. W tym przypadku fcntl() może zwrócić -1 z errno ustawionym na EPERM nawet wówczas, gdy właściciel procesu (grupy) był tym, do którego wywołujący ma prawo wysyłania sygnałów. Pomimo zwracania błędu, własność deskryptora pliku jest ustawiana, a sygnały będą wysyłane do właściciela.
Wykrywanie zakleszczeń¶
Algorytm wykrywania zakleszczeń używany przez jądro przy przetwarzaniu żądań F_SETLKW może skutkować wykryciami zarówno fałszywie negatywnymi (niewykryciem zakleszczeń, pozostawiając zestaw zakleszczonych procesów stale zablokowanymi), jak i fałszywie pozytywnymi (błąd EDEADLK, gdy zakleszczenie nie występuje). Przykładowo, jądro ogranicza głębokość poszukiwania zależności blokad do 10 kroków co oznacza, że łańcuch kolistych zakleszczeń większy od tego rozmiaru nie zostanie wykryty. Dodatkowo, jądro może nieprawidłowo wskazywać zakleszczenie, gdy dwa lub więcej procesów utworzonych za pomocą znacznika CLONE_FILES z clone(2), wyglądają (dla jądra) na będące w konflikcie.
Blokowanie obowiązujące (przymusowe)¶
Linuksowa implementacja blokowania obowiązującego (przymusowego) jest podatna na sytuację wyścigu, co czyni ją nierzetelną: wywołanie write(2), które nachodzi na blokadę może zmodyfikować dane po uzyskaniu blokady, wywołanie read(2) które nachodzi na blokadę może wykryć zmianę danych, dokonaną jedynie po uzyskaniu blokady zapisu. Podobny wyścig istnieje pomiędzy blokadami obowiązującymi a mmap(2). Z tego powodu nie należy polegać na blokowaniu obowiązującym.
ZOBACZ TAKŻE¶
dup2(2), flock(2), open(2), socket(2), lockf(3), capabilities(7), feature_test_macros(7), lslocks(8)
locks.txt, mandatory-locking.txt i dnotify.txt w katalogu Documentation/filesystems/ źródeł jądra Linux (w starszych jądrach pliki te znajdują się bezpośrednio w katalogu Documentation/, a plik mandatory-locking.txt ma nazwę mandatory.txt)
TŁUMACZENIE¶
Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Przemek Borys <pborys@dione.ids.pl>, Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl> i Michał Kułach <michal.kulach@gmail.com>
Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać zapoznając się z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.
Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-list@lists.sourceforge.net.
2 maja 2024 r. | Linux man-pages (niewydane) |