web-dev-qa-db-ja.com

マウントポイントのiノードが変更された場合、Linuxバインドマウントが表示されなくなるのはなぜですか?

要約すると、新しいマウント名前空間の_/tmp/a_の上にファイル_/tmp/b_をバインドマウントした場合、親の名前空間で_/tmp/b_のiノードが変更されると、子名前空間。その理由を理解しようとしています。

mount(8)は、個別のファイル(ディレクトリのみ)をバインドする機能を公開していません。そのため、これを再現するには、必要なmount(2)syscallを発行できる追加の実行可能ファイルが必要です。簡単な例を次に示します(以下ではbmountと呼びます)。

_#include <sys/mount.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("requires exactly 2 args\n");
        return 1;
    }

    int err = mount(argv[1], argv[2], "none", MS_BIND, NULL);
    if (err == 0) {
        return 0;
    } else {
        printf("mount error (%d): %s\n", errno, strerror(errno));
        return 1;
    }
}
_

テストケースを設定します。

_# echo a > /tmp/a; echo b > /tmp/b; echo c > /tmp/c;
# ls -ldi /tmp/a /tmp/b /tmp/c
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a                                                               
11403422 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/c
_

今、別のシェルで:

_# unshare -m /bin/bash
# bmount /tmp/a /tmp/b
# ls -ldi /tmp/a /tmp/b /tmp/c
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/c
# cat /tmp/b
a
# grep "\/tmp\/" /proc/self/mounts
[redacted] /tmp/b ext4 rw,relatime,errors=remount-ro,data=ordered 0 0
_

元のシェルの場合:

_# mv /tmp/c /tmp/b
# ls -ldi /tmp/a /tmp/b /tmp/c
ls: cannot access '/tmp/c': No such file or directory                                                               
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a                                                               
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
_

unshareシェル内:

_# ls -ldi /tmp/a /tmp/b /tmp/c
ls: cannot access '/tmp/c': No such file or directory
11403315 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/a
11403452 -rw-r--r-- 1 root root 2 Jan 19 13:34 /tmp/b
# cat /tmp/b
c
# grep "\/tmp\/" /proc/self/mounts
#
_

バインドマウントがサイレントに消え、基になるファイルシステムの_/tmp/b_ファイルが名前空間内に表示されるようになりました。

ここでセマンティクスの変更を説明する lwn.netの記事 を見つけました:2013年以前は、マウントポイントでのmvコマンドのrename(2)EBUSYですが、動作が変更されて成功し、マウントが削除されました。関連するカーネルコミットは 8ed936b5671 のようです。

私が持っている質問は:

  1. Iノードの変更時にマウントが削除されるのはなぜですか?マウントポイントが単純なパスではなく、dentryによって識別される、マウントシステムの実装の詳細にすぎませんか?
  2. 名前空間外のファイルシステム操作によって上書きまたは削除できないという意味で、「マウントの脆弱性」が少ないバインドマウントを作成する方法はありますか?

これが実際に関連する1つのケースは、 ip-netns(8) ;です。 _ip netns exec_は、_/etc/netns/${NAMESPACE}/resolv.conf_の上に_/etc/resolv.conf_をバインドマウントすることで機能します。 _/etc/resolv.conf_のiノードがresolvconf(8)またはsystemd-resolvedによって変更された場合、更新された_/etc/resolv.conf_は名前空間内で実行されているプロセスに表示されます。

7

これがマウントの伝播です。 Linuxはデフォルトでそれを有効にしませんが、systemdは有効にします。マウントとアンマウントを新しい名前空間に反映させたくない場合は、次のようにできます。実行mount --make-rprivate / その中。。ナレーター:これはマウントの伝播ではありません。

Iノードの変更時にマウントが削除されるのはなぜですか?マウントポイントが単純なパスではなく、dentryによって識別される、マウントシステムの実装の詳細にすぎませんか?

あなたが期待できる唯一の違いはrm b; mv c bおよびmv c bは、どの時点でもbが存在しないことを確認することはできないということです。私はこれを意図的に設計または保守された機能として説明します...これが歴史的なマルチユーザーUnixシステムにどの程度当てはまるかはわかりませんが、確かに信頼されるようになりました。実行中のシステムでのソフトウェア更新をサポートします。

私は...考えることができます 「iノードの変更」と呼ばれるもののために実装されたもう1つの特定の機能 -これはしぶしぶ行われ、ファイルシステム固有です。

5
sourcejedi