Mengapa mount tidak menghormati opsi read only untuk bind mounts?

35

Pada sistem Arch Linux saya (Linux Kernel 3.14.2) bind mount tidak menghormati opsi read only

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

membuat file /mnt/foo. Entri yang relevan /proc/mountsadalah

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

Mount pilihan tidak cocok pilihan saya diminta, tetapi melakukan mencocokkan kedua perilaku membaca / menulis dari mengikat mount dan opsi yang digunakan untuk awalnya me-mount /dev/sda2pada/

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

Namun, jika saya memasang kembali mount maka itu menghormati opsi read only

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

dan entri yang relevan di /proc/mounts/

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

sepertinya apa yang saya harapkan (walaupun sebenarnya saya akan berharap untuk melihat path lengkap dari testdirektori). Entri /proc/mounts/untuk mount orignal /dev/sda2/on /juga tidak berubah dan tetap baca / tulis

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

Perilaku ini dan pekerjaannya telah diketahui setidaknya sejak 2008 dan didokumentasikan di halaman manualmount

Perhatikan bahwa opsi pemasangan sistem berkas akan tetap sama dengan yang ada di titik pemasangan asli, dan tidak dapat diubah dengan melewatkan opsi -o bersama dengan --bind / - rbind. Opsi pemasangan dapat diubah dengan perintah remount terpisah

Tidak semua distribusi berperilaku sama. Arch tampaknya diam-diam gagal menghargai opsi sementara Debian menghasilkan peringatan ketika bind mount tidak mendapatkan mount read-only

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

Ada laporan bahwa perilaku ini "diperbaiki" di Debian Lenny dan Squeeze meskipun tampaknya tidak menjadi perbaikan universal juga tidak bekerja di Debian Wheezy. Apa yang paling sulit dikaitkan dengan membuat bind mount menghormati opsi read only pada mount awal?

StrongBad
sumber
Apakah Anda memiliki / etc / mtab?
eyoung100
Lihat juga thread.gmane.org/gmane.linux.utilities.util-linux-ng/2979 dan solusinya dengan menggunakan mount -t binddan skrip pembantu di bugs.launchpad.net/ubuntu/+source/mountall/+bug/519380
Stéphane Chazelas
@ECarterYoung ya saya punya /etc/mtab. Setelah mount awal entri mengatakan mount adalah rw dan setelah remount dikatakan ro, sehingga melaporkan keadaan mount dengan benar. Hanya perintah mount yang gagal.
StrongBad
3
Saya menguji pada dua mesin Debian pengujian / tidak stabil, satu menjalankan Debian kernel dan satu menjalankan kernel.org, tidak bekerja dengan mount --bind -o ro, mereka berdua mengeluarkan pesan mount: warning: «mountpoint» seems to be mounted read-write.Jadi sepertinya Debian menjatuhkan atau kehilangan tambalan di beberapa titik ... Remount bekerja, meskipun.
derobert
2
@ StrongBad Menguji itu seperti yang diminta, dan tidak berhasil juga.
derobert

Jawaban:

21

Bind mount hanya ... well ... bind mount. Yaitu itu bukan gunung baru. Itu hanya "tautan" / "memperlihatkan" / "menganggap" subdirektori sebagai titik pemasangan baru. Karena itu tidak dapat mengubah parameter mount. Itu sebabnya Anda mendapat keluhan:

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

Tetapi seperti yang Anda katakan, bind mount yang normal berfungsi:

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

Dan kemudian ro remount juga berfungsi:

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

Namun yang terjadi adalah Anda mengubah seluruh mount dan bukan hanya bind mount ini. Jika Anda melihat / proc / mounts Anda akan melihat bahwa bind mount dan mount asli berubah menjadi read-only:

/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

Jadi yang Anda lakukan adalah seperti mengubah mount awal menjadi mount read-only dan kemudian melakukan binding mount yang tentu saja akan menjadi read-only.

UPDATE 2016-07-20:

