Userspace part of reroot support. This makes it possible to change
the root filesystem without full reboot, using "reboot -r". This makes
it possible to eg. boot from a temporary md_image preloaded by loader(8),
setup an iSCSI session, and continue booting from rootfs mounted over
iSCSI.
Details
- Reviewers
kib bapt - Group Reviewers
manpages - Commits
- rS293744: MFC r290548:
rS290548: Userspace part of reroot support. This makes it possible to change
Diff Detail
- Repository
- rS FreeBSD src repository - subversion
- Lint
Lint Not Applicable - Unit
Tests Not Applicable
Event Timeline
sbin/init/init.c | ||
---|---|---|
233 ↗ | (On Diff #8834) | Wouldn't it be somewhat more consistent to use 'R' for option ? |
391 ↗ | (On Diff #8834) | Shouldn't some additional checks be done there ? E.g. verify that something is mounted (as a compliment to kernel, to avoid dangerous syscall), and that the type of the mounted fs is expected one (tmpfs) ? This again raises the question of the MNT flag that could be checked to ensure that we unmount our fs. |
724 ↗ | (On Diff #8834) | Style: do not use initialization in local declarations. |
727 ↗ | (On Diff #8834) | Unneeded empty line. |
746 ↗ | (On Diff #8834) | Same. |
753 ↗ | (On Diff #8834) | Style. Put error declaration last. |
757 ↗ | (On Diff #8834) | I hoped that userpace part of reroot kills all user processes except init. Apparently it does not. |
781 ↗ | (On Diff #8834) | Unneeded empty line. |
1753 ↗ | (On Diff #8834) | Why is this block moved ? |
sbin/reboot/reboot.8 | ||
---|---|---|
117 ↗ | (On Diff #8834) | This sentence is not very clear. Maybe After changing vfs.root.mountfrom with .Xr kenv 8 , .Nm can be used to change the root filesystem while preserving kernel state. |
sbin/reboot/reboot.c | ||
114 ↗ | (On Diff #8834) | Simpler: errx(1, "-r cannot be used with -d, -n, or -p"); |
182 ↗ | (On Diff #8834) | s/Nobody but/Only/ |
Would be nice to have a mechanism similat to init_chroot so that one could have a very minimal root and start it the following way:
init_path=/rescue/init
init_shell=/rescue/shell
init_script=/prepareroot.sh
init_reroot=ufs:/dev/md1
and in /prepareroot.sh one does prepare the root filesystem
exit 0 in prepareroot.sh
then init auto reroot
sbin/init/init.c | ||
---|---|---|
763 ↗ | (On Diff #8834) | Actually here it should read from the path provided by: kern.proc.pathname |
sbin/init/init.c | ||
---|---|---|
233 ↗ | (On Diff #8834) | Hm, all the other flags for reboot(8) are lowercase. Or did you mean to change "init -R" to "init -r"? |
391 ↗ | (On Diff #8834) | What's dangerous in unmount(2)? As for interfering: on one hand you're right, on the other - if someone wants to interfere with the operation, and they are UID 0, then it's their fault. |
1753 ↗ | (On Diff #8834) | To make it possible to call that whole block from reroot(), so that initial part of reroot process looks to userspace just like shutdown. |
sbin/init/init.c | ||
---|---|---|
233 ↗ | (On Diff #8834) | Erm, what I meant was - all the other flags for init(8) are lowercase, so how does "-R" improve consistency? |
sbin/init/init.c | ||
---|---|---|
757 ↗ | (On Diff #8834) | I've added a call to kill(-1, SIGKILL) in reroot_phase_two(). |
sbin/init/init.c | ||
---|---|---|
763 ↗ | (On Diff #9452) | I'd prefer to obtain init path in a single unified way. And the problem is, the executable is exec(2)ed twice, from different paths, so the kern.proc.pathname would return "/sbin/init" only the first time, and "/dev/reroot/init" after that. Perhaps we should have a sysctl, eg. kern.init_path? An alternative would be to use kenv(2) to obtain "init_path", and use the default init path if not found. But what if the kernel chose some other value, eg. in /rescue? |
sbin/init/init.c | ||
---|---|---|
233 ↗ | (On Diff #9452) | Several lines below, where you handle options for pid == 1 (i.e. reexec) case, you use '-R'. In fact I think that the re-exec flag should be changed to -r. |
391 ↗ | (On Diff #9452) | System should be as tamper-resistant as it could be, but not prevent users from being ingenious in their system usage. I do not see any useful consequences in tricking init into unmounting something which was not mounted transiently by reroot. In other words, the check could protect a mistaken user from destroying the system. |
1777 ↗ | (On Diff #9452) | Ok, let me explain my question explicitely. The runshutdown() function was clean, it executed /etc/rc.shutdown script and that was all. The death() state handler brings system to the single mode, it needs to execute several steps, like shut down the getty sessions, run the rc.shutdown, switch state to single user and so on. If you want to get the functionality of shutting down getty sessions + rc.shutdown, you should move getty code into new helper, and call the new helper and runshutdown() from that place, instead of hacking runshutdown. |
Replace -R with -r, get runshutdown() back to the original form, and move
kill(-1, ...) a little earlier; no reason to defer it to phase two.
sbin/init/init.c | ||
---|---|---|
391 ↗ | (On Diff #9452) | I understand your point, but still - if a "mistaken user" manages to mount something on /dev/reroot/ during root mount, before even the init(8) gets started, then... well, it's their fault. There is no way to do it by accident. |
1777 ↗ | (On Diff #9452) | Ah, you're right. Fixed. |
sbin/init/init.c | ||
---|---|---|
764 ↗ | (On Diff #9513) | respecting init_path from loader.conf/kenv is good enough for my usecase, for sure the current mechanism does not work for my use case. |
sbin/init/init.c | ||
---|---|---|
764 ↗ | (On Diff #9513) | Ok, I made it use init_path. Please test it to see if the semantics fits your use case. |
Make "reboot -r" work correctly when called from /etc/rc. This could
have been prettier, but it's the least intrusive - as in, safest - way.