Bind Mount es solo... bueno... un Bind Mount. Es decir. no es una montura nueva. Simplemente "enlaza"/"expone"/"considera" un subdirectorio como un nuevo punto de montaje. Como tal, no puede alterar los parámetros de montaje. Por eso recibe quejas:
# mount /mnt/1/lala /mnt/2 -o bind,ro
mount: warning: /mnt/2 seems to be mounted read-write.
Pero como dijiste, un montaje de vinculación normal funciona:
# mount /mnt/1/lala /mnt/2 -o bind
Y luego un montaje de ro también funciona:
# mount /mnt/1/lala /mnt/2 -o bind,remount,ro
Sin embargo, lo que sucede es que está cambiando todo el montaje y no solo este enlace. Si echa un vistazo a /proc/mounts, verá que tanto el montaje enlazado como el montaje original cambian a solo lectura:
/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
Entonces, lo que estás haciendo es como cambiar el montaje inicial a un montaje de solo lectura y luego haciendo un montaje de vinculación que, por supuesto, será de solo lectura.
ACTUALIZACIÓN 2016-07-20:
Lo siguiente es cierto para los kernels 4.5, pero no para los kernels 4.3 (esto es incorrecto. Consulte la actualización n.° 2 a continuación):
El kernel tiene dos banderas que controlan solo lectura:
- El
MS_READONLY
:indica si el montaje es de solo lectura - El
MNT_READONLY
:Indica si el "usuario" lo quiere de solo lectura
En un kernel 4.5, haciendo un mount -o bind,ro
realmente hará el truco. Por ejemplo, esto:
# 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
creará un montaje de enlace de solo lectura de /tmp/test/a/d
a /tmp/test/b
, que será visible en /proc/mounts
como:
none /tmp/test/a tmpfs rw,relatime 0 0
none /tmp/test/b tmpfs ro,relatime 0 0
Se puede ver una vista más detallada en /proc/self/mountinfo
, que tiene en cuenta la vista del usuario (espacio de nombres). Las líneas relevantes serán estas:
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
Donde en la segunda línea, puede ver que dice ambos ro
(MNT_READONLY
) y rw
(!MS_READONLY
).
El resultado final es este:
# echo a > /tmp/test/a/d/f
# echo a > /tmp/test/b/f
-su: /tmp/test/b/f: Read-only file system
ACTUALIZACIÓN 2016-07-20 #2:
Profundizar un poco más en esto muestra que el comportamiento, de hecho, depende de la versión de libmount que forma parte de util-linux. Se agregó soporte para esto con este compromiso y se lanzó con la versión 2.27:
commit 9ac77b8a78452eab0612523d27fee52159f5016a Author: Karel Zak Date: Mon Aug 17 11:54:26 2015 +0200 libmount: add support for "bind,ro" Now it's necessary t use two mount(8) calls to create a read-only mount: mount /foo /bar -o bind mount /bar -o remount,ro,bind This patch allows to specify "bind,ro" and the remount is done automatically by libmount by additional mount(2) syscall. It's not atomic of course. Signed-off-by: Karel Zak
que también proporciona la solución. El comportamiento se puede ver usando strace en una montura más antigua y una más nueva:
Antiguo:
mount("/tmp/test/a/d", "/tmp/test/b", 0x222e240, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.000681>
Nuevo:
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>
Conclusión:
Para lograr el resultado deseado, se deben ejecutar dos comandos (como ya dijo @Thomas):
mount SRC DST -o bind
mount DST -o remount,ro,bind
Las versiones más nuevas de mount (util-linux>=2.27) hacen esto automáticamente cuando se ejecuta
mount SRC DST -o bind,ro
La solución adecuada es realmente montarlo dos veces. En la línea de comando:
mount -t none -o bind /source/dir /destination/dir
mount -t none -o bind,remount,ro /source/dir /destination/dir
En /etc/fstab
:
/source/dir /destination/dir none bind 0 0
/source/dir /destination/dir none remount,bind,ro 0 0
El manual (man mount
) lo dice así:
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