Calling setns from Go returns EINVAL for mnt namespace
gopherbot opened this issue · comments
GopherBot commented
by iain.lowe:
The C code works fine and correctly enters the namespace, but the Go code always seems to return EINVAL from the `setns` call to enter the `mnt` namespace. I've tried a number of permutations (including embedded C code with cgo and external `.so`) on Go `1.2`, `1.3` and the current tip. Stepping through the code in `gdb` shows that both sequences are calling `setns` in `libc` the exact same way (or so it appears to me). I have boiled what seems to be the issue down to the code below. What am I doing wrong? ## Setup I have a shell alias for starting quick busybox containers: alias startbb='docker inspect --format "{{ .State.Pid }}" $(docker run -d busybox sleep 1000000)' After running this, `startbb` will start a container and output it's PID. `lxc-checkconfig` outputs: Found kernel config file /boot/config-3.8.0-44-generic --- Namespaces --- Namespaces: enabled Utsname namespace: enabled Ipc namespace: enabled Pid namespace: enabled User namespace: missing Network namespace: enabled Multiple /dev/pts instances: enabled --- Control groups --- Cgroup: enabled Cgroup clone_children flag: enabled Cgroup device: enabled Cgroup sched: enabled Cgroup cpu account: enabled Cgroup memory controller: missing Cgroup cpuset: enabled --- Misc --- Veth pair device: enabled Macvlan: enabled Vlan: enabled File capabilities: enabled `uname -a` produces: Linux gecko 3.8.0-44-generic #66~precise1-Ubuntu SMP Tue Jul 15 04:01:04 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux ## Working C code The attached C code works fine. After compiling with `gcc -o checkns checkns.c`, the output of `sudo ./checkns <PID>` is: setns on ipc namespace succeeded setns on uts namespace succeeded setns on net namespace succeeded setns on pid namespace succeeded setns on mnt namespace succeeded ## Failing Go code Conversely, the attached Go code (which should be identical) doesn't work quite as well. Instead, running `sudo go run main.go <PID>` produces: setns on ipc namespace succeeded setns on uts namespace succeeded setns on net namespace succeeded setns on pid namespace succeeded setns on mnt namespace failed: invalid argument
Attachments:
- checkns.c (786 bytes)
- checkns.go (730 bytes)
GopherBot commented
Minux Ma commented
is it possible that this is something to do with Go programs being multithreaded? Try using the cgo constructor trick to do this. /* __attribute__((constructor)) void enter_namespace(void) { // set ns here } */ import "C" this should make sure the C code runs before Go's main, thus it will enter the namespace before Go runtime starts new threads.
GopherBot commented
Ian Lance Taylor commented