Fix losetup race condition.

The following pattern creates a race condition:

   LOOP_DEV=$(sudo losetup -f)
   ...
   sudo losetup "${LOOP_DEV}" "${ROOT_FS_IMG}"

If two steps similar to the above run in parallel, and both steps pick up
the same free loop device, they may try to mount different images with the
same loop device and one of the two stages will get a "device is busy" error.

To fix this, we should switch to the following pattern:
   LOOP_DEV=$(sudo losetup --show -f "${ROOT_FS_IMG}")

This CL implements the above.`

BUG=chromium-os:18046
TEST=Run buildbot run. Test case where we run out of loop devices and verify
     logic still works.

Change-Id: Ie457701fda61e5fc3b9112c1bfef9fb9713ea265
Reviewed-on: http://gerrit.chromium.org/gerrit/4555
Tested-by: David James <davidjames@chromium.org>
Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
This commit is contained in:
David James 2011-07-21 22:11:11 -07:00
parent 8b3234a504
commit 8b9643f7d8
5 changed files with 34 additions and 53 deletions

View File

@ -587,13 +587,6 @@ create_base_image() {
# Create and format the root file system.
# Check for loop device before creating image.
LOOP_DEV=$(sudo losetup -f)
if [ -z "${LOOP_DEV}" ] ; then
echo "No free loop device. Free up a loop device or reboot. exiting. "
exit 1
fi
# Create root file system disk image.
ROOT_SIZE_BYTES=$((1024 * 1024 * ${FLAGS_rootfs_size}))
@ -603,7 +596,13 @@ create_base_image() {
dd if=/dev/zero of="${ROOT_FS_IMG}" bs=1 count=1 \
seek=$((ROOT_SIZE_BYTES + ROOT_HASH_PAD - 1))
sudo losetup "${LOOP_DEV}" "${ROOT_FS_IMG}"
LOOP_DEV=$(sudo losetup --show -f "${ROOT_FS_IMG}")
if [ -z "${LOOP_DEV}" ] ; then
echo "No free loop device. Free up a loop device or reboot. exiting. "
exit 1
fi
# Specify a block size and block count to avoid using the hash pad.
sudo mkfs.ext2 -b 4096 "${LOOP_DEV}" "$((ROOT_SIZE_BYTES / 4096))"
@ -624,11 +623,6 @@ create_base_image() {
sudo mount -t ext2 "${LOOP_DEV}" "${ROOT_FS_DIR}"
# Create stateful partition of the same size as the rootfs.
STATEFUL_LOOP_DEV=$(sudo losetup -f)
if [ -z "${STATEFUL_LOOP_DEV}" ] ; then
echo "No free loop device. Free up a loop device or reboot. exiting. "
exit 1
fi
STATEFUL_SIZE_BYTES=$((1024 * 1024 * ${FLAGS_statefulfs_size}))
dd if=/dev/zero of="${STATEFUL_FS_IMG}" bs=1 count=1 \
seek=$((STATEFUL_SIZE_BYTES - 1))
@ -636,7 +630,11 @@ create_base_image() {
# Tune and mount the stateful partition.
UUID=$(uuidgen)
DISK_LABEL="C-STATE"
sudo losetup "${STATEFUL_LOOP_DEV}" "${STATEFUL_FS_IMG}"
STATEFUL_LOOP_DEV=$(sudo losetup --show -f "${STATEFUL_FS_IMG}")
if [ -z "${STATEFUL_LOOP_DEV}" ] ; then
echo "No free loop device. Free up a loop device or reboot. exiting. "
exit 1
fi
sudo mkfs.ext3 "${STATEFUL_LOOP_DEV}"
sudo tune2fs -L "${DISK_LABEL}" -U "${UUID}" -c 0 -i 0 "${STATEFUL_LOOP_DEV}"
sudo mount -t ext3 "${STATEFUL_LOOP_DEV}" "${STATEFUL_FS_DIR}"

View File

@ -156,16 +156,14 @@ else
fi
echo "Resizing stateful partition to ${FLAGS_statefulfs_size}MB"
STATEFUL_LOOP_DEV=$(sudo losetup -f)
if [ -z "${STATEFUL_LOOP_DEV}" ]; then
die "No free loop device. Free up a loop device or reboot. Exiting."
fi
# Extend the original file size to the new size.
dd if=/dev/zero of="${TEMP_STATE}" bs=1 count=1 \
seek=$((STATEFUL_SIZE_BYTES - 1))
# Resize the partition.
sudo losetup "${STATEFUL_LOOP_DEV}" "${TEMP_STATE}"
STATEFUL_LOOP_DEV=$(sudo losetup --show -f "${TEMP_STATE}")
if [ -z "${STATEFUL_LOOP_DEV}" ]; then
die "No free loop device. Free up a loop device or reboot. Exiting."
fi
sudo e2fsck -pf "${STATEFUL_LOOP_DEV}"
sudo resize2fs "${STATEFUL_LOOP_DEV}"
sync

View File

@ -203,16 +203,13 @@ emerge_recovery_kernel() {
create_recovery_kernel_image() {
local sysroot="${FLAGS_build_root}/${FLAGS_board}"
local vmlinuz="$sysroot/boot/vmlinuz"
local root_dev=$(sudo losetup -f)
local root_offset=$(partoffset "$FLAGS_image" 3)
local root_size=$(partsize "$FLAGS_image" 3)
sudo losetup \
-o $((root_offset * 512)) \
--sizelimit $((root_size * 512)) \
"$root_dev" \
"$FLAGS_image"
local root_dev=$(sudo losetup --show -f \
-o $((root_offset * 512)) \
--sizelimit $((root_size * 512)) \
"$FLAGS_image")
trap "sudo losetup -d $root_dev" EXIT
cros_root="PARTUUID=%U/PARTNROFF=1" # only used for non-verified images
@ -273,15 +270,13 @@ create_recovery_kernel_image() {
# Update the EFI System Partition configuration so that the kern_hash check
# passes.
local efi_dev=$(sudo losetup -f)
local efi_offset=$(partoffset "$FLAGS_image" 12)
local efi_size=$(partsize "$FLAGS_image" 12)
sudo losetup \
-o $((efi_offset * 512)) \
--sizelimit $((efi_size * 512)) \
"$efi_dev" \
"$FLAGS_image"
local efi_dev=$(sudo losetup --show -f \
-o $((efi_offset * 512)) \
--sizelimit $((efi_size * 512)) \
"$FLAGS_image")
local efi_dir=$(mktemp -d)
trap "sudo losetup -d $efi_dev && rmdir \"$efi_dir\"" EXIT
sudo mount "$efi_dev" "$efi_dir"

View File

@ -46,14 +46,6 @@ cleanup_loop_dev() {
sudo losetup -d ${1} || /bin/true
}
get_loop_dev() {
local loop_dev=$(sudo losetup -f)
if [ -z "${loop_dev}" ]; then
die "No free loop device. Free up a loop device or reboot. Exiting."
fi
echo ${loop_dev}
}
# Resize stateful partition of install shim to hold payload content
# Due to this resize, we need to create a new partition table and a new image.
# (see update_partition_table() for details)
@ -66,15 +58,16 @@ enlarge_partition_image() {
local resized_sectors=$(roundup $(expr $source_sectors + $add_num_sectors))
info "resized partition has ${resized_sectors} 512-byte sectors."
local loop_dev=$(get_loop_dev)
trap "cleanup_loop_dev ${loop_dev}" EXIT
# Extend the source file size to the new size.
dd if=/dev/zero of="${source_part}" bs=1 count=1 \
seek=$((512 * ${resized_sectors} - 1)) &>/dev/null
# Resize the partition.
sudo losetup "${loop_dev}" "${source_part}"
local loop_dev=$(losetup --show -f "${source_part}")
if [ -z "${loop_dev}" ]; then
die "No free loop device. Free up a loop device or reboot. Exiting."
fi
trap "cleanup_loop_dev ${loop_dev}" EXIT
sudo e2fsck -fp "${loop_dev}" &> /dev/null
sudo resize2fs "${loop_dev}" &> /dev/null
# trap handler will clean up the loop device

View File

@ -142,24 +142,21 @@ if [[ ! -e "${FLAGS_to}" ]]; then
# We'll hard-code it to 16M for now.
ESP_BLOCKS=16384
/usr/sbin/mkfs.vfat -C "${FLAGS_to}" ${ESP_BLOCKS}
ESP_DEV=$(sudo losetup -f)
ESP_DEV=$(sudo losetup --show -f "${FLAGS_to}")
if [ -z "${ESP_DEV}" ]; then
die "No free loop devices."
fi
sudo losetup "${ESP_DEV}" "${FLAGS_to}"
else
if [[ -f "${FLAGS_to}" ]]; then
ESP_DEV=$(sudo losetup -f)
if [ -z "${ESP_DEV}" ]; then
die "No free loop devices."
fi
esp_offset="--offset ${FLAGS_to_offset}"
esp_size="--sizelimit ${FLAGS_to_size}"
if [ ${FLAGS_to_size} -lt 0 ]; then
esp_size=
fi
sudo losetup ${esp_offset} ${esp_size} "${ESP_DEV}" "${FLAGS_to}"
ESP_DEV=$(sudo losetup --show -f ${esp_offset} ${esp_size} "${FLAGS_to}")
if [ -z "${ESP_DEV}" ]; then
die "No free loop devices."
fi
else
# If it is a block device or something else, try to mount it anyway.
ESP_DEV="${FLAGS_to}"