Dlaczego mount nie respektuje opcji tylko do odczytu dla montowania bindów?

35

W moim systemie Arch Linux (jądro Linuksa 3.14.2) monitory łączenia nie uwzględniają opcji tylko do odczytu

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

tworzy plik /mnt/foo. Odpowiedni wpis w /proc/mountsto

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

Opcje montowania nie pasują moje żądanych opcji, ale czy pasuje zarówno zachowanie odczytu / zapisu wiążą montażu i zastosowane do opcji pierwotnie zamontować /dev/sda2na/

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

Jeśli jednak zamontuję ponownie mount, to respektuje opcję tylko do odczytu

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

i odpowiedni wpis w /proc/mounts/

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

wygląda na to, czego mogłem się spodziewać (chociaż tak naprawdę spodziewałbym się zobaczyć pełną ścieżkę testkatalogu). Wpis /proc/mounts/dotyczący orignal mount /dev/sda2/on /również pozostaje niezmieniony i pozostaje do odczytu / zapisu

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

To zachowanie i obejście są znane od co najmniej 2008 roku i są udokumentowane na stronie podręcznika manmount

Zauważ, że opcje montowania systemu plików pozostaną takie same jak te w oryginalnym punkcie montowania i nie można ich zmienić, przekazując opcję -o wraz z --bind / - rbind. Opcje montowania można zmienić za pomocą osobnego polecenia remount

Nie wszystkie dystrybucje zachowują się tak samo. Wydaje się, że Arch po cichu nie przestrzega opcji, podczas gdy Debian generuje ostrzeżenie, gdy mount mount nie otrzymuje mount tylko do odczytu

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

Istnieją doniesienia, że ​​takie zachowanie zostało „naprawione” w Debian Lenny i Squeeze, chociaż nie wydaje się być uniwersalną poprawką ani nie działa w Debian Wheezy. Co trudno powiązać z tworzeniem wiązania bind z opcją tylko do odczytu w pierwszym montażu?

StrongBad
źródło
Czy masz / etc / mtab?
eyoung100
Zobacz także thread.gmane.org/gmane.linux.utilities.util-linux-ng/2979 oraz obejście tego problemu za pomocą mount -t bindskryptu pomocniczego na stronie bugs.launchpad.net/ubuntu/+source/mountall/+bug/519380
Stéphane Chazelas
@ECarterYoung tak mam /etc/mtab. Po pierwszym zamontowaniu wpis mówi, że jest to rw, a po ponownym zamontowaniu mówi ro, więc poprawnie raportuje stan zamontowania. Nie działa tylko polecenie montowania.
StrongBad
3
Testowałem na dwóch testujących / niestabilnych maszynach Debiana, jednej z jądrem Debiana i drugiej z jądrem kernel.org, żadna z mount --bind -o ronich nie działa , oba wyrzucają komunikat mount: warning: «mountpoint» seems to be mounted read-write.Więc wygląda na to, że Debian upuścił lub zgubił łatkę w pewnym momencie ... Ponownie zamontować działa jednak.
derobert
2
@StrongBad Przetestowałem to zgodnie z żądaniem i nie działa.
derobert

Odpowiedzi:

21

Bind mount to po prostu ... cóż ... mocowanie bind. Tzn. To nie jest nowy wierzchowiec. Po prostu „links” / „exposing” / „uważa” podkatalog za nowy punkt montowania. Jako taki nie może zmieniać parametrów montowania. Dlatego otrzymujesz skargi:

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

Ale jak powiedziałeś, działa normalne mocowanie wiązania:

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

Następnie działa również remount ro:

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

Jednak dzieje się tak, że zmieniasz cały uchwyt, a nie tylko ten uchwyt wiązania. Jeśli spojrzysz na / proc / mounts, zobaczysz, że zarówno bind mount, jak i oryginalny mount zmieniają się na tylko do odczytu:

/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

Więc to, co robisz, jest jak zamiana początkowego montowania na montowanie tylko do odczytu, a następnie wykonanie montowania łączenia, które oczywiście będzie tylko do odczytu.

AKTUALIZACJA 2016-07-20:

Poniższe informacje są prawdziwe w przypadku jąder 4.5, ale nie są prawdziwe w przypadku jąder 4.3 (to źle. Zobacz aktualizację nr 2 poniżej):

Jądro ma dwie flagi, które kontrolują tylko do odczytu:

  • MS_READONLY: Wskazanie, czy mocowanie jest tylko do odczytu
  • MNT_READONLY: Wskazanie, czy „użytkownik” chce on tylko do odczytu

W jądrze 4.5, wykonanie polecenia mount -o bind,rofaktycznie załatwi sprawę. Na przykład:

# 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

utworzy montowanie wiązania tylko do odczytu /tmp/test/a/ddla /tmp/test/b, które będzie widoczne /proc/mountsjako:

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

Widoczny jest bardziej szczegółowy widok /proc/self/mountinfo, który uwzględnia widok użytkownika (przestrzeń nazw). Odpowiednie linie to:

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

W drugim wierszu widać, że jest napisane zarówno ro( MNT_READONLY), jak i rw( !MS_READONLY).

Wynik końcowy jest następujący:

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

AKTUALIZACJA 2016-07-20 # 2:

Nieco głębsze wnikanie w to pokazuje, że zachowanie w rzeczywistości zależy od wersji libmount, która jest częścią util-linux. Obsługa tego została dodana do tego zatwierdzenia i została wydana w wersji 2.27:

zatwierdzić 9ac77b8a78452eab0612523d27fee52159f5016a
Autor: Karel Zak 
Data: pon. 17 sierpnia 11:54:26 2015 +0200

    libmount: dodaj obsługę „bind, ro”

    Teraz konieczne jest użycie dwóch wywołań mount (8), aby utworzyć tylko do odczytu
    uchwyt:

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

    Ta łatka pozwala określić „bind, ro” i remont jest zakończony
    automatycznie przez libmount przez dodatkowe wywołanie systemowe mount (2). To nie jest
    atomowy oczywiście.

    Podpisano: Karel Zak 

