pivot_root() moves the root filesystem of the calling process to the directory put_old and makes new_root the new root filesystem of the calling process.
The typical use of pivot_root() is during system startup, when the system mounts a temporary root filesystem (e.g., an initrd), then mounts the real root filesystem, and eventually turns the latter into the current root of all relevant processes or threads.
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().
The paragraph above is intentionally vague because the implementation of pivot_root() may change in the future. At the time of writing, pivot_root() changes root and current working directory of each process or thread to new_root if they point to the old root directory. This is necessary in order to prevent kernel threads from keeping the old root directory busy with their root and current working directory, even if they never access the filesystem in any way. In the future, there may be a mechanism for kernel threads to explicitly relinquish any access to the filesystem, such that this fairly intrusive mechanism can be removed from pivot_root().
pivot_root() should not have to change root and current working direc‐ tory of all other processes in the system.
Some of the more obscure uses of pivot_root() may quickly lead to insanity.
man pivot_root, Linux man-pages 4.15
I'm working on a case where there are multiple processes running at when pivot_root() is called.
The manpage doesn't seem very clear about how both possible implementations of pivot_root() can handle the case with multiple processes. Let's say we have two processes, S(ystemd) and P(lymouth). Currently, both P and S change their root and working directory to new_root, and then S calls pivot_root(). With the current implementation, this works fine.
Say both S and P "change their root directory" before pivot_root(), using chroot(). But, as
man chroot tells us, it is possible to leave a chroot() jail if you are root (
mkdir foo; chroot foo; cd ..; chroot .). It seems clear that processes have two associated roots:
- their current chroot
- the root of their mount namespace
After pivot_root(), S must observe that the root of its mount namespace is equal to its current chroot. Because if there was a deeper root filesystem that it could escape to at a future point, then that root filesystem would be busy and could not be unmounted. I think allowing the old root filesystem to be unmounted was the main purpose of pivot_root().
Currently, P observes the same thing - because it is in the same mount namespace as S.
It sounds like the alternative implementation of pivot_root() would put the calling process in a new, altered mount namespace. Is that a valid reading?
(I note this alternative implementation would make
/sbin/pivot_root mostly pointless).
I believe the original pivot_root() actually predates mount namespaces. Do we know if this plan for an alternative implementation of pivot_root(), anticipated the need for some of the features of mount namespaces, or was this requirement overlooked?
(I note that mount namespaces also sound very much like a "mechanism for kernel threads to explicitly relinquish any access to the filesystem", e.g. kernel threads could do the equivalent of pivot_root() into an empty tmpfs).