从 Go 调用 setns 返回 mnt 命名空间的 EINVAL
问题描述
Go 代码中,尝试使用 syscall.RawSyscall 函数进入 mnt 命名空间调用setns系统调用返回EINVAL错误。尽管设置正确且 C 实现成功进入命名空间,此问题仍然存在。
原因和解决方案
问题的根本原因在于多方面Go 的线程本质。 setns 系统调用必须从单线程上下文执行才能成功。由于 Go 应用程序默认是多线程的,因此必须在 Go 运行时线程启动之前进行 setns 调用。
为了解决这个问题,可以使用“cgo 构造函数技巧”。该技术允许在 Go 运行时开始之前执行 C 代码。通过在 C 代码中使用 __attribute__((constructor)) 宏,可以将函数修饰为在 Go 初始化之前在单线程 C 上下文中运行。
修改的 Go 代码
以下修改后的 Go 代码使用构造函数技巧来解决该问题:
<code class="go">/* #include <sched.h> #include <stdio.h> #include <fcntl.h> __attribute__((constructor)) void enter_namespace(void) { setns(open("/proc/<PID>/ns/mnt", O_RDONLY, 0644), 0); } */ import "C" ... rest of file is unchanged ...</code>
通过利用通过 cgo 构造函数技巧,Go 应用程序现在可以使用 setns 系统调用成功进入 mnt 命名空间。
以上是为什么从 Go 调用“setns”会为 Mnt 命名空间返回“EINVAL”?的详细内容。更多信息请关注PHP中文网其他相关文章!