Bind mount is just... well... a bind mount. I.e. it's not a new mount. It just "links"/"exposes"/"considers" a subdirectory as a new mount point. As such it cannot alter the mount parameters. That's why you're getting complaints:
# mount /mnt/1/lala /mnt/2 -o bind,ro
mount: warning: /mnt/2 seems to be mounted read-write.
But as you said a normal bind mount works:
# mount /mnt/1/lala /mnt/2 -o bind
And then a ro remount also works:
# mount /mnt/1/lala /mnt/2 -o bind,remount,ro
However what happens is that you're changing the whole mount and not just this bind mount. If you take a look at /proc/mounts you'll see that both bind mount and the original mount change to 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
So what you're doing is like changing the initial mount to a read-only mount and then doing a bind mount which will of course be read-only.
UPDATE 2016-07-20:
The following are true for 4.5 kernels, but not true for 4.3 kernels (This is wrong. See update #2 below):
The kernel has two flags that control read-only:
- The
MS_READONLY
: Indicating whether the mount is read-only
- The
MNT_READONLY
: Indicating whether the "user" wants it read-only
On a 4.5 kernel, doing a mount -o bind,ro
will actually do the trick. For example, this:
# 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
will create a read-only bind mount of /tmp/test/a/d
to /tmp/test/b
, which will be visible in /proc/mounts
as:
none /tmp/test/a tmpfs rw,relatime 0 0
none /tmp/test/b tmpfs ro,relatime 0 0
A more detailed view is visible in /proc/self/mountinfo
, which takes into consideration the user view (namespace). The relevant lines will be these:
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
Where on the second line, you can see that it says both ro
(MNT_READONLY
) and rw
(!MS_READONLY
).
The end result is this:
# 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:
A bit more digging into this shows that the behavior in fact depends on the version of libmount which is part of util-linux. Support for this was added with this commit and was released with version 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
which also provides the workaround. The behavior can be seen using strace on an older and a newer mount:
Old:
mount("/tmp/test/a/d", "/tmp/test/b", 0x222e240, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.000681>
New:
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>
Conclusion:
To achieve the desired result one needs to run two commands (as @Thomas already said):
mount SRC DST -o bind
mount DST -o remount,ro,bind
Newer versions of mount (util-linux >=2.27) do this automatically when one runs
mount SRC DST -o bind,ro
Best Answer
1.)
/sys
is not a real on-disk filesystem: it is a representation of and a means to access kernel internal state in the form of a virtual filesystem. It is entirely RAM-based and there is no point in storing the contents of/sys
on disk.In a certain sense you might say that
/sys
is regenerated from scratch each time the kernel boots and hardware is detected; in another sense you might say that things in the/sys
filesystem don't actually have a permanent existence at all, and are only generated on demand, whenever you attempt to access them, based on the actual kernel state they're supposed to represent.While you're in the process of installing Gentoo, the new installation does not yet have its own kernel running, so the new installation cannot have its own separate
/sys
yet. But the installer environment has its own/sys
, and making the bind mount makes the "system under construction" borrow the/sys
filesystem tree of the installation environment. This makes certain tasks in the installation be exactly the same as when upgrading an existing system, and so the same scripts can be used for both cases: in an upgrade, they are used as-is, but during an installation they just need to be run chrooted to/mnt/gentoo
.2.) Under
/sys
, there may or may not bedebugfs
mounted as/sys/kernel/debug
,efivarfs
UEFI variable store pseudo-filesystem as/sys/firmware/efi/efivars
, and a potentially several RAM-based filesystems for the management of various control groups under/sys/fs/cgroup/*
.Under
/dev
there can be at least/dev/pts
,/dev/shm
,/dev/hugepages
and/or/dev/mqueue
, all various special-purpose RAM-based filesystems.So using rbind will clearly simplify things.