diff options
| -rwxr-xr-x | modules.d/slx-dmsetup/hooks/dmsetup-slx-device | 291 |
1 files changed, 179 insertions, 112 deletions
diff --git a/modules.d/slx-dmsetup/hooks/dmsetup-slx-device b/modules.d/slx-dmsetup/hooks/dmsetup-slx-device index 9da7ea44..7cf4df64 100755 --- a/modules.d/slx-dmsetup/hooks/dmsetup-slx-device +++ b/modules.d/slx-dmsetup/hooks/dmsetup-slx-device @@ -24,7 +24,9 @@ exec {BASH_XTRACEFD}> /run/openslx/dmsetup.log set -x # read-only device to prepare for CoW -[ -z "$1" ] && emergency_shell "Read-only device was not given!" +[ -n "$1" ] || emergency_shell "Read-only device was not given!" +[ -b "$1" ] || emergency_shell "Given device '$1' does not exist or is not block device" + declare -g read_only_device="$1" declare -g read_only_device_sz="$( blockdev --getsz "$1" )" # Use _sz suffix for sizes expressed in number of 512b sectors, @@ -59,18 +61,22 @@ handle_unit() { parse_config() { local remaining_device_sz="$writable_device_sz" + # First, handle absolute definitions parse_config_int "$1" 0 + # Then, distribute relative values to remaining space parse_config_int "$1" 1 } # global array variables storing the configuration of the partitions -declare -ag linear snapshot thin_snapshot thin_volume +declare -ag linear thin_volume +snapshot= +thin_snapshot= parse_config_int() { [ -z "$1" ] && return 1 local -i rel_only="$2" while IFS= read -r line || [ -n "$line" ]; do [ -z "$line" ] && continue - read -r type name range crypt ignore <<< "$line" + read -r type name range crypt _ <<< "$line" type=${type//-/_} # to use the type as variable in eval if ! [[ "$type" =~ \ ^(linear|snapshot|thin_snapshot|thin_volume)$ ]]; then @@ -124,9 +130,16 @@ parse_config_int() { # finally save it to the global array for this type case "$type" in linear) linear+=("${name} ${crypt} ${min} ${max}") ;; - snapshot) snapshot+=("${name} ${crypt} ${min} ${max}") ;; - thin_snapshot) thin_snapshot+=("${name} ${crypt} ${min} ${max}") ;; thin_volume) thin_volume+=("${name} ${crypt} ${min} ${max}") ;; + # Special - rootfs, only one makes sense + snapshot) + [ -n "$snapshot" ] && echo "Warning: More than one snapshot declared!" >&2 + snapshot="${name} ${crypt} ${min} ${max}" + ;; + thin_snapshot) + [ -n "$thin_snapshot" ] && echo "Warning: More than one thin_snapshot declared!" >&2 + thin_snapshot="${name} ${crypt} ${min} ${max}" + ;; *) echo "$0: SOMETHING NOT GOOT CHECK SOURCE CODE" ;; esac # Decrease for upcoming calculations if we used fixed values here @@ -149,55 +162,79 @@ dmsetup_create_noudevsync() { dmsetup create "$1" --noudevsync fi dmsetup mknodes --noudevsync "$1" + echo "dm: Created $1" ) local ret=$? [ -b "/dev/mapper/$1" ] || ret=99 - [ $ret -ne 0 ] && dmsetup remove --noudevsync "$1" + if [ $ret -ne 0 ]; then + echo "dm: Error creating $1, removing..." + dmsetup remove --noudevsync "$1" + fi return $ret } # encrypt_device <dev_path> <encrypted_name> [<start> <size>] encrypt_device() { # TODO: Send key back to us, demand ransom - modprobe dm-crypt || echo "$0: dm-crypt loading failed, maybe builtin?" - [ -b "$1" ] || return 1 - [ -n "$2" ] || return 1 + modprobe dm-crypt || echo "encrypt: dm-crypt loading failed, maybe builtin?" + if ! [ -b "$1" ]; then + echo "encrypt: Not block device: '$1'" + return 1 + fi + if [ -z "$2" ]; then + echo "encrypt: No name given" + return 1 + fi local dev_size="$( blockdev --getsz "$1" )" if [ -z "$dev_size" ]; then - echo "$0: Cannot encrypt non-existent device $1" + echo "encrypt: Cannot get size of $1" return 1 fi - local size="$4" - local start="$3" - # Sanitize - [ "$start" -ge 0 ] 2> /dev/null || start=0 - [ "$size" -gt 0 ] 2> /dev/null || size="$dev_size" + echo "encrypt: Encrypting device $1 as $2" + local size="${4:-0}" + local start="${3:-0}" + # Sanitize (negated check to catch non-numeric values) + if ! [ "$start" -ge 0 ] 2> /dev/null; then + echo "encrypt: Invalid start offset '$start', using 0" + start=0 + fi + if ! [ "$size" -gt 0 ] 2> /dev/null; then + echo "encrypt: Invalid end offset '$size', using entire device" + size="$dev_size" + fi # Put in bounds - (( start > dev_size )) && start="$dev_size" - (( start + size > dev_size )) && size="$(( dev_size - start ))" + if (( start >= dev_size )); then + echo "encrypt: Start offset $start past end of device ($dev_size)" + return 1 + fi + if (( start + size > dev_size )); then + echo "encrypt: End offset ($start + $size) past end of device ($dev_size), truncating" + size="$(( dev_size - start ))" + fi local key key="$( < /dev/urandom xxd -c32 -p -l32 )" [ -z "$key" ] && key="$( < /dev/urandom tr -c -d 'a-f0-9' | dd count=1 bs=32 )" [ -z "$key" ] && key="$( < /dev/urandom head -c32 | xxd -c32 -p )" [ -z "$key" ] && key="$( < /dev/urandom xxd -c32 -p | head -n 1 )" if [ -z "$key" ]; then - echo "$0: ERROR: Could not generate encryption key" + echo "encrypt: ERROR: Could not generate encryption key" return 1 fi if ! dmsetup_create_noudevsync "$2" \ "0 ${size} crypt aes-xts-plain64 $key 0 $1 ${start} 1 allow_discards"; then - echo "$0: Failed to encrypt $1." + echo "encrypt: Failed to encrypt $1." return 1 fi + echo "encrypt: Setup successful" return 0 } # create_snapshot "<name> <persist>" "cow_device" create_snapshot() { - modprobe dm-snapshot || echo "$0: dm-snapshot loading failed, maybe builtin?" + modprobe dm-snapshot || echo "snapshot: dm-snapshot loading failed, maybe builtin?" read -r name persist _ <<< "$1" + echo "snapshot: Creating $name for $read_only_device (using $2)" if ! dmsetup_create_noudevsync "$name" \ "0 $read_only_device_sz snapshot $read_only_device $2 ${persist:-N} 8"; then - echo "$0: Failed to create snapshot on '$2' for '$read_only_device'." return 1 fi return 0 @@ -210,7 +247,7 @@ create_snapshot() { # placed on a dedicated tmpfs. # THIS FUNCTION MUST NEVER RETURN ramdisk_fallback() { - echo "$0: Falling back to regular dm-snapshot on a RAMdisk." + echo "ramdisk: Falling back to regular dm-snapshot on a RAMdisk." # RAM size in kb, note that this is equal to half # of the entire RAM when interpreted as 512-bytes sectors. @@ -218,30 +255,30 @@ ramdisk_fallback() { # try to prepare the zero extension device local extended_device="/dev/mapper/${read_only_device##*/}-extended" - ( - set -e - lsmod | grep -q dm-zero || modprobe dm-zero - dmsetup_create_noudevsync "${extended_device##*/}" \ - "0 $read_only_device_sz linear $read_only_device 0 - $read_only_device_sz $ram_cow_sz zero" - ) + modprobe dm-zero + dmsetup_create_noudevsync "${extended_device##*/}" <<-EOF + 0 $read_only_device_sz linear $read_only_device 0 + $read_only_device_sz $ram_cow_sz zero + EOF local ret="$?" if [ "$ret" -eq 0 ]; then read_only_device="$extended_device" read_only_device_sz="$(( read_only_device_sz + ram_cow_sz ))" else - echo "$0: Failed to setup the fake larger '$read_only_device'." - echo "$0: Continuing with its original size." + echo "ramdisk: Failed to setup the virtual, larger '$read_only_device'." + echo "ramdisk: Continuing with its original size." fi # prepare dedicated tmpfs mount point + echo "ramdisk: Preparing dedicated tmpfs" local cow_tmpfs="/run/openslx/cow" if ! mkdir -p "$cow_tmpfs"; then cow_tmpfs="${cow_tmpfs}.$$.$RANDOM" mkdir -p "$cow_tmpfs" fi if ! mount -t tmpfs cow-tmpfs -o size="$(( read_only_device_sz / 2 + 100 ))k" "$cow_tmpfs"; then - echo "$0: Failed to mount tmpfs in '$cow_tmpfs' of size '$(( read_only_device_sz / 2 + 100 ))KiB', trying to use regular /run tmpfs." + echo "ramdisk: Failed to mount tmpfs in '$cow_tmpfs' of size '$(( read_only_device_sz / 2 + 100 ))KiB', trying to use regular /run tmpfs." + cow_tmpfs="/run" fi # create sparse file there @@ -259,6 +296,7 @@ ramdisk_fallback() { emergency_shell "CRITICAL: failed to setup RAMdisk fallback." exit 1 fi + # [noreturn] finish_setup "$cow_device_candidate" "0" "$read_only_device_sz" } @@ -314,16 +352,17 @@ save_partition_info() { require_exact_scratch_size() { local current_sz="$( blockdev --getsz "$scratch_device" )" (( current_sz == scratch_device_sz )) && return 0 # Everything fine + echo "exact_scratch: Adding another layer; want: $scratch_device_sz, is: $current_sz" if (( current_sz < scratch_device_sz )); then - echo "$0: WARNING: scratch_device_sz is larger than actual device." - echo "$0: This should never happen." + echo "exact_scratch: WARNING: scratch_device_sz is larger than actual device." + echo "exact_scratch: This should never happen." scratch_device_sz="$current_sz" return 0 fi # We could check if $scratch_device already is a dm target, and just adjust its # size, but I think that scenario isn't possible, currently. if ! dmsetup_create_noudevsync "scratch" "0 $scratch_device_sz linear $scratch_device 0"; then - echo "$0: Failed to create scratch space for the CoW layer." + echo "exact_scratch: Failed to create scratch space for the CoW layer." return 1 fi scratch_device="/dev/mapper/scratch" @@ -336,17 +375,19 @@ create_pool() { declare -r wanted_low_mb=100 # Free space below this will trigger a dm event # create external snapshot for read-only device # create remaining thin volumes - modprobe dm-thin-pool || echo "$0: dm-thin-pool load failed, maybe builtin?" + echo "pool: Creating thinpool for cow" + modprobe dm-thin-pool || echo "pool: dm-thin-pool load failed, maybe builtin?" # create temporary metadata device # calculate number of sectors needed and check boundaries: # XXX Formula from thin-pool.txt calculates size in *bytes*, we want 512b blocks metadata_dev_sz="$(( 48 * scratch_device_sz / data_block_sz / 512 ))" # If we want NTFS as a backup plan to extend the pool, check if the current size # is less than 100GB, and only then consider this feature. - # Maybe make that thresold configurable one day, but the the desktop client + # Maybe make that thresold configurable one day, but for the desktop client # use case this is sensible for now. if [ "$SLX_NTFSFREE" = "backup" ] && (( scratch_device_sz < 209715200 )) \ && [ -z "$metadata_persistent" ]; then + echo "pool: Considering NTFS partitions as backup since pool is small" find_ntfs_partitions if [ -s "$ntfs_list" ]; then # Look what size we end up if we want at least 50GB @@ -371,9 +412,11 @@ create_pool() { local metadata_persistent= if [ -n "$metadata_persistent" ]; then # create persistent slice of the writable device for the pool metadata + # Currently unused! Needs more work to reliably resume the pool on reboot, + # but only if booting exactly the same image if ! dmsetup_create_noudevsync "pool-metadata" \ "0 $metadata_dev_sz linear $scratch_device $scratch_device_offset"; then - echo "$0: Failed to create linear device for pool metadata device." + echo "pool: Failed to create linear device for pool metadata device." else # Adjust size for pool-data down accordingly scratch_device_offset="$metadata_dev_sz" @@ -387,6 +430,7 @@ create_pool() { fi if [ -z "$metadata_dev" ]; then # create RAMdisk in /run for metadata device + echo "pool: Creating loopdev in tmpfs for metadata" mkdir -p /run/openslx metadata_dev="$( mktemp /run/openslx/.pool-metadata.XXXXXX )" # Create sparse file of required size @@ -395,7 +439,7 @@ create_pool() { declare -r metadata_dev="$( losetup --show --find "$metadata_dev" )" fi if [ -z "$metadata_dev" ]; then - echo "$0: Could not set up persistent or tmpfs-loop metadata device. Aborting." + echo "pool: Could not set up persistent or tmpfs-loop metadata device. Aborting." return 1 fi @@ -404,21 +448,23 @@ create_pool() { # No offset, no potential expansion, don't create another linear target pool_data_dev="$scratch_device" else + echo "pool: Creating additional linear target for data device" pool_data_dev="/dev/mapper/pool-data" # Create linear device of the writable device, in case we have an offset from # the on-disk meta data. Also this way we can easily extend it later. if ! dmsetup_create_noudevsync "${pool_data_dev##*/}" \ "0 $scratch_device_sz linear $scratch_device $scratch_device_offset"; then - echo "$0: Failed to create pool data device on '$scratch_device'." + echo "pool: Failed to create pool data device on '$scratch_device'." return 1 fi fi local low_water_mark # Convert MB to blocks low_water_mark=$(( wanted_low_mb * 2048 / data_block_sz )) + echo "pool: Creating thinpool device" if ! dmsetup_create_noudevsync "${pool_dev##*/}" \ "0 $scratch_device_sz thin-pool $metadata_dev $pool_data_dev $data_block_sz $low_water_mark 1 skip_block_zeroing"; then - echo "$0: Failed to create thin-pool device (meta: $metadata_dev, data: $pool_data_dev)" + echo "pool: Failed to create thin-pool device (meta: $metadata_dev, data: $pool_data_dev)" return 1 fi return 0 @@ -427,11 +473,11 @@ create_pool() { # create_volume <name> <id> <size> [backing_dev] create_volume() { if [ -z "$pool_dev" ] || ! [ -b "$pool_dev" ]; then - echo "$0: Global pool device not set or present." + echo "volume: Global pool device not set or present." return 1 fi if [ $# -lt 3 ] || [ -z "$1" ]; then - echo "$0: create_volume: not enough arguments." + echo "volume: not enough arguments." return 1 fi local name="$1" @@ -439,12 +485,13 @@ create_volume() { local size="$3" local backing_dev="$4" # Optional, internal if empty + echo "volume: Creating $id/$name on $pool_dev" if ! dmsetup message "$pool_dev" 0 "create_thin $id"; then - echo "$0: Failed to create thin volume with id '$id' in pool '$pool_dev'." - echo "$0: It might already exists, trying anyway..." + echo "volume: Failed to create thin volume with id '$id' in pool '$pool_dev'." + echo "volume: It might already exist, trying anyway..." fi if ! dmsetup_create_noudevsync "$name" "0 $size thin $pool_dev $id $backing_dev"; then - echo "$0: Failed to create external snapshot named '$name':" + echo "volume: Failed to create external snapshot named '$name':" echo " Size: $size" echo " Backing device: $backing_dev" echo " Thin volume id: $id" @@ -464,8 +511,9 @@ find_ntfs_partitions() { [ -z "$SLX_NTFSFREE" ] && return [ "$SLX_NTFSFREE" = "never" ] && return [ -e "$ntfs_list" ] && return + echo "ntfs: Scanning for suitable NTFS partitions to use as writable device" if ! command -v ntfsfree &> /dev/null; then - echo "$0: ntfsfree not found, cannot use NTFS partitions as RW layer" + echo "ntfs: ntfsfree not found, cannot use NTFS partitions as RW layer" return fi local part sum ro dev @@ -480,10 +528,11 @@ find_ntfs_partitions() { sum="$( ntfsfree --block-size 512 --min-size "$(( 256 * 1024 * 1024 ))" "$part" 2> /dev/null \ | awk -v sum=0 '{if ($1 == "Range") sum += $4}END{printf "%.0f", sum}' )" # Only consider volume if sum of these ranges > 1GB (this is BLOCKS, not bytes) - (( "$sum" > 2 * 1024 * 1024 )) || continue + (( sum > 2 * 1024 * 1024 )) || continue echo "$sum $part" # only thing in loop going to stdout (( ntfs_extra_space_sz += sum )) done | sort -nr > "$ntfs_list" + echo "ntfs: Found $( wc -l < "$ntfs_list" ) suitable partitions" } ntfs_extra_space_sz=0 @@ -502,20 +551,25 @@ dev_swap_version &> /dev/null declare -g id44_crypted= declare -g writable_device= if [ -z "$SLX_WRITABLE_DEVICE_IDENTIFIER" ]; then - SLX_WRITABLE_DEVICE_IDENTIFIER=("44" "87f86132-ff94-4987-b250-444444444444") - # TODO make scripts reading this variable compatible with list of IDs - echo "SLX_WRITABLE_DEVICE_IDENTIFIER='${SLX_WRITABLE_DEVICE_IDENTIFIER[0]}'" >> /etc/openslx - echo "SLX_WRITABLE_DEVICE_IDENTIFIERS='${SLX_WRITABLE_DEVICE_IDENTIFIER[*]}'" >> /etc/openslx + SLX_WRITABLE_DEVICE_IDENTIFIER="44 87f86132-ff94-4987-b250-444444444444" + echo "SLX_WRITABLE_DEVICE_IDENTIFIER='${SLX_WRITABLE_DEVICE_IDENTIFIER}'" >> /etc/openslx fi -# XXX The fuck? This may or may not be an array? Shit will defintely break some day... + if [ -n "$SLX_WRITABLE_DEVICE_IDENTIFIER" ]; then + unset writable_devices declare -a writable_devices - writable_devices=( $( dev_find_partitions "${SLX_WRITABLE_DEVICE_IDENTIFIER[@]}" ) ) + read -r -a list <<<"$SLX_WRITABLE_DEVICE_IDENTIFIER" + echo "Scanning for partitions with type/label ${list[*]}..." + while read -r -a list; do + writable_devices+=( "${list[@]}" ) + done < <( dev_find_partitions "${list[@]}" ) + echo "Found ${#writable_devices[@]} matching partitions" if [[ "${#writable_devices[@]}" -eq 0 && "$SLX_NTFSFREE" != "never" ]] || [ "$SLX_NTFSFREE" = "always" ]; then find_ntfs_partitions fi if [ -s "$ntfs_list" ] || [[ "${#writable_devices[@]}" -gt 1 ]]; then # More than one device, and/or NTFS space, need linear + echo "Have more than one writable device, creating linear target" tbl="/run/openslx/dmsetup-linear-id44" pos=0 grow_max_sz=9999999999 @@ -531,6 +585,7 @@ if [ -n "$SLX_WRITABLE_DEVICE_IDENTIFIER" ]; then if [ -s "$ntfs_list" ]; then sum= while read -r sum dev _ || [ -n "$sum" ]; do # each dev + echo "Appending NTFS partition $dev..." word= while read -r word range_start_b _ range_sz _ || [ -n "$word" ]; do # each slice of dev [ "$word" = "Range" ] || continue @@ -543,7 +598,7 @@ if [ -n "$SLX_WRITABLE_DEVICE_IDENTIFIER" ]; then # Update counter (( pos += slice_sz )) else - echo "$0: Could not write new table row into $tbl" + echo "Could not write new table row into $tbl" fi done < <( ntfsfree --block-size 512 --min-size "$(( 256 * 1024 * 1024 ))" "$dev" ) done < "$ntfs_list" @@ -554,35 +609,35 @@ if [ -n "$SLX_WRITABLE_DEVICE_IDENTIFIER" ]; then fi # See if we need a linear target at all if ! [ -s "$tbl" ]; then - echo "$0: Empty tmp/id44 table, fallback to RAM" + echo "Empty tmp/id44 table, fallback to RAM" elif [ "$( wc -l < "$tbl" )" -eq 1 ] && [[ "${#writable_devices[@]}" -ge 1 ]]; then # Only one line, have writable device -> use directly + echo "Table somehow ended up with one entry, discarding" writable_device="${writable_devices[0]}" else # set up linera device + echo "Setting up linear id44 device with $( wc -l < "$tbl" ) slices" if ! dmsetup_create_noudevsync "id44-group" < "$tbl"; then - echo "$0: Error creating group of id44 devices. Fallback to RAM :-(" + echo "$0: Error creating group of writable devices. Fallback to RAM :-(" else writable_device="/dev/mapper/id44-group" fi fi else # Single device + echo "Have a single writable device, using it directly" writable_device="${writable_devices[0]}" fi fi if [ -z "$writable_device" ]; then - echo "$0: Could not find writable device with id '$SLX_WRITABLE_DEVICE_IDENTIFIER'." + echo "Could not find writable device with id(s) '$SLX_WRITABLE_DEVICE_IDENTIFIER'." ramdisk_fallback elif is_on "$SLX_ID44_CRYPT"; then # Config option crypts the entire ID44 device(s), before any slices are taken from it. if encrypt_device "$writable_device" "id44-crypt"; then - echo "$0: ID44 encrypted" writable_device="/dev/mapper/id44-crypt" # Remember the whole device is already encrypted, and ignore the crypt flag for the partition table later id44_crypted=1 - else - echo "$0: Error encrypting ID44 partition" fi fi @@ -598,6 +653,7 @@ fi # extra swap? if grep -qFw 'slx.swap' "/proc/cmdline"; then # Only if our basic writable_device is large enough, or we have ntfs backup + echo "Additional swap on ID44 requested if existing is too small" do_swap_sz=0 if (( writable_device_sz > 80078125 )); then # more than ~40GB, go ahead @@ -612,41 +668,36 @@ if grep -qFw 'slx.swap' "/proc/cmdline"; then # Check how many we have and if they're regular, unencrypted ones. # If it's plenty, don't cut out swap from our backing device swap_sz=0 - for part in $( dev_find_partitions "82" "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f" ); do - dev_swap_version "$part" &> /dev/null || continue - this_sz="$( blockdev --getsz "$part" )" - (( this_sz > 0 )) && (( swap_sz += this_sz )) - done - echo "Have existing swap of $swap_sz blocks" - # Go ahead with swap? Only if existing swap < 4GB. If so, add line to table. - if (( do_swap_sz > 0 )) && (( swap_sz < 7812500 )); then - echo "Adding $do_swap_sz blocks of additional swap on backing dev" - skb="$(( do_swap_sz / 2 ))" - SLX_WRITABLE_DEVICE_PARTITION_TABLE="$( printf "%s\n%s" "linear slx-swap ${skb}K 0" \ - "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" )" + if (( do_swap_sz == 0 )); then + echo "Not enough ID44 space for swap..." + else + for part in $( dev_find_partitions "82" "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f" ); do + dev_swap_version "$part" &> /dev/null || continue + this_sz="$( blockdev --getsz "$part" )" + (( this_sz > 0 )) && (( swap_sz += this_sz )) + done + echo "Have existing swap of $(( swap_sz / 2 / 1024 ))MiB" + (( do_swap_sz -= swap_sz )) + # Go ahead with swap? Only if we miss a reasonable amount... ( > 100MiB) + if (( do_swap_sz > 204800 )); then + echo "Adding $(( do_swap_sz / 2 / 1024 ))MiB of additional swap on backing dev" + skb="$(( do_swap_sz / 2 ))" + SLX_WRITABLE_DEVICE_PARTITION_TABLE="$( printf "%s\n%s" "linear slx-swap ${skb}K 0" \ + "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" )" + fi fi fi parse_config "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" # Default to thin-snapshot, if none were configured -if [ "${#snapshot[@]}" = 0 ] && [ "${#thin_snapshot[@]}" = 0 ]; then +if [ -z "${snapshot}" ] && [ -z "${thin_snapshot}" ]; then parse_config "thin-snapshot root 100% 0" fi # Sanity checks for weird configurations -# XXX These were declared array and now turn into strings... -if [ "${#snapshot[@]}" -gt 1 ]; then - echo "Multiple snapshots specified, using first one: ${snapshot[0]}" -fi -snapshot="${snapshot[0]}" -if [ "${#thin_snapshot[@]}" -gt 1 ]; then - echo "Multiple thin-snapshots specified, using first one: ${thin_snapshot[0]}" -fi -thin_snapshot="${thin_snapshot[0]}" if [ -n "$snapshot" ] && [ -n "$thin_snapshot" ]; then - echo "$0: Both snapshot and thin-snapshot specified, prefering thin-snapshot." - snapshot= + echo "Warning: Both snapshot and thin-snapshot specified, prefering thin-snapshot." >&2 fi ### @@ -659,7 +710,7 @@ declare -g pool_crypted= # first, reserve the space for the rootfs cow snapshot (of either type)... # (this is the first line of our custom partition table) -read -r name crypt min max ignore <<< "${thin_snapshot:-${snapshot}}" +read -r name crypt min max _ <<< "${thin_snapshot:-${snapshot}}" declare -g scratch_device="/dev/mapper/scratch" declare -gi scratch_device_sz=0 @@ -668,9 +719,9 @@ if (( min <= writable_device_sz )); then (( scratch_device_sz > writable_device_sz )) && scratch_device_sz="$writable_device_sz" else # minimum snapshot size is bigger than physical device size - echo "$0: Minimum snapshot size is too big for the scratch partition." - echo "$0: You probably need to use a more conservative value." - echo "$0: Using this client maximum scratch space ($writable_device_sz sectors)." + echo "Warning: Minimum snapshot size is too big for the scratch partition." >&2 + echo "Warning: You probably need to use a more conservative value." >&2 + echo "Warning: Using this client maximum scratch space ($writable_device_sz sectors)." >&2 scratch_device_sz="$writable_device_sz" fi @@ -678,7 +729,7 @@ if (( scratch_device_sz == writable_device_sz )); then # Only one, use directly, maybe crypt if [ -z "$id44_crypted" ] && [ "$crypt" -ne 0 ]; then if ! encrypt_device "$writable_device" "${scratch_device##*/}" 0 "$scratch_device_sz"; then - echo "$0: Continuing with unencrypted scratch" + echo "Warning: Continuing with unencrypted scratch" >&2 scratch_device="$writable_device" fi else @@ -695,13 +746,13 @@ else if encrypt_device "$writable_device" "${scratch_device##*/}" 0 "$scratch_device_sz"; then pool_crypted=1 else - echo "$0: Continuing with unencrypted scratch" + echo "Warning: Continuing with unencrypted scratch" >&2 crypt=0 # So we do the linear thing below fi fi if (( crypt == 0 )) && ! dmsetup_create_noudevsync "${scratch_device##*/}" \ "0 $scratch_device_sz linear $writable_device $writable_device_used_sz"; then - echo "$0: Failed to create scratch space for the CoW layer." + echo "Error: Failed to create scratch space for the CoW layer." >&2 # this should never fail, but if it does, we would likely not be able to use # $writable_device for any dmsetup stuff, so just fallback to ramdisk # until we have a better idea on what to do :) @@ -715,12 +766,13 @@ writable_device_used_sz="$scratch_device_sz" # setup linear slices of the writable device for line in "${linear[@]}"; do [ -z "$line" ] && continue - read -r name crypt min max ignore <<< "$line" + read -r name crypt min max _ <<< "$line" [ -n "$id44_crypted" ] && crypt=0 + echo "Creating linear slice '$name'..." free_space="$(( writable_device_sz - writable_device_used_sz ))" if [ "$min" -gt "$free_space" ]; then - echo "$0: Not enough space left for linear devices: '$line' - have $free_space sectors" - break + echo "Error: Not enough space left for linear device $name - have $free_space sectors, need $min" >&2 + continue fi # allocate its max if it fits within the free space, otherwise use the space left. to_allocate="$max" @@ -730,12 +782,12 @@ for line in "${linear[@]}"; do if (( crypt != 0 )) \ && ! encrypt_device "$writable_device" "${name}" "$writable_device_used_sz" "$to_allocate"; then - echo "$0: Failed to encrypt '$name', continuing without encryption." + echo "Warning: Failed to encrypt '$name', continuing without encryption." >&2 crypt=0 fi if (( crypt == 0 )) && ! dmsetup_create_noudevsync \ "$name" "0 $to_allocate linear $writable_device $writable_device_used_sz"; then - echo "$0: Failed to create linear device: $line" + echo "Warning: Failed to create linear device: $line" >&2 continue fi # TODO sane? @@ -750,14 +802,19 @@ declare -rg pool_dev="/dev/mapper/pool" declare -gi root_ntfs_extra=0 # Extra blocks to provision to root fs for later expansion # Now decide what to do for the writable layer -if [ -n "$thin_snapshot" ] || [ -n "$thin_volume" ]; then +if [ -n "$thin_snapshot" ] || [ -n "${thin_volume[*]}" ]; then if ! create_pool ; then - echo "Failed to create thin pool. Will ignore:" - echo -e "\tThin snapshot: $(declare -p thin_snapshot)" - echo -e "\tThin volumes: $(declare -p thin_volume)" - echo "Trying snapshot fallback..." - snapshot="$thin_snapshot" + { + echo "Error: Failed to create thin pool. Will ignore:" + echo " Thin snapshot: $(declare -p thin_snapshot)" + echo " Thin volumes: $(declare -p thin_volume)" + echo "Trying snapshot fallback..." + } >&2 + [ -z "$snapshot" ] && snapshot="$thin_snapshot" else + # Once we have created the pool, there is no point in snapshot fallback, + # as the space is already reserved by the pool + snapshot= # the order in which pool devices are created does not matter # so start with thin volumes starting with id 2 and end with # the thin-snapshot with id 1 which needs to call finish_setup. @@ -765,20 +822,22 @@ if [ -n "$thin_snapshot" ] || [ -n "$thin_volume" ]; then # go over thin-volumes for line in "${thin_volume[@]}"; do [ -z "$line" ] && continue - read -r name crypt min max ignore <<< "$line" + read -r name crypt min max _ <<< "$line" if [ -n "$id44_crypted" ] || [ -n "$pool_crypted" ]; then crypt=0 fi + echo "Adding thin volume '$name'..." # thin-volume can be created with max size, # since they are overprovisioned anyway. suffix= - (( crypt != 0 )) && suffix="-k" + (( crypt != 0 )) && suffix="-plain" if ! create_volume "$name$suffix" "$(( volume_id++ ))" "$max"; then - echo "Failed to create thin volume '$name'." + echo "Error: Failed to create thin volume $name" >&2 + continue fi if (( crypt != 0 )) && ! encrypt_device \ "/dev/mapper/$name$suffix" "$name" 0 "$max"; then - echo "Failed to encrypt thin volume '$name', continuing without encryption." + echo "Warning: Failed to encrypt thin volume '$name', continuing without encryption." >&2 name="$name$suffix" fi save_partition_info "$name" "*" "1" "${scratch_device_sz}-${max}" @@ -787,6 +846,7 @@ if [ -n "$thin_snapshot" ] || [ -n "$thin_volume" ]; then if [ -n "$thin_snapshot" ]; then # create thin-snapshot, use first one read -r name _ <<< "$thin_snapshot" + echo "Adding base system snapshot '$name'..." # min/max and crypt was used for the pool data device, ignore it here! # Calculate how much of the CoW space we reserve for changes in the base # system. Usually all the files in the base system should be static, but @@ -808,12 +868,12 @@ if [ -n "$thin_snapshot" ] || [ -n "$thin_volume" ]; then thin_snapshot_sz="$(( thin_snapshot_sz + root_ntfs_extra ))" fi if ! create_volume "$name" 1 "$thin_snapshot_sz" "$read_only_device"; then - echo "Failed to create external snapshot for '$read_only_device'." - ramdisk_fallback + echo "Error: Failed to create external snapshot for '$read_only_device'." >&2 + ramdisk_fallback # does not return fi finish_setup "$name" "1" "$thin_snapshot_sz" fi - echo "$0: Thin volumes defined, but no snapshot. Using tmpfs." + echo "Warning: Thin volumes defined, but no snapshot. Using tmpfs...." >&2 ramdisk_fallback fi fi @@ -824,9 +884,16 @@ fi if [ -n "$snapshot" ] && require_exact_scratch_size; then read -r name crypt min max _ <<< "$snapshot" [ -n "$id44_crypted" ] && crypt=0 - if create_snapshot "$name N" "$scratch_device"; then - finish_setup "$name" "1" "$scratch_device_sz" + suffix= + (( crypt != 0 )) && suffix="-plain" + if ! create_snapshot "$name$suffix N" "$scratch_device"; then + ramdisk_fallback # no return + fi + if (( crypt != 0 )) && ! encrypt_device "/dev/mapper/$name$suffix" "$name" 0 "$max"; then + echo "Warning: Failed to encrypt snapshot $name, continuing without encryption." >&2 + name="$name$suffix" fi + finish_setup "$name" "1" "$scratch_device_sz" fi # ultimate fallback |
