如何正确使用pivot_root(2)?自研简易容器遇EINVAL错误求助
解决pivot_root(2) EINVAL错误的实操方案
你遇到的EINVAL错误,都是因为违反了pivot_root(2)的核心要求,先明确几个必须满足的前提:
- 第一个参数
new_root必须是独立挂载点(不能是普通目录) - 第二个参数
put_old必须是new_root文件系统内的一个目录,且不能和new_root在同一挂载实例上 - 当前进程必须拥有
CAP_SYS_ADMIN权限,且处于独立的mnt命名空间 new_root所在的挂载必须设置为私有(避免共享挂载影响)
针对你的尝试,逐一修正:
常见错误点分析
- 第一次调用
pivot_root(".", "."):两个参数指向同一路径,违反put_old必须是new_root下独立目录的要求,直接触发EINVAL。 - 第四次尝试未做前置准备:你先调用了
pivot_root再设置挂载私有,顺序搞反了;且未确保/newroot是挂载点,也没提前创建putOld目录。
正确操作步骤
命令行预操作(或代码中实现)
# 1. 将/newroot绑定挂载为自身,确保它是独立挂载点 mount --bind /newroot /newroot # 2. 设置挂载为私有,避免全局共享影响 mount --make-private /newroot # 3. 在/newroot下创建putOld目录(用于存放旧根) mkdir -p /newroot/putOld
C代码实现完整流程
#include <sys/mount.h> #include <unistd.h> #include <sys/stat.h> #include <errno.h> #include <stdio.h> int main() { // 绑定挂载/newroot为自身,使其成为独立挂载点 if (mount("/newroot", "/newroot", NULL, MS_BIND, NULL) == -1) { perror("mount bind failed"); return 1; } // 递归设置/newroot挂载为私有 if (mount(NULL, "/newroot", NULL, MS_PRIVATE | MS_REC, NULL) == -1) { perror("mount make private failed"); return 1; } // 切换到/newroot目录 if (chdir("/newroot") == -1) { perror("chdir failed"); return 1; } // 创建putOld目录(已存在则忽略) struct stat st; if (stat("putOld", &st) == -1) { if (mkdir("putOld", 0755) == -1) { perror("mkdir putOld failed"); return 1; } } // 执行pivot_root if (pivot_root(".", "putOld") == -1) { perror("pivot_root failed"); return 1; } // 卸载旧根挂载(可选,若不需要保留旧根) if (umount2("putOld", MNT_DETACH) == -1) { perror("umount putOld failed"); // 非致命错误,可继续执行 } // 切换到新根的根目录(确保当前工作目录正确) chdir("/"); printf("pivot_root executed successfully\n"); return 0; }
额外注意事项
- 不要在调用
pivot_root前执行chroot:chroot会改变进程的根目录,导致pivot_root无法正确识别挂载层级,触发EINVAL。 - 若仍报错,检查
/newroot的文件系统是否支持挂载操作(比如是否为只读文件系统,或者挂载属性是否有冲突)。
内容的提问来源于stack exchange,提问作者Jakub Strzelecki
相关产品推荐
相关产品推荐

