マウントされたファイルバインディングが失敗し、リンクをキャンセルした後にENOENTが表示されるのはなぜですか?

マウントされたファイルバインディングが失敗し、リンクをキャンセルした後にENOENTが表示されるのはなぜですか?

リンクを解除した後にマウントをバインドするときにENOENTが発生する理由を理解できません。

kduda@penguin:/tmp$ echo hello > a
kduda@penguin:/tmp$ touch b c
kduda@penguin:/tmp$ sudo unshare -m
root@penguin:/tmp# mount -B a b
root@penguin:/tmp# rm a
root@penguin:/tmp# cat b
hello
root@penguin:/tmp# mount -B b c
mount: mount(2) failed: No such file or directory

これは私にとってバグのようです。同じinodeを指す「a」を再生成することもできますが、同じ結果が得られます。

kduda@penguin:/tmp$ echo hello > a
kduda@penguin:/tmp$ ln a a-save
kduda@penguin:/tmp$ sudo unshare -m
root@penguin:/tmp# mount -B a b
root@penguin:/tmp# rm a
root@penguin:/tmp# ln a-save a
root@penguin:/tmp# mount -B b c
mount: mount(2) failed: No such file or directory

世界に何が起こっていますか?

ベストアンサー1

システムmount(2)コールはマウントリンクとシンボリックリンクを介してパスを完全にチェックしますが、それとは異なり、削除されたファイルへのパス、つまりリンクされてopen(2)いないディレクトリエントリをチェックするパスは許可されません。

<filename> (deleted)(パスと同様に、/proc/PID/fd/FDprocfsは接続されていないディレクトリを次のように表示します。<filename>//deleted存在する/proc/PID/mountinfo

# unshare -m
# echo foo > foo; touch bar baz quux
# mount -B foo bar
# mount -B bar baz
# grep foo /proc/self/mountinfo
56 38 8:7 /tmp/foo /tmp/bar ...
57 38 8:7 /tmp/foo /tmp/baz ...

# rm foo
# grep foo /proc/self/mountinfo
56 38 8:7 /tmp/foo//deleted /tmp/bar ...
57 38 8:7 /tmp/foo//deleted /tmp/baz ...
# mount -B baz quux
mount: mount(2) failed: /tmp/quux: No such file or directory

これらの機能はすべて以前のカーネルで動作しましたが、v4.19以降は動作しなくなりました。この変化:

commit 1064f874abc0d05eeed8993815f584d847b72486
Author: Eric W. Biederman <[email protected]>
Date:   Fri Jan 20 18:28:35 2017 +1300

    mnt: Tuck mounts under others instead of creating shadow/side mounts.
...
+       /* Preallocate a mountpoint in case the new mounts need
+        * to be tucked under other mounts.
+        */
+       smp = get_mountpoint(source_mnt->mnt.mnt_root);
+       if (IS_ERR(smp))
+               return PTR_ERR(smp);
+

この効果が意図したすべてを変えないようです。その他関連のない事項多様性山が積み重なり、さらに混乱します。

これの結果は、削除されたファイルが開かれたfdを介して名前空間の他の場所に固定されるのを防ぎます。

# exec 7>foo; touch bar
# rm foo
# mount -B /proc/self/fd/7 bar
mount: mount(2) failed: /tmp/bar: No such file or directory

OPと同じ状況のため、最後のコマンドが失敗しました。

まったく同じ inode を指して再生成することもできますが、a同じ結果が得られます。

これは「シンボリックリンク」と同じです/proc/PID/fd/FD。カーネルは、ln+ rmlink(2)+ unlink(2))ではなく直接名前を変更してファイルを追跡するのに十分スマートです。

# unshare -m
# echo foo > foo; touch bar baz
# mount -B foo bar
# mount -B bar baz
# grep foo /proc/self/mountinfo
56 38 8:7 /tmp/foo /tmp/bar ...
57 38 8:7 /tmp/foo /tmp/baz ...

# mv foo quux
# grep bar /proc/self/mountinfo
56 38 8:7 /tmp/quux /tmp/bar ...

# ln quux foo; rm quux
# grep bar /proc/self/mountinfo
56 38 8:7 /tmp/quux//deleted /tmp/bar ...

おすすめ記事