Linuxでファイルの強制ロック(mandatory lock)をする方法です。
強制ロックとは
- アドバイザリロックとは異なり、Linux固有の機能。POSIXやUNIXにはない。
- ロックを掛けたプロセス以外からの、read()やwrite()をできなくする。
- race conditionが発生する可能性があったりして、ロックの信頼性は高くない。ロックと同時にreadやwriteが獲得されると、ロック中なのに読み書きできてしまうらしい。
強制ロックが有効になる環境を作る
強制ロックを有効にするには、2つの条件を満たす必要があります。
- ロックされるファイルは
-o mand
でマウントされたファイルシステムでないとならない。 - ロックされるファイルは、set-group-IDビットがOnで、group-executeビットがOffでないとならない。
mkdir dir
mount -t tmpfs -o mand,size=1m tmpfs ./dir
chmod g+s,g-x dir/lockfile
echo hello > dir/lockfile
強制ロックを発動する
強制ロックを発動するために、システムコールを呼び出すPythonスクリプトを作ります。
lock.py
#!/usr/bin/env python
import fcntl, os, time, sys
f = open(sys.argv[1], "r+")
fcntl.lockf(f, fcntl.LOCK_EX)
print(f.readlines())
time.sleep(10)
このlock.pyは、10秒間dir/lockfileを排他的強制ロックします。lock.pyを実行している10秒間の間に、他のプロセスからdir/lockfileを読み込もうとすると、pythonのプロセスが終了するまで待たされます。
# ロックする
./lock.py
# 別ターミナルで
cat dir/lockfile # 10秒程度待たされる
この10秒間に、lslocks
や/proc/locks
を確認すると、ロックが掛かっている事がわかります。
root@vagrant:~/dir# lslocks
COMMAND PID TYPE SIZE MODE M START END PATH
lvmetad 463 POSIX 4B WRITE 0 0 0 /run/lvmetad.pid
cron 866 FLOCK 4B WRITE 0 0 0 /run/crond.pid
atd 848 POSIX 4B WRITE 0 0 0 /run/atd.pid
lxcfs 849 POSIX 4B WRITE 0 0 0 /run/lxcfs.pid
iscsid 1135 POSIX 5B WRITE 0 0 0 /run/iscsid.pid
python 1818 POSIX 0B WRITE 1 0 0 /dev/pts/0
☝🏻ここ
root@vagrant:~/dir# cat /proc/locks
1: POSIX MANDATORY WRITE 1818 00:2c:3 0 EOF 👈🏻ここ
2: POSIX ADVISORY WRITE 1135 00:13:1503 0 EOF
3: POSIX ADVISORY WRITE 849 00:13:1498 0 EOF
4: POSIX ADVISORY WRITE 848 00:13:1487 0 EOF
5: FLOCK ADVISORY WRITE 866 00:13:1485 0 EOF
6: POSIX ADVISORY WRITE 463 00:13:1258 0 EOF