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 <behlendorf1@llnl.gov>
Signed-off-by: Prakash Surya <surya1@llnl.gov>
Closes #2249
This commit is contained in:
Brian Behlendorf 2014-04-08 16:46:13 -07:00
parent 787c455ed7
commit cc9ee13e1a

View File

@ -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() { unused_loop_device() {
for DEVICE in `ls -1 /dev/loop[0-9]* 2>/dev/null`; do local DEVICE=`${LOSETUP} -f`
${LOSETUP} ${DEVICE} &>/dev/null local MAX_LOOP_PATH="/sys/module/loop/parameters/max_loop"
if [ $? -ne 0 ]; then local MAX_LOOP;
echo ${DEVICE}
return # 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 fi
done done
fi
die "Error: Unable to find unused loopback device" die "Error: Unable to create new loopback device"
} }
# #
# This can be slightly dangerous because the loop devices we are # This can be slightly dangerous because the loop devices we are
# cleaning up may not be ours. However, if the devices are currently # 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 # 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 # devices which include 'zpool' or 'deleted' in the name. So any
# do should be limited to other zfs related testing. # damage we might do should be limited to other zfs related testing.
# #
cleanup_loop_devices() { cleanup_loop_devices() {
local TMP_FILE=`mktemp` local TMP_FILE=`mktemp`
${LOSETUP} -a | tr -d '()' >${TMP_FILE} ${LOSETUP} -a | tr -d '()' >${TMP_FILE}
${AWK} -F":" -v losetup="$LOSETUP" \ ${AWK} -F":" -v losetup="$LOSETUP" \
'/zpool/ { system("losetup -d "$1) }' ${TMP_FILE} '/zpool/ || /deleted/ { system("losetup -d "$1) }' ${TMP_FILE}
${AWK} -F" " '/zpool/ { system("rm -f "$3) }' ${TMP_FILE} ${AWK} -F" " '/zpool/ || /deleted/ { system("rm -f "$3) }' ${TMP_FILE}
rm -f ${TMP_FILE} rm -f ${TMP_FILE}
} }