From cc9ee13e1a36511decb526bf84146e20a846b3d6 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Tue, 8 Apr 2014 16:46:13 -0700 Subject: [PATCH] Dynamically create loop devices Several of the in-tree regression tests depend on the availability of loop devices. If for some reason no loop devices are available the tests will fail. Normally this isn't an issue because most Linux distributions create 8 loop devices by default. This is enough for our purposes. However, recent Fedora releases have only been creating a single loop device and this leads to failures. Alternately, if something else of the system is using the loop devices we may see failures. The fix for this is to update the support scripts to dynamically create loop devices as needed. The scripts need only create a node under /dev/ and the loop driver with create the minor. This behavior has been supported by the loop driver for ages. Additionally this patch updates cleanup_loop_devices() to cleanup loop devices which have already had their file store deleted. This helps prevent stale loop devices from accumulating on the system due to test failures. Signed-off-by: Brian Behlendorf Signed-off-by: Prakash Surya Closes #2249 --- scripts/common.sh.in | 53 +++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/scripts/common.sh.in b/scripts/common.sh.in index ae1c5cf09..a6586f4aa 100644 --- a/scripts/common.sh.in +++ b/scripts/common.sh.in @@ -288,34 +288,61 @@ check_loop_utils() { # -# Find and return an unused loopback device. +# Find and return an unused loop device. A new /dev/loopN node will be +# created if required. The kernel loop driver will automatically register +# the minor as long as it's less than /sys/module/loop/parameters/max_loop. # unused_loop_device() { - for DEVICE in `ls -1 /dev/loop[0-9]* 2>/dev/null`; do - ${LOSETUP} ${DEVICE} &>/dev/null - if [ $? -ne 0 ]; then - echo ${DEVICE} - return - fi - done + local DEVICE=`${LOSETUP} -f` + local MAX_LOOP_PATH="/sys/module/loop/parameters/max_loop" + local MAX_LOOP; - die "Error: Unable to find unused loopback device" + # An existing /dev/loopN device was available. + if [ -n "${DEVICE}" ]; then + echo "${DEVICE}" + return 0 + fi + + # Create a new /dev/loopN provided we are not at MAX_LOOP. + if [ -f "${MAX_LOOP_PATH}" ]; then + MAX_LOOP=`cat /sys/module/loop/parameters/max_loop` + if [ ${MAX_LOOP} -eq 0 ]; then + MAX_LOOP=255 + fi + + for (( i=0; i<=${MAX_LOOP}; i++ )); do + DEVICE="/dev/loop$i" + + if [ -b "${DEVICE}" ]; then + continue + else + mknod -m660 "${DEVICE}" b 7 $i + chown root.disk "${DEVICE}" + chmod 666 "${DEVICE}" + + echo "${DEVICE}" + return 0 + fi + done + fi + + die "Error: Unable to create new loopback device" } # # This can be slightly dangerous because the loop devices we are # cleaning up may not be ours. However, if the devices are currently # in use we will not be able to remove them, and we only remove -# devices which include 'zpool' in the name. So any damage we might -# do should be limited to other zfs related testing. +# devices which include 'zpool' or 'deleted' in the name. So any +# damage we might do should be limited to other zfs related testing. # cleanup_loop_devices() { local TMP_FILE=`mktemp` ${LOSETUP} -a | tr -d '()' >${TMP_FILE} ${AWK} -F":" -v losetup="$LOSETUP" \ - '/zpool/ { system("losetup -d "$1) }' ${TMP_FILE} - ${AWK} -F" " '/zpool/ { system("rm -f "$3) }' ${TMP_FILE} + '/zpool/ || /deleted/ { system("losetup -d "$1) }' ${TMP_FILE} + ${AWK} -F" " '/zpool/ || /deleted/ { system("rm -f "$3) }' ${TMP_FILE} rm -f ${TMP_FILE} }