pivot_root(2)
Rev.1を表示中。最新版はこちら。
旧バージョンで実行可能だった下記サンプルpivot_rootが、現バージョンではpivot_rootシステムコールがEINVALでの不可となっています。[root@localhost v.north]# mount -t ramfs none /ramdisk [root@localhost v.north]# mkdir /ramdisk/old-root [root@localhost v.north]# strace -o babakaka pivot_root /ramdisk/ /ramdisk/old-root/ pivot_root: ルートディレクトリを `/ramdisk/' から `/ramdisk/old-root/' に変更する処理が失敗しました: 無効な引数です [root@localhost a]# cat babakaka | grep "pivot_root(" pivot_root("/ramdisk/", "/ramdisk/old-root/") = -1 EINVAL (Invalid argument)
SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, const char __user *, put_old) { struct path new, old, parent_path, root_parent, root; struct mount *new_mnt, *root_mnt; int error; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = user_path_dir(new_root, &new); if (error) goto out0; error = user_path_dir(put_old, &old); if (error) goto out1; error = security_sb_pivotroot(&old, &new); if (error) goto out2; get_fs_root(current->fs, &root); error = lock_mount(&old); if (error) goto out3; error = -EINVAL; new_mnt = real_mount(new.mnt); root_mnt = real_mount(root.mnt); if (IS_MNT_SHARED(real_mount(old.mnt)) || IS_MNT_SHARED(new_mnt->mnt_parent) || IS_MNT_SHARED(root_mnt->mnt_parent)) goto out4; if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) goto out4; error = -ENOENT; if (d_unlinked(new.dentry)) goto out4; if (d_unlinked(old.dentry)) goto out4; error = -EBUSY; if (new.mnt == root.mnt || old.mnt == root.mnt) goto out4; /* loop, on the same file system */ error = -EINVAL; if (root.mnt->mnt_root != root.dentry) goto out4; /* not a mountpoint */ if (!mnt_has_parent(root_mnt)) goto out4; /* not attached */ if (new.mnt->mnt_root != new.dentry) goto out4; /* not a mountpoint */ if (!mnt_has_parent(new_mnt)) goto out4; /* not attached */ /* make sure we can reach put_old from new_root */ if (!is_path_reachable(real_mount(old.mnt), old.dentry, &new)) goto out4; br_write_lock(&vfsmount_lock); detach_mnt(new_mnt, &parent_path); detach_mnt(root_mnt, &root_parent); attach_mnt(root_mnt, &old); attach_mnt(new_mnt, &root_parent); touch_mnt_namespace(current->nsproxy->mnt_ns); br_write_unlock(&vfsmount_lock); chroot_fs_refs(&root, &new); error = 0; out4: unlock_mount(&old); if (!error) { path_put(&root_parent); path_put(&parent_path); } out3: path_put(&root); out2: path_put(&old); out1: path_put(&new); out0: return error; }以前のバージョンからEINVALエラーに係る以下の条件が追加されています。
if (IS_MNT_SHARED(real_mount(old.mnt)) || IS_MNT_SHARED(new_mnt->mnt_parent) || IS_MNT_SHARED(root_mnt->mnt_parent)) goto out4; if (!mnt_has_parent(root_mnt)) goto out4;
備考
MNT_SHAREDはmount後にマウント属性変更での設定で、mountでのMNT_SHAREDは設定できません。従ってサンプルのpivot_rootエラーは、if (!mnt_has_parent(root_mnt))で、プロセスのrootのデバイスが親を有しないシステム起動時のrootデバイス故です。従って、現行バージョンでpivot_rootするには、プロセスのrootをカーネル起動時のmntでなく、mountされているディレクトリをchrootでプロセスのrootとする事でpivot_rootの実行が可能となるようです。