mirror of
https://codeberg.org/shufflecake/shufflecake-c.git
synced 2026-01-10 21:11:09 -05:00
style: Convert leading spaces to tabs in benchmarks, change duration to 2s for testing
This commit is contained in:
parent
327ff6b672
commit
c1c8052f1b
6 changed files with 1356 additions and 1356 deletions
|
|
@ -39,176 +39,176 @@ NC='\033[0m' # No color
|
|||
# Help
|
||||
print_help() {
|
||||
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to benchmark LUKS/dm-crypt on this machine."
|
||||
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 " "
|
||||
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 LUKS volume within a given device."
|
||||
echo "2) Opens the volume, formats it with ext4 and mounts it."
|
||||
echo "3) Performs various fio r/w stress operations on it."
|
||||
echo "4) Unmounts and closes the used volume."
|
||||
echo " "
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to benchmark LUKS/dm-crypt on this machine."
|
||||
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 " "
|
||||
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 LUKS volume within a given device."
|
||||
echo "2) Opens the volume, formats it with ext4 and mounts it."
|
||||
echo "3) Performs various fio r/w stress operations on it."
|
||||
echo "4) Unmounts and closes the used volume."
|
||||
echo " "
|
||||
# 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 " "
|
||||
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
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
# Function for debugging
|
||||
bpx() {
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
echo "BPX: $1. Press any key to continue..." >&2
|
||||
fi
|
||||
read -n1 -s
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
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} --help${NC} for usage and help."
|
||||
}
|
||||
|
||||
# Check that this is run as root
|
||||
check_sudo() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
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
|
||||
else
|
||||
echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ -b "$1" ]; then
|
||||
echo "OK, block device path $1 is valid." >&2
|
||||
else
|
||||
echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create loop device
|
||||
create_loop_device() {
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
echo "$LOOP_DEVICE"
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
echo "$LOOP_DEVICE"
|
||||
}
|
||||
|
||||
# Generate a suitable LUKS volume name
|
||||
find_luksvolname() {
|
||||
volname="/dev/mapper/luks-benchmark-testvol" #placeholder
|
||||
echo "$volname"
|
||||
volname="/dev/mapper/luks-benchmark-testvol" #placeholder
|
||||
echo "$volname"
|
||||
}
|
||||
|
||||
# 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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Benchmarks
|
||||
benchmark() {
|
||||
|
||||
LUKSVOLUME="luks-test"
|
||||
MNTPOINT=""
|
||||
PASSPHRASE="mypassword"
|
||||
TESTNAME="luks"
|
||||
RUNTIME="10" # running time in seconds FOR EACH TEST
|
||||
DATASIZE="500M"
|
||||
TESTFILENAME="testfile"
|
||||
echo "Starting benchmark for LUKS/dm-crypt..."
|
||||
LUKSVOLUME="luks-test"
|
||||
MNTPOINT=""
|
||||
PASSPHRASE="mypassword"
|
||||
TESTNAME="luks"
|
||||
RUNTIME="2" # running time in seconds FOR EACH TEST
|
||||
DATASIZE="500M"
|
||||
TESTFILENAME="testfile"
|
||||
echo "Starting benchmark for LUKS/dm-crypt..."
|
||||
# First, make sure that dm_mod is loaded
|
||||
modprobe dm_mod
|
||||
# Volume setup
|
||||
echo "Initializing block device $BLOCK_DEVICE as a LUKS volume..."
|
||||
etime=$( (time echo -n "$PASSPHRASE" | cryptsetup --batch-mode --cipher aes-xts-plain64 luksFormat $BLOCK_DEVICE - > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action luksFormat took $etime seconds.${NC}"
|
||||
echo "LUKS device initialized. Opening encrypted volume..."
|
||||
etime=$( (time echo -n "$PASSPHRASE" | cryptsetup luksOpen $BLOCK_DEVICE $LUKSVOLUME - > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action luksOpen took $etime seconds.${NC}"
|
||||
echo "LUKS volume opened as /dev/mapper/$LUKSVOLUME. Formatting with ext4..."
|
||||
# format with ext4, but mute output (too verbose)
|
||||
mkfs.ext4 /dev/mapper/$LUKSVOLUME > /dev/null
|
||||
echo "Volume /dev/mapper/$SFLCVOLUME formatted. Mounting that..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./luks_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount /dev/mapper/$LUKSVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fio tests..."
|
||||
# TESTS HERE
|
||||
# test 01: random read
|
||||
echo "Test 01: random read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-rnd --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 02: random write
|
||||
echo "Test 02: random write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-rnd --ioengine=libaio --iodepth=32 --rw=randwrite --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 03: sequential read
|
||||
echo "Test 03: sequential read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-seq --ioengine=libaio --iodepth=32 --rw=read --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 04: sequential write
|
||||
echo "Test 04: sequential write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# END TESTS
|
||||
echo "LUKS/dm-crypt fio tests ended. Unmounting volume."
|
||||
# unmount
|
||||
umount $MNTPOINT
|
||||
rmdir $MNTPOINT
|
||||
echo "Volume unmounted. Closing LUKS device..."
|
||||
# close
|
||||
etime=$( (time cryptsetup luksClose $LUKSVOLUME > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action close took $etime seconds.${NC}"
|
||||
#end
|
||||
echo "Initializing block device $BLOCK_DEVICE as a LUKS volume..."
|
||||
etime=$( (time echo -n "$PASSPHRASE" | cryptsetup --batch-mode --cipher aes-xts-plain64 luksFormat $BLOCK_DEVICE - > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action luksFormat took $etime seconds.${NC}"
|
||||
echo "LUKS device initialized. Opening encrypted volume..."
|
||||
etime=$( (time echo -n "$PASSPHRASE" | cryptsetup luksOpen $BLOCK_DEVICE $LUKSVOLUME - > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action luksOpen took $etime seconds.${NC}"
|
||||
echo "LUKS volume opened as /dev/mapper/$LUKSVOLUME. Formatting with ext4..."
|
||||
# format with ext4, but mute output (too verbose)
|
||||
mkfs.ext4 /dev/mapper/$LUKSVOLUME > /dev/null
|
||||
echo "Volume /dev/mapper/$SFLCVOLUME formatted. Mounting that..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./luks_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount /dev/mapper/$LUKSVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fio tests..."
|
||||
# TESTS HERE
|
||||
# test 01: random read
|
||||
echo "Test 01: random read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-rnd --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 02: random write
|
||||
echo "Test 02: random write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-rnd --ioengine=libaio --iodepth=32 --rw=randwrite --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 03: sequential read
|
||||
echo "Test 03: sequential read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-seq --ioengine=libaio --iodepth=32 --rw=read --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 04: sequential write
|
||||
echo "Test 04: sequential write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# END TESTS
|
||||
echo "LUKS/dm-crypt fio tests ended. Unmounting volume."
|
||||
# unmount
|
||||
umount $MNTPOINT
|
||||
rmdir $MNTPOINT
|
||||
echo "Volume unmounted. Closing LUKS device..."
|
||||
# close
|
||||
etime=$( (time cryptsetup luksClose $LUKSVOLUME > /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 "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
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -229,17 +229,17 @@ echo -e "${BLUE}================================================================
|
|||
|
||||
case "$1" in
|
||||
# help
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
check_sudo
|
||||
|
||||
if ! which cryptsetup >/dev/null; then
|
||||
echo -e "${RED}ERROR: cryptsetup not found, please install it.${NC}"
|
||||
exit 1
|
||||
echo -e "${RED}ERROR: cryptsetup not found, please install it.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " "
|
||||
|
|
@ -248,28 +248,28 @@ 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 "benchmarks (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"
|
||||
;;
|
||||
echo "Now you will be asked to enter the path for a block device to be used for the "
|
||||
echo "benchmarks (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
|
||||
|
||||
check_block_device "$BLOCK_DEVICE"
|
||||
|
|
@ -277,9 +277,9 @@ check_block_device "$BLOCK_DEVICE"
|
|||
# MAIN PROGRAM
|
||||
|
||||
if confirm; then
|
||||
benchmark
|
||||
benchmark
|
||||
else
|
||||
echo "Aborting..."
|
||||
echo "Aborting..."
|
||||
fi
|
||||
|
||||
cleanup
|
||||
|
|
|
|||
|
|
@ -42,272 +42,272 @@ NC='\033[0m' # No color
|
|||
# Help
|
||||
print_help() {
|
||||
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to benchmark Shufflecake Legacy on this machine."
|
||||
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 " "
|
||||
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 ext4 and mounts it."
|
||||
echo "3) Performs various fio r/w stress operations on it."
|
||||
echo "4) Unmounts and closes the used volume."
|
||||
echo " "
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to benchmark Shufflecake Legacy on this machine."
|
||||
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 " "
|
||||
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 ext4 and mounts it."
|
||||
echo "3) Performs various fio r/w stress operations on it."
|
||||
echo "4) Unmounts and closes the used volume."
|
||||
echo " "
|
||||
# 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 " "
|
||||
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
|
||||
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 " "
|
||||
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
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function for debugging
|
||||
bpx() {
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
echo "BPX: $1. Press any key to continue..." >&2
|
||||
fi
|
||||
read -n1 -s
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
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} --help${NC} for usage and help."
|
||||
}
|
||||
|
||||
# Check that this is run as root
|
||||
check_sudo() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Find the path of Shufflecake executable
|
||||
find_sflc_path() {
|
||||
local cmd="shufflecake"
|
||||
local cmd="shufflecake"
|
||||
|
||||
# Check if the command exists in the current directory
|
||||
if [[ -x "./$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ./)
|
||||
SFLCNAME=$(realpath ./$cmd)
|
||||
return
|
||||
fi
|
||||
# Check if the command exists in the current directory
|
||||
if [[ -x "./$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ./)
|
||||
SFLCNAME=$(realpath ./$cmd)
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if the command exists in the parent directory
|
||||
if [[ -x "../$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ../)
|
||||
SFLCNAME=$(realpath ../$cmd)
|
||||
return
|
||||
fi
|
||||
# Check if the command exists in the parent directory
|
||||
if [[ -x "../$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ../)
|
||||
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)
|
||||
return
|
||||
fi
|
||||
done
|
||||
# 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)
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
# If the command was not found, print an error message
|
||||
echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2
|
||||
exit 1
|
||||
# If the command was not found, print an error message
|
||||
echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Find and load module dm-sflc
|
||||
load_dmsflc() {
|
||||
local mod="dm-sflc"
|
||||
local mod="dm-sflc"
|
||||
|
||||
# First, make sure that dm_mod is loaded
|
||||
modprobe dm_mod
|
||||
|
||||
# Check if the module is already loaded
|
||||
if lsmod | grep -q "^$mod "; then
|
||||
DMSFLC_INSTALLED=true
|
||||
echo "Module '$mod' is already loaded."
|
||||
return
|
||||
fi
|
||||
# Check if the module is already loaded
|
||||
if lsmod | grep -q "^$mod "; then
|
||||
DMSFLC_INSTALLED=true
|
||||
echo "Module '$mod' is already loaded."
|
||||
return
|
||||
fi
|
||||
|
||||
# If not, look for the module file and try to load it
|
||||
local mod_file="$mod.ko"
|
||||
# If not, look for the module file and try to load it
|
||||
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."
|
||||
return
|
||||
fi
|
||||
# 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."
|
||||
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."
|
||||
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."
|
||||
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
|
||||
exit 1
|
||||
# If the module file was not found, print an error message
|
||||
echo -e "${RED} ERROR: Module file '$mod_file' not found.${NC}." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Unload dm-sflc if it was loaded locally
|
||||
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."
|
||||
fi
|
||||
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."
|
||||
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
|
||||
else
|
||||
echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}"
|
||||
unload_dmsflc
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ -b "$1" ]; then
|
||||
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
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create loop device
|
||||
create_loop_device() {
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
echo "$LOOP_DEVICE"
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
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}"
|
||||
return 1
|
||||
else
|
||||
echo $volname
|
||||
return 0
|
||||
fi
|
||||
# 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}"
|
||||
return 1
|
||||
else
|
||||
echo $volname
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Benchmarks
|
||||
benchmark() {
|
||||
|
||||
SFLCVOLUME=""
|
||||
MNTPOINT=""
|
||||
TESTNAME="sflc-lgc"
|
||||
RUNTIME="10" # running time in seconds FOR EACH TEST
|
||||
DATASIZE="500M"
|
||||
TESTFILENAME="testfile"
|
||||
echo "Starting benchmark for Shufflecake Legacy..."
|
||||
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 -e "${GREEN}Action init took $etime seconds.${NC}"
|
||||
echo "Shufflecake device initialized. Opening hidden volume (nr. 2)..."
|
||||
# open
|
||||
etime=$( (time echo -e "passwd2" | $SFLCNAME --legacy open $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action open took $etime seconds.${NC}"
|
||||
# fetch SFLCVOLUME
|
||||
SFLCVOLUME=$(find_sflcvolname)
|
||||
echo "Shufflecake Legacy volume opened as $SFLCVOLUME. Formatting with ext4..."
|
||||
# format with ext4, but mute output (too verbose)
|
||||
mkfs.ext4 $SFLCVOLUME > /dev/null
|
||||
echo "Volume $SFLCVOLUME formatted. Mounting that..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./sflc_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount $SFLCVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fio tests..."
|
||||
# TESTS HERE
|
||||
# test 01: random read
|
||||
echo "Test 01: random read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-rnd --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 02: random write
|
||||
echo "Test 02: random write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-rnd --ioengine=libaio --iodepth=32 --rw=randwrite --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 03: sequential read
|
||||
echo "Test 03: sequential read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-seq --ioengine=libaio --iodepth=32 --rw=read --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 04: sequential write
|
||||
echo "Test 04: sequential write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# END TESTS
|
||||
echo "Shufflecake Legacy fio tests 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
|
||||
|
||||
SFLCVOLUME=""
|
||||
MNTPOINT=""
|
||||
TESTNAME="sflc-lgc"
|
||||
RUNTIME="2" # running time in seconds FOR EACH TEST
|
||||
DATASIZE="500M"
|
||||
TESTFILENAME="testfile"
|
||||
echo "Starting benchmark for Shufflecake Legacy..."
|
||||
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 -e "${GREEN}Action init took $etime seconds.${NC}"
|
||||
echo "Shufflecake device initialized. Opening hidden volume (nr. 2)..."
|
||||
# open
|
||||
etime=$( (time echo -e "passwd2" | $SFLCNAME --legacy open $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action open took $etime seconds.${NC}"
|
||||
# fetch SFLCVOLUME
|
||||
SFLCVOLUME=$(find_sflcvolname)
|
||||
echo "Shufflecake Legacy volume opened as $SFLCVOLUME. Formatting with ext4..."
|
||||
# format with ext4, but mute output (too verbose)
|
||||
mkfs.ext4 $SFLCVOLUME > /dev/null
|
||||
echo "Volume $SFLCVOLUME formatted. Mounting that..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./sflc_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount $SFLCVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fio tests..."
|
||||
# TESTS HERE
|
||||
# test 01: random read
|
||||
echo "Test 01: random read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-rnd --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 02: random write
|
||||
echo "Test 02: random write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-rnd --ioengine=libaio --iodepth=32 --rw=randwrite --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 03: sequential read
|
||||
echo "Test 03: sequential read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-seq --ioengine=libaio --iodepth=32 --rw=read --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 04: sequential write
|
||||
echo "Test 04: sequential write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# END TESTS
|
||||
echo "Shufflecake Legacy fio tests 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 "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
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -328,14 +328,14 @@ echo -e "${BLUE}================================================================
|
|||
|
||||
case "$1" in
|
||||
# help
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
check_sudo
|
||||
|
||||
|
||||
echo -e "${BLUE}Initializing Shufflecake...${NC}"
|
||||
echo "Searching Shufflecake executable..."
|
||||
find_sflc_path
|
||||
|
|
@ -349,38 +349,38 @@ 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 "benchmarks (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"
|
||||
;;
|
||||
echo "Now you will be asked to enter the path for a block device to be used for the "
|
||||
echo "benchmarks (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
|
||||
|
||||
check_block_device "$BLOCK_DEVICE"
|
||||
|
||||
|
||||
# MAIN PROGRAM
|
||||
|
||||
if confirm; then
|
||||
benchmark
|
||||
benchmark
|
||||
else
|
||||
echo "Aborting..."
|
||||
echo "Aborting..."
|
||||
fi
|
||||
|
||||
unload_dmsflc
|
||||
|
|
|
|||
|
|
@ -46,336 +46,336 @@ NC='\033[0m' # No color
|
|||
# Help
|
||||
print_help() {
|
||||
# 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 " "
|
||||
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 "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 " "
|
||||
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 " "
|
||||
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 "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
|
||||
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 " "
|
||||
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
|
||||
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 " "
|
||||
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
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function for debugging
|
||||
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
|
||||
fi
|
||||
read -n1 -s
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
echo -e "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} --help${NC} for usage and help."
|
||||
}
|
||||
|
||||
# Check that this is run as root
|
||||
check_sudo() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Find the path of Shufflecake executable
|
||||
find_sflc_path() {
|
||||
local cmd="shufflecake"
|
||||
local cmd="shufflecake"
|
||||
|
||||
# Check if the command exists in the current directory
|
||||
if [[ -x "./$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ./)
|
||||
SFLCNAME=$(realpath ./$cmd)
|
||||
return
|
||||
fi
|
||||
# Check if the command exists in the current directory
|
||||
if [[ -x "./$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ./)
|
||||
SFLCNAME=$(realpath ./$cmd)
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if the command exists in the parent directory
|
||||
if [[ -x "../$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ../)
|
||||
SFLCNAME=$(realpath ../$cmd)
|
||||
return
|
||||
fi
|
||||
# Check if the command exists in the parent directory
|
||||
if [[ -x "../$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ../)
|
||||
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)
|
||||
return
|
||||
fi
|
||||
done
|
||||
# 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)
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
# If the command was not found, print an error message
|
||||
echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2
|
||||
exit 1
|
||||
# If the command was not found, print an error message
|
||||
echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Find and load module dm-sflc
|
||||
load_dmsflc() {
|
||||
local mod="dm-sflc"
|
||||
local mod="dm-sflc"
|
||||
|
||||
# First, make sure that dm_mod is loaded
|
||||
modprobe dm_mod
|
||||
|
||||
# Check if the module is already loaded
|
||||
if lsmod | grep -q "^$mod "; then
|
||||
DMSFLC_INSTALLED=true
|
||||
echo "Module '$mod' is already loaded."
|
||||
return
|
||||
fi
|
||||
# Check if the module is already loaded
|
||||
if lsmod | grep -q "^$mod "; then
|
||||
DMSFLC_INSTALLED=true
|
||||
echo "Module '$mod' is already loaded."
|
||||
return
|
||||
fi
|
||||
|
||||
# If not, look for the module file and try to load it
|
||||
local mod_file="$mod.ko"
|
||||
# If not, look for the module file and try to load it
|
||||
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."
|
||||
return
|
||||
fi
|
||||
# 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."
|
||||
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."
|
||||
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."
|
||||
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
|
||||
exit 1
|
||||
# If the module file was not found, print an error message
|
||||
echo -e "${RED} ERROR: Module file '$mod_file' not found.${NC}." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Unload dm-sflc if it was loaded locally
|
||||
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."
|
||||
fi
|
||||
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."
|
||||
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
|
||||
else
|
||||
echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}"
|
||||
unload_dmsflc
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ -b "$1" ]; then
|
||||
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
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create loop device
|
||||
create_loop_device() {
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
echo "$LOOP_DEVICE"
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
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}"
|
||||
return 1
|
||||
else
|
||||
echo $volname
|
||||
return 0
|
||||
fi
|
||||
# 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}"
|
||||
return 1
|
||||
else
|
||||
echo $volname
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Benchmarks
|
||||
benchmark() {
|
||||
|
||||
SFLCVOLUME=""
|
||||
VOLNAME=""
|
||||
MNTPOINT=""
|
||||
NUMPOINTS=21 # number of graph points
|
||||
VOLSIZE=$(blockdev --getsize64 "$BLOCK_DEVICE") # first approximation, in bytes
|
||||
SFLCVOLUME=""
|
||||
VOLNAME=""
|
||||
MNTPOINT=""
|
||||
NUMPOINTS=21 # number of graph points
|
||||
VOLSIZE=$(blockdev --getsize64 "$BLOCK_DEVICE") # first approximation, in bytes
|
||||
|
||||
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 -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 )
|
||||
echo -e "${GREEN}Action open took $etime seconds.${NC}"
|
||||
# fetch SFLCVOLUME
|
||||
SFLCVOLUME=$(find_sflcvolname)
|
||||
# trim path of SFLCVOLUME
|
||||
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..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./sflc_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount $SFLCVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fragmentation test..."
|
||||
# TESTS HERE
|
||||
|
||||
# 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}"
|
||||
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
|
||||
|
||||
# refine down block device max size according to available slices, to make sure there is no overflow
|
||||
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
|
||||
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}"
|
||||
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 -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 )
|
||||
echo -e "${GREEN}Action open took $etime seconds.${NC}"
|
||||
# fetch SFLCVOLUME
|
||||
SFLCVOLUME=$(find_sflcvolname)
|
||||
# trim path of SFLCVOLUME
|
||||
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..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./sflc_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount $SFLCVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fragmentation test..."
|
||||
# TESTS HERE
|
||||
|
||||
# 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}"
|
||||
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
|
||||
|
||||
# refine down block device max size according to available slices, to make sure there is no overflow
|
||||
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
|
||||
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
|
||||
# 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
|
||||
|
||||
# loop for i = 1 to NUMPOINTS
|
||||
for (( i=1; i<$NUMPOINTS-1; i++ )); do
|
||||
X_COORD=$(echo "scale=3; $i / ($NUMPOINTS-1) " | bc)
|
||||
# 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)
|
||||
[ ! -e "${MNTPOINT}/${RNDDIRNAME}" ] && break
|
||||
done
|
||||
# create random dir
|
||||
mkdir "${MNTPOINT}/${RNDDIRNAME}"
|
||||
|
||||
# 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)
|
||||
[ ! -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
|
||||
sync
|
||||
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
|
||||
|
||||
# loop for i = 1 to NUMPOINTS
|
||||
for (( i=1; i<$NUMPOINTS-1; i++ )); do
|
||||
X_COORD=$(echo "scale=3; $i / ($NUMPOINTS-1) " | bc)
|
||||
# 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)
|
||||
[ ! -e "${MNTPOINT}/${RNDDIRNAME}" ] && break
|
||||
done
|
||||
# create random dir
|
||||
mkdir "${MNTPOINT}/${RNDDIRNAME}"
|
||||
|
||||
# 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)
|
||||
[ ! -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
|
||||
sync
|
||||
|
||||
# compute slice occupation threshold
|
||||
read -r OCCSLICES < ${MOST_RECENT_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"
|
||||
exit 1
|
||||
fi
|
||||
# print point coords
|
||||
echo -e "${GREEN}$X_COORD $Y_COORD${NC}"
|
||||
done
|
||||
# manually print last point to avoid rounding error artifacts at the last write
|
||||
echo -e "${GREEN}1.0 1.0${NC}"
|
||||
|
||||
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
|
||||
|
||||
# compute slice occupation threshold
|
||||
read -r OCCSLICES < ${MOST_RECENT_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"
|
||||
exit 1
|
||||
fi
|
||||
# print point coords
|
||||
echo -e "${GREEN}$X_COORD $Y_COORD${NC}"
|
||||
done
|
||||
# manually print last point to avoid rounding error artifacts at the last write
|
||||
echo -e "${GREEN}1.0 1.0${NC}"
|
||||
|
||||
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 "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
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -396,14 +396,14 @@ echo -e "${BLUE}================================================================
|
|||
|
||||
case "$1" in
|
||||
# help
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
check_sudo
|
||||
|
||||
|
||||
echo -e "${BLUE}Initializing Shufflecake...${NC}"
|
||||
echo "Searching Shufflecake executable..."
|
||||
find_sflc_path
|
||||
|
|
@ -417,28 +417,28 @@ 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"
|
||||
;;
|
||||
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
|
||||
|
||||
check_block_device "$BLOCK_DEVICE"
|
||||
|
|
@ -446,9 +446,9 @@ check_block_device "$BLOCK_DEVICE"
|
|||
# MAIN PROGRAM
|
||||
|
||||
if confirm; then
|
||||
benchmark
|
||||
benchmark
|
||||
else
|
||||
echo "Aborting..."
|
||||
echo "Aborting..."
|
||||
fi
|
||||
|
||||
unload_dmsflc
|
||||
|
|
|
|||
|
|
@ -42,272 +42,272 @@ NC='\033[0m' # No color
|
|||
# Help
|
||||
print_help() {
|
||||
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to benchmark Shufflecake Lite on this machine."
|
||||
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 " "
|
||||
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 (Lite) device with two volumes."
|
||||
echo "2) Opens the second (hidden) volume, formats it with ext4 and mounts it."
|
||||
echo "3) Performs various fio r/w stress operations on it."
|
||||
echo "4) Unmounts and closes the used volume."
|
||||
echo " "
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to benchmark Shufflecake Lite on this machine."
|
||||
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 " "
|
||||
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 (Lite) device with two volumes."
|
||||
echo "2) Opens the second (hidden) volume, formats it with ext4 and mounts it."
|
||||
echo "3) Performs various fio r/w stress operations on it."
|
||||
echo "4) Unmounts and closes the used volume."
|
||||
echo " "
|
||||
# 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 " "
|
||||
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
|
||||
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 " "
|
||||
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
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function for debugging
|
||||
bpx() {
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
echo "BPX: $1. Press any key to continue..." >&2
|
||||
fi
|
||||
read -n1 -s
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
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} --help${NC} for usage and help."
|
||||
}
|
||||
|
||||
# Check that this is run as root
|
||||
check_sudo() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Find the path of Shufflecake executable
|
||||
find_sflc_path() {
|
||||
local cmd="shufflecake"
|
||||
local cmd="shufflecake"
|
||||
|
||||
# Check if the command exists in the current directory
|
||||
if [[ -x "./$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ./)
|
||||
SFLCNAME=$(realpath ./$cmd)
|
||||
return
|
||||
fi
|
||||
# Check if the command exists in the current directory
|
||||
if [[ -x "./$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ./)
|
||||
SFLCNAME=$(realpath ./$cmd)
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if the command exists in the parent directory
|
||||
if [[ -x "../$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ../)
|
||||
SFLCNAME=$(realpath ../$cmd)
|
||||
return
|
||||
fi
|
||||
# Check if the command exists in the parent directory
|
||||
if [[ -x "../$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ../)
|
||||
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)
|
||||
return
|
||||
fi
|
||||
done
|
||||
# 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)
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
# If the command was not found, print an error message
|
||||
echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2
|
||||
exit 1
|
||||
# If the command was not found, print an error message
|
||||
echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Find and load module dm-sflc
|
||||
load_dmsflc() {
|
||||
local mod="dm-sflc"
|
||||
local mod="dm-sflc"
|
||||
|
||||
# First, make sure that dm_mod is loaded
|
||||
modprobe dm_mod
|
||||
|
||||
# Check if the module is already loaded
|
||||
if lsmod | grep -q "^$mod "; then
|
||||
DMSFLC_INSTALLED=true
|
||||
echo "Module '$mod' is already loaded."
|
||||
return
|
||||
fi
|
||||
# Check if the module is already loaded
|
||||
if lsmod | grep -q "^$mod "; then
|
||||
DMSFLC_INSTALLED=true
|
||||
echo "Module '$mod' is already loaded."
|
||||
return
|
||||
fi
|
||||
|
||||
# If not, look for the module file and try to load it
|
||||
local mod_file="$mod.ko"
|
||||
# If not, look for the module file and try to load it
|
||||
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."
|
||||
return
|
||||
fi
|
||||
# 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."
|
||||
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."
|
||||
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."
|
||||
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
|
||||
exit 1
|
||||
# If the module file was not found, print an error message
|
||||
echo -e "${RED} ERROR: Module file '$mod_file' not found.${NC}." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Unload dm-sflc if it was loaded locally
|
||||
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."
|
||||
fi
|
||||
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."
|
||||
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
|
||||
else
|
||||
echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}"
|
||||
unload_dmsflc
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ -b "$1" ]; then
|
||||
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
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create loop device
|
||||
create_loop_device() {
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
echo "$LOOP_DEVICE"
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
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}"
|
||||
return 1
|
||||
else
|
||||
echo $volname
|
||||
return 0
|
||||
fi
|
||||
# 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}"
|
||||
return 1
|
||||
else
|
||||
echo $volname
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Benchmarks
|
||||
benchmark() {
|
||||
|
||||
SFLCVOLUME=""
|
||||
MNTPOINT=""
|
||||
TESTNAME="sflc-lite"
|
||||
RUNTIME="10" # running time in seconds FOR EACH TEST
|
||||
DATASIZE="500M"
|
||||
TESTFILENAME="testfile"
|
||||
echo "Starting benchmark for Shufflecake Lite..."
|
||||
echo "Initializing block device $BLOCK_DEVICE with two Shufflecake Lite volumes (--skip-randfill)..."
|
||||
etime=$( (time echo -e "passwd1\npasswd2" | $SFLCNAME --skip-randfill -n 2 init $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action init took $etime seconds.${NC}"
|
||||
echo "Shufflecake device initialized. Opening hidden volume (nr. 2)..."
|
||||
# open
|
||||
etime=$( (time echo -e "passwd2" | $SFLCNAME open $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action open took $etime seconds.${NC}"
|
||||
# fetch SFLCVOLUME
|
||||
SFLCVOLUME=$(find_sflcvolname)
|
||||
echo "Shufflecake Lite volume opened as $SFLCVOLUME. Formatting with ext4..."
|
||||
# format with ext4, but mute output (too verbose)
|
||||
mkfs.ext4 $SFLCVOLUME > /dev/null
|
||||
echo "Volume $SFLCVOLUME formatted. Mounting that..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./sflc_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount $SFLCVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fio tests..."
|
||||
# TESTS HERE
|
||||
# test 01: random read
|
||||
echo "Test 01: random read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-rnd --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 02: random write
|
||||
echo "Test 02: random write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-rnd --ioengine=libaio --iodepth=32 --rw=randwrite --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 03: sequential read
|
||||
echo "Test 03: sequential read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-seq --ioengine=libaio --iodepth=32 --rw=read --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 04: sequential write
|
||||
echo "Test 04: sequential write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# END TESTS
|
||||
echo "Shufflecake Lite fio tests 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
|
||||
|
||||
SFLCVOLUME=""
|
||||
MNTPOINT=""
|
||||
TESTNAME="sflc-lite"
|
||||
RUNTIME="2" # running time in seconds FOR EACH TEST
|
||||
DATASIZE="500M"
|
||||
TESTFILENAME="testfile"
|
||||
echo "Starting benchmark for Shufflecake Lite..."
|
||||
echo "Initializing block device $BLOCK_DEVICE with two Shufflecake Lite volumes (--skip-randfill)..."
|
||||
etime=$( (time echo -e "passwd1\npasswd2" | $SFLCNAME --skip-randfill -n 2 init $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action init took $etime seconds.${NC}"
|
||||
echo "Shufflecake device initialized. Opening hidden volume (nr. 2)..."
|
||||
# open
|
||||
etime=$( (time echo -e "passwd2" | $SFLCNAME open $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action open took $etime seconds.${NC}"
|
||||
# fetch SFLCVOLUME
|
||||
SFLCVOLUME=$(find_sflcvolname)
|
||||
echo "Shufflecake Lite volume opened as $SFLCVOLUME. Formatting with ext4..."
|
||||
# format with ext4, but mute output (too verbose)
|
||||
mkfs.ext4 $SFLCVOLUME > /dev/null
|
||||
echo "Volume $SFLCVOLUME formatted. Mounting that..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./sflc_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount $SFLCVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fio tests..."
|
||||
# TESTS HERE
|
||||
# test 01: random read
|
||||
echo "Test 01: random read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-rnd --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 02: random write
|
||||
echo "Test 02: random write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-rnd --ioengine=libaio --iodepth=32 --rw=randwrite --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 03: sequential read
|
||||
echo "Test 03: sequential read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-seq --ioengine=libaio --iodepth=32 --rw=read --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 04: sequential write
|
||||
echo "Test 04: sequential write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# END TESTS
|
||||
echo "Shufflecake Lite fio tests 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 "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
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -328,14 +328,14 @@ echo -e "${BLUE}================================================================
|
|||
|
||||
case "$1" in
|
||||
# help
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
check_sudo
|
||||
|
||||
|
||||
echo -e "${BLUE}Initializing Shufflecake...${NC}"
|
||||
echo "Searching Shufflecake executable..."
|
||||
find_sflc_path
|
||||
|
|
@ -349,38 +349,38 @@ 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 "benchmarks (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"
|
||||
;;
|
||||
echo "Now you will be asked to enter the path for a block device to be used for the "
|
||||
echo "benchmarks (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
|
||||
|
||||
check_block_device "$BLOCK_DEVICE"
|
||||
|
||||
|
||||
# MAIN PROGRAM
|
||||
|
||||
if confirm; then
|
||||
benchmark
|
||||
benchmark
|
||||
else
|
||||
echo "Aborting..."
|
||||
echo "Aborting..."
|
||||
fi
|
||||
|
||||
unload_dmsflc
|
||||
|
|
|
|||
|
|
@ -46,336 +46,336 @@ NC='\033[0m' # No color
|
|||
# Help
|
||||
print_help() {
|
||||
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to evaluate Shufflecake Lite 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 " "
|
||||
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 Lite device with two volumes."
|
||||
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 " "
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to evaluate Shufflecake Lite 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 " "
|
||||
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 Lite device with two volumes."
|
||||
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
|
||||
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 " "
|
||||
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
|
||||
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 " "
|
||||
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
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function for debugging
|
||||
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
|
||||
fi
|
||||
read -n1 -s
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
echo -e "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} --help${NC} for usage and help."
|
||||
}
|
||||
|
||||
# Check that this is run as root
|
||||
check_sudo() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Find the path of Shufflecake executable
|
||||
find_sflc_path() {
|
||||
local cmd="shufflecake"
|
||||
local cmd="shufflecake"
|
||||
|
||||
# Check if the command exists in the current directory
|
||||
if [[ -x "./$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ./)
|
||||
SFLCNAME=$(realpath ./$cmd)
|
||||
return
|
||||
fi
|
||||
# Check if the command exists in the current directory
|
||||
if [[ -x "./$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ./)
|
||||
SFLCNAME=$(realpath ./$cmd)
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if the command exists in the parent directory
|
||||
if [[ -x "../$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ../)
|
||||
SFLCNAME=$(realpath ../$cmd)
|
||||
return
|
||||
fi
|
||||
# Check if the command exists in the parent directory
|
||||
if [[ -x "../$cmd" ]]; then
|
||||
SFLCPATH=$(realpath ../)
|
||||
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)
|
||||
return
|
||||
fi
|
||||
done
|
||||
# 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)
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
# If the command was not found, print an error message
|
||||
echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2
|
||||
exit 1
|
||||
# If the command was not found, print an error message
|
||||
echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Find and load module dm-sflc
|
||||
load_dmsflc() {
|
||||
local mod="dm-sflc"
|
||||
local mod="dm-sflc"
|
||||
|
||||
# First, make sure that dm_mod is loaded
|
||||
modprobe dm_mod
|
||||
|
||||
# Check if the module is already loaded
|
||||
if lsmod | grep -q "^$mod "; then
|
||||
DMSFLC_INSTALLED=true
|
||||
echo "Module '$mod' is already loaded."
|
||||
return
|
||||
fi
|
||||
# Check if the module is already loaded
|
||||
if lsmod | grep -q "^$mod "; then
|
||||
DMSFLC_INSTALLED=true
|
||||
echo "Module '$mod' is already loaded."
|
||||
return
|
||||
fi
|
||||
|
||||
# If not, look for the module file and try to load it
|
||||
local mod_file="$mod.ko"
|
||||
# If not, look for the module file and try to load it
|
||||
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."
|
||||
return
|
||||
fi
|
||||
# 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."
|
||||
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."
|
||||
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."
|
||||
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
|
||||
exit 1
|
||||
# If the module file was not found, print an error message
|
||||
echo -e "${RED} ERROR: Module file '$mod_file' not found.${NC}." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Unload dm-sflc if it was loaded locally
|
||||
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."
|
||||
fi
|
||||
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."
|
||||
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
|
||||
else
|
||||
echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}"
|
||||
unload_dmsflc
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ -b "$1" ]; then
|
||||
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
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create loop device
|
||||
create_loop_device() {
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
echo "$LOOP_DEVICE"
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
sudo 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
|
||||
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}"
|
||||
return 1
|
||||
else
|
||||
echo $volname
|
||||
return 0
|
||||
fi
|
||||
# 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}"
|
||||
return 1
|
||||
else
|
||||
echo $volname
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# 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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
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}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Benchmarks
|
||||
benchmark() {
|
||||
|
||||
SFLCVOLUME=""
|
||||
VOLNAME=""
|
||||
MNTPOINT=""
|
||||
NUMPOINTS=21 # number of graph points
|
||||
VOLSIZE=$(blockdev --getsize64 "$BLOCK_DEVICE") # first approximation, in bytes
|
||||
SFLCVOLUME=""
|
||||
VOLNAME=""
|
||||
MNTPOINT=""
|
||||
NUMPOINTS=21 # number of graph points
|
||||
VOLSIZE=$(blockdev --getsize64 "$BLOCK_DEVICE") # first approximation, in bytes
|
||||
|
||||
echo "Starting fragmentation test for Shufflecake Lite..."
|
||||
# init
|
||||
echo "Initializing block device $BLOCK_DEVICE with two Shufflecake Lite volumes (--skip-randfill)..."
|
||||
etime=$( (time echo -e "passwd1\npasswd2" | $SFLCNAME --skip-randfill -n 2 init $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action init took $etime seconds.${NC}"
|
||||
echo "Shufflecake Lite device initialized. Opening hidden volume (nr. 2)..."
|
||||
# open
|
||||
etime=$( (time echo -e "passwd2" | $SFLCNAME open $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action open took $etime seconds.${NC}"
|
||||
# fetch SFLCVOLUME
|
||||
SFLCVOLUME=$(find_sflcvolname)
|
||||
# trim path of SFLCVOLUME
|
||||
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..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./sflc_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount $SFLCVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fragmentation test..."
|
||||
# TESTS HERE
|
||||
|
||||
# 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}"
|
||||
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
|
||||
|
||||
# refine down block device max size according to available slices, to make sure there is no overflow
|
||||
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
|
||||
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}"
|
||||
echo "Starting fragmentation test for Shufflecake Lite..."
|
||||
# init
|
||||
echo "Initializing block device $BLOCK_DEVICE with two Shufflecake Lite volumes (--skip-randfill)..."
|
||||
etime=$( (time echo -e "passwd1\npasswd2" | $SFLCNAME --skip-randfill -n 2 init $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action init took $etime seconds.${NC}"
|
||||
echo "Shufflecake Lite device initialized. Opening hidden volume (nr. 2)..."
|
||||
# open
|
||||
etime=$( (time echo -e "passwd2" | $SFLCNAME open $BLOCK_DEVICE > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action open took $etime seconds.${NC}"
|
||||
# fetch SFLCVOLUME
|
||||
SFLCVOLUME=$(find_sflcvolname)
|
||||
# trim path of SFLCVOLUME
|
||||
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..."
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./sflc_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount
|
||||
mount $SFLCVOLUME $MNTPOINT
|
||||
echo "Volume mounted at $MNTPOINT. Starting fragmentation test..."
|
||||
# TESTS HERE
|
||||
|
||||
# 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}"
|
||||
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
|
||||
|
||||
# refine down block device max size according to available slices, to make sure there is no overflow
|
||||
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
|
||||
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
|
||||
# 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
|
||||
|
||||
# loop for i = 1 to NUMPOINTS
|
||||
for (( i=1; i<$NUMPOINTS-1; i++ )); do
|
||||
X_COORD=$(echo "scale=3; $i / ($NUMPOINTS-1) " | bc)
|
||||
# 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)
|
||||
[ ! -e "${MNTPOINT}/${RNDDIRNAME}" ] && break
|
||||
done
|
||||
# create random dir
|
||||
mkdir "${MNTPOINT}/${RNDDIRNAME}"
|
||||
|
||||
# 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)
|
||||
[ ! -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
|
||||
sync
|
||||
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
|
||||
|
||||
# loop for i = 1 to NUMPOINTS
|
||||
for (( i=1; i<$NUMPOINTS-1; i++ )); do
|
||||
X_COORD=$(echo "scale=3; $i / ($NUMPOINTS-1) " | bc)
|
||||
# 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)
|
||||
[ ! -e "${MNTPOINT}/${RNDDIRNAME}" ] && break
|
||||
done
|
||||
# create random dir
|
||||
mkdir "${MNTPOINT}/${RNDDIRNAME}"
|
||||
|
||||
# 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)
|
||||
[ ! -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
|
||||
sync
|
||||
|
||||
# compute slice occupation threshold
|
||||
read -r OCCSLICES < ${MOST_RECENT_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"
|
||||
exit 1
|
||||
fi
|
||||
# print point coords
|
||||
echo -e "${GREEN}$X_COORD $Y_COORD${NC}"
|
||||
done
|
||||
# manually print last point to avoid rounding error artifacts at the last write
|
||||
echo -e "${GREEN}1.0 1.0${NC}"
|
||||
|
||||
fi
|
||||
# end table
|
||||
echo -e "${GREEN}---------------------------------${NC}"
|
||||
|
||||
# END TESTS
|
||||
echo "Shufflecake Lite 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
|
||||
|
||||
# compute slice occupation threshold
|
||||
read -r OCCSLICES < ${MOST_RECENT_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"
|
||||
exit 1
|
||||
fi
|
||||
# print point coords
|
||||
echo -e "${GREEN}$X_COORD $Y_COORD${NC}"
|
||||
done
|
||||
# manually print last point to avoid rounding error artifacts at the last write
|
||||
echo -e "${GREEN}1.0 1.0${NC}"
|
||||
|
||||
fi
|
||||
# end table
|
||||
echo -e "${GREEN}---------------------------------${NC}"
|
||||
|
||||
# END TESTS
|
||||
echo "Shufflecake Lite 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 "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
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -396,14 +396,14 @@ echo -e "${BLUE}================================================================
|
|||
|
||||
case "$1" in
|
||||
# help
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
check_sudo
|
||||
|
||||
|
||||
echo -e "${BLUE}Initializing Shufflecake...${NC}"
|
||||
echo "Searching Shufflecake executable..."
|
||||
find_sflc_path
|
||||
|
|
@ -417,28 +417,28 @@ 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"
|
||||
;;
|
||||
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
|
||||
|
||||
check_block_device "$BLOCK_DEVICE"
|
||||
|
|
@ -446,9 +446,9 @@ check_block_device "$BLOCK_DEVICE"
|
|||
# MAIN PROGRAM
|
||||
|
||||
if confirm; then
|
||||
benchmark
|
||||
benchmark
|
||||
else
|
||||
echo "Aborting..."
|
||||
echo "Aborting..."
|
||||
fi
|
||||
|
||||
unload_dmsflc
|
||||
|
|
|
|||
|
|
@ -38,174 +38,174 @@ NC='\033[0m' # No color
|
|||
# Help
|
||||
print_help() {
|
||||
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to benchmark VeraCrypt on this machine."
|
||||
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 " "
|
||||
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 standard and unformatted VeraCrypt volumes within a given device."
|
||||
echo "2) Creates a hidden ext4 VeraCrypt volume within the standard one."
|
||||
echo "3) Opens the hidden volume, and mounts it."
|
||||
echo "4) Performs various fio r/w stress operations on it."
|
||||
echo "5) Unmounts and closes the used volume."
|
||||
echo " "
|
||||
echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}"
|
||||
echo " "
|
||||
echo "This script is used to benchmark VeraCrypt on this machine."
|
||||
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 " "
|
||||
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 standard and unformatted VeraCrypt volumes within a given device."
|
||||
echo "2) Creates a hidden ext4 VeraCrypt volume within the standard one."
|
||||
echo "3) Opens the hidden volume, and mounts it."
|
||||
echo "4) Performs various fio r/w stress operations on it."
|
||||
echo "5) Unmounts and closes the used volume."
|
||||
echo " "
|
||||
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
|
||||
echo "You can pass the path to a (non-loop) block device as an optional argument, "
|
||||
echo "otherwise the script will ask for one. If no path is provided, the script "
|
||||
echo "will create a 1 GiB VeraCrypt container file which will be removed at the end."
|
||||
echo "NOTICE: This script has been tested only with VeraCrypt v 1.25.9."
|
||||
echo " "
|
||||
echo "You can pass the path to a (non-loop) block device as an optional argument, "
|
||||
echo "otherwise the script will ask for one. If no path is provided, the script "
|
||||
echo "will create a 1 GiB VeraCrypt container file which will be removed at the end."
|
||||
echo "NOTICE: This script has been tested only with VeraCrypt v 1.25.9."
|
||||
echo " "
|
||||
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}"
|
||||
echo " "
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
# Function for debugging
|
||||
bpx() {
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
echo "BPX: $1. Press any key to continue..." >&2
|
||||
fi
|
||||
read -n1 -s
|
||||
if [ -z "$1" ]; then
|
||||
echo "BPX: Paused. Press any key to continue..." >&2
|
||||
else
|
||||
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} --help${NC} for usage and help."
|
||||
}
|
||||
|
||||
# Check that this is run as root
|
||||
check_sudo() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo -e "${RED}Error: This script must be run as root.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
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
|
||||
else
|
||||
echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ -b "$1" ]; then
|
||||
echo "OK, block device path $1 is valid." >&2
|
||||
else
|
||||
echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_not_loopdevice() {
|
||||
DEVCHECK=$1
|
||||
if [[ $DEVCHECK == /dev/loop* ]]; then
|
||||
echo -e "${RED}Error: $DEVCHECK is a loop device, this script does not work well with this type of devices due to how VeraCrypt works. Please either enter a non-loop block device, or just do not pass any path as input, this script will work on a container file directly.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
DEVCHECK=$1
|
||||
if [[ $DEVCHECK == /dev/loop* ]]; then
|
||||
echo -e "${RED}Error: $DEVCHECK is a loop device, this script does not work well with this type of devices due to how VeraCrypt works. Please either enter a non-loop block device, or just do not pass any path as input, this script will work on a container file directly.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create container file
|
||||
create_container_file() {
|
||||
CONTAINER_FILENAME="$SCRIPT_DIR/veracrypt-benchmark-container-file.img"
|
||||
echo "Creating an empty file $CONTAINER_FILENAME ..." >&2
|
||||
if [ -e "$CONTAINER_FILENAME" ]; then
|
||||
echo -e "${RED}Error: Impossible to generate file, $CONTAINER_FILENAME already exists.${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
touch $CONTAINER_FILENAME
|
||||
#dd if=/dev/zero of="$CONTAINER_FILENAME" bs=1M count=1024 > /dev/null
|
||||
#echo "Writing of empty file complete." >&2
|
||||
echo "$CONTAINER_FILENAME"
|
||||
CONTAINER_FILENAME="$SCRIPT_DIR/veracrypt-benchmark-container-file.img"
|
||||
echo "Creating an empty file $CONTAINER_FILENAME ..." >&2
|
||||
if [ -e "$CONTAINER_FILENAME" ]; then
|
||||
echo -e "${RED}Error: Impossible to generate file, $CONTAINER_FILENAME already exists.${NC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
touch $CONTAINER_FILENAME
|
||||
#dd if=/dev/zero of="$CONTAINER_FILENAME" bs=1M count=1024 > /dev/null
|
||||
#echo "Writing of empty file complete." >&2
|
||||
echo "$CONTAINER_FILENAME"
|
||||
}
|
||||
|
||||
# Function for user confirmation
|
||||
confirm() {
|
||||
while true; do
|
||||
echo -e "${BLUE}Are you sure you want to proceed? All data in $BLOCK_DEVICE will be erased. (y/n)${NC}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
while true; do
|
||||
echo -e "${BLUE}Are you sure you want to proceed? All data in $BLOCK_DEVICE will be erased. (y/n)${NC}"
|
||||
read -r response
|
||||
case "$response" in
|
||||
[yY]|[yY][eE][sS]) # Responded Yes
|
||||
return 0 # Return 0 for Yes (success, convention for bash scripting)
|
||||
;;
|
||||
[nN]|[nN][oO]) # Responded No
|
||||
return 1 # Return 1 for No (error, convention for bash scripting)
|
||||
;;
|
||||
*) # Responded something else
|
||||
echo "Please press only (y)es or (n)o."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Benchmarks
|
||||
benchmark() {
|
||||
|
||||
MNTPOINT=""
|
||||
TESTNAME="vc"
|
||||
RUNTIME="10" # running time in seconds FOR EACH TEST
|
||||
DATASIZE="500M"
|
||||
TESTFILENAME="testfile"
|
||||
echo "Starting benchmark for VeraCrypt..."
|
||||
MNTPOINT=""
|
||||
TESTNAME="vc"
|
||||
RUNTIME="2" # running time in seconds FOR EACH TEST
|
||||
DATASIZE="500M"
|
||||
TESTFILENAME="testfile"
|
||||
echo "Starting benchmark for VeraCrypt..."
|
||||
# First, make sure that dm_mod is loaded
|
||||
modprobe dm_mod
|
||||
# Create a new standard volume
|
||||
if [ -z "$CONTAINER_FILENAME" ]; then
|
||||
# it's a real block device, do not specify size
|
||||
etime=$( (time echo "passdecoy" | veracrypt --text --non-interactive --quick --create $BLOCK_DEVICE --volume-type=normal --password - --encryption=AES --hash=SHA-512 --filesystem=None --random-source=/dev/urandom > /dev/null) 2>&1 )
|
||||
else
|
||||
# it's file-based, then VeraCrypt requires specifying the size
|
||||
etime=$( (time echo "passdecoy" | veracrypt --text --non-interactive --quick --create $BLOCK_DEVICE --size=1G --volume-type=normal --password - --encryption=AES --hash=SHA-512 --filesystem=None --random-source=/dev/urandom > /dev/null) 2>&1 )
|
||||
fi
|
||||
echo -e "${GREEN}Creation of standard VeraCrypt volume took $etime seconds.${NC}"
|
||||
# Create a hidden ext4 volume inside the previous one
|
||||
etime=$( (time echo "passhidden" | veracrypt --text --non-interactive --quick --create $BLOCK_DEVICE --volume-type=hidden --size="800M" --password - --encryption=AES --hash=SHA-512 --filesystem=ext4 --random-source=/dev/urandom > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Creation of hidden VeraCrypt volume took $etime seconds.${NC}"
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./veracrypt_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount hidden volume
|
||||
etime=$( (time echo -"passhidden" | veracrypt --text --non-interactive $BLOCK_DEVICE $MNTPOINT --password - > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Opening and mounting hidden VeraCrypt volume took $etime seconds.${NC}"
|
||||
# TESTS HERE
|
||||
# test 01: random read
|
||||
echo "Test 01: random read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-rnd --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 02: random write
|
||||
echo "Test 02: random write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-rnd --ioengine=libaio --iodepth=32 --rw=randwrite --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 03: sequential read
|
||||
echo "Test 03: sequential read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-seq --ioengine=libaio --iodepth=32 --rw=read --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 04: sequential write
|
||||
echo "Test 04: sequential write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# END TESTS
|
||||
# close
|
||||
echo "Veracrypt fio tests ended. Detaching VeraCrypt volume..."
|
||||
etime=$( (time veracrypt -d $MNTPOINT > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action close took $etime seconds.${NC}"
|
||||
rmdir $MNTPOINT
|
||||
echo "Volume detached and local mountpoint removed."
|
||||
#end
|
||||
# Create a new standard volume
|
||||
if [ -z "$CONTAINER_FILENAME" ]; then
|
||||
# it's a real block device, do not specify size
|
||||
etime=$( (time echo "passdecoy" | veracrypt --text --non-interactive --quick --create $BLOCK_DEVICE --volume-type=normal --password - --encryption=AES --hash=SHA-512 --filesystem=None --random-source=/dev/urandom > /dev/null) 2>&1 )
|
||||
else
|
||||
# it's file-based, then VeraCrypt requires specifying the size
|
||||
etime=$( (time echo "passdecoy" | veracrypt --text --non-interactive --quick --create $BLOCK_DEVICE --size=1G --volume-type=normal --password - --encryption=AES --hash=SHA-512 --filesystem=None --random-source=/dev/urandom > /dev/null) 2>&1 )
|
||||
fi
|
||||
echo -e "${GREEN}Creation of standard VeraCrypt volume took $etime seconds.${NC}"
|
||||
# Create a hidden ext4 volume inside the previous one
|
||||
etime=$( (time echo "passhidden" | veracrypt --text --non-interactive --quick --create $BLOCK_DEVICE --volume-type=hidden --size="800M" --password - --encryption=AES --hash=SHA-512 --filesystem=ext4 --random-source=/dev/urandom > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Creation of hidden VeraCrypt volume took $etime seconds.${NC}"
|
||||
# assign and create MNTPOINT
|
||||
MNTPOINT=$(realpath "./veracrypt_mnt")
|
||||
mkdir $MNTPOINT
|
||||
# mount hidden volume
|
||||
etime=$( (time echo -"passhidden" | veracrypt --text --non-interactive $BLOCK_DEVICE $MNTPOINT --password - > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Opening and mounting hidden VeraCrypt volume took $etime seconds.${NC}"
|
||||
# TESTS HERE
|
||||
# test 01: random read
|
||||
echo "Test 01: random read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-rnd --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 02: random write
|
||||
echo "Test 02: random write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-rnd --ioengine=libaio --iodepth=32 --rw=randwrite --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 03: sequential read
|
||||
echo "Test 03: sequential read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-r-seq --ioengine=libaio --iodepth=32 --rw=read --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# test 04: sequential write
|
||||
echo "Test 04: sequential write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..."
|
||||
OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}')
|
||||
echo -e "${GREEN}${OUTPUT}${NC}"
|
||||
# END TESTS
|
||||
# close
|
||||
echo "Veracrypt fio tests ended. Detaching VeraCrypt volume..."
|
||||
etime=$( (time veracrypt -d $MNTPOINT > /dev/null) 2>&1 )
|
||||
echo -e "${GREEN}Action close took $etime seconds.${NC}"
|
||||
rmdir $MNTPOINT
|
||||
echo "Volume detached and local mountpoint removed."
|
||||
#end
|
||||
}
|
||||
|
||||
# Clean up
|
||||
cleanup() {
|
||||
echo "Exiting and cleaning..."
|
||||
if [[ -n $CONTAINER_FILENAME ]]; then
|
||||
echo "Deleting $CONTAINER_FILENAME..."
|
||||
rm -f "$CONTAINER_FILENAME"
|
||||
echo "Container file deleted."
|
||||
fi
|
||||
echo "Exiting and cleaning..."
|
||||
if [[ -n $CONTAINER_FILENAME ]]; then
|
||||
echo "Deleting $CONTAINER_FILENAME..."
|
||||
rm -f "$CONTAINER_FILENAME"
|
||||
echo "Container file deleted."
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -226,17 +226,17 @@ echo -e "${BLUE}================================================================
|
|||
|
||||
case "$1" in
|
||||
# help
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
--help|-?)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
check_sudo
|
||||
|
||||
if ! which veracrypt >/dev/null; then
|
||||
echo -e "${RED}ERROR: VeraCrypt not found, please install it.${NC}"
|
||||
exit 1
|
||||
echo -e "${RED}ERROR: VeraCrypt not found, please install it.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " "
|
||||
|
|
@ -245,34 +245,34 @@ echo " "
|
|||
# PARSER
|
||||
|
||||
case "$1" in
|
||||
"") # no argument passed
|
||||
"") # no argument passed
|
||||
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars
|
||||
|
||||
echo "Now you will be asked to enter the path for a block device to be used for the "
|
||||
echo "benchmarks (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 a VeraCrypt container instead, then the file will be removed at the end."
|
||||
echo " "
|
||||
echo -n "Please enter the path for a (non-loop) block device (default: none): "
|
||||
read BLOCK_DEVICE
|
||||
if [ -z "$BLOCK_DEVICE" ]; then
|
||||
echo "No path provided, using a local container file."
|
||||
CONTAINER_FILENAME=$(create_container_file)
|
||||
if [ -z "$CONTAINER_FILENAME" ]; then
|
||||
exit
|
||||
fi
|
||||
BLOCK_DEVICE="$CONTAINER_FILENAME"
|
||||
else
|
||||
check_block_device "$BLOCK_DEVICE"
|
||||
fi
|
||||
|
||||
;;
|
||||
|
||||
# argument passed
|
||||
*)
|
||||
BLOCK_DEVICE="$1"
|
||||
check_block_device "$BLOCK_DEVICE"
|
||||
;;
|
||||
echo "Now you will be asked to enter the path for a block device to be used for the "
|
||||
echo "benchmarks (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 a VeraCrypt container instead, then the file will be removed at the end."
|
||||
echo " "
|
||||
echo -n "Please enter the path for a (non-loop) block device (default: none): "
|
||||
read BLOCK_DEVICE
|
||||
if [ -z "$BLOCK_DEVICE" ]; then
|
||||
echo "No path provided, using a local container file."
|
||||
CONTAINER_FILENAME=$(create_container_file)
|
||||
if [ -z "$CONTAINER_FILENAME" ]; then
|
||||
exit
|
||||
fi
|
||||
BLOCK_DEVICE="$CONTAINER_FILENAME"
|
||||
else
|
||||
check_block_device "$BLOCK_DEVICE"
|
||||
fi
|
||||
|
||||
;;
|
||||
|
||||
# argument passed
|
||||
*)
|
||||
BLOCK_DEVICE="$1"
|
||||
check_block_device "$BLOCK_DEVICE"
|
||||
;;
|
||||
esac
|
||||
|
||||
check_not_loopdevice "$BLOCK_DEVICE"
|
||||
|
|
@ -280,9 +280,9 @@ check_not_loopdevice "$BLOCK_DEVICE"
|
|||
# MAIN PROGRAM
|
||||
|
||||
if confirm; then
|
||||
benchmark
|
||||
benchmark
|
||||
else
|
||||
echo "Aborting..."
|
||||
echo "Aborting..."
|
||||
fi
|
||||
|
||||
cleanup
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue