Heim  >  Artikel  >  Backend-Entwicklung  >  Warum gibt der Aufruf von Setns von Go aus EINVAL für den Mnt-Namespace zurück?

Warum gibt der Aufruf von Setns von Go aus EINVAL für den Mnt-Namespace zurück?

Susan Sarandon
Susan SarandonOriginal
2024-11-01 05:35:02567Durchsuche

Why Does Calling Setns from Go Return EINVAL for the Mnt Namespace?

Aufruf von Setns von Go gibt EINVAL für Mnt-Namespace zurück

Hintergrund

Das Ziel ist Geben Sie den mnt-Namespace eines Containers mit C- oder Go-Code ein. Der Go-Code gibt jedoch konsistent EINVAL vom setns-Aufruf zurück, wenn versucht wird, den mnt-Namespace einzugeben.

Arbeitender C-Code

Der folgende C-Code gibt erfolgreich alle angegebenen Namespaces ein :

<code class="c">#include <sched.h>

main() {
    // ...
    for (i=0; i<5; i++) {
        setns(fd, 0); // Join the provided namespace
    }
}</code>

Fehlerhafter Go-Code

Andererseits gibt der entsprechende Go-Code einen EINVAL-Fehler für den mnt-Namespace zurück:

<code class="go">import (
    "syscall"
)

func main() {
    // ...
    err := syscall.RawSyscall(308, fd, 0, 0) // Calling setns
    if err != 0 {
        fmt.Println("setns on", namespaces[i], "namespace failed")
    }
}</code>

Antwort

Das Problem liegt in der Multithread-Natur von Go. Wenn Go setns aus einem Multithread-Kontext aufruft, schlägt dies für den mnt-Namespace fehl, da ein Single-Thread-Aufrufer erforderlich ist. Um dieses Problem zu beheben, muss der setns-Aufruf erfolgen, bevor die Go-Laufzeit zusätzliche Threads erstellt.

Lösung: Single-Threaded-Konstruktor-Trick

Eine Möglichkeit, dies zu erreichen, ist um den CGO-Konstruktor-Trick zu verwenden, bei dem eine C-Funktion ausgeführt wird, bevor Go startet:

<code class="c">__attribute__((constructor)) void enter_namespace(void) { setns(...); }</code>

Das Hinzufügen dieses Konstruktors zum Go-Code zusammen mit der Festcodierung der PID ermöglicht den erfolgreichen Eintritt in den mnt-Namespace:

<code class="go">/*
__attribute__((constructor)) void enter_namespace(void) { ... }
*/
import "C"</code>

Dieser Ansatz erfordert jedoch eine harte Codierung der PID, was nicht ideal ist.

Alternative: Linux Kernel 4.16 und höher

Im Linux-Kernel 4.16 und höher wurde ein neuer Modus für setns eingeführt, der einen sicheren Aufruf aus Multithread-Kontexten ermöglicht. Durch die Verwendung einer modifizierten Version des setns-Aufrufs, die ein zusätzliches Argument (CLONE_IOCLONE_COMMON) akzeptiert, ist es möglich, den mnt-Namespace von Go aus einzugeben, auch wenn dieser multithreaded ist.

Das obige ist der detaillierte Inhalt vonWarum gibt der Aufruf von Setns von Go aus EINVAL für den Mnt-Namespace zurück?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn