Record lock POSIX tradisional memiliki sifat yang dapat menimbulkan efek tak terduga pada kode dengan beberapa descriptor untuk file yang sama: kepemilikan lock terkait dengan proses, dan penutupan descriptor untuk file tersebut dapat melepas lock milik proses. Open file description lock di Linux memindahkan batas kepemilikan itu ke open file description kernel yang dirujuk descriptor.
Antarmukanya tetap memakai fcntl() dan struct flock, tetapi identitas pemiliknya berubah. F_OFD_SETLK, F_OFD_SETLKW, dan F_OFD_GETLK membuat byte-range lock mengikuti open file description, bukan identitas proses.
Pemilik lock berada di belakang descriptor
File descriptor adalah integer pada tabel descriptor proses. Nilai itu merujuk ke open file description yang menyimpan state untuk satu instance file yang dibuka. dup(), dup2(), F_DUPFD, serta descriptor yang diwariskan melalui fork() dapat merujuk ke open file description yang sama.
OFD lock terkait dengan objek bersama tersebut. Duplikasi descriptor tidak membentuk pemilik lock kedua.
fd 4 ----\
-> open file description A -> inode
fd 9 ----/ |
+-> OFD byte-range lockPemanggilan open() terpisah pada pathname yang sama biasanya membentuk open file description lain:
fd 4 -> open file description A -> inode
fd 7 -> open file description B -> inodeOFD lock melalui A dan B dapat berkonflik meskipun kedua descriptor berada dalam proses yang sama. Model ini dapat dipakai antar-thread ketika setiap thread membuka file secara independen.
Menutup satu duplicate tidak melepas lock bersama
Pada OFD lock, pelepasan otomatis terjadi saat descriptor terakhir yang merujuk open file description terkait ditutup. Jika fd_a diduplikasi menjadi fd_b, penutupan fd_a saja masih menyisakan referensi melalui fd_b, sehingga OFD lock tetap aktif.
Perilaku ini berbeda dari record lock berbasis proses melalui F_SETLK. Di Linux, penutupan descriptor mana pun untuk file yang sama pada proses tersebut dapat menghapus lock berbasis proses, termasuk lock yang dibuat melalui descriptor lain.
Aturan OFD menyelaraskan masa hidup lock dengan masa hidup open file description:
open -> fd 4 -> OFD A -> lock aktif
dup -> fd 9 -> OFD A -> lock aktif
close(fd 4) -> OFD A -> lock aktif
close(fd 9) -> OFD A dihancurkan -> lock dilepasPenerapan F_UNLCK secara eksplisit dapat melepas range lebih awal.
fork mempertahankan relasi kepemilikan
Sesudah fork(), descriptor yang diwarisi child merujuk ke open file description yang sama dengan descriptor terkait di parent. OFD lock tetap melekat pada description bersama tersebut melintasi batas fork().
Hal ini bukan salinan lock independen yang dimiliki child. Descriptor parent dan child yang mengarah ke open file description yang sama beroperasi pada pemilik OFD lock yang sama. Perubahan lock melalui salah satu descriptor tersebut memengaruhi state lock pada description itu.
Record lock tradisional berbasis proses memakai model kepemilikan berbeda dan tidak diwariskan sebagai lock baru milik child.
Semantik range tetap berasal dari struct flock
Perubahan kepemilikan tidak menghapus semantik byte-range. Request tetap memakai field struct flock seperti l_type, l_whence, l_start, dan l_len.
#define _GNU_SOURCE
#include <fcntl.h>
#include <string.h>
struct flock lock;
memset(&lock, 0, sizeof(lock));
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 4096;
lock.l_len = 4096;
lock.l_pid = 0;
int rc = fcntl(fd, F_OFD_SETLK, &lock);Untuk operasi OFD lock, l_pid harus bernilai nol. F_OFD_SETLK bersifat nonblocking dan gagal dengan EAGAIN jika lock yang tidak kompatibel menghalangi akuisisi. F_OFD_SETLKW menunggu lock yang berkonflik dilepas dan dapat menghasilkan EINTR jika penantian terinterupsi oleh sinyal yang ditangkap.
Read lock mengizinkan read lock kompatibel pada region yang sama, sedangkan write lock berkonflik dengan read atau write lock yang overlap dan dimiliki melalui pemilik lock lain yang berkonflik.
Descriptor duplicate kompatibel dengan dirinya sendiri
Request melalui descriptor yang merujuk open file description yang sama dianggap berasal dari satu pemilik. Request yang overlap dapat mengubah state lock yang ada alih-alih berkonflik dengan dirinya sendiri. Range yang dihasilkan dapat terpecah, menyusut, atau bergabung ketika tipe dan range lock berubah.
Sifat ini berbeda dari dua pemanggilan open() terpisah. Open file description yang berbeda dapat saling berkontensi, termasuk ketika keduanya dipegang thread berbeda dalam satu proses.
Batas concurrency utamanya adalah:
dup(existing_fd) -> identitas OFD bersama
open(path, ...) -> identitas OFD baruPilihan di antara kedua operasi itu dapat menentukan apakah dua konteks eksekusi berbagi satu pemilik lock atau dapat saling memblokir.
OFD dan record lock tradisional tetap berinteraksi
OFD lock tidak berada pada namespace terpisah dari record lock POSIX tradisional. OFD lock dan record lock tradisional yang tidak kompatibel pada region file yang sama akan berkonflik, bahkan ketika request berasal dari proses dan descriptor yang sama.
Kode tidak dapat memperlakukan F_OFD_SETLK dan F_SETLK sebagai dua sistem koordinasi independen pada range yang sama. Penggunaan campuran perlu memperhitungkan konflik lintas tipe serta perbedaan aturan kepemilikan dan pelepasannya.
flock() merupakan antarmuka locking lain dengan pertimbangan platform dan filesystem tersendiri. Kemiripan konsep kepemilikan tidak membuat API tersebut dapat dipertukarkan.
Blocking OFD lock tidak memiliki deteksi deadlock
Linux tidak melakukan deteksi deadlock untuk OFD lock. Request blocking F_OFD_SETLKW dapat masuk ke siklus lock tanpa laporan kernel melalui mekanisme deteksi deadlock yang tersedia pada record lock tradisional berbasis proses.
Aplikasi yang memakai beberapa byte range atau beberapa file memerlukan kebijakan urutan lock jika cyclic wait mungkin terjadi. Model kepemilikan OFD menyelesaikan persoalan masa hidup descriptor; model tersebut tidak menyediakan analisis dependensi global untuk akuisisi lock yang blocking.
Batas pentingnya adalah identitas masa hidup
OFD lock paling relevan ketika identitas proses terlalu kasar untuk masa hidup kepemilikan yang dibutuhkan. Descriptor hasil duplikasi atau warisan dapat sengaja berbagi satu pemilik lock, sedangkan descriptor dari open() independen dapat menjadi pemilik lain di dalam proses yang sama.
Dengan demikian, topologi descriptor menjadi bagian dari desain locking. Hal yang menentukan bukan sekadar integer descriptor yang memanggil fcntl(), melainkan open file description yang dicapai descriptor tersebut dan berapa lama referensi ke description itu tetap hidup.