Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically set may_detach_mounts=1 on startup #34886

Merged
merged 1 commit into from
Sep 20, 2017

Conversation

cpuguy83
Copy link
Member

This is kernel config available in RHEL7.4 based kernels that enables
mountpoint removal where the mountpoint exists in other namespaces.
In particular this is important for making this pattern work:

umount -l /some/path
rm -r /some/path

Where /some/path exists in another mount namespace.
Setting this value will prevent device or resource busy errors when
attempting to the removal of /some/path in the example.

This setting is the default, and non-configurable, on upstream kernels
since 3.15.

@runcom
Copy link
Member

runcom commented Sep 18, 2017

Looks good, ping @rhvgoyal

@rhvgoyal
Copy link
Contributor

LGTM.

We already do this with the help of sysctl interface. So over a boot, all the sysctl settings are applied and this is already enabled by the time docker runs.

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor nits, but LGTM otherwise :)

if os.IsNotExist(err) {
return nil
}
return errors.Wrap(err, "error opening may_deatch_mounts kernel config file")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh! typo: s/may_deatch_mounts/may_detach_mounts/

// unprivileged container. Ignore the error, but log
// it if we appear not to be in that situation.
if !rsystem.RunningInUserNS() {
logrus.Debugf("Permission denied writing %q to /proc/sys/fs/may_detach_mounts", "1")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there's no need to use %q here, because "1" is hardcoded

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it quotes it, which is pretty ugly to do otherwise.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

backticks for the string?

`Permission denied writing "1" to ....`

This is kernel config available in RHEL7.4 based kernels that enables
mountpoint removal where the mountpoint exists in other namespaces.
In particular this is important for making this pattern work:

```
umount -l /some/path
rm -r /some/path
```

Where `/some/path` exists in another mount namespace.
Setting this value will prevent `device or resource busy` errors when
attempting to the removal of `/some/path` in the example.

This setting is the default, and non-configurable, on upstream kernels
since 3.15.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kolyshkin
Copy link
Contributor

kolyshkin commented Sep 21, 2017

Wonderful! I was just going to work on a similar PR, but for the devmapper graph driver only (as its "deferred deletion" feature only works in case fs.may_detach_mounts=1). I did not realize it might be helpful in non-devmapper case, too. This patch will also help in case of autodetection whether deferred deletion is working or not (see mbentley/docker-devicemapper-setup#4).

The alternative approach is to add a /usr/lib/sysctl.d/90-docker.conf file to docker rpm spec, containing fs.may_detach_mounts=1, and adding a kludge to the .spec so that the setting is also applied upon rpm installation. This would be cleaner (and this is what Red Hat's runc rpm does) -- the only downside is anyone who's not installing from an rpm would not get it.

Yet another alternative is something like:

// -q: not display the value set, -e: ignore non-existent key
err := exec.Command("sysctl", "-q", "-e", "fs.may_detach_mounts=1").Run()
...

While exec sn ugly in general, this is only done once upon daemon (re)start so it's OK.

@thaJeztah
Copy link
Member

Yet another alternative is something like:

I do like the alternative approach (cleaner); would the permissions denied error still be properly returned with that code?

@kolyshkin
Copy link
Contributor

I do like the alternative approach (cleaner); would the permissions denied error
still be properly returned with that code?

Well, what we'll get is an exit code (most probably a generic 1) and a text from stderr (which we can parse for "permission denied" but it's a slippery slope as the locale might change that). I suggest treating any error, not just EPERM, in the same way, like:

s := "fs.may_detach_mounts=1"
// -q: not display the value set, -e: ignore non-existent key
err := exec.Command("sysctl", "-q", "-e", s).Run()
// ignore the error if the daemon is inside userns
if err != nil && !rsystem.RunningInUserNS() {
	logrus.Warnf("Error setting %s: %v", s, err)
}

Or maybe even not try setting this at all if we're in userns:

// do not try to set sysctls from inside userns
if !rsystem.RunningInUserNS() {
	s := "fs.may_detach_mounts=1"
	// -q: not display the value set, -e: ignore non-existent key
	if err := exec.Command("sysctl", "-q", "-e", s).Run(); err != nil {
		logrus.Warnf("Error setting %s sysctl: %v", s, err)
}

@thaJeztah
Copy link
Member

(If @cpuguy83 agrees) feel free to open a PR with that change

@cpuguy83
Copy link
Member Author

Why use exec here?

@cpuguy83
Copy link
Member Author

I'd be fine with setting this in the systemd conf, however that's really a packaging issue which we don't really deal with in this repo (though there are some init scripts in contrib).

@kolyshkin
Copy link
Contributor

kolyshkin commented Sep 21, 2017

Why use exec here?

As I said earlier, While exec sn ugly in general, this is only done once upon daemon (re)start so it's OK.

The benefits I see are:

  • using more standard interface
  • less code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants