首页  >  文章  >  后端开发  >  为什么从 Go 调用“setns”会为 Mnt 命名空间返回“EINVAL”?

为什么从 Go 调用“setns”会为 Mnt 命名空间返回“EINVAL”?

Linda Hamilton
Linda Hamilton原创
2024-11-02 21:00:30388浏览

Why Does Calling `setns` from Go Return `EINVAL` for Mnt Namespace?

从 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中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn