Posted at

cpとmvとinodeの話

More than 3 years have passed since last update.

実行中のファイルに対して、

cpで上書きする場合だと、Text file busyで置き換えられず、

mvだと何も聞かれず置き換えられます。

この挙動の違いについて、まとめと実験。

inodeを見ると、それとなく分かります。

https://ja.wikipedia.org/wiki/Inode

以下引用

リンクを全く持たない inode もありうる。

通常そのようなファイルはディスクから削除され、

そのリソース(ディスクブロック)はファイル削除処理の過程で

再利用のために解放されるが、何らかのプロセスが

そのファイルを使用中ならば、アクセスし続けることができ、

最後にクローズされるときに削除処理が行われる。

このため、プログラムを改版(リコンパイル)するときは、

以前の実行ファイルをまず削除して、新しい版の実行ファイルは

新たな inode で作成されるようにすることが推奨される。

これにより、古い版が実行中であっても何ら問題なく処理を続行することになる。

(訳注:削除しないで上書きすると、実行中の実行ファイルが書き換えられるため、

メモリ管理の実装によってはおかしな状態が発生する)。

引用終わり

つまり、

以下のファイルがあるとして。

・/sa/sbin/org_exec inode=100 inodeの中身=abc

・/sa/sbin/new_exec inode=200 inodeの中身=123

cp /sa/sbin/new_exec /sa/sbin/org_exec

とした場合、inode=100の内容を、

inode=200の内容で上書きするので、

以下のようになる。

・/sa/sbin/org_exec inode=100 inodeの中身=123

・/sa/sbin/new_exec inode=200 inodeの中身=123

org_execを使っている人は、突然abcが123になって、

なんぞ?っとなる。そしてcpコマンドは、こうなるとまずいので、

Text file busyを出して、失敗にする。

mv /sa/sbin/new_exec /sa/sbin/org_exec

とした場合、/sa/sbin/org_exec inode=200となり、

inode=100は、何もファイルパスを指さない状態となるだけになる。

・ファイルパスは無い inode=100 inodeの中身=abc

・/sa/sbin/org_exec inode=200 inodeの中身=123

・/sa/sbin/new_execは無くなった状態になる(org_execにmvしているので)

inode=100はファイルパスはなくなるが、inodeの中身は変わっていないので、

現状誰かが使用していたとしても、問題なくabc、という中身を見ることができる。

なので、実行中のファイルに、別のファイルをmvしても問題ないので、

mvは成功する。

そして、inode=100の内容は、それを使っているプロセスが

ファイルをクローズすれば再利用可能な状態に戻る。

以下、実際にやってみた結果。

cpだとエラーがでて失敗し、

mvは成功している。

mvはinodeの内容自体は変えず、

inodeとファイルパスの関連を変えているだけ、

というのが分かるはず。

そしてmvした後も、a.exeは動き続けている。

ただしこれは、mvする前の状態のa.exeである点に

注意が必要。

[root@localhost ~]#

[root@localhost ~]# stat a.exe

File: a.exe'

Size: 6777 Blocks: 16 IO Block: 4096 regular file

Device: 802h/2050d Inode: 790530 Links: 1

Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)

Access: 2015-09-09 13:14:19.642295609 +0900

Modify: 2015-09-09 13:14:18.178283786 +0900

Change: 2015-09-09 13:14:18.178283786 +0900

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]# stat b.exe

File:
b.exe'

Size: 6800 Blocks: 16 IO Block: 4096 regular file

Device: 802h/2050d Inode: 790537 Links: 1

Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)

Access: 2015-09-09 13:16:20.022259845 +0900

Modify: 2015-09-09 13:16:17.200237245 +0900

Change: 2015-09-09 13:16:17.200237245 +0900

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]# ./a.exe &

[1] 21205

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]# cp b.exe a.exe

cp: overwrite a.exe'? y

cp: cannot create regular file
a.exe': Text file busy

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]# mv b.exe a.exe

mv: overwrite a.exe'? y

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]# stat a.exe

File:
a.exe'

Size: 6800 Blocks: 16 IO Block: 4096 regular file

Device: 802h/2050d Inode: 790537 Links: 1

Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)

Access: 2015-09-09 13:16:20.022259845 +0900

Modify: 2015-09-09 13:16:17.200237245 +0900

Change: 2015-09-09 13:17:12.565688924 +0900

[root@localhost ~]#

[root@localhost ~]#

[root@localhost ~]# ps aux | grep a.exe

root 21205 0.0 0.0 11736 828 pts/0 S 13:16 0:00 ./a.exe

root 31922 0.0 0.0 103304 884 pts/0 S+ 13:54 0:00 grep a.exe

間違い等あれば、指摘ください。。