從Go 調用setns 返回mnt 命名空間的EINVAL
問題描述
Go 代碼中,嘗試進入mnt命名空間使用syscall.RawSyscall函數呼叫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中文網其他相關文章!