web-dev-qa-db-ja.com

マウントがバインドマウントの読み取り専用オプションを尊重しないのはなぜですか?

Arch Linuxシステム(Linuxカーネル3.14.2)で、バインドマウントが読み取り専用オプションを考慮しません

# mkdir test
# mount --bind -o ro test/ /mnt
# touch /mnt/foo

ファイル/mnt/fooを作成します。 /proc/mountsの関連エントリは

/dev/sda2 /mnt ext4 rw,noatime,data=ordered 0 0

マウントオプションは、要求されたオプションとは一致しませんが、バインドマウントの読み取り/書き込み動作と、/dev/sda2を最初にマウントするために使用されたオプションの両方に一致します/

/dev/sda2 / ext4 rw,noatime,data=ordered 0 0

ただし、マウントを再マウントすると、読み取り専用オプションが考慮されます

# mount --bind -o remount,ro test/ /mnt
# touch /mnt/bar
touch: cannot touch ‘/mnt/bar’: Read-only file system

および/proc/mounts/の関連エントリ

/dev/sda2 /mnt ext4 ro,relatime,data=ordered 0 0

私が期待するように見えます(実際にはtestディレクトリの完全なパスが表示されることを期待しています)。 /proc/mounts/上の/dev/sda2/の元のマウントの/のエントリも変更されず、読み取り/書き込みのままです

/dev/sda2 / ext4 rw,noatime,data=ordered 0 0

この動作と回避策は、少なくとも 2008 から既知であり、mountのマニュアルページに記載されています。

ファイルシステムのマウントオプションは元のマウントポイントのオプションと同じままであり、-oオプションを--bind /-rbindと一緒に渡して変更することはできません。マウントオプションは、別のremountコマンドで変更できます。

すべてのディストリビューションが同じように動作するわけではありません。バインドマウントがマウントを読み取り専用にしない場合、Debianは警告を生成しますが、Archは暗黙のうちにオプションを尊重しません。

mount: warning: /mnt seems to be mounted read-write.

この動作はDebian Lenny and Squeeze で「修正」されたとの報告がありますが、 ユニバーサルフィックス ではないようであり、Debian Wheezyでも動作しません。バインドマウントで初期マウントの読み取り専用オプションを尊重することの難しさは何ですか?

36
StrongBad

バインドマウントは、まさに...バインドマウントです。つまり新しいマウントではありません。新しいマウントポイントとしてサブディレクトリを「リンク」/「公開」/「検討」するだけです。そのため、マウントパラメータを変更することはできません。それがあなたが不満を得ている理由です:

# mount /mnt/1/lala /mnt/2 -o bind,ro
mount: warning: /mnt/2 seems to be mounted read-write.

しかし、あなたが言ったように、通常のバインドマウントは機能します:

# mount /mnt/1/lala /mnt/2 -o bind

そしてro remountも機能します:

# mount /mnt/1/lala /mnt/2 -o bind,remount,ro 

ただし、このバインドマウントだけでなく、マウント全体を変更することになります。/proc/mountsを見ると、バインドマウントと元のマウントの両方が読み取り専用に変更されていることがわかります。

/dev/loop0 /mnt/1 ext2 ro,relatime,errors=continue,user_xattr,acl 0 0
/dev/loop0 /mnt/2 ext2 ro,relatime,errors=continue,user_xattr,acl 0 0

つまり、あなたがしていることは、最初のマウントを読み取り専用マウントに変更し、その後バインドマウントを実行するようなもので、もちろん読み取り専用になります。

更新2016-07-20:

以下は、4.5カーネルには当てはまりますが、4.3カーネルには当てはまりません(これは誤りです。以下の更新#2を参照してください)。

カーネルには、読み取り専用を制御する2つのフラグがあります。

  • MS_READONLY:マウントが読み取り専用かどうかを示します
  • MNT_READONLY:「ユーザー」が読み取り専用かどうかを示します

4.5カーネルでは、実際にmount -o bind,roを実行するとうまくいきます。たとえば、これ:

# mkdir /tmp/test
# mkdir /tmp/test/a /tmp/test/b
# mount -t tmpfs none /tmp/test/a
# mkdir /tmp/test/a/d
# mount -o bind,ro /tmp/test/a/d /tmp/test/b

/tmp/test/a/dから/tmp/test/bへの読み取り専用バインドマウントが作成され、/proc/mountsで次のように表示されます。

none /tmp/test/a tmpfs rw,relatime 0 0
none /tmp/test/b tmpfs ro,relatime 0 0

より詳細なビューは/proc/self/mountinfoにあり、ユーザービュー(名前空間)を考慮しています。関連する行は次のとおりです。

363 74 0:49 / /tmp/test/a rw,relatime shared:273 - tmpfs none rw
368 74 0:49 /d /tmp/test/b ro,relatime shared:273 - tmpfs none rw

2行目には、roMNT_READONLY)とrw!MS_READONLY)の両方が表示されていることがわかります。

最終結果はこれです:

# echo a > /tmp/test/a/d/f
# echo a > /tmp/test/b/f
-su: /tmp/test/b/f: Read-only file system

UPDATE 2016-07-20#2:

