From 8b9643f7d8b10877f15b7b36a94f9621b90fba9d Mon Sep 17 00:00:00 2001 From: David James Date: Thu, 21 Jul 2011 22:11:11 -0700 Subject: [PATCH] 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 Reviewed-by: Daniel Kurtz --- build_image | 26 ++++++++++++-------------- image_to_vm.sh | 10 ++++------ mod_image_for_recovery.sh | 21 ++++++++------------- resize_stateful_partition.sh | 17 +++++------------ update_bootloaders.sh | 13 +++++-------- 5 files changed, 34 insertions(+), 53 deletions(-) diff --git a/build_image b/build_image index 12e57a0843..1d3d3c9195 100755 --- a/build_image +++ b/build_image @@ -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}" diff --git a/image_to_vm.sh b/image_to_vm.sh index fb0d627aec..d4ee0a2434 100755 --- a/image_to_vm.sh +++ b/image_to_vm.sh @@ -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 diff --git a/mod_image_for_recovery.sh b/mod_image_for_recovery.sh index 8248caa865..e223719658 100755 --- a/mod_image_for_recovery.sh +++ b/mod_image_for_recovery.sh @@ -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" diff --git a/resize_stateful_partition.sh b/resize_stateful_partition.sh index 455807491b..00392592d3 100755 --- a/resize_stateful_partition.sh +++ b/resize_stateful_partition.sh @@ -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 diff --git a/update_bootloaders.sh b/update_bootloaders.sh index 5cede9deba..12b67906cb 100755 --- a/update_bootloaders.sh +++ b/update_bootloaders.sh @@ -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}"