From f52d4d2b594e61cfd310c11c44e59302c5b97f43 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 30 Sep 2020 16:05:19 +0200 Subject: [slx-dmsetup] Add support for ntfsfree For now, prepare for later on-demand growing of the pool-data davice by using unused space of NTFS partitions. We do this by scanning available NTFS partitions and recording the available free space on them. Additionally, we make the pool-metadata volume a little larger to account for potential future growth of the data part. This feature is controlled by the SLX_NTFSFREE variable which can be empty/"never", "backup" for the scenario described above, or "always" for always using NTFS partition's free space (to be implemented). --- modules.d/slx-dmsetup/scripts/dmsetup-slx-device | 58 +++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/modules.d/slx-dmsetup/scripts/dmsetup-slx-device b/modules.d/slx-dmsetup/scripts/dmsetup-slx-device index f986f6e9..f9bbdd9d 100755 --- a/modules.d/slx-dmsetup/scripts/dmsetup-slx-device +++ b/modules.d/slx-dmsetup/scripts/dmsetup-slx-device @@ -28,6 +28,8 @@ exec &> /run/openslx/dmsetup.log declare -g read_only_device="$1" declare -g read_only_device_size="$( blockdev --getsz "$1" )" +declare -rg ntfs_list="/run/openslx/.thin-ntfs-candidates" + # global array variables storing the configuration of the partitions declare -ag linear snapshot thin_snapshot thin_volume parse_config() { @@ -362,11 +364,12 @@ done writable_device="$scratch_device" writable_device_size="$scratch_device_size" -### +### ## THIN-PROVISIONING ### declare -rg pool_data_dev="/dev/mapper/pool-data" 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_size=256 # Desired Block size (number of 512byte sectors) declare -r wanted_low_mb=100 # Free space below this will trigger a dm event @@ -375,8 +378,29 @@ create_pool() { modprobe dm-thin-pool || echo "$0: dm-thin-pool load failed, maybe builtin?" # create temporary metadata device # calculate number of sectors needed and check boundaries: - # XXX According to thin-provisioning.txt the / 512 part is WRONG! + # XXX Formula from thin-pool.txt calculates size in *bytes*, we want 512b blocks metadata_dev_size="$(( 48 * writable_device_size / data_block_size / 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 + # use case this is sensible for now. + if [ "$SLX_NTFSFREE" = "backup" ] && (( writable_device_size < 209715200 )) \ + && [ -z "$metadata_persistent" ]; then + find_ntfs_partitions + if [ -s "$ntfs_list" ]; then + # Look what size we end up if we want at least 50GB + local sum="$( awk -v sum=0 \ + '{sum+=$1; if (sum >= 104857600) exit}END{printf "%.0f", sum}' \ + "$ntfs_list" )" + if (( sum > 0 )); then + (( sum > 209715200 )) && sum=209715200 # Max 100GB + # Account for this potential growth in the metadata device size for future expansion + metadata_dev_size="$(( metadata_dev_size + 48 * sum / data_block_size / 512 ))" + echo "$sum" > "/run/openslx/.thin-ntfs-growsize" + root_ntfs_extra="$sum" + fi + fi + fi # Min 2MB -> 4096 sectors, max 16GB -> 33554432 sectors [ "$metadata_dev_size" -lt 4096 ] && metadata_dev_size="4096" # TODO handle the exotic case of a too large metadata device to fit within RAM. @@ -451,6 +475,32 @@ create_volume() { return 0 } +# Find NTFS partitions with decently sized ranges of +# free space. We can use these as our writable layer +# for our thin-pool, if configured. +# If suitable, this will create the file $ntfs_list with +# one line per suitable partition, format +# total_size_blocks devpath +# Results are sorted by size, descending order +find_ntfs_partitions() { + [ -z "$SLX_NTFSFREE" ] && return + [ "$SLX_NTFSFREE" = "never" ] && return + [ -e "$ntfs_list" ] && return + if ! command -v ntfsfree &> /dev/null; then + echo "$0: ntfsfree not found, cannot use NTFS partitions as RW layer" + return + fi + local part sum + for part in /dev/disk/by-partuuid/*; do + # Only count ranges >= 256MB, sum will be in number of 512b blocks + sum="$( ntfsfree --block-size 512 --min-size "$(( 256 * 1024 * 1024 ))" "$part" \ + | 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 + echo "$sum $part" # only thing in loop going to stdout + done | sort -nr > "$ntfs_list" +} + # Now decide what to do for the writable layer if [ -n "$thin_snapshot" ] || [ -n "$thin_volume" ]; then @@ -495,6 +545,10 @@ if [ -n "$thin_snapshot" ] || [ -n "$thin_volume" ]; then else thin_snapshot_size="$read_only_device_size" fi + # For later on-demand growing + if (( root_ntfs_extra > 0 )); then + thin_snapshot_size="$(( thin_snapshot_size + root_ntfs_extra ))" + fi if ! create_volume "$name" 1 "$thin_snapshot_size" "$read_only_device"; then echo "Failed to create external snapshot for '$read_only_device'." ramdisk_fallback -- cgit v1.2.3-55-g7522