Чому монтування не поважає параметр "лише читання" для прив'язки кріплення?


35

У моїй системі Arch Linux (Linux Kernel 3.14.2) вбудовані файли прив’язки не відповідають параметру лише читання

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

створює файл /mnt/foo. Відповідний запис в /proc/mountsIS

/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/для Orignal кріплення з /dev/sda2/на /також без змін і залишається для читання / запису

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

Така поведінка та обстановка навколо відомі щонайменше з 2008 року та задокументовані на сторінці людиниmount

Зауважте, що параметри кріплення файлової системи залишаться тими ж, що й у початковій точці монтажу, і їх неможливо змінити, передавши параметр -o разом з --bind / - rbind. Параметри кріплення можна змінити окремою командою перезавантаження

Не всі дистрибуції ведуть себе однаково. Арка, здається, мовчки не дотримується параметрів, в той час як Debian створює попередження, коли кріплення прив'язки не отримує кріплення лише для читання

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

Є повідомлення, що така поведінка була "виправлена" в Debian Lenny і Squeeze, хоча це не є універсальним виправленням і не працює в Debian Wheezy. Що важко пов'язане з тим, щоб змусити прив’язати монтаж дотримуватися опції лише для читання на початковому кріпленні?


У вас є / etc / mtab?
eyoung100

Див. Також thread.gmane.org/gmane.linux.utilities.util-linux-ng/2979 та вирішення способу використання mount -t bindта допоміжного сценарію на bugs.launchpad.net/ubuntu/+source/mountall/+bug/519380
Stéphane Chazelas

@ECarterYoung так, я маю /etc/mtab. Після початкового монтажу запис каже, що кріплення є rw, а після повторного перезапису - "ro", тож він повідомляє про стан версії правильно. Збій саме команди команд mount.
StrongBad

3
Я протестував на двох тестувальних / нестабільних машинах Debian, на одній із керуванням ядра Debian і на одній із керуванням ядра kernel.org, ні з якою не працює mount --bind -o ro, вони обоє виплюнули повідомлення. mount: warning: «mountpoint» seems to be mounted read-write.Тому, здається, Debian в якийсь момент скинув або втратив патч ... Перерахунок працює, хоча.
дероберт

2
@StrongBad Випробував це як вимагається, і він не працює.
дероберт

Відповіді:


21

Прив’язати кріплення просто ... добре ... прив'язувати кріплення. Тобто це не нове кріплення. Він просто "посилається" / "розкриває" / "розглядає" підкаталог як нову точку монтажу. Як такий, він не може змінювати параметри кріплення. Ось чому ви отримуєте скарги:

# 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

А потім також працює перерахунок ро:

# 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 нижче):

Ядро має два прапори, які керують лише для читання:

  • MS_READONLY: Вказує чи монтування тільки для читання
  • The 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

У другому рядку ви бачите, що в ньому написано і ro( MNT_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

ОНОВЛЕННЯ 2016-07-20 №2:

Трохи більше розглядаючи це, показує, що поведінка насправді залежить від версії libmount, яка є частиною util-linux. Підтримка для цього була додана до цього комітету та була випущена у версії 2.27:

фіксація 9ac77b8a78452eab0612523d27fee52159f5016a
Автор: Карел Зак 
Дата: пн 17 серпня 11:54:26 2015 +0200

    libmount: додайте підтримку для "bind, ro"

    Тепер необхідно створити два дзвінки на монтажі (8), щоб створити режим лише для читання
    кріплення:

      кріплення / foo / bar -o прив’язувати
      mount / bar -o перерахувати, ro, прив’язати

    Цей патч дозволяє вказати "bind, ro", і повторний перелік зроблено
    автоматично за допомогою libmount додатковою системою підключення (2). Це не
    атомний звичайно.

    Підписався: Карел Зак 

що також забезпечує вирішення. Поведінку можна побачити, використовуючи штрихи на більш старому та новітньому кріпленні:

Старий:

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>

Висновок:

Для досягнення бажаного результату потрібно виконати дві команди (як @Thomas вже сказав):

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

Новіші версії mount (util-linux> = 2,27) роблять це автоматично під час запуску

mount SRC DST -o bind,ro

3
Так, але ні. IIRC є деяка підтримка в ядрі для різних точок монтажу (не файлових систем), щоб мати різні параметри. У Debian використовувався патч, який mount -o bind,roстворював перегляд лише для читання файлової системи для читання-запису (але вона, здається, не знаходиться в хрипі).
Жил 'ТАК - перестань бути злим'

Я не бачу, як це суперечить вищесказаному. Хаки можуть дозволити всілякі речі, включаючи речі, які не мають особливого сенсу. В даний час перезапис лише для читання в ядрі 3.14 в кінцевому підсумку обробляється цим викликом: mnt_make_readonly (real_mount (mnt)), який, як ви бачите, використовує real_mount (), тому він практично впливає на реальне монтування і змушує прив'язувати монти відображати нову (лише для читання) прапор. Принаймні, це моє розуміння.
V13

Таким чином, це буде наслідком патчу "розповсюдження структури" (конкретно цього комітету ), вперше з'явившись у ядрі 3.3. Чи знаєте ви, чи обговорювались наслідки цього виправлення у lkml чи lwn?
Жил 'ТАК - перестань бути злим'

7
mount --bind /tmp/ /mnt/tmp/; mount -o remount,bind,ro /mnt/tmp/... тоді touch /tmp/aдобре, але touch /mnt/tmp/bдає touch: cannot touch ‘/mnt/tmp/b’: Read-only file system. Це працює як на Debian 3.13, так і на kernel.org 3.14.2. Таким чином, це не просто змінює все кріплення. Принаймні, не з останніми ядрами.
дероберт

1
Імовірно, твердження про те, що "Прив’язати кріплення - це просто ... добре ... прив'язувати кріплення". насправді важливо, але для мене нічого не означає. Я також не розумію, чому це працює вдруге з опцією ремонтажу.
StrongBad

9

Правильне рішення - це справді встановити його двічі. У командному рядку:

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

Це, здається, працює як мінімум з Ubuntu 14.04 LTS та ядром 3.19.0-51 з низькою затримкою. Приємно!
Мікко Ранталайнен

0

Ви запитуєте з точки зору mount(8)командного рядка (що прийнятно на цьому сайті). Ця команда обговорювалася в інших відповідях, а в деяких випадках абстрагує необхідний другий mount(2)виклик системи.

Але для чого потрібен другий виклик системи? Чому один mount(2)виклик не може створити кріплення прив’язки лише для читання?

Сторінка " mount(2)man" пояснює, що, як уже вказували інші, встановлюються два набори прапорів:

  • Прапори базової файлової системи
  • Прапори 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), виконайте прив'язку. ... Решта бітів в аргументі mountflags також ігноруються, за винятком MS_REC. (Прив’язане кріплення має ті самі параметри монтажу, що і нижня точка кріплення.)

Здається, що замість того, щоб використовувати MS_BIND | MS_REMOUNTяк сигнал для встановлення лише прапорців VFS, вони могли вибрати, крім (і прийняти) MS_RDONLYразом із початковим MS_BIND, і застосувати його до точки монтажу.

Тож через дещо дивну семантику mount(2)системного виклику:

  • Перший виклик створює кріплення прив’язки, а всі інші прапори ігноруються
  • Другий виклик (із перерахунком) встановлює прапори точки монтажу лише для читання
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.