FCNTL(2) | Linux Programmer's Manual | FCNTL(2) |
fcntl - ファイルディスクリプターの操作を行う
#include <unistd.h> #include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
fcntl() は、オープンされたファイルディスクリプター fd に関して下記の操作を行う。操作は cmd によって決まる:
fcntl() はオプションとして第三引数をとることができる。 第三引数が必要 かどうかは cmd により決まる。必要な引数の型は cmd 名の後ろの括弧内で 指定されている (ほとんどの場合、必要な型は int であり、この引数を表すの に arg という名前を使っている)。引数が必要ない場合には void が指定さ れている。
下記のいくつかの操作は特定のバージョンの Linux カーネルでのみサポートされている。 ホストカーネルが特定の操作をサポートしているかを確認する推奨の方法は、 fcntl() を所望の cmd 値で呼び出し、 EINVAL で失敗するかを検査することである。 EINVAL が返った場合、カーネルがこの値を認識していないことを示す。
The following commands manipulate the flags associated with a file descriptor. Currently, only one such flag is defined: FD_CLOEXEC, the close-on-exec flag. If the FD_CLOEXEC bit is set, the file descriptor will automatically be closed during a successful execve(2). (If the execve(2) fails, the file descriptor is left open.) If the FD_CLOEXEC bit is not set, the file descriptor will remain open across an execve(2).
マルチスレッドプログラムでは、 fcntl() の F_SETFD を使って close-on-exec フラグを設定するのと同時に、 別のスレッドで execve(2) と fork(2) を実行することは、競合条件次第では、 そのファイルディスクリプターが子プロセスで実行されるプログラムに意図せず見えてしまうという危険性がある。 詳細とこの問題への対処法については open(2) の O_CLOEXEC フラグの議論を参照のこと。
オープンファイル記述 (open file description) には、 ファイル記述毎に設定される状態フラグがいくつかある。これらのフラグは open(2) によって初期化され、 fcntl(2) により変更することもできる。これらは、 (dup(2), fcntl(F_DUPFD), fork(2) などで) 複製されたファイルディスクリプター同士は 同じオープンファイル記述を参照する。 そのため、 同じファイル状態フラグが共有される。
ファイル状態フラグとその意味は open(2) で説明されている。
Linux は昔からある (「プロセスに関連付けられる」) UNIX のレコードロックを実装している。 このレコードロックは POSIX で標準化されている。 Linux 固有のより良い動作を行うロックについては、下記のオープンファイル記述ロックの議論を参照のこと。
F_SETLK, F_SETLKW, F_GETLK は、レコードロックの獲得/解放/テストのために使用する (レコードロックは、バイト範囲ロック、ファイルセグメントロック、ファイル領域ロックとも呼ばれる)。 三番目の引数 lock は、以下に示すフィールドを含む構造体へのポインターである (フィールドの順序は関係なく、構造体に他のフィールドがあってもよい)。
struct flock { ... short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* Starting offset for lock */ off_t l_len; /* Number of bytes to lock */ pid_t l_pid; /* PID of process blocking our lock (set by F_GETLK and F_OFD_GETLK) */ ... };
この構造体の l_whence, l_start, l_len フィールドで、ロックを行いたいバイト範囲を指定する。 ファイルの末尾より後ろのバイトをロックすることはできるが、 ファイルの先頭より前のバイトをロックすることはできない。
l_start はロックを行う領域の開始オフセットである。 その意味は l_whence により異なる: l_whence が SEEK_SET の場合はファイルの先頭からのオフセット、 l_whence が SEEK_CUR の場合は現在のファイルオフセットからのオフセット、 l_whence が SEEK_END の場合はファイルの末尾からのオフセットと解釈される。 後ろの2つの場合には、 ファイルの先頭より前にならない範囲で、 l_start に負の値を指定することができる。
l_len はロックしたいバイト数を示す。 l_len が正の場合、ロックされるバイト範囲は l_start 以上 l_start+l_len-1 以下となる。 l_len に 0 を指定した場合は特別な意味を持つ: l_whence and l_start で指定される位置からファイルの末尾までの全てのバイトをロックする (ファイルがどんなに大きくなったとしてもファイルの末尾までロックする)。
POSIX.1-2001 では、負の値の l_len をサポートする実装を認めている (必須ではない)。 l_len が負の場合、ロックされるバイト範囲は l_start+l_len 以上 l_start-1 以下となる。 この動作はカーネル 2.4.21 以降および 2.5.49 以降の Linux で サポートされている。
l_type フィールドは、ファイルに対して読み出しロック (F_RDLCK) と書き込みロック (F_WRLCK) のどちらを 設定するかを指定する。 ファイルのある領域に対して、読み出しロック (共有ロック) を保持できる プロセス数に制限はないが、書き込みロック (排他ロック) を保持できる のは一つのプロセスだけである。排他ロックを設定すると、(共有ロックか 排他ロックにかかわらず) 他のロックは何も設定できない。 一つのプロセスは、ファイルのある領域に対して一種類のロックしか保持できない。 新規のロックがロックが設定されている領域に対して適用されると、既存のロック は新規のロックの種別に変換される (新規のロックで指定されたバイト範囲が既存ロックの範囲と一致する場合以外では、 変換の過程で既存のロックの分割、縮小、結合が行われることがある)。
読み出しロックを適用するには、 fd は読み出し用にオープンされていなければならない。 書き込みロックを適用するには、 fd は書き込み用にオープンされていなければならない。 読み書き両方のロックを適用するには、読み書き両用で ファイルをオープンしなければならない。
F_SETLKW でロックを適用する際、 カーネルはデッドロックの検出を行う。 2 つ以上のプロセスが、 他のプロセスが保持するロックにより互いにブロックされるようなロック要求を行っているかを検査する。 例えば、 プロセス A があるファイルのバイト 100 に対して書き込みロックを保持していて、 プロセス B がバイト 200 に対して書き込みロックを保持しているとする。 各プロセスが F_SETLKW を使って他のプロセスによるすでにロックされているバイトをロックしようとすると、 デッドロック検出がない場合、 両方のプロセスが無限に停止することになる。 カーネルはこのようなデッドロックを検出すると、 停止していたロック要求の一つをエラー EDEADLK ですぐに失敗させる。 このエラーを受け取ったアプリケーションは、 必要なロックを再度獲得しようとする前に、 他のアプリケーションが実行できるように自分が保持するロックのいくつかを解放する必要がある。 3 つ以上のプロセスが関連する循環するデッドロックも検出される。 ただし、 カーネルのデッドロック検出アルゴリズムには制限がある点に注意すること。 「バグ」を参照。
レコードロックは F_UNLCK で明示的に削除されるだけでなく、 そのプロセスが終了した際には自動的に解放される。
レコードのロックは fork(2) で作成された子プロセスには継承されないが、 execve(2) の前後では保存される。
stdio(3) ではバッファーリングが行われるので、 stdio 関連の関数ではレコードのロックの使用は回避される; 代わりに read(2) や write(2) を使用すること。
上記で説明したレコードロックはプロセスと関連付けられる (以下で説明するオープンファイル記述ロックと異なる点である)。 そのため、 残念ながら以下のようなことが起こる。
オープンファイル記述ロックを使うとこれらの問題が解決できる。
Open file description locks are advisory byte-range locks whose operation is in most respects identical to the traditional record locks described above. This lock type is Linux-specific, and available since Linux 3.15. (There is a proposal with the Austin Group to include this lock type in the next revision of POSIX.1.) For an explanation of open file descriptions, see open(2).
2 つのロック種別の主な違いは、 昔からあるレコードロックはプロセスに関連付けられるのに対して、 オープンファイル記述ロックはロックが獲得されるオープンファイル記述に関連付けられる点である。 この動作は flock(2) で獲得されるロックによく似ている。 結果として (昔からあるアドバイザリーレコードロックと違い)、 オープンファイル記述ロックは fork(2) (や CLONE_FILES 付きの clone(2)) の前後で継承され、 ファイルのクローズ時に解放されるのではなく、 オープンファイル記述の最後のクローズ時にのみ自動的に解放される。
Conflicting lock combinations (i.e., a read lock and a write lock or two write locks) where one lock is an open file description lock and the other is a traditional record lock conflict even when they are acquired by the same process on the same file descriptor.
同じオープンファイル記述経由 (同じファイルディスクリプター経由や fork(2), dup(2), fcntl() F_DUPFD などで作成されたファイルディスクリプターの複製経由) で適用されたオープンファイル記述ロックは常に互換性がある。 つまり、 すでにロックされている領域に対して新しいロックが適用された場合、 既存のロックは新しいロック種別に変換される。 (上記で説明した通り、 このような変換の結果、 既存のロックの分割、 縮小、 結合が行われることがある。)
一方、 異なるオープンファイル記述経由で獲得されると、 オープンファイル記述ロックは互いに競合する。 したがって、 マルチスレッドプログラムのスレッドは、 各スレッドがそれぞれ自分で open(2) を実行し、 得られたファイルディスクリプター経由でロックを適用することで、 オープンファイル記述ロックを使って一つのファイル領域えのアクセスを同期させることができる。
昔からあるレコードロックの場合と同様、 fcntl() の第 3 引数 lock は flock 構造体へのポインターである。 昔からあるレコードロックと違い、 下記で説明するコマンドを使う際には、 この構造体のフィールド l_pid に 0 を設定しなければならない。
オープンファイル記述ロックで使用できるコマンドは、 昔からあるロックのコマンドと同じである。
現在の実装では、 オープンファイル記述ロクではデッドロックの検出は行われない。 (これがプロセスと関連付けられるレコードロックとは異なる点である。 プロセスと関連付けられるレコードロックではカーネルはデッドロックの検出を行う。)
Warning: the Linux implementation of mandatory locking is unreliable. See BUGS below. Because of these bugs, and the fact that the feature is believed to be little used, since Linux 4.5, mandatory locking has been made an optional feature, governed by a configuration option (CONFIG_MANDATORY_FILE_LOCKING). This is an initial step toward removing this feature completely.
デフォルトでは、 昔からある (プロセスに関連付けられる) レコードロックも、 オープンファイル記述のレコードロックも、 アドバイザリーロックである。 アドバイザリーロックに強制力はなく、協調して動作するプロセス間でのみ有効である。
両方のタイプのロックも強制ロックにすることもできる。 強制ロックは全てのプロセスに対して効果がある。 あるプロセスが互換性のない強制ロックが適用されたファイル領域に対して (read(2) や write(2) により) 互換性のないアクセスを実行しようとした場合、 アクセスの結果は そのファイルのオープンファイル記述で O_NONBLOCK フラグが有効になっているかにより決まる。 O_NONBLOCK フラグが有効になっていないときは、ロックが削除されるか、 ロックがアクセスと互換性のあるモードに変換されるまで、 システムコールは停止 (block) される。 O_NONBLOCK フラグが有効になっているときは、システムコールはエラー EAGAIN で失敗する。
強制ロックを使用するためには、ロック対象のファイルが含まれるファイルシステム と、ロック対象のファイル自身の両方について、強制ロックが有効になっていなけれ ばならない。ファイルシステムについて強制ロックを有効にするには、 mount(8) に "-o mand" オプションを渡すか、 mount(2) に MS_MANDLOCK フラグを指定する。ファイルについて強制ロックを有効にするには、 そのファイルのグループ実行許可 (group execute permission) を無効とし、 かつ set-group-ID 許可ビットを有効にする (chmod(1) と chmod(2) を参照)。
強制ロックは POSIX では規定されていない。 他のいくつかのシステムでも強制ロックはサポートされているが、 強制ロックをどのようにして有効にするかの詳細はシステムより異なる。
When an advisory lock is obtained on a networked filesystem such as NFS it is possible that the lock might get lost. This may happen due to administrative action on the server, or due to a network partition (i.e., loss of network connectivity with the server) which lasts long enough for the server to assume that the client is no longer functioning.
When the filesystem determines that a lock has been lost, future read(2) or write(2) requests may fail with the error EIO. This error will persist until the lock is removed or the file descriptor is closed. Since Linux 3.12, this happens at least for NFSv4 (including all minor versions).
Some versions of UNIX send a signal (SIGLOST) in this circumstance. Linux does not define this signal, and does not provide any asynchronous notification of lost locks.
F_GETOWN, F_SETOWN, F_GETOWN_EX, F_SETOWN_EX, F_GETSIG, F_SETSIG は、I/O が利用可能になったことを示すシグナルを管理するために使用される。
struct f_owner_ex { int type; pid_t pid; };
これらの機構を使用することで、ほとんどの場合で select(2) や poll(2) を使用せずに完全な非同期 I/O を実装することができる。
O_ASYNC の使用方法は BSD と Linux に特有である。 POSIX.1 で規定されている F_GETOWN と F_SETOWN の使用方法は、ソケットに対する SIGURG シグナルとの組み合わせだけである (POSIX は SIGIO シグナルは規定していない)。 F_GETOWN_EX, F_SETOWN_EX, F_GETSIG, F_SETSIG は Linux 固有である。POSIX には、同様のことを行うために、非同期 I/O と aio_sigevent 構造体がある。Linux では、GNU C ライブラリ (Glibc) の一部として これらも利用可能である。
(Linix 2.4 以降で利用可能) F_SETLEASE は、 fd が参照するオープンファイル記述に対して新しいリースを設定するのに使用される。 F_GETLEASE は、 fd が参照するオープンファイル記述に対して設定されている 現在のリースを取得するのに使用される。 ファイルのリースにより、 あるプロセス ("lease breaker") がそのファイルディスクリプターが参照 しているファイルに対して open(2) や truncate(2) を行おうとした際に、リースを保持しているプロセス ("lease holder") へ (シグナルの配送による) 通知が行われるという機構が提供される。
リースはオープンファイル記述に対して関連付けられる (open(2) 参照)。 つまり、 (fork(2) や dup(2) などにより作成された) ファイルディスクリプターの複製は同じリースを参照し、 複製も含めたどのファイルディスクリプターを使ってもこのリースを変更したり 解放したりできる。 また、これらのファイルディスクリプターのいずれかに対して F_UNLCK 操作が明示的に実行された場合や、すべてのファイルディスクリプターが 閉じられた場合にも、リースは解放される。
リースの取得は通常のファイル (regular file) に対してのみ可能である。 非特権プロセスがリースを取得できるのは、UID (所有者) がプロセスの ファイルシステム UID と一致するファイルに対してだけである。 CAP_LEASE ケーパビリティを持つプロセスは任意のファイルに対してリースを取得できる。
あるプロセス ("lease breaker") が F_SETLEASE で設定されたリースと矛 盾するような open(2) や truncate(2) を実行した場合、 そのシステム コールはカーネルによって停止され、 カーネルは lease holder にシグナル (デフォルトでは SIGIO) を送って通知を行う。 lease holder はこのシグ ナルを受信したときにはきちんと対応すべきである。 具体的には、別のプロセ スがそのファイルにアクセスするための準備として 必要な後片付け (例えば、 キャッシュされたバッファーのフラッシュ) を すべて行ってから、そのファイル のリースの削除または格下げを行う。リースを削除をするには、 arg に F_UNLCK を指定して F_SETLEASE を実行する。lease holder がファイル に書き込みリースを保持していて、 lease breaker が読み出し用にそのファイ ルをオープンしている場合、 lease holder が保持しているリースを読み出し リースに格下げすれば 十分である。これをするには、 arg に F_RDLCK を指定して F_SETLEASE を実行する。
If the lease holder fails to downgrade or remove the lease within the number of seconds specified in /proc/sys/fs/lease-break-time, then the kernel forcibly removes or downgrades the lease holder's lease.
いったん lease break が開始されると、 lease holder が自発的にそのリース の格下げか削除を行うか、lease break timer の満了後にカーネルが強制的に リースの格下げか削除を行うまで、 F_GETLEASE は対象となるリースの型を 返す (リースの型は F_RDLCK か F_UNLCK のどちらであり、lease breaker と互換性のある型となる)。
一度リースの削除か格下げが自発的もしくは強制的に行われると、 lease breaker がまだシステムコールを再開していない場合には、 カーネルが lease breaker のシステムコールの続行を許可する。
lease breaker が実行した open(2) や truncate(2) が停止中にシグナルハンドラーにより中断された場合、 そのシステムコールは EINTR エラーで失敗するが、上で述べた他の処理は そのまま行われる。 open(2) や truncate(2) が停止中に lease breaker がシグナルにより kill された場合、 上で述べた他の処理はそのまま行われる。 lease breaker が open(2) を呼ぶ際に O_NONBLOCK フラグを指定した場合、そのシステムコールは EWOULDBLOCK エラーで直ちに失敗するが、上で述べた他の処理はそのまま行われる。
lease holder への通知に使われるデフォルトのシグナルは SIGIO だが、 fcntl() の F_SETSIG コマンドで変更することができる。 F_SETSIG コマンドが実行され (SIGIO を指定された場合も含む)、 SA_SIGINFO フラグ付きでシグナルハンドラーが設定されている場合には、 ハンドラーの第二引数として siginfo_t 構造体が渡され、この引数の si_fd フィールドには別のプロセスがアクセスしたリース設定済みファイルのファイルディスクリプターが入っている (この機能は複数のファイルに対してリースを設定する場合に有用である)。
file seal は指定されたファイルで許可される操作の集合を制限する。 ファイルに設定される seal 毎に対応する操作の集合が規定されており、 それ以降のそのファイルに対する対応する操作は EPERM で失敗する。 このようなファイルは sealed (seal が適用されている) と呼ばれる。 デフォルトの seal の集合は、適用されるファイルやファイルシステムに依存する。 file seal の概要、 その目的、 サンプルコードについては memfd_create(2) を参照。
Currently, file seals can be applied only to a file descriptor returned by memfd_create(2) (if the MFD_ALLOW_SEALING was employed). On other filesystems, all fcntl() operations that operate on seals will return EINVAL.
seal は inode の属性である。 したがって、 同じ inode を参照するすべてのオープンされたファイルディスクリプターは、 同じ seal の集合を共有する。 さらに、 seal は削除することはできず、 追加のみ可能である。
以下の seal が利用できる。
Write lifetime hints can be used to inform the kernel about the relative expected lifetime of writes on a given inode or via a particular open file description. (See open(2) for an explanation of open file descriptions.) In this context, the term "write lifetime" means the expected time the data will live on media, before being overwritten or erased.
An application may use the different hint values specified below to separate writes into different write classes, so that multiple users or applications running on a single storage back-end can aggregate their I/O patterns in a consistent manner. However, there are no functional semantics implied by these flags, and different I/O classes can use the write lifetime hints in arbitrary ways, so long as the hints are used consistently.
The following operations can be applied to the file descriptor, fd:
If an open file description has not been assigned a read/write hint, then it shall use the value assigned to the inode, if any.
The following read/write hints are valid since Linux 4.13:
All the write-specific hints are relative to each other, and no individual absolute meaning should be attributed to them.
成功した場合の返り値は操作の種類により違う:
エラーの時は -1 が返され、 errno に適切な値が設定される。
SVr4, 4.3BSD, POSIX.1-2001. POSIX.1-2001 で規定されている操作は、 F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK, F_SETLK, F_SETLKW だけである。
F_GETOWN と F_SETOWN は POSIX.1-2001 で規定されている。 (これら定義するには、 _XOPEN_SOURCE を 500 以上の値で定義するか、 _POSIX_C_SOURCE を 200809L 以上の値で定義するか、 のいずれが必要である。)
F_DUPFD_CLOEXEC は POSIX.1-2008 で規定されている。 (これら定義するには、 _POSIX_C_SOURCE を 200809L 以上の値で定義するか、 _XOPEN_SOURCE を 700 以上の値で定義すること。)
F_GETOWN_EX, F_SETOWN_EX, F_SETPIPE_SZ, F_GETPIPE_SZ, F_GETSIG, F_SETSIG, F_NOTIFY, F_GETLEASE, F_SETLEASE は Linux 固有である (これらの定義を有効にするには _GNU_SOURCE マクロを定義すること)。
F_OFD_SETLK, F_OFD_SETLKW, F_OFD_GETLK は Linux 固有だが (これらの定義を得るには _GNU_SOURCE を定義しなければならない)、 POSIX.1 の次のバージョンに含めようという活動が進められている。
F_ADD_SEALS と F_GET_SEALS は Linux 固有である。
エラーの際の返り値が dup2(2) と F_DUPFD では異なっている。
元々の Linux の fcntl() システムコールは (flock 構造体で) 大きな ファイルオフセットを扱えるように設計されていなかった。 その結果、Linux 2.4 で fcntl64() システムコールが追加された。 この新しいシステムコールは、ファイルのロックに flock64 という別の 構造体を利用し、これに対応するコマンドとして F_GETLK64, F_SETLK64, F_SETLKW64 を使用する。 しかし、 glibc を使うアプリケーションではこれらの詳細を無視することが できる。 glibc の fcntl のラッパー関数は新しいシステムコールが 利用できる場合はそれを利用するようになっているからである。
カーネル 2.0 以降では、 flock(2) と fcntl() が設定するロック種別の間に相互作用はない。
Several systems have more fields in struct flock such as, for example, l_sysid (to identify the machine where the lock is held). Clearly, l_pid alone is not going to be very useful if the process holding the lock may live on a different machine; on Linux, while present on some architectures (such as MIPS32), this field is not used.
元々の Linux の fcntl() システムコールは (flock 構造体で) 大きな ファイルオフセットを扱えるように設計されていなかった。 その結果、Linux 2.4 で fcntl64() システムコールが追加された。 この新しいシステムコールは、ファイルのロックに flock64 という別の 構造体を利用し、これに対応するコマンドとして F_GETLK64, F_SETLK64, F_SETLKW64 を使用する。 しかし、 glibc を使うアプリケーションではこれらの詳細を無視することが できる。 glibc の fcntl のラッパー関数は新しいシステムコールが 利用できる場合はそれを利用するようになっているからである。
Linux 3.12 より前では、 NFSv4 クライアントが一定時間サーバーと通信がなかった場合 (90 秒間通信がない場合と定義されている)、 クライアントが気付かずにロックを失い再獲得する場合がある。 (通信がなくなったみなす時間は NFSv4 leastime と呼ばれる。 Linux NFS サーバーでは、 この値は /proc/fs/nfsd/nfsv4leasetime を見て決定される。 このファイルの値の単位は秒であり、 このファイルのデフォルト値は 90 である。) この状況では潜在的にデータ破壊が起こる危険性がある。 通信がなかった間に他のプロセスがロックを獲得しファイル入出力を行う場合があるからである。
Linux 3.12 以降、 NFSv4 クライアントがサーバーと通信がなかった場合、 ロックを持っていると「思っている」プロセスがそのファイルに入出力を行うと失敗する。 そのプロセスがそのファイルをいったんクローズし再オープンするまでは入出力は失敗する。 カーネルパラメーター nfs.recover_lost_locks を 1 に設定すると、 Linux 3.12 より前の動作にすることができる。 この場合、 サーバーとの通信が再確立された場合、 クライアントがは失われたロックを回復しようとする。 データ破壊が起こる危険性があるため、 このパラメーターはデフォルトでは 0 (無効) になっている。
F_SETFL を使って、 フラグ O_DSYNC と O_SYNC の状態を変更することはできない。これらのフラグの状態を変更しようとした場合には、黙って無視される。
いくつかのアーキテクチャー (特に i386) における Linux システムコールの慣習 のため以下の制限が存在する。 F_GETOWN が返す (負の) プロセスグループID が -1 から -4095 の範囲に入った場合、 glibc はこの返り値をシステムコールでエラーが起こったと間違って解釈してしまう。 つまり、 fcntl() の返り値は -1 となり、 errno には (正の) プロセスグループID が設定されることになる。Linux 固有の F_GETOWN_EX ではこの問題を回避できる。 glibc バージョン 2.11 以降では、glibc では F_GETOWN_EX を使って F_GETOWN を実装することで、カーネルの F_GETOWN の問題を見えないようにしている。
Linux 2.4 以前では、非特権プロセスが F_SETOWN を使って、ソケットのファイルディスクリプターの所有者に 呼び出し元以外のプロセス (やプロセスグループ) を指定すると 発生するバグがある。この場合、 呼び出し元が所有者として指定したプロセス (やプロセスグループ) に シグナルを送る許可を持っていたとしても、 fcntl() が -1 を返し errno に EPERM を設定することがある。 このエラーが返ったにもかかわらず、ファイルディスクリプターの所有者 は設定され、シグナルはその所有者に送られる。
F_SETLKW 要求を処理する際にカーネルが使用するデッドロック検出アルゴリズムは、 false negative になる場合 (デッドロックを検出できず、 デッドロックになったプロセスは無限に停止する) も false positive になる場合 (デッドロックがない場合でも EDEADLK エラーとなる) もある。 例えば、 カーネルは依存関係の検索を行うロックの深さを 10 ステップに限定しているが、 このためこれよりも長い循環するデッドロックは検出されない。 また、 clone(2) の CLONE_FILES フラグを使って作成された 2 つ以上のプロセスが (カーネルにとって) 衝突するように見えるロックを適用した場合、 カーネルはデッドロックを誤って検出する。
Linux の強制ロックの実装は、 競合条件下で強制ロックが不完全になるような場合がある。 ロックと重なって実行された write(2) の呼び出しは強制ロックが獲得された後にもデータを変更することができる。 ロックと重なって実行された read(2) の呼び出しは強制ロックが獲得された後になって行われたデータの変更を 検出することができる。 同様の競合条件が強制ロックと mmap(2) の間にも存在する。それゆえ、強制ロックに頼るのはお薦めできない。
dup2(2), flock(2), open(2), socket(2), lockf(3), capabilities(7), feature_test_macros(7), lslocks(8)
Linux カーネルソースの Documentation/filesystems/ ディレクトリ内の locks.txt, mandatory-locking.txt, dnotify.txt (以前のカーネルでは、これらのファイルは Documentation/ ディレクトリ直下にあり、 mandatory-locking.txt は mandatory.txt という名前であった)
この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。
2020-12-21 | Linux |