Recognize rd.live.ram=1

1,091 views
Skip to first unread message

iwillalwa...@gmail.com

unread,
Oct 30, 2018, 2:08:44 AM10/30/18
to kiwi
Dracut documentation explains rd.live.ram=1 but I can't get it to work in kiwi-live.  There is code for it in dmsquash-live but kiwi-live doesn't seem to use it.

Therefore I'm starting an experiment.  Here is kiwi-live-lib.sh for my intended first experiment.  I haven't tested it yet and it might contain any kind of bug, because it's cumbersome to rebuild the initrd, iso, and USB stick.  Does anyone have any comments or suggestions?

The purpose of rd.live.ram=1 is to allow disconnecting the USB stick after booting.

If boot parameters include both rd.live.ram=1 and rd.overlay.persistent then I read the existing cow partition but don't persist any new changes, so the USB stick can be disconnected.

(This also includes the one-line edit discussed in "Enable ISO image to be in any partition of USB stick", https://groups.google.com/forum/#!topic/kiwi-images/XdLIhPlfi1Y )


#!/bin/bash
type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh

function lookupIsoDiskDevice {
    local root=$1
    local iso_label=${root#/dev/disk/by-label/}
    local disk
    for disk in $(lsblk -p -n -r -o NAME,TYPE | grep disk | cut -f1 -d' ');do
        if [[ ${disk} =~ ^/dev/fd ]];then
            # ignore floppy disk devices
            continue
        fi
        iso_volid=$(lsblk -p -n -r -o LABEL "${disk}" | grep "${iso_label}")
        if [ "${iso_volid}" = "${iso_label}" ];then
            echo "${disk}"
            return
        fi
    done
}

function setupDebugMode {
    if getargbool 0 rd.kiwi.debug; then
        local log=/run/initramfs/log
        mkdir -p ${log}
        exec > ${log}/boot.kiwi
        exec 2>> ${log}/boot.kiwi
        set -x
    fi
}

function initialize {
    local profile=/.profile
    test -f ${profile} && cat ${profile}
}

function loadKernelModules {
    modprobe squashfs
}

function initGlobalDevices {
    if [ -z "$1" ]; then
        die "No root device for operation given"
    fi
    isodev="$1"
    isodiskdev=$(lookupIsoDiskDevice "${isodev}")
    isofs_type=$(blkid -s TYPE -o value "${isodev}")
    media_check_device=${isodev}
    if [ ! -z "${isodiskdev}" ]; then
        media_check_device=${isodiskdev}
    fi
    export media_check_device
    export isodev
    export isodiskdev
    export isofs_type
}

function initGlobalOptions {
    live_dir=$(getarg rd.live.dir -d live_dir)
    [ -z "${live_dir}" ] && live_dir="LiveOS"

    squash_image=$(getarg rd.live.squashimg)
    [ -z "${squash_image}" ] && squash_image="squashfs.img"

    cow_filesystem=$(getarg rd.live.overlay.cowfs)
    [ -z "${cow_filesystem}" ] && cow_filesystem="ext4"

    getargbool 0 rd.live.ram -d -y live_ram && live_ram="yes"
}

function mountIso {
    ln -s "${isodev}" /run/initramfs/isodev
    local iso_mount_point=/run/initramfs/live
    mkdir -m 0755 -p "${iso_mount_point}"
    if ! mount -n -t "${isofs_type}" "${isodev}" "${iso_mount_point}"; then
        die "Failed to mount live ISO device"
    fi
    if [ -n "$live_ram" ]; then
        umount ${iso_mount_point}
        iso_image="run/initramfs/${isodev}.iso"
        echo "Copying live image to RAM..."
        echo "(this may take a few minutes)"
        dd if="${isodev}" of="${iso_image}" bs=2048 2>/dev/null
        echo "Done copying live image to RAM."
        if ! mount -n -o loop,ro -t "{isofs_type}" "${iso_image}" "${iso_mount_point}"; then
            die "Failed to mount live image"
        fi
        rm /run/initramfs/isodev
        ln -s "${iso_image}" /run/initramfs/isodev
    fi
    echo "${iso_mount_point}"
}

function mountCompressedContainerFromIso {
    local iso_mount_point=$1
    local container_mount_point=/run/initramfs/squashfs_container
    squashfs_container="${iso_mount_point}/${live_dir}/${squash_image}"
    mkdir -m 0755 -p "${container_mount_point}"
    if ! mount -n "${squashfs_container}" "${container_mount_point}";then
        die "Failed to mount live ISO squashfs container"
    fi
    echo "${container_mount_point}"
}

function mountReadOnlyRootImageFromContainer {
    local container_mount_point=$1
    local rootfs_image="${container_mount_point}/LiveOS/rootfs.img"
    local root_mount_point=/run/rootfsbase
    mkdir -m 0755 -p "${root_mount_point}"
    if ! mount -n "${rootfs_image}" "${root_mount_point}"; then
        die "Failed to mount live ISO root filesystem"
    fi
    echo "${root_mount_point}"
}

function prepareTemporaryOverlay {
    mkdir -m 0755 -p /run/overlayfs/rw
    mkdir -m 0755 -p /run/overlayfs/work
}

function preparePersistentOverlay {
    if [ -z "${isodiskdev}" ]; then
        return 1
    fi
    local overlay_mount_point=/run/overlayfs
    local partitions_before_cow_part
    mkdir -m 0755 -p "${overlay_mount_point}"
    if [ -n "$live_ram" ]; then
        mkdir -m 0755 -p "${overlay_mount_point}/rw"
        mkdir -m 0755 -p "${overlay_mount_point}/work"
        mkdir -m 0755 -p /run/cow
        if mount -L cow "/run/cow"; then
            (cd "/run/cow"; tar cf - . | (cd "${overlay_mount_point}" ; tar xf -))
            umount /run/cow
        fi
        rmdir /run/cow
        return 0
    fi
    if ! mount -L cow "${overlay_mount_point}"; then
        partitions_before_cow_part=$(_partition_count)
        echo -e "n\np\n\n\n\nw\nq" | fdisk "${isodiskdev}"
        if ! partprobe "${isodiskdev}"; then
            return 1
        fi
        if [ "$(_partition_count)" -le "${partitions_before_cow_part}" ];then
            return 1
        fi
        local write_partition
        write_partition=$(lsblk "${isodiskdev}" -p -r -n -o NAME | tail -n1)
        if ! mkfs."${cow_filesystem}" -L cow "${write_partition}"; then
            return 1
        fi
        if ! mount -L cow ${overlay_mount_point}; then
            return 1
        fi
    fi
    mkdir -m 0755 -p ${overlay_mount_point}/rw
    mkdir -m 0755 -p ${overlay_mount_point}/work
}

function runMediaCheck {
    # messages are redirected to stderr because this code is called
    # as part of the pre-mount hook via the dracut-pre-mount.service
    # which only shows messages on stderr to the console and we want
    # to see the check results during boot
    if ! command -v checkmedia &>/dev/null; then
        echo "No mediacheck program installed, mediacheck skipped" 1>&2
        return
    fi
    local timeout=20
    local check_result
    check_result=/run/initramfs/checkmedia.result
    checkmedia "${media_check_device}" &>${check_result}
    local check_status=$?
    if [ ${check_status} != 0 ];then
        echo "ISO check failed" >> ${check_result}
    else
        echo "ISO check passed" >> ${check_result}
    fi
    echo "Press key to continue (waiting ${timeout}sec...)" >> ${check_result}
    _run_dialog --timeout ${timeout} --textbox ${check_result} 20 70
    if [ ${check_status} != 0 ];then
        die "Failed to verify system integrity"
    fi
}

#=========================================
# Methods considered private
#-----------------------------------------
function _setup_interactive_service {
    local service=/usr/lib/systemd/system/dracut-run-interactive.service
    [ -e ${service} ] && return
    {
        echo "[Unit]"
        echo "Description=Dracut Run Interactive"
        echo "DefaultDependencies=no"
        echo "After=systemd-vconsole-setup.service"
        echo "Wants=systemd-vconsole-setup.service"
        echo "Conflicts=emergency.service emergency.target"
        echo "[Service]"
        echo "Environment=HOME=/"
        echo "Environment=DRACUT_SYSTEMD=1"
        echo "Environment=NEWROOT=/sysroot"
        echo "WorkingDirectory=/"
        echo "ExecStart=/bin/bash /bin/dracut-interactive"
        echo "Type=oneshot"
        echo "StandardInput=tty-force"
        echo "StandardOutput=inherit"
        echo "StandardError=inherit"
        echo "KillMode=process"
        echo "IgnoreSIGPIPE=no"
        echo "TaskMax=infinity"
        echo "KillSignal=SIGHUP"
    } > ${service}
}

function _run_interactive {
    _setup_interactive_service
    systemctl start dracut-run-interactive.service
}

function _run_dialog {
    echo "dialog $*" >/bin/dracut-interactive
    _run_interactive
}

function _partition_count {
    if [ -z "${isodiskdev}" ]; then
        echo 0
    else
        lsblk "${isodiskdev}" -p -r -n -o TYPE | grep -c part
    fi
}

kiwi-live-lib.sh

Marcus Schäfer

unread,
Oct 31, 2018, 8:37:54 AM10/31/18
to kiwi-...@googlegroups.com
Hi,

> Dracut documentation explains rd.live.ram=1 but I can't get it to work
> in kiwi-live. There is code for it in dmsquash-live but kiwi-live
> doesn't seem to use it.

You can switch to the upstream dmsquash-live module if you set the
following in your kiwi XML description:

<type ... flags="dmsquash"/>

> Therefore I'm starting an experiment. Here is kiwi-live-lib.sh for my
> intended first experiment. I haven't tested it yet and it might
> contain any kind of bug, because it's cumbersome to rebuild the initrd,
> iso, and USB stick. Does anyone have any comments or suggestions?
> The purpose of rd.live.ram=1 is to allow disconnecting the USB stick
> after booting.

This means you want an OS completely in RAM, which you could also achieve
with a ramonly deployment ISO. If you specify the type in your kiwi XML
description as follows:

<type image="oem" filesystem="ext4" installiso="true" bootloader="grub2" initrd_system="dracut" installboot="install" boottimeout="1" kernelcmdline="rd.kiwi.ramdisk ramdisk_size=2048000">
<oemconfig>
<oem-skip-verify>true</oem-skip-verify>
<oem-unattended>true</oem-unattended>
<oem-unattended-id>/dev/ram1</oem-unattended-id>
<oem-swap>false</oem-swap>
<oem-multipath-scan>false</oem-multipath-scan>
</oemconfig>
</type>

I have tested this setup in a qemu VM and it worked if enough RAM size
is configured for the brd ramdisk driver with the ramdisk_size=N and
N=kbsize value.

During my tests I found a bug in the kiwi code to handle this
properly. Thus if you consider to make use of this feature please
check out the following PR or wait until we have submitted a new
kiwi with this path:

https://github.com/SUSE/kiwi/pull/865

> If boot parameters include both rd.live.ram=1 and rd.overlay.persistent
> then I read the existing cow partition but don't persist any new
> changes, so the USB stick can be disconnected.

Are you sure ? The filesystem is mounted via overlayfs the read-only block
device (your stick) is for sure an active mount to the system. As soon as
the kernel gets to read a block not yet read and you have plugged off the
stick already the system will crash. The only way to safely disconnect the
USB stick is to keep the read-only and any read-write portions in RAM.
Which leads to the suggestion to deploy a complete system to RAM as I wrote
above

Contributions are great, thanks much for your effort.

However for review and discussion it would be really helpful if you could
consider to follow the github process (Issue and Pull-Requests) or send a
patch along such that we can actually see the changes. Review on a complete
file basis is pretty time consuming.

Thanks

Regards,
Marcus
--
Public Key available via: https://keybase.io/marcus_schaefer/key.asc
keybase search marcus_schaefer
-------------------------------------------------------
Marcus Schäfer (Res. & Dev.) SUSE Linux GmbH
Tel: 0911-740 53 0 Maxfeldstrasse 5
FAX: 0911-740 53 479 D-90409 Nürnberg
HRB: 21284 (AG Nürnberg) Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
http://www.suse.de
-------------------------------------------------------

iwillalwa...@gmail.com

unread,
Oct 31, 2018, 9:30:02 PM10/31/18
to kiwi
Sorry, using Google Groups, I can't see how to insert replies inline.  Sorry I have no experience with the github process.

I don't know where GeckoLinux's kiwi XML file is.  I guess the contributor of GeckoLinux did some valuable work setting a brd ramdisk and other things that I never knew about.  Is there another appropriate live CD?  OpenSuse's rescue CDs seemed to be too minimal.  Yes I want ram-only sometimes (the user can choose when booting).

I wrote:  "If boot parameters include both rd.live.ram=1 and rd.overlay.persistent then I read the existing cow partition but don't persist any new changes, so the USB stick can be disconnected."

You asked if I'm sure.  Yes that is the reason why some of my edits check for that combination, make a temporary overlay directory, and copy (using tar) the existing cow partition into the temporary overlay.  Though I haven't tested it yet because it's cumbersome to build and I hope to get it right the first time.

iwillalwa...@gmail.com

unread,
Oct 31, 2018, 9:48:10 PM10/31/18
to kiwi
Mr. Schäfer, if I understand your other posting correctly, you created a new boot option rd.kiwi.ramdisk.  Thank you. 

However, to copy in changes which were previously persisted (though new changes will not be persisted), it seems some of my changes to kiwi-live-lib.sh are still necessary.


Marcus Schäfer

unread,
Nov 5, 2018, 5:47:49 AM11/5/18
to kiwi-...@googlegroups.com
Hi,

> Sorry I have no experience with the github process.

That's ok, patches are also fine:

diff -u original_file new_file

> I don't know where GeckoLinux's kiwi XML file is. I guess the
> contributor of GeckoLinux did some valuable work setting a brd ramdisk
> and other things that I never knew about. Is there another appropriate
> live CD? OpenSuse's rescue CDs seemed to be too minimal.

There are some live builds here:

https://build.opensuse.org/package/show/openSUSE:Factory:Live/livecd-openSUSE

> Yes I want
> ram-only sometimes (the user can choose when booting).
> I wrote: "If boot parameters include both rd.live.ram=1 and
> rd.overlay.persistent then I read the existing cow partition but don't
> persist any new changes, so the USB stick can be disconnected."
> You asked if I'm sure. Yes that is the reason why some of my edits
> check for that combination, make a temporary overlay directory, and
> copy (using tar) the existing cow partition into the temporary
> overlay. Though I haven't tested it yet because it's cumbersome to
> build and I hope to get it right the first time.

I agree that this will ensure the cow to be in ram only, but as the
cow says it's copy-on-write. So assume there is a block on the USB
stick read-only(squashfs) part which was not yet read-in by the kernel
and also not yet part of the cow. In this case the block gets read
from the only location it exists, which is if I got it correctly
still the stick. If at that time the stick is not present you end
in a block read error and that crashes the system.

I'm not familiar with the development of GeckoLinux so I might be
wrong with all this, but if your booted system shows a mount like
this:

mount | grep overlay

LiveOS_rootfs on / type overlay (rw,relatime,lowerdir=/run/rootfsbase,upperdir=/run/overlayfs/rw,workdir=/run/overlayfs/work)

with only one of:

/run/rootfsbase
/run/overlayfs/rw
/run/overlayfs/work

pointing to the stick device you are not safe to unplug.

In my case /run/rootfsbase is a squashfs mount:

/dev/sda1 on /run/initramfs/live type iso9660 (ro,relatime)

/run/initramfs/live/LiveOS/squashfs.img on /run/initramfs/squashfs_container type squashfs (ro,relatime)

/run/initramfs/squashfs_container/LiveOS/rootfs.img on /run/rootfsbase type ext4 (ro,relatime,data=ordered)

So /dev/sda1 (my stick) holds a reference to /run/rootfsbase
and it's advisable to better not cut that limb

iwillalwa...@gmail.com

unread,
Nov 5, 2018, 6:25:03 PM11/5/18
to kiwi
I found two bugs after posting, but still haven't been able to make it work, so it's not ready for another posting.

Yes the ordinary operation of Gecko does do the overlay the way you describe and the stick cannot be unplugged.  Again, this is why my script creates directories in RAM for temporary overlays, but uses the tar command to copy the existing cow partition (mounting at a different directory, copying and then unmounting) into the temporary.  But my boots fail before reaching this point.

Where Gecko mounts a USB partition on /run/initramfs/live, I've been able to do a loop mount.  But then at the point where /run/initramfs/live/LiveOS/squashfs.img is supposed to get mounted on /run/initramfs/squashfs_container, mount gives an error message that gets garbled.  If I boot Gecko normally, I can type commands to do the same operations (though mounting on differently named directories to avoid conflicts with the running system).  But when my changes to kiwi-live-lib.sh try to do it during boot, it fails.

iwillalwa...@gmail.com

unread,
Nov 5, 2018, 11:48:58 PM11/5/18
to kiwi
As mentioned I fixed two bugs, but those were in copying and mounting the ISO image.  At this moment I don't see any further bugs, but here are the error messages with [comments].  Things seem to be happening in the wrong order.

mount: /run/initramfs/live: WARNING: device write-protected, mounted read-only. [This is correct for a copied ISO image.]
FATAL: Failed to mount live ISO squashfs container [This error is displayed too early.]
Refusing to continue
mount: /run/initramfs/squashfs_container: special device Copying live image to RAM... [Half of an error message, followed by an informational message too late.]
(This may take a few minutes) [No kidding.]
Done copying live image to RAM. [Good but too late.]
/run/initramfs/live/LiveOS/squashfs.img does not exist. [I think it exists now, but something tried to mount it too early.]
FATL: Failed to mount live ISO root filesystem [Because of the earlier error.]
[Further errors also occur because of the earlier error.]

iwillalwa...@gmail.com

unread,
Nov 6, 2018, 12:32:08 AM11/6/18
to kiwi
I think I got it.  Where I thought I would echo some useful messages to the console, my echos actually went to the caller in kiwi-live-root.sh and messed up subsequent operations.

iwillalwa...@gmail.com

unread,
Nov 6, 2018, 5:55:51 AM11/6/18
to kiwi
I'm getting closer.  Nothing from the USB stick remains mounted.  The overlay is temporary.  But the contents of my cow partition don't get copied into the temporary overlay.



--- kiwi-live-lib.sh.org    2018-06-04 15:33:22.000000000 +0900
+++ kiwi-live-lib.sh    2018-11-06 15:11:31.000000000 +0900
@@ -10,7 +10,7 @@

             
# ignore floppy disk devices
             
continue
         
fi
-        iso_volid=$(blkid -s LABEL -o value "${disk}")
+        iso_volid=$(lsblk -p -n -r -o LABEL "${disk}" | grep "${iso_label}")

         
if [ "${iso_volid}" = "${iso_label}" ];then
             echo
"${disk}"
             
return
@@ -63,6 +63,8 @@

 
     cow_filesystem
=$(getarg rd.live.overlay.cowfs)
     
[ -z "${cow_filesystem}" ] && cow_filesystem="ext4"
+
+    getargbool 0 rd.live.ram -d -y live_ram && live_ram="yes"
 
}
 
 
function mountIso {
@@ -72,6 +74,16 @@

     
if ! mount -n -t "${isofs_type}" "${isodev}" "${iso_mount_point}"; then

         
die "Failed to mount live ISO device"
     
fi
+    if [ -n "$live_ram" ]; then
+        umount ${iso_mount_point}
+        iso_image="/run/initramfs/$(echo ${isodev} | cut -f5 -d'/').iso"
+        dd if="${isodev}" of="${iso_image}" bs=2048 >/dev/null 2>/dev/null
+        if ! mount -n -o loop,ro -t "${isofs_type}" "${iso_image}" "${iso_mount_point}"; then
+            die "Failed to mount live image"
+        fi
+        rm /run/initramfs/isodev
+        ln -s "${iso_image}" /run/initramfs/isodev
+    fi
     echo
"${iso_mount_point}"
 
}
 
@@ -109,6 +121,17 @@

     
local overlay_mount_point=/run/overlayfs
     
local partitions_before_cow_part
     mkdir
-m 0755 -p "${overlay_mount_point}"
+    if [ -n "$live_ram" ]; then
+        mkdir -m 0755 -p "${overlay_mount_point}/rw"
+        mkdir -m 0755 -p "${overlay_mount_point}/work"
+        mkdir -m 0755 -p /run/cow
+        if mount -L cow "/run/cow"; then
+            (cd "/run/cow"; tar cf - . | (cd "${overlay_mount_point}" ; tar xf -))
+            umount /run/cow
+        fi
+        rmdir /run/cow
+        return 0
+    fi

iwillalwa...@gmail.com

unread,
Nov 7, 2018, 12:40:06 AM11/7/18
to kiwi
The initrd doesn't include the tar command.

iwillalwa...@gmail.com

unread,
Nov 7, 2018, 1:11:45 AM11/7/18
to kiwi
When did the cp command get the -a parameter?  Anyway, it looks like the classic tar trick isn't needed any more.

iwillalwa...@gmail.com

unread,
Nov 7, 2018, 4:51:18 AM11/7/18
to kiwi
Success.

--- kiwi-live-lib.sh.org    2018-06-04 15:33:22.000000000 +0900
+++ kiwi-live-lib.sh    2018-11-07 15:14:47.000000000 +0900
+            cp -a /run/cow/rw /run/cow/work "${overlay_mount_point}"

jbluck

unread,
May 13, 2020, 3:10:16 PM5/13/20
to kiwi
Happy I found this thread.  I'm having a similar problem getting an iso to mount.  I'd like to get your expertise on this matter.
Reply all
Reply to author
Forward
0 new messages