Bug 81695

Summary: duplicate bind mounts
Product: systemd Reporter: Corey Hickey <bugfood-c>
Component: generalAssignee: systemd-bugs
Status: RESOLVED NOTABUG QA Contact: systemd-bugs
Severity: normal    
Priority: medium    
Version: unspecified   
Hardware: All   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:

Description Corey Hickey 2014-07-24 02:27:41 UTC
Hi,

I'm not absolutely certain this is due to systemd, but I cannot reproduce it when booted with "init=/bin/bash". I can reproduce it on debian unstable and on centos 7, but not on any non-systemd OS. My apologies if I'm wrong about the reason.


Expected behavior: Bind mounts are nonrecursive, and anything mounted outside the bind mount's target will not be reflected inside the bind mount.

Example: centos 6.5

[root@dpuppetcorey01 ~]# cd /mnt
[root@dpuppetcorey01 mnt]# mkdir foo bar
[root@dpuppetcorey01 mnt]# mount --bind / foo
[root@dpuppetcorey01 mnt]# mount | egrep '(foo|bar)'
/ on /mnt/foo type none (rw,bind)
[root@dpuppetcorey01 mnt]# # so far so good
[root@dpuppetcorey01 mnt]# mount --bind / bar
[root@dpuppetcorey01 mnt]# mount | egrep '(foo|bar)'
/ on /mnt/foo type none (rw,bind)
/ on /mnt/bar type none (rw,bind)
[root@dpuppetcorey01 mnt]# # still good
[root@dpuppetcorey01 mnt]# umount foo
[root@dpuppetcorey01 mnt]# umount bar
[root@dpuppetcorey01 mnt]# # all good



Observed behavior: Any mount (bind or otherwise) made to a subdirectory within the source of a bind mount is propagated to the corresponding subdirectory within the bind mount, resulting in an unwanted duplicate. This only applies to mounts made _after_ the bind mount has been made. Also, these bind mounts prevent the original bind mount from being umounted. Attempting to umount the unwanted extra mount also umounts the original.


Example: centos 7.0

[root@dcoreytest01 ~]# cd /mnt
[root@dcoreytest01 mnt]# mkdir foo bar
[root@dcoreytest01 mnt]# mount --bind / foo
[root@dcoreytest01 mnt]# mount | egrep '(foo|bar)'
/dev/vda3 on /mnt/foo type ext4 (rw,relatime,data=ordered)
[root@dcoreytest01 mnt]# # so far so good
[root@dcoreytest01 mnt]# mount --bind / bar
[root@dcoreytest01 mnt]# mount | egrep '(foo|bar)'
/dev/vda3 on /mnt/foo type ext4 (rw,relatime,data=ordered)
/dev/vda3 on /mnt/bar type ext4 (rw,relatime,data=ordered)
/dev/vda3 on /mnt/foo/mnt/bar type ext4 (rw,relatime,data=ordered)
[root@dcoreytest01 mnt]# # at this point, bar is mounted twice--undesirable
[root@dcoreytest01 mnt]# umount foo
umount: /mnt/foo: target is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))
[root@dcoreytest01 mnt]# # help! let's try umounting the subdirectory
[root@dcoreytest01 mnt]# umount foo/mnt/bar
[root@dcoreytest01 mnt]# mount | egrep '(foo|bar)'
/dev/vda3 on /mnt/foo type ext4 (rw,relatime,data=ordered)
[root@dcoreytest01 mnt]# # oh no, that got rid of both of them!

Both of the systems I can reproduce this on (debian unstable and centos 7) are running sytemd 208.

# systemctl --version
systemd 208
+PAM +LIBWRAP +AUDIT +SELINUX +IMA +SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ


I would test this on a newer version of systemd, but I'm kind of afraid of messing with it since it's so integrated with the distribution. I would be happy to test patches, though, since I can probably apply them to the distributions' versions.

Thanks,
Corey
Comment 1 Lennart Poettering 2014-08-18 21:09:25 UTC
systemd enables mount propagation by default for all bind mounts. This is necessary to make sure propagation by default works for container managers such as nspawn/lxc/docker/libvirt.

It's recommended to turn off mount propagation if you want to disable it:

mount --make-rslave /foo/bar
Comment 2 Corey Hickey 2014-08-19 00:59:20 UTC
Thanks for the explanation. I do wish the default behavior hadn't changed, but this does get me an acceptable workaround. I wasn't aware of those mount options. I think what I actually want is --make-private, i.e.:

[root@dcoreytest01 mnt]# mount --bind --make-private / foo
[root@dcoreytest01 mnt]# mount --bind --make-private / bar
[root@dcoreytest01 mnt]# mount | egrep '(foo|bar)'
/dev/vda3 on /mnt/foo type ext4 (rw,relatime,data=ordered)
/dev/vda3 on /mnt/bar type ext4 (rw,relatime,data=ordered)

That works fine for me. Alternatively, making / private first works as well:

[root@dcoreytest01 mnt]# mount --make-private /
[root@dcoreytest01 mnt]# mount --bind / foo
[root@dcoreytest01 mnt]# mount --bind / bar
[root@dcoreytest01 mnt]# mount | egrep '(foo|bar)'
/dev/vda3 on /mnt/foo type ext4 (rw,relatime,data=ordered)
/dev/vda3 on /mnt/bar type ext4 (rw,relatime,data=ordered)

Thanks,
Corey

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.