Berikut ini berlaku untuk 4.5 kernel, tetapi tidak benar untuk 4.3 kernel (Ini salah. Lihat pembaruan # 2 di bawah):

Kernel memiliki dua flag yang mengontrol read-only:

  • The MS_READONLY: Menunjukkan apakah mount hanya baca
  • The MNT_READONLY: Menunjukkan apakah "pengguna" hanya menginginkannya untuk dibaca

Pada kernel 4.5, melakukan mount -o bind,rowasiat benar-benar melakukan triknya. Sebagai contoh, ini:

# 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

akan membuat read-only bind mount dari /tmp/test/a/duntuk /tmp/test/b, yang akan terlihat dalam /proc/mountssebagai:

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

Tampilan yang lebih rinci terlihat di /proc/self/mountinfo, yang mempertimbangkan tampilan pengguna (namespace). Baris yang relevan adalah sebagai berikut:

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

Di mana pada baris kedua, Anda dapat melihat bahwa ia mengatakan keduanya ro( MNT_READONLY) dan rw( !MS_READONLY).

Hasil akhirnya adalah ini:

# 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:

Sedikit lebih dalam menggali ini menunjukkan bahwa perilaku sebenarnya tergantung pada versi libmount yang merupakan bagian dari util-linux. Dukungan untuk ini ditambahkan dengan komit ini dan dirilis dengan versi 2.27:

komit 9ac77b8a78452eab0612523d27fee52159f5016a
Penulis: Karel Zak 
Tanggal: Senin 17 Agustus 11:54:26 2015 +200

    libmount: tambahkan dukungan untuk "bind, ro"

    Sekarang perlu untuk menggunakan dua panggilan mount (8) untuk membuat read-only
    meningkat:

      mount / foo / bar -o bind
      mount / bar -o remount, ro, bind

    Patch ini memungkinkan untuk menentukan "bind, ro" dan remount selesai
    secara otomatis oleh libmount dengan tambahan mount (2) syscall. Ini bukan
    atom tentu saja.

    Ditandatangani oleh: Karel Zak 

yang juga menyediakan solusi. Perilaku dapat dilihat menggunakan strace pada mount yang lebih tua dan lebih baru:

Tua:

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

Baru:

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>

Kesimpulan:

Untuk mencapai hasil yang diinginkan, seseorang perlu menjalankan dua perintah (seperti yang sudah dikatakan @Thomas):

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

Versi mount yang lebih baru (util-linux> = 2.27) melakukan ini secara otomatis ketika seseorang menjalankannya

mount SRC DST -o bind,ro
V13
sumber
3
Ya, tapi tidak. IIRC ada beberapa dukungan di kernel untuk titik mount yang berbeda (bukan filesystem) untuk memiliki opsi yang berbeda. Debian dulu memiliki tambalan yang membuat mount -o bind,romembuat tampilan read-only dari sistem file read-write (tapi sepertinya tidak lagi ada di sana saat mengi).
Gilles 'SO- berhenti menjadi jahat'
Saya tidak melihat bagaimana ini bertentangan dengan yang di atas. Hacks dapat memungkinkan segala macam hal, termasuk hal-hal yang tidak masuk akal. Saat ini remount read-only pada kernel 3,14 akhirnya ditangani oleh panggilan ini: mnt_make_readonly (real_mount (mnt)), yang seperti yang Anda lihat menggunakan real_mount (), sehingga secara praktis memengaruhi mount sebenarnya dan yang menyebabkan bind mount untuk mencerminkan yang baru (baca-saja) bendera pemasangan. Setidaknya itulah pemahaman saya.
V13
Jadi ini akan menjadi konsekuensi dari patch "spread struct mount" (khusus commit ini ), pertama kali muncul di kernel 3.3. Apakah Anda tahu jika konsekuensi dari tambalan ini dibahas pada lkml atau lwn?
Gilles 'SANGAT berhenti menjadi jahat'
7
mount --bind /tmp/ /mnt/tmp/; mount -o remount,bind,ro /mnt/tmp/... maka touch /tmp/atidak apa-apa, tetapi touch /mnt/tmp/bmemberi touch: cannot touch ‘/mnt/tmp/b’: Read-only file system. Itu berfungsi baik pada Debian 3.13 dan kernel.org 3.14.2. Jadi itu tidak hanya mengubah seluruh mount. Setidaknya tidak dengan kernel terbaru.
derobert
1
Agaknya pernyataan bahwa "Bind mount hanya ... yah ... bind mount." sangat penting tetapi tidak ada artinya bagi saya. Saya juga tidak mengerti mengapa ini kemudian bekerja kedua kalinya dengan opsi remount.
StrongBad
9

Solusi yang tepat adalah memasangnya dua kali. Di baris perintah:

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

Di /etc/fstab:

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

Manual ( man mount) menyatakan seperti itu:

   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
Thomas
sumber
Ini tampaknya bekerja dengan setidaknya Ubuntu 14.04 LTS dan kernel 3.19.0-51-lowlatency. Bagus!
Mikko Rantalainen
0

Anda bertanya dari perspektif mount(8)baris perintah (yang dapat diterima di situs ini). Perintah itu telah dibahas dalam jawaban lain dan dalam beberapa kasus, abstraksi mount(2)panggilan sistem kedua yang diperlukan .

Tetapi mengapa panggilan sistem kedua diperlukan? Mengapa satu mount(2)panggilan tidak dapat membuat bind mount read-only?

The mount(2)halaman man menjelaskan bahwa ada, seperti orang lain telah menunjukkan, dua set bendera menjadi set:

  • Bendera sistem file yang mendasarinya
  • Bendera titik-mount VFS

Ia mengatakan:

Sejak Linux 2.6.16, MS_RDONLYdapat diatur atau dihapus berdasarkan per-mount-point serta pada sistem file yang mendasarinya. Filesystem yang di-mount hanya akan dapat ditulis jika filesystem atau mountpoint tidak ditandai sebagai hanya-baca.

Dan tentang MS_REMOUNT:

Sejak Linux 2.6.26, flag ini dapat digunakan MS_BINDuntuk memodifikasi hanya flag per-mount-point. Ini sangat berguna untuk mengatur atau menghapus flag "read-only" pada titik mount tanpa mengubah sistem file yang mendasarinya. Menentukan mountflags sebagai:

      MS_REMOUNT | MS_BIND | MS_RDONLY

akan membuat akses melalui titik mount ini hanya-baca, tanpa memengaruhi titik mount lainnya.

Saya pikir masalah muncul ketika bind mount pertama kali diperkenalkan:

Jika mountflags termasuk MS_BIND(tersedia sejak Linux 2.4), maka lakukan bind mount. ... Bit yang tersisa dalam argumen mountflags juga diabaikan, dengan pengecualian MS_REC. (Bind mount memiliki opsi pemasangan yang sama dengan titik pemasangan yang mendasarinya.)

Tampaknya, alih-alih menggunakan MS_BIND | MS_REMOUNTsebagai sinyal untuk mengatur hanya flag VFS, mereka bisa memilih untuk kecuali (dan menerima) MS_RDONLYbersama dengan inisial MS_BIND, dan menerapkannya ke titik mount.

Jadi karena semantik yang agak aneh dari mount(2)pemanggilan sistem:

  • Panggilan pertama membuat bind mount dan semua flag lainnya diabaikan
  • Panggilan kedua (dengan remount) mengatur tanda mount-point menjadi read-only
Jonathon Reinhart
sumber