From 5de6edcdad87ad717129462b0fe89c47e6f3b288 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 23 May 2022 12:16:43 +0200 Subject: [slx-dmsetup] linear ID44 target; support SLX_NTFSFREE = "always" --- modules.d/slx-dmsetup/scripts/dmsetup-slx-device | 323 ++++++++++++++--------- 1 file changed, 193 insertions(+), 130 deletions(-) diff --git a/modules.d/slx-dmsetup/scripts/dmsetup-slx-device b/modules.d/slx-dmsetup/scripts/dmsetup-slx-device index 8856a10e..f2977b9e 100755 --- a/modules.d/slx-dmsetup/scripts/dmsetup-slx-device +++ b/modules.d/slx-dmsetup/scripts/dmsetup-slx-device @@ -121,11 +121,16 @@ parse_config() { # Helper to call 'dmsetup setup' without syncing with udev # and then actively create the devices with the mknodes command. -# dmsetup_create_noudevsync +# Either pass the table contents as $2, or pipe them into the function +# dmsetup_create_noudevsync [table] dmsetup_create_noudevsync() { ( set -o errexit - printf "%s\n" "$2" | dmsetup create "$1" --noudevsync + if [ -n "$2" ]; then + printf "%s\n" "$2" | dmsetup create "$1" --noudevsync + else + dmsetup create "$1" --noudevsync + fi dmsetup mknodes --noudevsync "$1" ) local ret=$? @@ -182,7 +187,8 @@ ramdisk_fallback() { "0 $read_only_device_sz linear $read_only_device 0 $read_only_device_sz $ram_cow_sz zero" ) - if [ "$?" -eq 0 ]; then + local ret="$?" + if [ "$ret" -eq 0 ]; then read_only_device="$extended_device" read_only_device_sz="$(( read_only_device_sz + ram_cow_sz ))" else @@ -262,128 +268,6 @@ save_partition_info() { echo "/dev/mapper/$1 $2 ${opts}" >> "$partitions_config" } -### -## MAIN -### - -. /etc/openslx -# This is the main variable driving this script -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 -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 - # only first one for now TODO create linear devices of all ID44s - writable_device="$(slx-tools dev_find_partitions "${SLX_WRITABLE_DEVICE_IDENTIFIER[@]}" | head -n 1)" -fi -if [ -z "$writable_device" ]; then - echo "$0: Could not find writable device with id '$SLX_WRITABLE_DEVICE_IDENTIFIER'." - ramdisk_fallback -fi - -# NOTE: from here on out, every value related to size is in 512 bytes sectors! -declare -rg writable_device_sz="$( blockdev --getsz "$writable_device" )" - -# If SLX_WRITABLE_DEVICE_PARTITION_TABLE is not set, just do -# regular thin-snapshot for the CoW layer, else parse it. -if [ -n "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" ]; then - parse_config "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" -fi -# Default to thin-snapshot, if none were configured -if [ "${#snapshot[@]}" = 0 ] && [ "${#thin_snapshot[@]}" = 0 ]; 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= -fi - -### -## LINEAR SLICES -### - -# start allocating spaces to the configured devices -declare -g writable_device_used_sz=0 - -# first, reserve the space for the rootfs cow snapshot (of either type)... -read -r name crypt min max ignore <<< "${thin_snapshot:-${snapshot}}" - -declare -g scratch_device="/dev/mapper/scratch" -declare -gi scratch_device_sz=0 -if (( min <= writable_device_sz )); then - scratch_device_sz="$max" - (( 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)." - scratch_device_sz="$writable_device_sz" -fi - -# Create a linear target for the scratch device. This might seem superfluous, -# but it works around problems when using NVMe as pool data device directly. -if ! 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." - # 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 :) - ramdisk_fallback -fi -save_partition_info "${scratch_device##*/}" "*" "1" "$scratch_device_sz" - -# encrypt the scratch device, if configured -if [ "$crypt" -ne 0 ] && encrypt_device \ - "$scratch_device" "${scratch_device##*/}-crypt" "$scratch_device_sz"; then - scratch_device="/dev/mapper/${scratch_device##*/}-crypt" -else - echo "$0: Continuing with unencrypted scratch" -fi - -writable_device_used_sz="$scratch_device_sz" - -# first setup linear slices of the writable device -for line in "${linear[@]}"; do - [ -z "$line" ] && continue - read -r name crypt min max ignore <<< "$line" - 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'" - break - fi - # allocate its max if it fits within the free space, otherwise use the space left. - to_allocate="$max" - [ "$to_allocate" -gt "$free_space" ] && to_allocate="$free_space" - - if ! dmsetup_create_noudevsync "$name" "0 $to_allocate linear $writable_device $writable_device_used_sz"; then - echo "$0: Failed to create linear device: $line" - continue - fi - # TODO sane? - save_partition_info "$name" "*" "1" "$to_allocate" - if [ "$crypt" -ne 0 ] && \ - ! encrypt_device "/dev/mapper/$name" "${name}-crypt" "$to_allocate"; then - echo "$0: Failed to encrypt '$name'." - fi - writable_device_used_sz=$(( to_allocate + writable_device_used_sz )) -done - # This will create another dm-linear on top of $scratch_device in case its # size differs from $scratch_device_sz. This is useful for setups where you # cannot explicitly configure how much space to use from the underlying device, @@ -408,11 +292,6 @@ require_exact_scratch_size() { return 0 } -### -## THIN-PROVISIONING -### -declare -rg pool_dev="/dev/mapper/pool" -declare -gi root_ntfs_extra=0 # Extra blocks to provision to root fs for later expansion create_pool() { declare -r data_block_sz=256 # Desired Block size (number of 512byte sectors) declare -r wanted_low_mb=100 # Free space below this will trigger a dm event @@ -559,6 +438,190 @@ find_ntfs_partitions() { done | sort -nr > "$ntfs_list" } +### +## MAIN +### + +. /etc/openslx +# This is the main variable driving this script +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 +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 + # only first one for now TODO create linear devices of all ID44s + declare -a writable_devices + writable_devices=( $( slx-tools dev_find_partitions "${SLX_WRITABLE_DEVICE_IDENTIFIER[@]}" ) ) + 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 + SLX_NTFSFREE="never" # Don't try to add NTFS space later + tbl="/run/openslx/dmsetup-linear-id44" + pos=0 + grow_max_sz=9999999999 + for dev in "${writable_devices[@]}"; do + max="$(( grow_max_sz - pos ))" + (( max <= 0 )) && break + sz="$( blockdev --getsz "$dev" )" + (( sz > 0 )) || continue + (( sz > max )) && sz="$max" + echo "$pos $sz linear $dev 0" + (( pos += sz )) + done > "$tbl" + if [ -s "$ntfs_list" ]; then + sum= + while read -r sum dev _ || [ -n "$sum" ]; do # each dev + word= + while read -r word range_start_b _ range_sz _ || [ -n "$word" ]; do # each slice of dev + [ "$word" = "Range" ] || continue + (( range_sz > 0 )) || continue + slice_sz="$(( grow_max_sz - pos ))" + (( slice_sz <= 0 )) && break + (( slice_sz > range_sz )) && slice_sz="$range_sz" + # Append line + if echo "$pos $slice_sz linear $dev $range_start_b" >> "$tbl"; then + # Update counter + (( pos += slice_sz )) + else + echo "$0: Could not write new table row into $tbl" + fi + done < <( ntfsfree --block-size 512 --min-size "$(( 256 * 1024 * 1024 ))" "$dev" ) + done < "$ntfs_list" + fi + # See if we need a linear target at all + if ! [ -s "$tbl" ]; then + echo "$0: 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 + writable_device="${writable_devices[0]}" + else + # set up linera device + if ! dmsetup_create_noudevsync "id44-group" < "$tbl"; then + echo "$0: Error creating group of id44 devices. Fallback to RAM :-(" + else + writable_device="/dev/mapper/id44-group" + fi + fi + else + # Single device + 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'." + ramdisk_fallback +fi + +# NOTE: from here on out, every value related to size is in 512 bytes sectors! +declare -rg writable_device_sz="$( blockdev --getsz "$writable_device" )" + +# If SLX_WRITABLE_DEVICE_PARTITION_TABLE is not set, just do +# regular thin-snapshot for the CoW layer, else parse it. +if [ -n "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" ]; then + parse_config "$SLX_WRITABLE_DEVICE_PARTITION_TABLE" +fi +# Default to thin-snapshot, if none were configured +if [ "${#snapshot[@]}" = 0 ] && [ "${#thin_snapshot[@]}" = 0 ]; 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= +fi + +### +## LINEAR SLICES +### + +# start allocating spaces to the configured devices +declare -g writable_device_used_sz=0 + +# first, reserve the space for the rootfs cow snapshot (of either type)... +read -r name crypt min max ignore <<< "${thin_snapshot:-${snapshot}}" + +declare -g scratch_device="/dev/mapper/scratch" +declare -gi scratch_device_sz=0 +if (( min <= writable_device_sz )); then + scratch_device_sz="$max" + (( 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)." + scratch_device_sz="$writable_device_sz" +fi + +# Create a linear target for the scratch device. This might seem superfluous, +# but it works around problems when using NVMe as pool data device directly. +if ! 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." + # 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 :) + ramdisk_fallback +fi +save_partition_info "${scratch_device##*/}" "*" "1" "$scratch_device_sz" + +# encrypt the scratch device, if configured +if [ "$crypt" -ne 0 ] && encrypt_device \ + "$scratch_device" "${scratch_device##*/}-crypt" "$scratch_device_sz"; then + scratch_device="/dev/mapper/${scratch_device##*/}-crypt" +else + echo "$0: Continuing with unencrypted scratch" +fi + +writable_device_used_sz="$scratch_device_sz" + +# first setup linear slices of the writable device +for line in "${linear[@]}"; do + [ -z "$line" ] && continue + read -r name crypt min max ignore <<< "$line" + 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'" + break + fi + # allocate its max if it fits within the free space, otherwise use the space left. + to_allocate="$max" + [ "$to_allocate" -gt "$free_space" ] && to_allocate="$free_space" + + if ! dmsetup_create_noudevsync "$name" "0 $to_allocate linear $writable_device $writable_device_used_sz"; then + echo "$0: Failed to create linear device: $line" + continue + fi + # TODO sane? + save_partition_info "$name" "*" "1" "$to_allocate" + if [ "$crypt" -ne 0 ] && \ + ! encrypt_device "/dev/mapper/$name" "${name}-crypt" "$to_allocate"; then + echo "$0: Failed to encrypt '$name'." + fi + writable_device_used_sz=$(( to_allocate + writable_device_used_sz )) +done + +### +## THIN-PROVISIONING +### +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 -- cgit v1.2.3-55-g7522