Почему mount не поддерживает параметр только для чтения для bind mounts?

35

В моей системе Arch Linux (Linux Kernel 3.14.2) bind mounts не учитывают параметр только для чтения

# 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/для первоначального монтирования /dev/sda2/on /также не изменяется и остается доступной для чтения / записи.

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

Такое поведение и обходные пути известны как минимум с 2008 года и описаны на странице руководстваmount

Обратите внимание, что параметры монтирования файловой системы останутся такими же, как и в исходной точке монтирования, и их нельзя изменить, передав параметр -o вместе с --bind / - rbind. Параметры монтирования могут быть изменены отдельной командой перемонтирования

Не все дистрибутивы ведут себя одинаково. Похоже, что Arch молча игнорирует эти параметры, в то время как Debian выдает предупреждение, когда монтирование bind не получает монтирование только для чтения.

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

Есть сообщения о том, что это поведение было «исправлено» в Debian Lenny и Squeeze, хотя оно не является универсальным и не работает в Debian Wheezy. С чем трудно связать привязку при монтировании с опцией «только чтение» при первоначальной монтировке?

StrongBad
источник
У вас есть / etc / mtab?
eyoung100
См. Также thread.gmane.org/gmane.linux.utilities.util-linux-ng/2979 и обходной путь с помощью mount -t bindскрипта-помощника на bugs.launchpad.net/ubuntu/+source/mountall/+bug/519380
Стефан. 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 удалил или потерял патч ... Remount работает, хотя.
Дероберт
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

И тогда также работает ro remount:

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

Однако происходит то, что вы меняете целое крепление, а не только это крепление связывания. Если вы посмотрите на / proc / mounts, то увидите, что и bind mount, и исходное монтирование перейдут в режим только для чтения:

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

Ядро имеет два флага, которые контролируют только чтение:

  • The 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:

commit 9ac77b8a78452eab0612523d27fee52159f5016a
Автор: Карел Зак 
Дата: понедельник, 17 августа 11:54:26 2015 +0200

    libmount: добавить поддержку "bind, ro"

    Теперь необходимо использовать два вызова mount (8) для создания только для чтения
    крепление:

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

    Этот патч позволяет указать «bind, ro» и перемонтирование сделано
    автоматически с помощью libmount путем дополнительного системного вызова mount (2). Это не
    атомный конечно.

    Подписано: Карел Зак 

что также обеспечивает обходной путь. Поведение можно увидеть с помощью 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>

Вывод:

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

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

Более новые версии mount (util-linux> = 2.27) делают это автоматически при запуске

mount SRC DST -o bind,ro
V13
источник
3
Да, но нет IIRC есть некоторая поддержка в ядре для разных точек монтирования (не файловых систем) для разных опций. Раньше в Debian был патч, который mount -o bind,roсоздавал представление «только для чтения» для файловой системы «чтение и запись» (но, похоже, его больше нет в wheezy).
Жиль "ТАК - перестань быть злым"
Я не вижу, как это противоречит вышесказанному. Хаки могут позволить все виды вещей, включая вещи, которые не имеют особого смысла. В настоящее время перемонтирование только для чтения в ядре 3.14 в конечном счете обрабатывается этим вызовом: mnt_make_readonly (real_mount (mnt)), который, как вы можете видеть, использует real_mount (), так что он практически влияет на реальное монтирование и заставляет монтирование bind отражать новое (только для чтения) флаг монтирования. По крайней мере, это мое понимание.
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-lowlatency. Ницца!
Микко Ранталайнен,
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)системного вызова:

  • Первый вызов создает монтирование bind, а все остальные флаги игнорируются.
  • Второй вызов (с remount) устанавливает флаги точки монтирования только для чтения
Джонатон Рейнхарт
источник