fix: Fix fragscript sflc legacy

This commit is contained in:
Tommaso Gagliardoni 2025-09-02 11:31:50 +02:00
parent 66d9afa5c3
commit 55a926a15f

View file

@ -1,39 +1,42 @@
#!/usr/bin/env bash
# Copyright The Shufflecake Project Authors (2022)
# Copyright The Shufflecake Project Contributors (2022)
# Copyright Contributors to the The Shufflecake Project.
# See the AUTHORS file at the top-level directory of this distribution and at
# <https://www.shufflecake.net/permalinks/shufflecake-c/AUTHORS>
# This file is part of the program shufflecake-c, which is part of the Shufflecake
# Project. Shufflecake is a plausible deniability (hidden storage) layer for
# Linux. See <https://www.shufflecake.net>.
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 2 of the License, or (at your option)
# any later version. This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details. You should have received a copy of the
# GNU General Public License along with this program.
# If not, see <https://www.gnu.org/licenses/>.
#  Copyright The Shufflecake Project Authors (2022)
#  Copyright The Shufflecake Project Contributors (2022)
#  Copyright Contributors to the The Shufflecake Project.
#  See the AUTHORS file at the top-level directory of this distribution and at
#  <https://www.shufflecake.net/permalinks/shufflecake-c/AUTHORS>
#  This file is part of the program shufflecake-c, which is part of the Shufflecake 
#  Project. Shufflecake is a plausible deniability (hidden storage) layer for 
#  Linux. See <https://www.shufflecake.net>.
#  This program is free software: you can redistribute it and/or modify it 
#  under the terms of the GNU General Public License as published by the Free 
#  Software Foundation, either version 2 of the License, or (at your option) 
#  any later version. This program is distributed in the hope that it will be 
#  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 
#  Public License for more details. You should have received a copy of the 
#  GNU General Public License along with this program. 
#  If not, see <https://www.gnu.org/licenses/>.
# Fragmentation evaluation script for Shufflecake
# Global variables
SCRIPTNAME=$(basename "$0")
SCRIPT_DIR="$(dirname "$(realpath "$0")")"
LOOP_FILENAME="$SCRIPT_DIR/sflc-legacy-frag-loop-file.img"
LOOP_FILENAME="${SCRIPT_DIR}/sflc-legacy-frag-loop-file.img"
LOOP_DEVICE=""
BLOCK_DEVICE=""
SFLCVOLUME=""
MNTPOINT=""
TIMEFORMAT='%3R'
SFLCPATH=""
SFLCNAME=""
DMSFLC_INSTALLED=false
VOLSIZE=0
NUMPOINTS=11 # number of samples, max 65536
NUMPOINTS=21 # number of samples, max 65536
FSTYPE="ext4" # fragmentation performance can depend on FS type in theory, so change it here if you want to test others
@ -45,36 +48,36 @@ NC='\033[0m' # No color
# Help
print_help() {
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
#         xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   79 chars
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
echo " "
echo "This script is used to evaluate Shufflecake Legacy volume fragmentation."
echo "This script is part of the Shufflecake benchmark suite."
echo "Shufflecake is a plausible deniability (hidden storage) layer for Linux."
echo -e "Please visit ${BLUE}https://www.shufflecake.net${NC} for more info and documentation."
echo -e "Visit ${BLUE}https://www.shufflecake.net${NC} for more info and documentation."
echo " "
echo "This script requires root because it operates on block devices, please run it "
echo -e "with ${BLUE}sudo${NC}. It does the following:"
echo "1) Creates a Shufflecake Legacy device with two volumes."
echo "2) Opens the second (hidden) volume, formats it with $FSTYPE and mounts it."
echo "2) Opens the second (hidden) volume, formats it with ${FSTYPE} and mounts it."
echo "3) Performs incremental random write up to filling the space."
echo "4) After every write round, checks fragmentation status and reports it."
echo "5) Unmounts and closes the used volume."
echo " "
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
#         xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   79 chars
echo "You must have already compiled and installed Shufflecake in order to run this."
echo "The script will search for Shufflecake either in the default installation "
echo "directory, or in the current directory, or in the parent directory (one level"
echo -e "above this). If the module ${BLUE}dm-sflc${NC} is not loaded, the script "
echo "will load it, execute, and then unload it."
echo " "
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
#         xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   79 chars
echo "You can pass the path to a block device as an optional argument, otherwise the "
echo "script will ask for one. If no path is provided, the script will create a 1 GiB"
echo "local file and use it to back a loop device as a virtual block device to be "
echo "formatted with the appropriate tools. The file will be removed at the end."
echo " "
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
#         xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   79 chars
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
echo " "
exit 0
@ -85,16 +88,49 @@ bpx() {
if [ -z "$1" ]; then
echo "BPX: Paused. Press any key to continue..." >&2
else
echo -e "BPX: $1. Press any key to continue..." >&2
echo "BPX: $1. Press any key to continue..." >&2
fi
read -n1 -s
}
# Show usage
usage() {
echo -e "Use ${BLUE}${SCRIPTNAME} --help${NC} for usage and help."
echo -e "Use ${BLUE}${SCRIPTNAME}${NC} --help for usage and help."
}
# Clean up function, called by trap on exit
cleanup() {
echo "Exiting and cleaning..."
# Unmount filesystem if mounted
if [ -n "$MNTPOINT" ] && grep -qs "$MNTPOINT" /proc/mounts; then
echo "Unmounting \"$MNTPOINT\" ..."
umount "$MNTPOINT"
rmdir "$MNTPOINT"
fi
# Close shufflecake volume if open.
if [ -n "$SFLCVOLUME" ] && [ -b "$SFLCVOLUME" ]; then
echo "Closing Shufflecake device on \"$BLOCK_DEVICE\" ..."
"$SFLCNAME" close "$BLOCK_DEVICE" &> /dev/null
fi
# Unload kernel module if we loaded it
unload_dmsflc
# Detach loop device if created
if [[ -n "$LOOP_DEVICE" ]]; then
echo "Detaching \"$LOOP_DEVICE\" ..."
losetup -d "$LOOP_DEVICE"
echo "Deleting \"$LOOP_FILENAME\" ..."
rm -f "$LOOP_FILENAME"
echo "Loop device detached and backing file deleted."
fi
}
# Set trap to run cleanup function on exit
trap cleanup EXIT SIGHUP SIGINT SIGTERM
# Check that this is run as root
check_sudo() {
if [[ $EUID -ne 0 ]]; then
@ -109,89 +145,101 @@ find_sflc_path() {
local cmd="shufflecake"
# Check if the command exists in the current directory
if [[ -x "./$cmd" ]]; then
if [[ -x "./${cmd}" ]]; then
SFLCPATH=$(realpath ./)
SFLCNAME=$(realpath ./$cmd)
SFLCNAME=$(realpath "./${cmd}")
return
fi
# Check if the command exists in the parent directory
if [[ -x "../$cmd" ]]; then
if [[ -x "../${cmd}" ]]; then
SFLCPATH=$(realpath ../)
SFLCNAME=$(realpath ../$cmd)
SFLCNAME=$(realpath "../${cmd}")
return
fi
# Check if the command exists in the directories listed in PATH
IFS=':' read -ra dirs <<< "$PATH"
for dir in "${dirs[@]}"; do
if [[ -x "$dir/$cmd" ]]; then
SFLCPATH=$(realpath $dir)
SFLCNAME=$(realpath $dir/$cmd)
if [[ -x "${dir}/${cmd}" ]]; then
SFLCPATH=$(realpath "$dir")
SFLCNAME=$(realpath "${dir}/${cmd}")
return
fi
done
# If the command was not found, print an error message
echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2
echo -e "${RED}ERROR: Command '${cmd}' not found${NC}." >&2
exit 1
}
# Find and load module dm-sflc
load_dmsflc() {
local mod="dm-sflc"
# Kernel uses underscores, but module files may use hyphens.
local mod_name_loaded="${mod//-/_}"
# First, make sure that dm_mod is loaded
modprobe dm_mod
# Check if the module is already loaded
if lsmod | grep -q "^$mod "; then
if lsmod | grep -q "^${mod_name_loaded} "; then
DMSFLC_INSTALLED=true
echo "Module '$mod' is already loaded."
echo "Module '${mod}' is already loaded."
return
fi
# Try loading from system modules first
if modprobe "$mod" &> /dev/null; then
echo "Module '${mod}' loaded from system modules."
return
fi
# If not, look for the module file and try to load it
local mod_file="$mod.ko"
local mod_file="${mod}.ko"
# Check if the module file exists in the current directory
if [[ -f "./$mod_file" ]]; then
insmod $(realpath ./$mod_file) || exit 1
echo "Module '$mod' loaded from current directory."
if [[ -f "./${mod_file}" ]]; then
insmod "$(realpath "./${mod_file}")" || exit 1
echo "Module '${mod}' loaded from current directory."
return
fi
# Check if the module file exists in the parent directory
if [[ -f "../$mod_file" ]]; then
insmod $(realpath ../$mod_file) || exit 1
echo "Module '$mod' loaded from parent directory."
if [[ -f "../${mod_file}" ]]; then
insmod "$(realpath "../${mod_file}")" || exit 1
echo "Module '${mod}' loaded from parent directory."
return
fi
# If the module file was not found, print an error message
echo -e "${RED} ERROR: Module file '$mod_file' not found.${NC}." >&2
echo -e "${RED} ERROR: Module file '${mod_file}' not found.${NC}." >&2
exit 1
}
# Unload dm-sflc if it was loaded locally
# Unload dm-sflc if it was loaded by this script
unload_dmsflc() {
local mod="dm-sflc"
# Only unload dm-sflc if it was loaded manually when the script was invoked
if ! $DMSFLC_INSTALLED; then
rmmod $mod || exit 1
echo "Module '$mod' unloaded."
else
echo "Module '$mod' was not unloaded because it was already loaded when the script was run."
# Kernel uses underscores, but module files may use hyphens.
local mod_name_loaded="${mod//-/_}"
if [ "$DMSFLC_INSTALLED" = true ]; then
echo "Module '${mod}' will not be unloaded because it was already present when the script started."
return
fi
if lsmod | grep -q "^${mod_name_loaded} "; then
echo "Unloading module '${mod}'..."
rmmod "${mod_name_loaded}" || echo -e "${RED}Warning: Failed to unload module '${mod}'.${NC}" >&2
fi
}
# Function to check if argument is a block device
check_block_device() {
if [ -b "$1" ]; then
echo "OK, block device path $1 is valid." >&2
echo "OK, block device path \"$1\" is valid." >&2
else
echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}"
unload_dmsflc
echo -e "${RED}Error: \"$1\" is not a valid block device, aborting.${NC}"
usage
exit 1
fi
@ -199,36 +247,39 @@ check_block_device() {
# Function to create loop device
create_loop_device() {
echo "I will now try to create a file $LOOP_FILENAME ..." >&2
echo "I will now try to create a file \"$LOOP_FILENAME\" ..." >&2
if [ -e "$LOOP_FILENAME" ]; then
echo -e "${RED}Error: Impossible to generate file, $LOOP_FILENAME already exists.${NC}"
echo -e "${RED}Error: Impossible to generate file, \"$LOOP_FILENAME\" already exists.${NC}"
exit 1
fi
sudo dd if=/dev/zero of="$LOOP_FILENAME" bs=1M count=1024 > /dev/null
dd if=/dev/zero of="$LOOP_FILENAME" bs=1M count=1024 &> /dev/null
echo "Writing of empty file complete. I will now try to attach it to a new loop device..." >&2
LOOP_DEVICE=$(sudo losetup -f --show "$LOOP_FILENAME")
echo "Successfully created loop device $LOOP_DEVICE ." >&2
LOOP_DEVICE=$(losetup -f --show "$LOOP_FILENAME")
if [ $? -ne 0 ] || [ -z "$LOOP_DEVICE" ]; then
echo -e "${RED}Error: Failed to create loop device.${NC}"
exit 1
fi
echo "Successfully created loop device \"$LOOP_DEVICE\" ." >&2
echo "$LOOP_DEVICE"
}
# Finds the sflc volume that was created last
find_sflcvolname() {
# List all files in /dev/mapper, select those starting with sflc_, sort them, and pick the last one.
volname=$(ls /dev/mapper/sflc_* 2>/dev/null | sort -t '_' -k 2n,2 -k 3n,3 | tail -n 1)
# Check if volname is empty (no sflc_ files found).
if [ -z "$volname" ]; then
echo -e "${RED}ERROR: No sflc_ devices found in /dev/mapper !${NC}"
local files=(/dev/mapper/sflc_*)
# Check if the glob expanded to any existing files
if [ ! -e "${files[0]}" ]; then
echo -e "${RED}ERROR: No sflc_ devices found in /dev/mapper !${NC}" >&2
return 1
else
echo $volname
return 0
fi
# Use printf to list one file per line, then sort and get the last one
printf '%s\n' "${files[@]}" | sort -t '_' -k 2n,2 -k 3n,3 | tail -n 1
return 0
}
# Function for user confirmation
confirm() {
while true; do
echo -e "${BLUE}Are you sure you want to proceed? All data on disk $BLOCK_DEVICE will be erased. (y/n)${NC}"
echo -e "${BLUE}Are you sure you want to proceed? All data on disk \"$BLOCK_DEVICE\" will be erased. (y/n)${NC}"
read -r response
case "$response" in
[yY]|[yY][eE][sS]) # Responded Yes
@ -244,103 +295,116 @@ confirm() {
done
}
# Benchmarks
benchmark() {
SFLCVOLUME=""
VOLNAME=""
MNTPOINT=""
NUMPOINTS=21 # number of graph points
# Main test function
evaluate() {
local VOLNAME=""
VOLSIZE=$(blockdev --getsize64 "$BLOCK_DEVICE") # first approximation, in bytes
if [ $? -ne 0 ]; then echo -e "${RED}ERROR: Failed to get size of '$BLOCK_DEVICE'.${NC}" >&2; exit 1; fi
echo "Starting fragmentation test for Shufflecake Legacy..."
# init
echo "Initializing block device $BLOCK_DEVICE with two Shufflecake Legacy volumes (--skip-randfill)..."
etime=$( (time echo -e "passwd1\npasswd2" | $SFLCNAME --skip-randfill --legacy -n 2 init $BLOCK_DEVICE > /dev/null) 2>&1 )
echo "Initializing block device \"$BLOCK_DEVICE\" with two Shufflecake Legacy volumes (--skip-randfill)..."
etime=$( (time echo -e "passwd1\npasswd2" | "$SFLCNAME" --skip-randfill --legacy -n 2 init "$BLOCK_DEVICE" &> /dev/null) 2>&1 )
if [ $? -ne 0 ]; then echo -e "${RED}ERROR: Shufflecake init failed.${NC}" >&2; exit 1; fi
echo -e "${GREEN}Action init took $etime seconds.${NC}"
echo "Shufflecake Legacy device initialized. Opening hidden volume (nr. 2)..."
# open
etime=$( (time echo -e "passwd2" | $SFLCNAME --legacy open $BLOCK_DEVICE > /dev/null) 2>&1 )
etime=$( (time echo -e "passwd2" | "$SFLCNAME" --legacy open "$BLOCK_DEVICE" &> /dev/null) 2>&1 )
if [ $? -ne 0 ]; then echo -e "${RED}ERROR: Shufflecake open failed.${NC}" >&2; exit 1; fi
echo -e "${GREEN}Action open took $etime seconds.${NC}"
# fetch SFLCVOLUME
SFLCVOLUME=$(find_sflcvolname)
if [ $? -ne 0 ]; then exit 1; fi # Error message is already in the function
# trim path of SFLCVOLUME
VOLNAME=${SFLCVOLUME##*/}
echo "Shufflecake volume opened as $VOLNAME. Formatting with $FSTYPE..."
VOLNAME="${SFLCVOLUME##*/}"
echo "Shufflecake volume opened as \"$VOLNAME\". Formatting with $FSTYPE..."
# format with FSTYPE, but mute output (too verbose)
mkfs.$FSTYPE $SFLCVOLUME > /dev/null
echo "Volume $SFLCVOLUME formatted. Mounting that..."
"mkfs.${FSTYPE}" "$SFLCVOLUME" &> /dev/null
if [ $? -ne 0 ]; then echo -e "${RED}ERROR: mkfs failed on '$SFLCVOLUME'.${NC}" >&2; exit 1; fi
echo "Volume \"$SFLCVOLUME\" formatted. Mounting that..."
# assign and create MNTPOINT
MNTPOINT=$(realpath "./sflc_mnt")
mkdir $MNTPOINT
mkdir -p "$MNTPOINT"
if [ $? -ne 0 ]; then echo -e "${RED}ERROR: Could not create mountpoint '$MNTPOINT'.${NC}" >&2; exit 1; fi
# mount
mount $SFLCVOLUME $MNTPOINT
echo "Volume mounted at $MNTPOINT. Starting fragmentation test..."
# TESTS HERE
mount "$SFLCVOLUME" "$MNTPOINT"
if [ $? -ne 0 ]; then echo -e "${RED}ERROR: Mount failed for '$SFLCVOLUME' on '$MNTPOINT'.${NC}" >&2; exit 1; fi
echo "Volume mounted at \"$MNTPOINT\". Starting fragmentation test..."
# Fragmentation test
# Shufflecake allocates data on disk by lazily allocating "slices", and then writing data on those slices.
# If no suitable slice is available for writing data, a new one is allocated.
# The number of allocated slices for a volume is tracked into /sys/module/dm_sflc/bdevs/${MAJ}:${MIN}/${VOLNAME}/mapped_slices
# At this point the volume is already formatted as FSTYPE and mounted at MNTPOINT
# sanity check: NUMPOINTS must be at least 1 and at most 65536, otherwise exit 1
if [ $NUMPOINTS -lt 1 ] || [ $NUMPOINTS -gt 65536 ]; then
echo -e "${RED}Error: NUMPOINTS must be between 1 and 65536. Aborting...${NC}"
# Sanity check: NUMPOINTS must be at least 1 and at most 65536, otherwise exit 1
if [ "$NUMPOINTS" -lt 1 ] || [ "$NUMPOINTS" -gt 65536 ]; then
echo -e "${RED}Error: NUMPOINTS must be between 1 and 65536. Aborting...${NC}" >&2
exit 1
fi
# read number of total available slices (round down) from /sys/module/dm_sflc/bdevs/${MAJ}:${MIN}/tot_slices
MOST_RECENT_DIR=$(ls -td /sys/module/dm_sflc/bdevs/*/ | head -n 1) # include final slash /
read -r TOTSLICES < ${MOST_RECENT_DIR}tot_slices
# Find the statistics directory for this device.
local stat_dirs=(/sys/module/dm_sflc/bdevs/*/)
local stat_dir="${stat_dirs[0]}" # Assume only one is created by this script
if [ ! -d "$stat_dir" ]; then
echo -e "${RED}Error: Could not find Shufflecake statistics directory in /sys.${NC}" >&2
exit 1
fi
read -r TOTSLICES < "${stat_dir}tot_slices"
# refine down block device max size according to available slices, to make sure there is no overflow
NEWUPPERBOUND=$((TOTSLICES * 1048576 )) # in bytes
# Refine down block device max size according to available slices, to make sure there is no overflow
local NEWUPPERBOUND=$((TOTSLICES * 1048576 )) # in bytes
if ((VOLSIZE > NEWUPPERBOUND)); then
VOLSIZE=$NEWUPPERBOUND
fi
# manage case NUMPOINTS = 1
read -r OCCSLICES < ${MOST_RECENT_DIR}${VOLNAME}/mapped_slices
X_COORD=.0
read -r OCCSLICES < "${stat_dir}${VOLNAME}/mapped_slices"
local X_COORD=.0
local Y_COORD
Y_COORD=$(echo "scale=3; $OCCSLICES/$TOTSLICES" | bc)
# Print occupation table for graph
echo -e "${GREEN}Occupation table: X = percentage of data written, Y = percentage of slices used.${NC}"
echo -e "${GREEN}---------------------------------${NC}"
echo -e "${GREEN}$X_COORD $Y_COORD${NC}"
if [ $NUMPOINTS -gt 1 ]; then
if [ "$NUMPOINTS" -gt 1 ]; then
# point 1 is always at X=0 and point NUMPOINT is always at X=1
DATASIZE=$(( $VOLSIZE / ($NUMPOINTS-1) / 1048576 )) # data increments in MB, round down
local DATASIZE=$(( VOLSIZE / (NUMPOINTS - 1) / 1048576 )) # data increments in MB, round down
# loop for i = 1 to NUMPOINTS
# loop for i = 1 to NUMPOINTS-1
for (( i=1; i<$NUMPOINTS-1; i++ )); do
X_COORD=$(echo "scale=3; $i / ($NUMPOINTS-1) " | bc)
local RNDDIRNAME
local RNDFILENAME
# RNDDIRNAME = random name with 16 characters (loop while it does not exist already)
while :; do
RNDDIRNAME=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 16 | head -n 1)
RNDDIRNAME=$(head -c 12 /dev/urandom | base64 | tr -dc 'a-z0-9')
[ ! -e "${MNTPOINT}/${RNDDIRNAME}" ] && break
done
# create random dir
mkdir "${MNTPOINT}/${RNDDIRNAME}"
if [ $? -ne 0 ]; then echo -e "${RED}ERROR: Failed to create random directory.${NC}" >&2; exit 1; fi
# RNDFILENAME= random name with 16 characters (loop while it does not exist already)
while :; do
RNDFILENAME=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 16 | head -n 1)
RNDFILENAME=$(head -c 12 /dev/urandom | base64 | tr -dc 'a-z0-9')
[ ! -e "${MNTPOINT}/${RNDDIRNAME}/${RNDFILENAME}" ] && break
done
# create random file
dd if=/dev/zero of=${MNTPOINT}/${RNDDIRNAME}/${RNDFILENAME} bs=1M count=$DATASIZE >/dev/null 2>&1
dd if=/dev/zero of="${MNTPOINT}/${RNDDIRNAME}/${RNDFILENAME}" bs=1M count="$DATASIZE" &> /dev/null
if [ $? -ne 0 ]; then echo -e "${RED}ERROR: dd write failed.${NC}" >&2; exit 1; fi
sync
# compute slice occupation threshold
read -r OCCSLICES < ${MOST_RECENT_DIR}${VOLNAME}/mapped_slices
read -r OCCSLICES < "${stat_dir}${VOLNAME}/mapped_slices"
Y_COORD=$(echo "scale=3; $OCCSLICES / $TOTSLICES" | bc)
# sanity check i.e. Y_COORD is between 0 and 1
if (( $(echo "$Y_COORD < 0" | bc -l) )) || (( $(echo "$Y_COORD > 1" | bc -l) )); then
echo "Error: Y_COORD is not between 0 and 1"
echo -e "${RED}Error: Y_COORD ($Y_COORD) is not between 0 and 1.${NC}" >&2
exit 1
fi
# print point coords
@ -348,34 +412,12 @@ benchmark() {
done
# manually print last point to avoid rounding error artifacts at the last write
echo -e "${GREEN}1.0 1.0${NC}"
fi
fi
# end table
echo -e "${GREEN}---------------------------------${NC}"
# END TESTS
echo "Shufflecake Legacy fragmentation test ended. Unmounting volume."
# unmount
umount $MNTPOINT
rmdir $MNTPOINT
echo "Volume unmounted. Closing Shufflecake device..."
# close
etime=$( (time $SFLCNAME close $BLOCK_DEVICE > /dev/null) 2>&1 )
echo -e "${GREEN}Action close took $etime seconds.${NC}"
#end
}
# Clean up
cleanup() {
echo "Exiting and cleaning..."
if [[ -n $LOOP_DEVICE ]]; then
echo "Detaching $LOOP_DEVICE ..."
sudo losetup -d "$LOOP_DEVICE"
echo "Deleting $LOOP_FILENAME ..."
sudo rm -f "$LOOP_FILENAME"
echo "Loop device detached and backing file deleted."
fi
echo "Shufflecake Legacy fragmentation test ended."
# The cleanup trap will handle the rest
}
@ -386,74 +428,69 @@ cleanup() {
#####################################################################
# BANNER
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
#                xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   79 chars
echo -e "${BLUE}===============================================================================${NC}"
echo -e "${BLUE} Evaluation Script for Shufflecake Legacy Volume Fragmentation${NC}"
echo -e "${BLUE}         Evaluation Script for Shufflecake Legacy Volume Fragmentation${NC}"
echo -e "${BLUE}===============================================================================${NC}"
# PRELIMINARY: PARSE HELP, SUDO, AND LOAD SHUFFLECAKE (IF IT EXISTS, OTHERWISE ERROR)
case "$1" in
# help
--help|-?)
print_help
exit 0
;;
esac
# ARGUMENT PARSING
while [ "$#" -gt 0 ]; do
case "$1" in
--help|-?)
print_help
;;
*)
if [ -n "$BLOCK_DEVICE" ]; then
echo -e "${RED}Error: You can only specify one block device.${NC}" >&2
usage
exit 1
fi
BLOCK_DEVICE="$1"
;;
esac
shift
done
# PRELIMINARY CHECKS
check_sudo
echo -e "${BLUE}Initializing Shufflecake...${NC}"
echo "Searching Shufflecake executable..."
find_sflc_path
echo "Shufflecake executable found at $SFLCNAME ."
echo "Shufflecake executable found at \"$SFLCNAME\"."
echo "Searching and loading dm-sflc module..."
load_dmsflc
echo "Module dm-sflc found and loaded. Status DMSFLC_INSTALLED: $DMSFLC_INSTALLED ."
echo "Module dm-sflc status determined. DMSFLC_INSTALLED flag is: $DMSFLC_INSTALLED."
echo " "
# PARSER
case "$1" in
"")
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
echo "Now you will be asked to enter the path for a block device to be used for the "
echo "evaluation (all content will be erased). If no path is provided (default"
echo "choice), then the script will create a 1 GiB file in the current directory and "
echo "use it to back a loop device instead, then the file will be removed at the end."
echo " "
echo -n "Please enter the path for a block device (default: none): "
read BLOCK_DEVICE
if [ -z "$BLOCK_DEVICE" ]; then
echo "No path provided, creating a local file and loop device..."
LOOP_DEVICE=$(create_loop_device)
BLOCK_DEVICE=$LOOP_DEVICE
fi
;;
# argument passed
*)
BLOCK_DEVICE="$1"
;;
esac
# DETERMINE BLOCK DEVICE
if [ -z "$BLOCK_DEVICE" ]; then
echo "Now you will be asked to enter the path for a block device to be used for the "
echo "evaluation (all content will be erased). If no path is provided (default" 
echo "choice), then the script will create a 1 GiB file in the current directory and "
echo "use it to back a loop device instead, then the file will be removed at the end."
echo " "
echo -n "Please enter the path for a block device (default: none): "
read -r BLOCK_DEVICE
if [ -z "$BLOCK_DEVICE" ]; then
echo "No path provided, creating a local file and loop device..."
LOOP_DEVICE=$(create_loop_device)
BLOCK_DEVICE="$LOOP_DEVICE"
fi
fi
check_block_device "$BLOCK_DEVICE"
# MAIN PROGRAM
if confirm; then
benchmark
evaluate
else
echo "Aborting..."
fi
unload_dmsflc
cleanup
# The cleanup trap will automatically run on exit.
# END SCRIPT