これをもう少し掘り下げると、実際の動作はutil-linuxの一部であるlibmountのバージョンに依存することがわかります。これのサポートはthis commit で追加され、バージョン2.27でリリースされました。

 commit 9ac77b8a78452eab0612523d27fee52159f5016a 
作成者:Karel Zak 
日付:月8月17日11:54:26 2015 +0200 
 
 libmount:「 bind、ro "
 
これで、2つのmount(8)呼び出しを使用して、読み取り専用の
マウントを作成する必要があります:
 
 mount/foo/bar -o bind 
 mount/bar -o remount、ro、bind 
 
このパッチでは、「bind、ro」を指定して再マウントを行うことができます
追加のmount(2)syscallによってlibmountによって自動的に。もちろん、アトミックではありません。
アトミックではありません。

これも回避策を提供します。この動作は、古いマウントと新しいマウントでstraceを使用して確認できます。

古い:

mount("/tmp/test/a/d", "/tmp/test/b", 0x222e240, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.000681>

新着:

mount("/tmp/test/a/d", "/tmp/test/b", 0x1a8ee90, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.011492>
mount("none", "/tmp/test/b", NULL, MS_RDONLY|MS_REMOUNT|MS_BIND, NULL) = 0 <0.006281>

結論:

望ましい結果を得るには、2つのコマンドを実行する必要があります(@Thomasがすでに言ったように)。

mount SRC DST -o bind
mount DST -o remount,ro,bind

新しいバージョンのマウント(util-linux> = 2.27)を実行すると、これが自動的に行われます

mount SRC DST -o bind,ro
23
V13

適切な解決策は、実際に2回マウントすることです。コマンドラインで:

mount -t none -o bind /source/dir /destination/dir
mount -t none -o bind,remount,ro /source/dir /destination/dir

/etc/fstab

/source/dir            /destination/dir    none  bind            0 0
/source/dir            /destination/dir    none  remount,bind,ro 0 0

マニュアル(man mount)はそのように述べています:

   The bind mounts.
          Since Linux 2.4.0 it is possible to remount part of the file hierarchy somewhere else. The call is
                 mount --bind olddir newdir
   [...]
          Note that the filesystem mount options will remain the same as those on the original mount point, and cannot be changed  by  passing  the  -o  option
          along with --bind/--rbind. The mount options can be changed by a separate remount command, for example:
          .
                 mount --bind olddir newdir
                 mount -o remount,ro newdir
          .
          Note  that  behavior  of  the remount operation depends on the /etc/mtab file. The first command stores the 'bind' flag to the /etc/mtab file and the
          second command reads the flag from the file.  If you have a system without the /etc/mtab file or if you explicitly define source and target  for  the
          remount command (then mount(8) does not read /etc/mtab), then you have to use bind flag (or option) for the remount command too. For example:
          .
                 mount --bind olddir newdir
                 mount -o remount,ro,bind olddir newdir
9
Thomas

mount(8)コマンドライン(このサイトでは許容可能)の観点から質問しています。そのコマンドは他の回答で説明されており、場合によっては、必要な2番目のmount(2)システムコールを抽象化しています。

しかし、なぜ2番目のシステムコールが必要なのでしょうか。単一のmount(2)呼び出しで読み取り専用バインドマウントを作成できないのはなぜですか?

mount(2)のマニュアルページ は、他の人が指摘したように、2つのセットのフラグがあることを説明しています設定中:

  • 基礎となるファイルシステムフラグ
  • VFSマウントポイントフラグ

それは言う:

Linux 2.6.16以降、_MS_RDONLY_は、基になるファイルシステムだけでなく、マウントポイントごとに設定またはクリアできます。マウントされたファイルシステムは、ファイルシステムもマウントポイントも読み取り専用としてフラグが立てられていない場合にのみ書き込み可能になります。

そして_MS_REMOUNT_に関して:

Linux 2.6.26以降、このフラグを_MS_BIND_とともに使用して、マウントポイントごとのフラグのみを変更できます。これは、基礎となるファイルシステムを変更せずにマウントポイントの「読み取り専用」フラグを設定またはクリアする場合に特に便利です。マウントフラグを次のように指定します。

_      MS_REMOUNT | MS_BIND | MS_RDONLY
_

他のマウントポイントに影響を与えることなく、このマウントポイントを介して読み取り専用でアクセスします。

この問題は、バインドマウントが最初に導入されたときに発生したと思います。

Mountflagsに_MS_BIND_(Linux 2.4以降で使用可能)が含まれている場合は、バインドマウントを実行します。 ... _MS_REC_を除いて、mountflags引数の残りのビットも無視されます。 (バインドマウントには、基礎となるマウントポイントと同じマウントオプションがあります。)

_MS_BIND | MS_REMOUNT_をVFSフラグのみを設定する信号として使用する代わりに、_MS_RDONLY_を最初の_MS_BIND_とともに除外(および受け入れる)して、それを適用することを選択できたようですマウントポイントに。

したがって、mount(2)システムコールのやや奇妙なセマンティクスのため、次のようになります。

  • 最初の呼び出しはバインドマウントを作成し、他のすべてのフラグは無視されます
  • 2番目の呼び出し(再マウントあり)は、mount-pointフラグを読み取り専用に設定します
1