Maison > développement back-end > Golang > le corps du texte

Pourquoi l'appel de Setns depuis Go renvoie-t-il EINVAL pour l'espace de noms Mnt ?

Susan Sarandon
Libérer: 2024-11-01 05:35:02
original
578 Les gens l'ont consulté

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

L'appel de Setns depuis Go renvoie EINVAL pour l'espace de noms Mnt

Contexte

Le but est de entrez l'espace de noms mnt d'un conteneur en utilisant le code C ou Go. Cependant, le code Go renvoie systématiquement EINVAL à partir de l'appel setns lors de la tentative d'entrée dans l'espace de noms mnt.

Code C de travail

Le code C suivant entre avec succès dans tous les espaces de noms spécifiés :

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

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

Échec du code Go

En revanche, le code Go équivalent renvoie une erreur EINVAL pour l'espace de noms mnt :

<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>
Copier après la connexion

Réponse

Le problème réside dans la nature multithread de Go. Lorsque Go appelle setns à partir d'un contexte multithread, il échoue pour l'espace de noms mnt car il nécessite un appelant monothread. Pour résoudre ce problème, l'appel setns doit être effectué avant que le runtime Go ne crée des threads supplémentaires.

Solution : astuce du constructeur à thread unique

Une façon d'y parvenir est pour utiliser l'astuce du constructeur CGO, où une fonction C est exécutée avant le démarrage de Go :

<code class="c">__attribute__((constructor)) void enter_namespace(void) { setns(...); }</code>
Copier après la connexion

L'ajout de ce constructeur au code Go, ainsi que le codage en dur du PID, permettent une entrée réussie dans l'espace de noms mnt :

<code class="go">/*
__attribute__((constructor)) void enter_namespace(void) { ... }
*/
import "C"</code>
Copier après la connexion

Cependant, cette approche nécessite de coder en dur le PID, ce qui n'est pas idéal.

Alternative : Linux Kernel 4.16 et supérieur

Dans le noyau Linux 4.16 et versions ultérieures, un nouveau mode a été introduit pour setns qui permet de l'appeler en toute sécurité à partir de contextes multithread. En utilisant une version modifiée de l'appel setns qui prend un argument supplémentaire (CLONE_IOCLONE_COMMON), il est possible de saisir l'espace de noms mnt depuis Go, même s'il est multi-thread.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!