zfs/contrib/dracut/90zfs/zfs-generator.sh.in

43 lines
1.2 KiB
Bash
Raw Normal View History

dracut: use /bin/sh instead of bash as the intepreter Despite that dracut has a hard dependency on bash, its modules doesn't, dracut only has a hard dependency on bash for module-setup (on a fully usable machine). Inside initramfs, dracut allows users choose from a list of handful other shells, e.g. bash, busybox, dash, mkfsh. In fact, my local machine's initramfs is being built with dash, and it's functional for a very long time. Before 64025fa3a (Silence 'make checkbashisms', 2020-08-20), we also allows our users to have that right, too. Let's fix the problem 'make checkbashisms' reported and allows our users to have that right, again. For 'plymouth' case, let's simply run the command inside the if instead of checking for the existence of command before running it, because the status is also failture if plymouth is unavailable. While we're at it, let's remove an unnecessary fork for grep in zfs-generator.sh.in and its following complicated 'if elif fi' with a simple 'case ... esac'. To support this change, also exclude 90zfs from "make checkbashisms" because the current CI infrastructure ships an old version of "checkbashisms", which complains about "command -v", while the current latest "checkbashisms" thinks it's fine. In the near future, we can revert that change to "Makefile.am" when CI infrastructure is updated. Reviewed-by: Gabriel A. Devenyi <gdevenyi@gmail.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Đoàn Trần Công Danh <congdanhqx@gmail.com> Closes #11244
2020-11-28 19:02:08 +00:00
#!/bin/sh
# shellcheck disable=SC2016,SC1004,SC2154
grep -wq debug /proc/cmdline && debug=1
[ -n "$debug" ] && echo "zfs-generator: starting" >> /dev/kmsg
Use a different technique to detect whether to mount-zfs The behavior of the Dracut module was very wrong before. The correct behavior: initramfs should not run `zfs-mount` to completion if the two generator files exist. If, however, one of them is missing, it indicates one of three cases: * The kernel command line did not specify a root ZFS file system, and another Dracut module is already handling root mount (via systemd). `mount-zfs` can run, but it will do nothing. * There is no systemd to run `sysroot.mount` to begin with. `mount-zfs` must run. * The root parameter is zfs:AUTO, which cannot be run in sysroot.mount. `mount-zfs` must run. In any of these three cases, it is safe to run `zfs-mount` to completion. `zfs-mount` must also delete itself if it determines it should not run, or else Dracut will do the insane thing of running it over and over again. Literally, the definition of insanity, doing the same thing that did not work before, expecting different results. Doing that may have had a great result before, when we had a race between devices appearing and pools being mounted, and `mount-zfs` was tasked with the full responsibility of importing the needed pool, but nowadays it is wrong behavior and should be suppressed. I deduced that self-deletion was the correct thing to do by looking at other Dracut code, because (as we all are very fully aware of) Dracut is entirely, ahem, "implementation-defined". Tested-by: @wphilips Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Manuel Amador (Rudd-O) <rudd-o@rudd-o.com> Closes #5157 Closes #5204
2016-10-06 17:26:47 +00:00
GENERATOR_DIR="$1"
Use a different technique to detect whether to mount-zfs The behavior of the Dracut module was very wrong before. The correct behavior: initramfs should not run `zfs-mount` to completion if the two generator files exist. If, however, one of them is missing, it indicates one of three cases: * The kernel command line did not specify a root ZFS file system, and another Dracut module is already handling root mount (via systemd). `mount-zfs` can run, but it will do nothing. * There is no systemd to run `sysroot.mount` to begin with. `mount-zfs` must run. * The root parameter is zfs:AUTO, which cannot be run in sysroot.mount. `mount-zfs` must run. In any of these three cases, it is safe to run `zfs-mount` to completion. `zfs-mount` must also delete itself if it determines it should not run, or else Dracut will do the insane thing of running it over and over again. Literally, the definition of insanity, doing the same thing that did not work before, expecting different results. Doing that may have had a great result before, when we had a race between devices appearing and pools being mounted, and `mount-zfs` was tasked with the full responsibility of importing the needed pool, but nowadays it is wrong behavior and should be suppressed. I deduced that self-deletion was the correct thing to do by looking at other Dracut code, because (as we all are very fully aware of) Dracut is entirely, ahem, "implementation-defined". Tested-by: @wphilips Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Manuel Amador (Rudd-O) <rudd-o@rudd-o.com> Closes #5157 Closes #5204
2016-10-06 17:26:47 +00:00
[ -n "$GENERATOR_DIR" ] || {
echo "zfs-generator: no generator directory specified, exiting" >> /dev/kmsg
exit 1
}
# shellcheck source=zfs-lib.sh.in
. /lib/dracut-zfs-lib.sh
decode_root_args || exit 0
[ -n "$debug" ] && echo "zfs-generator: writing extension for sysroot.mount to $GENERATOR_DIR/sysroot.mount.d/zfs-enhancement.conf" >> /dev/kmsg
Use a different technique to detect whether to mount-zfs The behavior of the Dracut module was very wrong before. The correct behavior: initramfs should not run `zfs-mount` to completion if the two generator files exist. If, however, one of them is missing, it indicates one of three cases: * The kernel command line did not specify a root ZFS file system, and another Dracut module is already handling root mount (via systemd). `mount-zfs` can run, but it will do nothing. * There is no systemd to run `sysroot.mount` to begin with. `mount-zfs` must run. * The root parameter is zfs:AUTO, which cannot be run in sysroot.mount. `mount-zfs` must run. In any of these three cases, it is safe to run `zfs-mount` to completion. `zfs-mount` must also delete itself if it determines it should not run, or else Dracut will do the insane thing of running it over and over again. Literally, the definition of insanity, doing the same thing that did not work before, expecting different results. Doing that may have had a great result before, when we had a race between devices appearing and pools being mounted, and `mount-zfs` was tasked with the full responsibility of importing the needed pool, but nowadays it is wrong behavior and should be suppressed. I deduced that self-deletion was the correct thing to do by looking at other Dracut code, because (as we all are very fully aware of) Dracut is entirely, ahem, "implementation-defined". Tested-by: @wphilips Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Manuel Amador (Rudd-O) <rudd-o@rudd-o.com> Closes #5157 Closes #5204
2016-10-06 17:26:47 +00:00
contrib: dracut: fix race with root=zfs:dset when necessities required This had always worked in my testing, but a user on hardware reported this to happen 100%, and I reproduced it once with cold VM host caches. dracut-zfs-generator runs as a systemd generator, i.e. at Some Relatively Early Time; if root= is a fixed dataset, it tries to "solve [necessities] statically at generation time". If by that point zfs-import.target hasn't popped (because the import is taking a non-negligible amount of time for whatever reason), it'll see no children for the root datase, and as such generate no mounts. This has never had any right to work. No-one caught this earlier because it's just that much more convenient to have root=zfs:AUTO, which orders itself properly. To fix this, always run zfs-nonroot-necessities.service; this additionally simplifies the implementation by: * making BOOTFS from zfs-env-bootfs.service be the real, canonical, root dataset name, not just "whatever the first bootfs is", and only set it if we're ZFS-booting * zfs-{rollback,snapshot}-bootfs.service can use this instead of re-implementing it * having zfs-env-bootfs.service also set BOOTFSFLAGS * this means the sysroot.mount drop-in can be fixed text * zfs-nonroot-necessities.service can also be constant and always enabled, because it's conditioned on BOOTFS being set There is no longer any code generated at run-time (the sysroot.mount drop-in is an unavoidable gratuitous cp). The flow of BOOTFS{,FLAGS} from zfs-env-bootfs.service to sysroot.mount is not noted explicitly in dracut.zfs(7), because (a) at some point it's just visual noise and (b) it's already ordered via d-p-m.s from z-i.t. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz> Closes #14690
2023-03-31 16:47:48 +00:00
mkdir -p "$GENERATOR_DIR"/sysroot.mount.d "$GENERATOR_DIR"/dracut-pre-mount.service.d
{
echo "[Unit]"
Use a different technique to detect whether to mount-zfs The behavior of the Dracut module was very wrong before. The correct behavior: initramfs should not run `zfs-mount` to completion if the two generator files exist. If, however, one of them is missing, it indicates one of three cases: * The kernel command line did not specify a root ZFS file system, and another Dracut module is already handling root mount (via systemd). `mount-zfs` can run, but it will do nothing. * There is no systemd to run `sysroot.mount` to begin with. `mount-zfs` must run. * The root parameter is zfs:AUTO, which cannot be run in sysroot.mount. `mount-zfs` must run. In any of these three cases, it is safe to run `zfs-mount` to completion. `zfs-mount` must also delete itself if it determines it should not run, or else Dracut will do the insane thing of running it over and over again. Literally, the definition of insanity, doing the same thing that did not work before, expecting different results. Doing that may have had a great result before, when we had a race between devices appearing and pools being mounted, and `mount-zfs` was tasked with the full responsibility of importing the needed pool, but nowadays it is wrong behavior and should be suppressed. I deduced that self-deletion was the correct thing to do by looking at other Dracut code, because (as we all are very fully aware of) Dracut is entirely, ahem, "implementation-defined". Tested-by: @wphilips Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Manuel Amador (Rudd-O) <rudd-o@rudd-o.com> Closes #5157 Closes #5204
2016-10-06 17:26:47 +00:00
echo "Before=initrd-root-fs.target"
echo "After=zfs-import.target"
echo
echo "[Mount]"
contrib: dracut: fix race with root=zfs:dset when necessities required This had always worked in my testing, but a user on hardware reported this to happen 100%, and I reproduced it once with cold VM host caches. dracut-zfs-generator runs as a systemd generator, i.e. at Some Relatively Early Time; if root= is a fixed dataset, it tries to "solve [necessities] statically at generation time". If by that point zfs-import.target hasn't popped (because the import is taking a non-negligible amount of time for whatever reason), it'll see no children for the root datase, and as such generate no mounts. This has never had any right to work. No-one caught this earlier because it's just that much more convenient to have root=zfs:AUTO, which orders itself properly. To fix this, always run zfs-nonroot-necessities.service; this additionally simplifies the implementation by: * making BOOTFS from zfs-env-bootfs.service be the real, canonical, root dataset name, not just "whatever the first bootfs is", and only set it if we're ZFS-booting * zfs-{rollback,snapshot}-bootfs.service can use this instead of re-implementing it * having zfs-env-bootfs.service also set BOOTFSFLAGS * this means the sysroot.mount drop-in can be fixed text * zfs-nonroot-necessities.service can also be constant and always enabled, because it's conditioned on BOOTFS being set There is no longer any code generated at run-time (the sysroot.mount drop-in is an unavoidable gratuitous cp). The flow of BOOTFS{,FLAGS} from zfs-env-bootfs.service to sysroot.mount is not noted explicitly in dracut.zfs(7), because (a) at some point it's just visual noise and (b) it's already ordered via d-p-m.s from z-i.t. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz> Closes #14690
2023-03-31 16:47:48 +00:00
echo "PassEnvironment=BOOTFS BOOTFSFLAGS"
echo 'What=${BOOTFS}'
echo "Type=zfs"
contrib: dracut: fix race with root=zfs:dset when necessities required This had always worked in my testing, but a user on hardware reported this to happen 100%, and I reproduced it once with cold VM host caches. dracut-zfs-generator runs as a systemd generator, i.e. at Some Relatively Early Time; if root= is a fixed dataset, it tries to "solve [necessities] statically at generation time". If by that point zfs-import.target hasn't popped (because the import is taking a non-negligible amount of time for whatever reason), it'll see no children for the root datase, and as such generate no mounts. This has never had any right to work. No-one caught this earlier because it's just that much more convenient to have root=zfs:AUTO, which orders itself properly. To fix this, always run zfs-nonroot-necessities.service; this additionally simplifies the implementation by: * making BOOTFS from zfs-env-bootfs.service be the real, canonical, root dataset name, not just "whatever the first bootfs is", and only set it if we're ZFS-booting * zfs-{rollback,snapshot}-bootfs.service can use this instead of re-implementing it * having zfs-env-bootfs.service also set BOOTFSFLAGS * this means the sysroot.mount drop-in can be fixed text * zfs-nonroot-necessities.service can also be constant and always enabled, because it's conditioned on BOOTFS being set There is no longer any code generated at run-time (the sysroot.mount drop-in is an unavoidable gratuitous cp). The flow of BOOTFS{,FLAGS} from zfs-env-bootfs.service to sysroot.mount is not noted explicitly in dracut.zfs(7), because (a) at some point it's just visual noise and (b) it's already ordered via d-p-m.s from z-i.t. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz> Closes #14690
2023-03-31 16:47:48 +00:00
echo 'Options=${BOOTFSFLAGS}'
Use a different technique to detect whether to mount-zfs The behavior of the Dracut module was very wrong before. The correct behavior: initramfs should not run `zfs-mount` to completion if the two generator files exist. If, however, one of them is missing, it indicates one of three cases: * The kernel command line did not specify a root ZFS file system, and another Dracut module is already handling root mount (via systemd). `mount-zfs` can run, but it will do nothing. * There is no systemd to run `sysroot.mount` to begin with. `mount-zfs` must run. * The root parameter is zfs:AUTO, which cannot be run in sysroot.mount. `mount-zfs` must run. In any of these three cases, it is safe to run `zfs-mount` to completion. `zfs-mount` must also delete itself if it determines it should not run, or else Dracut will do the insane thing of running it over and over again. Literally, the definition of insanity, doing the same thing that did not work before, expecting different results. Doing that may have had a great result before, when we had a race between devices appearing and pools being mounted, and `mount-zfs` was tasked with the full responsibility of importing the needed pool, but nowadays it is wrong behavior and should be suppressed. I deduced that self-deletion was the correct thing to do by looking at other Dracut code, because (as we all are very fully aware of) Dracut is entirely, ahem, "implementation-defined". Tested-by: @wphilips Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Manuel Amador (Rudd-O) <rudd-o@rudd-o.com> Closes #5157 Closes #5204
2016-10-06 17:26:47 +00:00
} > "$GENERATOR_DIR"/sysroot.mount.d/zfs-enhancement.conf
ln -fs ../sysroot.mount "$GENERATOR_DIR"/initrd-root-fs.target.requires/sysroot.mount
{
echo "[Unit]"
echo "After=zfs-import.target"
} > "$GENERATOR_DIR"/dracut-pre-mount.service.d/zfs-enhancement.conf
[ -n "$debug" ] && echo "zfs-generator: finished" >> /dev/kmsg
exit 0