[arch-projects] [PATCH] init_functions: rework `default_mount_handler` -- assume less/succeed more
mostly shuffling, save: 1) immediate mount attempt: assume hooks have allowed for this $root is opaque, attempts to dechiper it's meaning are out of scope. 2) first mount fail: print details, offer to mount(0) or boot(1) 3) second mount fail: print details, offer to reboot(0) or boot(1) this work allows the default handler to be used in nearly all cases mount itself could handle -- work prompted by needless failing of a virtio/9p2000.L based passthru "device" as $root. Signed-off-by: C Anthony Risinger <anthony@xtfx.me> --- init_functions | 37 ++++++++++++++++++++++++++----------- 1 files changed, 26 insertions(+), 11 deletions(-) diff --git a/init_functions b/init_functions index 42e6249..d0bd042 100644 --- a/init_functions +++ b/init_functions @@ -197,18 +197,33 @@ resolve_device() { } default_mount_handler() { - if [ ! -b "$root" ]; then - err "Unable to determine major/minor number of root device '$root'." - echo "You are being dropped to a recovery shell" - echo " Type 'exit' to try and continue booting" - launch_interactive_shell - msg "Trying to continue (this will most likely fail) ..." - fi + local opts="${rootfstype:+-t $rootfstype} -o ${rwopt:-ro}${rootflags:+,$rootflags}" - if ! mount ${fstype:+-t $fstype} -o ${rwopt:-ro}${rootflags:+,$rootflags} "$root" "$1"; then - echo "You are now being dropped into an emergency shell." - launch_interactive_shell - msg "Trying to continue (this will most likely fail) ..." + if ! mount ${opts} "$root" "$1"; then + if [ ! -b "$root" ]; then + err "Unable to determine major/minor number of root device '$root'." + fi + echo $'\n'"Unable to mount root device '$root'! (1 of 2)"$'\n' + echo "mount ${opts} '$root' '$1'"$'\n' + echo "You are being dropped to an recovery shell, typing ..." + echo " 'exit 0' attempts to boot after first retrying the failed mount." + echo " 'exit 1' attempts to boot immediately -- '$1' MUST be mounted." + if launch_interactive_shell; then + echo "Attempting to mount '$root' ..." + if ! mount ${opts} "$root" "$1"; then + echo $'\n'"Unable to mount root device '$root'! (2 of 2)"$'\n' + echo "mount ${opts} '$root' '$1'"$'\n' + echo "You are being dropped to an emergency shell, typing ..." + echo " 'exit 0' abruptly ends our adventure and reboots the machine." + echo " 'exit 1' attempts to boot immediately -- '$1' MUST be mounted." + if launch_interactive_shell; then + echo $'\n'":: Boot aborted, reboot in progress" + sleep 2 + reboot -f + fi + fi + fi + echo "Trying to continue (will fail unless '$root' is mounted) ..." fi } -- 1.7.7.3
Am 17.11.2011 07:20, schrieb C Anthony Risinger:
+ if ! mount ${opts} "$root" "$1"; then + if [ ! -b "$root" ]; then + err "Unable to determine major/minor number of root device '$root'." + fi
This error message no longer makes sense. Replace it by something understandable.
On Thu, Nov 17, 2011 at 12:20:54AM -0600, C Anthony Risinger wrote:
mostly shuffling, save:
1) immediate mount attempt: assume hooks have allowed for this $root is opaque, attempts to dechiper it's meaning are out of scope.
I have no idea what this means.
2) first mount fail: print details, offer to mount(0) or boot(1) 3) second mount fail: print details, offer to reboot(0) or boot(1)
Why twice? Seems arbitrary. Why not just run a while loop? while ! mount $opts; do if ! launch_interactive_shell; then break fi done Let the user figure out when to quit (reboot).
this work allows the default handler to be used in nearly all cases mount itself could handle -- work prompted by needless failing of a virtio/9p2000.L based passthru "device" as $root.
Why not just write a mount hook that covers this one use case? plan 9 isn't exactly common.
Signed-off-by: C Anthony Risinger <anthony@xtfx.me> --- init_functions | 37 ++++++++++++++++++++++++++----------- 1 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/init_functions b/init_functions index 42e6249..d0bd042 100644 --- a/init_functions +++ b/init_functions @@ -197,18 +197,33 @@ resolve_device() { }
default_mount_handler() { - if [ ! -b "$root" ]; then - err "Unable to determine major/minor number of root device '$root'." - echo "You are being dropped to a recovery shell" - echo " Type 'exit' to try and continue booting" - launch_interactive_shell - msg "Trying to continue (this will most likely fail) ..." - fi + local opts="${rootfstype:+-t $rootfstype} -o ${rwopt:-ro}${rootflags:+,$rootflags}"
- if ! mount ${fstype:+-t $fstype} -o ${rwopt:-ro}${rootflags:+,$rootflags} "$root" "$1"; then - echo "You are now being dropped into an emergency shell." - launch_interactive_shell - msg "Trying to continue (this will most likely fail) ..." + if ! mount ${opts} "$root" "$1"; then + if [ ! -b "$root" ]; then + err "Unable to determine major/minor number of root device '$root'." + fi + echo $'\n'"Unable to mount root device '$root'! (1 of 2)"$'\n'
I'd rather use printf than embed shell expanded newlines.
+ echo "mount ${opts} '$root' '$1'"$'\n' + echo "You are being dropped to an recovery shell, typing ..." + echo " 'exit 0' attempts to boot after first retrying the failed mount." + echo " 'exit 1' attempts to boot immediately -- '$1' MUST be mounted."
Why $1 and not $root? The latter has a lot more meaning to the user. You mount block devices, not directories (ignoring bind mounts).
+ if launch_interactive_shell; then + echo "Attempting to mount '$root' ..." + if ! mount ${opts} "$root" "$1"; then + echo $'\n'"Unable to mount root device '$root'! (2 of 2)"$'\n' + echo "mount ${opts} '$root' '$1'"$'\n' + echo "You are being dropped to an emergency shell, typing ..." + echo " 'exit 0' abruptly ends our adventure and reboots the machine." + echo " 'exit 1' attempts to boot immediately -- '$1' MUST be mounted."
same here re: $1 v $root.
+ if launch_interactive_shell; then + echo $'\n'":: Boot aborted, reboot in progress"
same here re: echo v printf.
+ sleep 2 + reboot -f + fi + fi + fi + echo "Trying to continue (will fail unless '$root' is mounted) ..." fi }
-- 1.7.7.3
On Thu, Nov 17, 2011 at 3:24 AM, Thomas Bächler <thomas@archlinux.org> wrote:
Am 17.11.2011 07:20, schrieb C Anthony Risinger:
+ if ! mount ${opts} "$root" "$1"; then + if [ ! -b "$root" ]; then + err "Unable to determine major/minor number of root device '$root'." + fi
This error message no longer makes sense. Replace it by something understandable.
sure, how about (as a msg instead of err): "Is root device a /dev/<blockdev>? Unable to determine it's major/minor number." ... or... "Root device does not exist -- not a block device, or unable to locate/determine it's major/minor number." ... something like that? On Thu, Nov 17, 2011 at 8:11 AM, Dave Reisner <d@falconindy.com> wrote:
On Thu, Nov 17, 2011 at 12:20:54AM -0600, C Anthony Risinger wrote:
mostly shuffling, save:
1) immediate mount attempt: assume hooks have allowed for this $root is opaque, attempts to dechiper it's meaning are out of scope.
I have no idea what this means.
i meant that to the handler, $root is an arbitrary string (ie, "black box" of sorts) -- it has no way to really understand what it could mean. IMO, the `handler` should only be concerned with the high-level flow, not attempt to make concrete decisions. in fact, i would take this one step further by introducing a `mount_exec` variable/identifier pointing to the concrete function responsible for "mounting the root" ... this would allow the `default_mount_handler` to be used in *any* concrete `mount_handler` ... one would only change `mount_handler` if they wanted to change the questions asked, or the options presented on failure -- i'll save that for another day :-)
2) first mount fail: print details, offer to mount(0) or boot(1) 3) second mount fail: print details, offer to reboot(0) or boot(1)
Why twice? Seems arbitrary. Why not just run a while loop?
while ! mount $opts; do if ! launch_interactive_shell; then break fi done
Let the user figure out when to quit (reboot).
ok, i did consider (and prefer) that as well -- i chose twice to maintain the "now in recover/emergency" of the original. its not currently possible for the interactive shell to change anything though (the $root variable/etc), so i don't know how useful it will be (maybe introduce an fd the user can echo variables into??). i'll explore this a bit for v2.
this work allows the default handler to be used in nearly all cases mount itself could handle -- work prompted by needless failing of a virtio/9p2000.L based passthru "device" as $root.
Why not just write a mount hook that covers this one use case? plan 9 isn't exactly common.
true, but its not even failing -- if i just type `exit` the VM boots fine. there isn't much need for a hook -- it's a bug to me that the `default_mount_handler` is failing because it tries to know more than `mount`. <excess> 9p2000.L passthru ("VirtFS") is a pretty hot topic in the virtualization world, and most of what i do with Arch is related to that -- im trying to make it more virt friendly. this method can achieve better perf than raw-block by taking advantage of the host page cache (my systemd VMs boot cold-to-100% in less than 2-3 seconds), it's significantly less management overhead than raw-block, and allows dead simple guest sharing via bind-mounts and several other advantages -- i fully expect it to be wildly popular :-) </excess> also see: http://mailman.archlinux.org/pipermail/arch-general/2011-July/021195.html ... i'm basically just fixing that permanently
Signed-off-by: C Anthony Risinger <anthony@xtfx.me> --- init_functions | 37 ++++++++++++++++++++++++++----------- 1 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/init_functions b/init_functions index 42e6249..d0bd042 100644 --- a/init_functions +++ b/init_functions @@ -197,18 +197,33 @@ resolve_device() { }
default_mount_handler() { - if [ ! -b "$root" ]; then - err "Unable to determine major/minor number of root device '$root'." - echo "You are being dropped to a recovery shell" - echo " Type 'exit' to try and continue booting" - launch_interactive_shell - msg "Trying to continue (this will most likely fail) ..." - fi + local opts="${rootfstype:+-t $rootfstype} -o ${rwopt:-ro}${rootflags:+,$rootflags}"
- if ! mount ${fstype:+-t $fstype} -o ${rwopt:-ro}${rootflags:+,$rootflags} "$root" "$1"; then - echo "You are now being dropped into an emergency shell." - launch_interactive_shell - msg "Trying to continue (this will most likely fail) ..." + if ! mount ${opts} "$root" "$1"; then + if [ ! -b "$root" ]; then + err "Unable to determine major/minor number of root device '$root'." + fi + echo $'\n'"Unable to mount root device '$root'! (1 of 2)"$'\n'
I'd rather use printf than embed shell expanded newlines.
hmm, i agree, and had used printf first, but for some reason i thought i *had* to use minimum of 2 args to `printf`, not the case ... will update this.
+ echo "mount ${opts} '$root' '$1'"$'\n' + echo "You are being dropped to an recovery shell, typing ..." + echo " 'exit 0' attempts to boot after first retrying the failed mount." + echo " 'exit 1' attempts to boot immediately -- '$1' MUST be mounted."
Why $1 and not $root? The latter has a lot more meaning to the user. You mount block devices, not directories (ignoring bind mounts).
i chose $1 because $root is already shown in the mount command (well, so is $1) ... but $1 is less known to user. everybody knows *what* they use as root, but far less people know *where* it needs to be mounted during initramfs (impl detail) ... ... is there value in that? $root can get huge too ... i'd prefer to write both but i didn't want to be too verbose. maybe reword to "$1 must be a mountpoint", or similar? -- C Anthony
Am 17.11.2011 19:01, schrieb C Anthony Risinger:
On Thu, Nov 17, 2011 at 3:24 AM, Thomas Bächler <thomas@archlinux.org> wrote:
Am 17.11.2011 07:20, schrieb C Anthony Risinger:
+ if ! mount ${opts} "$root" "$1"; then + if [ ! -b "$root" ]; then + err "Unable to determine major/minor number of root device '$root'." + fi
This error message no longer makes sense. Replace it by something understandable.
sure, how about (as a msg instead of err):
"Is root device a /dev/<blockdev>? Unable to determine it's major/minor number."
... or...
"Root device does not exist -- not a block device, or unable to locate/determine it's major/minor number."
... something like that?
The whole major/minor comment confuses people. Simply state that the root device does not exist and/or could not be created.
On Thu, Nov 17, 2011 at 12:25 PM, Thomas Bächler <thomas@archlinux.org> wrote:
The whole major/minor comment confuses people. Simply state that the root device does not exist and/or could not be created.
sure sure, can do. On Thu, Nov 17, 2011 at 12:45 PM, Dave Reisner <d@falconindy.com> wrote:
On Thu, Nov 17, 2011 at 12:01:52PM -0600, C Anthony Risinger wrote:
root= is extremely *non*-arbitrary. It always exists, and it's 1 of three things:
- a filesystem path to a block device (e.g. /dev/sdxy or /dev/disk/by-....) - a tag with a value (LABEL=mysweetdisk) - a hex encoded major/minor device number (e.g. fe01)
That's all it can ever be in the current codebase.
but this is the crux of what i meant by `is opaque` -- by assuming the root= can never be anything but the above, you have limited it's general applicability. all it needs to do is attempt running "some command that makes /new_root available", it doesn't need to care about anything else because it's essentially a high level interface for the user. by moving the blockdev check somewhere else, you could reuse `default_mount_handler` as general "UI" logic for any mount hook, be nfs/9p/.../.../etc
And that said, I broke out resolution of the root= parameter to its own function so that the mount handler never needs to see it as anything but a filesystem path to a block device.
... and that is a great change, taking it 95%, this is just the last %5.
There seems to be a much simpler solution to all this, which is sort of in line with your idea. Don't assume that mount will fail. Just try it, and let it fail. Only then, when it does, check to see if its a block device and complain, e.g.
http://code.falconindy.com/cgit/mkinitcpio.git/commit/?h=throwaway
that solves my immediate need, yes. i figured i would improve the interface while i was there, since by default, no details are provided about the fail, and it's lees than obvious what the next step could/should be (esp. for someone not expecting the fail, or seeing it for the first time).
Not going to comment on the rest of this.
excellente! i presume that's roughly analogous to "i like my opponent, i think he's a good man, but quite frankly" ... ... "i-agree-with-everything-he-just-said" ... ;-) tbc -- C Anthony
On Thu, Nov 17, 2011 at 12:01:52PM -0600, C Anthony Risinger wrote:
On Thu, Nov 17, 2011 at 3:24 AM, Thomas Bächler <thomas@archlinux.org> wrote:
Am 17.11.2011 07:20, schrieb C Anthony Risinger:
+ if ! mount ${opts} "$root" "$1"; then + if [ ! -b "$root" ]; then + err "Unable to determine major/minor number of root device '$root'." + fi
This error message no longer makes sense. Replace it by something understandable.
sure, how about (as a msg instead of err):
"Is root device a /dev/<blockdev>? Unable to determine it's major/minor number."
... or...
"Root device does not exist -- not a block device, or unable to locate/determine it's major/minor number."
... something like that?
On Thu, Nov 17, 2011 at 8:11 AM, Dave Reisner <d@falconindy.com> wrote:
On Thu, Nov 17, 2011 at 12:20:54AM -0600, C Anthony Risinger wrote:
mostly shuffling, save:
1) immediate mount attempt: assume hooks have allowed for this $root is opaque, attempts to dechiper it's meaning are out of scope.
I have no idea what this means.
i meant that to the handler, $root is an arbitrary string (ie, "black box" of sorts) -- it has no way to really understand what it could mean. IMO, the `handler` should only be concerned with the high-level flow, not attempt to make concrete decisions.
root= is extremely *non*-arbitrary. It always exists, and it's 1 of three things: - a filesystem path to a block device (e.g. /dev/sdxy or /dev/disk/by-....) - a tag with a value (LABEL=mysweetdisk) - a hex encoded major/minor device number (e.g. fe01) That's all it can ever be in the current codebase. And that said, I broke out resolution of the root= parameter to its own function so that the mount handler never needs to see it as anything but a filesystem path to a block device. There seems to be a much simpler solution to all this, which is sort of in line with your idea. Don't assume that mount will fail. Just try it, and let it fail. Only then, when it does, check to see if its a block device and complain, e.g. http://code.falconindy.com/cgit/mkinitcpio.git/commit/?h=throwaway Not going to comment on the rest of this. d
participants (3)
-
C Anthony Risinger
-
Dave Reisner
-
Thomas Bächler