unshare --pid /bin/bash - fork 无法分配内存
unshare --pid /bin/bash - fork cannot allocate memory
我正在试验 linux 命名空间。特别是 pid 命名空间。
我想我会用 bash 来测试一些东西,但是 运行 这个问题:
unshare -p /bin/bash
bash: fork: Cannot allocate memory
运行 ls 从那里给出了核心转储。退出是唯一的可能。
为什么要这样做?
这并没有解释为什么会发生这种情况,而是展示了如何在新的 pid 命名空间中正确启动 shell:
使用 -f
标志从 unshare
:
中分叉出 shell
unshare -fp /bin/bash
您还需要传递 --mount-proc
选项以确保 shell 将在新创建的命名空间中获得 PID 1:
unshare -fp --mount-proc /bin/bash
现在运行ps
:
# ps
PID TTY TIME CMD
1 pts/1 00:00:00 bash
11 pts/1 00:00:00 ps
该错误是由于 PID 1 进程退出到新命名空间造成的。
在bash开始到运行之后,bash会fork几个新的子进程做一些事情。如果您 运行 不使用 -f 取消共享,bash 将具有与当前 "unshare" 进程相同的 pid。当前"unshare"进程调用unshare系统调用,创建新的pid命名空间,但是当前"unshare"进程不在新的pid命名空间中。这是linux内核期望的行为:进程A创建一个新的命名空间,进程A本身不会被放入新的命名空间,只有进程A的子进程会被放入新的命名空间。所以当你 运行:
unshare -p /bin/bash
unshare进程会执行/bin/bash,/bin/bash会fork出几个子进程,bash的第一个子进程会成为新命名空间的PID 1,子进程将在完成其工作后退出。所以新命名空间的PID 1退出。
PID 1 进程有一个特殊的功能:它应该成为所有孤儿进程的父进程。如果根命名空间中的 PID 1 进程退出,内核将崩溃。如果子命名空间中的 PID 1 进程退出,linux 内核将调用 disable_pid_allocation 函数,该函数将清除该命名空间中的 PIDNS_HASH_ADDING 标志。当linux内核创建一个新进程时,内核会调用alloc_pid函数在命名空间中分配一个PID,如果PIDNS_HASH_ADDING标志没有设置,alloc_pid函数将return -ENOMEM 错误。这就是您收到 "Cannot allocate memory" 错误的原因。
您可以使用“-f”选项解决此问题:
unshare -fp /bin/bash
如果您 运行 使用“-f”选项取消共享,取消共享将在创建新的 pid 命名空间后派生一个新进程。而新进程中的运行/bin/bash。新进程将是新 pid 命名空间的 pid 1。然后bash也会fork几个子进程做一些工作。由于bash本身就是新的pid命名空间的pid 1,它的子进程可以正常退出。
我正在试验 linux 命名空间。特别是 pid 命名空间。
我想我会用 bash 来测试一些东西,但是 运行 这个问题:
unshare -p /bin/bash
bash: fork: Cannot allocate memory
运行 ls 从那里给出了核心转储。退出是唯一的可能。
为什么要这样做?
这并没有解释为什么会发生这种情况,而是展示了如何在新的 pid 命名空间中正确启动 shell:
使用 -f
标志从 unshare
:
unshare -fp /bin/bash
您还需要传递 --mount-proc
选项以确保 shell 将在新创建的命名空间中获得 PID 1:
unshare -fp --mount-proc /bin/bash
现在运行ps
:
# ps
PID TTY TIME CMD
1 pts/1 00:00:00 bash
11 pts/1 00:00:00 ps
该错误是由于 PID 1 进程退出到新命名空间造成的。
在bash开始到运行之后,bash会fork几个新的子进程做一些事情。如果您 运行 不使用 -f 取消共享,bash 将具有与当前 "unshare" 进程相同的 pid。当前"unshare"进程调用unshare系统调用,创建新的pid命名空间,但是当前"unshare"进程不在新的pid命名空间中。这是linux内核期望的行为:进程A创建一个新的命名空间,进程A本身不会被放入新的命名空间,只有进程A的子进程会被放入新的命名空间。所以当你 运行:
unshare -p /bin/bash
unshare进程会执行/bin/bash,/bin/bash会fork出几个子进程,bash的第一个子进程会成为新命名空间的PID 1,子进程将在完成其工作后退出。所以新命名空间的PID 1退出。
PID 1 进程有一个特殊的功能:它应该成为所有孤儿进程的父进程。如果根命名空间中的 PID 1 进程退出,内核将崩溃。如果子命名空间中的 PID 1 进程退出,linux 内核将调用 disable_pid_allocation 函数,该函数将清除该命名空间中的 PIDNS_HASH_ADDING 标志。当linux内核创建一个新进程时,内核会调用alloc_pid函数在命名空间中分配一个PID,如果PIDNS_HASH_ADDING标志没有设置,alloc_pid函数将return -ENOMEM 错误。这就是您收到 "Cannot allocate memory" 错误的原因。
您可以使用“-f”选项解决此问题:
unshare -fp /bin/bash
如果您 运行 使用“-f”选项取消共享,取消共享将在创建新的 pid 命名空间后派生一个新进程。而新进程中的运行/bin/bash。新进程将是新 pid 命名空间的 pid 1。然后bash也会fork几个子进程做一些工作。由于bash本身就是新的pid命名空间的pid 1,它的子进程可以正常退出。