który zapewnia również obejście. Zachowanie można zobaczyć za pomocą strace na starszym i nowszym wierzchowcu:

Stary:

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

Nowy:

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>

Wniosek:

Aby osiągnąć pożądany rezultat, należy uruchomić dwie komendy (jak już powiedział @ Thomas):

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

Nowsze wersje mount (util-linux> = 2.27) robią to automatycznie po uruchomieniu

mount SRC DST -o bind,ro
V13
źródło
3
Tak ale nie. IIRC jest pewne wsparcie w jądrze dla różnych punktów montowania (nie systemów plików), aby mieć różne opcje. Debian miał łatkę, która tworzyła mount -o bind,rowidok systemu plików tylko do odczytu do odczytu i zapisu (ale wydaje się, że już go nie ma w wheezy).
Gilles „SO- przestań być zły”
Nie rozumiem, jak to zaprzecza powyższemu. Hacki mogą dopuszczać wszelkiego rodzaju rzeczy, w tym takie, które nie mają większego sensu. Obecnie remount tylko do odczytu w jądrze 3.14 jest ostatecznie obsługiwany przez to wywołanie: mnt_make_readonly (real_mount (mnt)), który, jak widać, używa real_mount (), więc praktycznie wpływa na rzeczywiste montowanie i powoduje, że montowania wiązania odzwierciedlają nowy (tylko do odczytu) flaga montowania. Przynajmniej tak rozumiem.
V13
Byłoby to zatem konsekwencją łatki „spread struct mount” (szczególnie tej zmiany ), która pojawiła się po raz pierwszy w jądrze 3.3. Czy wiesz, czy konsekwencje tej łatki były omawiane na lkml czy lwn?
Gilles „SO- przestań być zły”
7
mount --bind /tmp/ /mnt/tmp/; mount -o remount,bind,ro /mnt/tmp/... więc touch /tmp/ajest OK, ale touch /mnt/tmp/bdaje touch: cannot touch ‘/mnt/tmp/b’: Read-only file system. Działa to zarówno na Debianie 3.13, jak i na kernel.org 3.14.2. Więc to nie tylko zmienia cały wierzchowiec. Przynajmniej nie w najnowszych jądrach.
derobert
1
Przypuszczalnie stwierdzenie, że „mocowanie Bind jest po prostu… cóż… mocowaniem Bind”. jest naprawdę ważne, ale nic dla mnie nie znaczy. Nie rozumiem też, dlaczego to działa po raz drugi z opcją remount.
StrongBad
9

Właściwe rozwiązanie to naprawdę zamontowanie go dwa razy. W wierszu poleceń:

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

W /etc/fstab:

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

Instrukcja ( man mount) stwierdza to w ten sposób:

   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
Tomasz
źródło
Wydaje się, że działa to przynajmniej z Ubuntu 14.04 LTS i jądrem 3.19.0-51-lowlatency. Miły!
Mikko Rantalainen
0

Pytasz z perspektywy mount(8)wiersza poleceń (co jest dopuszczalne na tej stronie). To polecenie zostało omówione w innych odpowiedziach, aw niektórych przypadkach streszcza niezbędne drugie mount(2)wywołanie systemowe.

Ale dlaczego potrzebne jest drugie wywołanie systemowe? Dlaczego pojedyncze mount(2)wywołanie nie może utworzyć montowania wiązania tylko do odczytu?

mount(2)Strona mężczyzna wyjaśnia, że istnieją, jak inni zwrócili uwagę, dwa zestawy flag jest zestaw:

  • Flagi systemu plików
  • Flagi punktu podłączenia VFS

To mówi:

Począwszy od Linuksa 2.6.16, MS_RDONLYmożna go ustawić lub wyczyścić dla poszczególnych punktów montowania, a także dla bazowego systemu plików. Zainstalowany system plików będzie zapisywalny tylko wtedy, gdy ani system plików, ani punkt instalacji nie zostaną oznaczone jako tylko do odczytu.

I dotyczące MS_REMOUNT:

Od Linuksa 2.6.26 tej flagi można używać MS_BINDdo modyfikowania tylko flag punktów montowania. Jest to szczególnie przydatne do ustawiania lub usuwania flagi „tylko do odczytu” w punkcie montowania bez zmiany bazowego systemu plików. Określanie mountflags jako:

      MS_REMOUNT | MS_BIND | MS_RDONLY

zapewni dostęp przez ten punkt montowania tylko do odczytu, bez wpływu na inne punkty montowania.

Wydaje mi się, że problem pojawił się, gdy po raz pierwszy wprowadzono mocowania opraw:

Jeśli mountflags zawiera MS_BIND(dostępne od Linuksa 2.4), to wykonaj podłączenie bind. ... Pozostałe bity w argumencie mountflags są również ignorowane, z wyjątkiem MS_REC. (Montaż łączenia ma te same opcje, co podstawowy punkt podłączenia).

Wydaje się, że zamiast używać MS_BIND | MS_REMOUNTjako sygnału do ustawiania tylko flag VFS, mogliby wybrać oprócz (i zaakceptować) MS_RDONLYwraz z początkową MS_BINDi zastosować go do punktu montowania.

Z powodu nieco dziwnej semantyki mount(2)wywołania systemowego:

  • Pierwsze wywołanie tworzy mount bind i wszystkie inne flagi są ignorowane
  • Drugie wywołanie (z remountem) ustawia flagi punktu montowania na „tylko do odczytu”
Jonathon Reinhart
źródło