sonic-buildimage/files/initramfs-tools/arista-convertfs.j2
Baptiste Covolato c706a1079f [arista/aboot]: Zero out 1st MB before repartitioning (#5220)
The first partition starting point was changed to be 1M as part of this
commit: 6ba2f97f1e. On systems that are misaligned before conversion
(partition start is the first sector), the relica partition that is
left in the first MB can cause problems in Aboot and result in corruption
of the filesystem on the new aligned partition.

Zeroing this old relica makes sure that there is nothing left of the old
partition lying around. There won't be any risk of having Aboot corrupt
the new filesystem because of the old relica.

Signed-off-by: Baptiste Covolato <baptiste@arista.com>
2020-08-22 18:48:10 -07:00

248 lines
6.9 KiB
Django/Jinja

#!/bin/sh
case $1 in
prereqs)
exit 0
;;
esac
set -e
# set -x
total_mem=$(free | awk '/^Mem:/{print $2}')
tmpfs_size=$(( $total_mem / 20 * 17 ))
free_mem_thres=$(( $total_mem / 20 * 18 ))
tmp_mnt='/mnt/ramdisk-convfs'
root_mnt='/mnt/root-convfs'
root_dev=''
flash_dev=''
block_flash=''
aboot_flag=''
backup_file=''
prev_os=''
sonic_fast_reboot=''
# Wait until get the fullpath of flash device, e.g., /dev/sda
wait_get_flash_dev() {
local try_rounds=30
while [ $try_rounds -gt 0 ]; do
for dev in $(ls /sys/block); do
local is_mmc=$(echo "$dev" | grep 'mmcblk.*boot.*' | cat)
if [ -n "$is_mmc" ]; then
continue
fi
local devid=$(realpath "/sys/block/$dev/device")
local is_device=$(echo "$devid" | grep '^/sys/devices/' | cat)
local is_flash=$(echo "$devid" | grep "$block_flash" | cat)
if [ -n "$is_device" -a -n "$is_flash" ]; then
flash_dev="/dev/$dev"
return 0
fi
done
sleep 1
try_rounds=$(( $try_rounds - 1 ))
done
return 1
}
# Wait for root_dev to be ready
wait_for_root_dev() {
local try_rounds=30
while [ $try_rounds -gt 0 ]; do
if blkid | sed 's/"//g' | grep -q "$root_dev"; then
return 0
fi
if [ -e "$root_dev" ]; then
return 0
fi
sleep 1
try_rounds=$(( $try_rounds - 1 ))
done
return 1
}
# Alway run cleanup before exit
cleanup() {
if grep -q "$root_mnt" /proc/mounts; then
umount "$root_mnt"
fi
if grep -q "$tmp_mnt" /proc/mounts; then
umount "$tmp_mnt"
fi
[ -e "$root_mnt" ] && rmdir "$root_mnt"
[ -e "$tmp_mnt" ] && rmdir "$tmp_mnt"
}
trap cleanup EXIT
notification() {
cat << EOF
A failure happend in modifying the root file system which stopped the upgrade. Manual interventions are needed to fix the issue. Note that:
1) files in the old root file system may have been lost and the old partition table may have been corrupted;
2) The files in the old root file system were copied to $tmp_mnt;
3) The old partition table was dumped to the file $tmp_mnt/$backup_file by sfdisk;
4) Quitting the current shell will lose all files mentioned above permanently.
EOF
}
run_cmd() {
if ! eval "$1"; then
echo "$2"
notification
sh
exit 1
fi
}
fixup_flash_permissions() {
# properly set flash permissions for others
# this allows the sonic admin user to have read access on the flash
local flash_mnt="$1"
chmod o+rx "$flash_mnt"
# remove all the filesystem acls from the flash
setfacl -Rb "$flash_mnt"
}
# Update ROOT device referring to the path under block_flash
# This is for the occasional name swap between /dev/sda and /dev/sdb
update_root() {
# Check that root=/dev/*, ignoring any cases like root=UUID=*
[ "${ROOT#/dev}" = "${ROOT}" ] && return 0
# Replace the beginning chars of ROOT by the ones of flash_dev with same index
{% raw %}
prefix_length="${#flash_dev}"
{% endraw %}
part_id="${ROOT:$prefix_length}"
ROOT="$flash_dev$part_id"
echo "ROOT=$ROOT" > /conf/param.conf
}
# Extract kernel parameters
set -- $(cat /proc/cmdline)
for x in "$@"; do
case "$x" in
block_flash=*)
block_flash="${x#block_flash=}"
;;
Aboot=*)
aboot_flag="${x#Aboot=}"
;;
loop=*)
x1="${x#loop=}"
image_dir="${x1%/*}"
;;
docker_inram=*)
docker_inram="${x#docker_inram=}"
;;
prev_os=*)
prev_os="${x#prev_os=}"
;;
SONIC_BOOT_TYPE=warm*|SONIC_BOOT_TYPE=fast*)
sonic_fast_reboot=true
;;
esac
done
#Check aboot
[ -z "$aboot_flag" ] && exit 0
# Skip this script for warm-reboot/fast-reboot from sonic
[ "$sonic_fast_reboot" == true ] && [ "$prev_os" != eos ] && exit 0
# Get flash dev name
if [ -z "$block_flash" ]; then
echo "Error: flash device info is not provided"
exit 1
fi
if ! wait_get_flash_dev; then
echo "Error: flash device is not found"
exit 1
fi
# If root=/dev/*, update ROOT to the device under block_flash
update_root
root_dev="$ROOT"
if [ -z "$root_dev" ]; then
echo "Error: root device name is not provided"
exit 1
fi
if ! wait_for_root_dev; then
echo "Error: timeout in waiting for $root_dev"
exit 1
fi
# exit when the root is ext4
if ! blkid | grep "$root_dev.*vfat" -q; then
mkdir -p "$root_mnt"
mount -t ext4 "$root_dev" "$root_mnt"
fixup_flash_permissions "$root_mnt"
umount "$root_mnt"
rmdir "$root_mnt"
exit 0
fi
# Check memory size for tmpfs
free_mem=$(free | awk '/^Mem:/{print $4}')
if [ "$free_mem" -lt "$free_mem_thres" ]; then
echo "Error: memory is not enough"
exit 1
fi
# Backup partition table
mkdir -p "$root_mnt"
mount "$root_dev" "$root_mnt"
backup_file=backup.$(date +%Y-%m-%d.%H-%M-%S)
sfdisk -d "$flash_dev" > "$root_mnt/$backup_file"
# Check total size of files in root
total_file_size=$(du -s "$root_mnt" | awk '{print $1}')
if [ "$total_file_size" -gt "$tmpfs_size" ]; then
echo "Error: total file size is too large"
exit 1
fi
# Create tmpfs, and copy files to tmpfs
mkdir -p "$tmp_mnt"
mount -t tmpfs -o size="${tmpfs_size}k" tmpfs "$tmp_mnt"
cp -a "$root_mnt/." "$tmp_mnt/"
umount "$root_mnt"
#### Lines below will modify the root file system, so any failure will be trapped to shell for manual interventions.
if [ $(echo -n "$root_dev" | tail -c 1) == "1" ]; then
# Create a new partition table (content in flash_dev will be deleted)
err_msg="Error: Failed to zero out first MB"
cmd="dd if=/dev/zero of=$flash_dev bs=512 count=2048"
run_cmd "$cmd" "$err_msg"
err_msg="Error: repartitioning $flash_dev failed"
cmd="echo '2048' | sfdisk $flash_dev || (sleep 3; blockdev --rereadpt $flash_dev && fdisk -l $flash_dev | grep -q ${root_dev}.*Linux)"
run_cmd "$cmd" "$err_msg"
fi
sleep 2
err_msg="Error: timeout in waiting for $root_dev after repartition"
cmd="wait_for_root_dev"
run_cmd "$cmd" "$err_msg"
err_msg="Error: formatting to ext4 failed"
cmd="mke2fs -t ext4 -F -O '^huge_file,^metadata_csum' $root_dev"
run_cmd "$cmd" "$err_msg"
err_msg="Error: mounting $root_dev to $root_mnt failed"
cmd="mount -t ext4 $root_dev $root_mnt"
run_cmd "$cmd" "$err_msg"
if [ x"$docker_inram" != x"on" ]; then
err_msg="Error: extract docker directory"
cmd="[ -f $tmp_mnt/$image_dir/{{ FILESYSTEM_DOCKERFS }} ] && rm -rf $root_mnt/$image_dir/{{ DOCKERFS_DIR }} && mkdir -p $root_mnt/$image_dir/{{ DOCKERFS_DIR }} && tar xzf $tmp_mnt/$image_dir/{{ FILESYSTEM_DOCKERFS }} -C $root_mnt/$image_dir/{{ DOCKERFS_DIR }} && rm -f $tmp_mnt/$image_dir/{{ FILESYSTEM_DOCKERFS }}"
run_cmd "$cmd" "$err_msg"
fi
err_msg="Error: copying files form $tmp_mnt to $root_mnt failed"
cmd="cp -a $tmp_mnt/. $root_mnt/"
run_cmd "$cmd" "$err_msg"
fixup_flash_permissions "$root_mnt"