6

Synopsis:

pivot_root new_root put_old

Question:

Why is it necessary to execute exec to change the running executable in order to unmount the old root filesystem (put_old)?

Suppose put_old is moved to a directory not inside the new root filesystem (new_root). Is it possible to unmount it then?

Why is chroot needed after executing pivot_root? new_root is already made the new root filesystem at this point.

Finally, how can pivot_root change the root directory of the parent process (e.g. bash), if it has been forked from the shell? Shouldn't the change only affect the pivot_root process itself? Does "current process" in the man page refer to the parent process or pivot_root itself?

Example:

mount /dev/hda1 /new-root
cd /new-root
pivot_root . old-root
exec chroot . sh <dev/console >dev/console 2>&1
umount /old-root

man pivot_root:

Note that exec chroot changes the running executable, which is necessary if the old root directory should be unmounted afterwards.

1 Answer 1

4

Q: Why is it necessary to execute exec to change the running executable in order to unmount the old root filesystem (put_old)?

Because filesystems cannot be unmounted when they are busy, and if a running executable (e.g. bash) or its shared libraries are on the old root filesystem they would keep it busy.


Q: Suppose put_old is moved to a directory not inside the new root filesystem (new_root). Is it possible to unmount it then?

It's not allowed for put_old to be outside new_root. From the manual page for the system call:

put_old must be at or underneath new_root


Q: Why is chroot needed after executing pivot_root? new_root is already made the new root filesystem at this point.

It isn't needed any more. The original manual page for the system call was substantially rewritten in 2019[alternative link], and the updated manual page[archive link][alternative link] explains the behaviour and the historical uncertainty:

pivot_root() changes the root directory and the current working directory of each process or thread in the same mount namespace to new_root if they point to the old root directory.

...

[This behavior] is necessary in order to prevent kernel threads from keeping the old root mount busy with their root and current working directories[...]

...

Historical notes

For many years, this manual page carried the following text:

pivot_root() may or may not change the current root and the current working directory of any processes or threads which use the old root directory. The caller of pivot_root() must ensure that processes with root or current working directory at the old root operate correctly in either case. An easy way to ensure this is to change their root and current working directory to new_root before invoking pivot_root().

This text, written before the system call implementation was even finalized in the kernel, was probably intended to warn users at that time that the implementation might change before final release. However, the behavior stated in DESCRIPTION has remained consistent since this system call was first implemented and will not change now.


Q: Finally, how can pivot_root change the root directory of the parent process (e.g. bash), if it has been forked from the shell? Shouldn't the change only affect the pivot_root process itself? Does "current process" in the man page refer to the parent process or pivot_root itself?

This is because pivot_root() operates on the mount namespace of the calling process, which is shared with the parent process. The manual page for the utility (pivot_root(8)) doesn't state this clearly, but the updated manual page for the system call (pivot_root(2)) does (emphasis added):

pivot_root() changes the root mount in the mount namespace of the calling process. [...]

pivot_root() changes the root directory and the current working directory of each process or thread in the same mount namespace to new_root if they point to the old root directory.

5
  • Thank you. If pivot_root(2) operates on the mount namespace, and multiple processes are running in that namespace, it's very likely that after calling exec(2), other processes will still be running binaries on the old root filesystem? In that case, it won't be possible to umount(2) the old root filesystem, since it's busy?
    – Shuzheng
    Nov 4, 2021 at 9:26
  • It's not strictly necessary to call exec(2), if the process' binary is not located on the old root filesystem?
    – Shuzheng
    Nov 4, 2021 at 10:08
  • Do kernel threads also have root and current directories? They are not namespaced, right?
    – Shuzheng
    Nov 4, 2021 at 10:43
  • (1) Yes, if other processes are running binaries from the old root fs it will be busy. (2) Yes, exec is not necessary if the process' binary and shared libraries are not on the old root fs. Debugging tip: fuser can identify open files in some cases. (3) Yes, kernel threads have root and current directories, and even namespaces. For example the kernel thread kdevtmpfs uses a new mount namespaces (compare readlink "/proc/$(pgrep -x kdevtmpfs)/ns/mnt" and readlink "/proc/$(pgrep -x kthreadd)/ns/mnt").
    – tom
    Nov 4, 2021 at 20:49
  • let me mention also why cd /new-root is useful : because a filesystem is busy also when a process has its cwd in it
    – am70
    Jan 14, 2023 at 13:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .