Skip to content

Commit

Permalink
[Arista]: Add support to convert vfat file system to ext4 (#201)
Browse files Browse the repository at this point in the history
This commit will convert the existing file system of flash drive on Arista switches from VFAT to EXT4 in the booting of SONiC. It will take the whole flash and therefore remove the recovery partition. There is a check in the script making sure that the conversion operation will not happen on a non-Arista switch or if the existing file system is not VFAT.
  • Loading branch information
byu343 authored and Shuotian Cheng committed Jan 24, 2017
1 parent 7bd9050 commit 6d8f576
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 0 deletions.
7 changes: 7 additions & 0 deletions build_debian.sh
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ sudo dpkg --root=$FILESYSTEM_ROOT -i target/debs/linux-image-3.16.0-4-amd64_*.de
## Update initramfs for booting with squashfs+aufs
cat files/initramfs-tools/modules | sudo tee -a $FILESYSTEM_ROOT/etc/initramfs-tools/modules > /dev/null

## Hook into initramfs: change fs type from vfat to ext4 on arista switches
sudo mkdir -p $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-premount/
sudo cp files/initramfs-tools/arista-convertfs $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-premount/arista-convertfs
sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/scripts/init-premount/arista-convertfs
sudo cp files/initramfs-tools/mke2fs $FILESYSTEM_ROOT/etc/initramfs-tools/hooks/mke2fs
sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/hooks/mke2fs

## Hook into initramfs: after partition mount and loop file mount
## 1. Prepare layered file system
## 2. Bind-mount docker working directory (docker aufs cannot work over aufs rootfs)
Expand Down
170 changes: 170 additions & 0 deletions files/initramfs-tools/arista-convertfs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#!/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=''

# Get the fullpath of flash device, e.g., /dev/sda
get_flash_dev() {
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
return 1
}

# Wait for root_dev to be ready
wait_for_root_dev() {
local try_rounds=30
while [ $try_rounds -gt 0 ]; do
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
}

# 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=}"
esac
done
root_dev="$ROOT"

#Check aboot and root_dev is vfat
[ -z "$aboot_flag" ] && exit 0
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
blkid | grep "$root_dev.*vfat" -q || exit 0


# Get flash dev name
if [ -z "$block_flash" ]; then
echo "Error: flash device info is not provided"
exit 1
fi
if ! get_flash_dev; then
echo "Error: flash device is not found"
exit 1
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.

# Create a new partition table (content in flash_dev will be deleted)
err_msg="Error: repartitioning $flash_dev failed"
cmd="echo ';' | sfdisk $flash_dev"
run_cmd "$cmd" "$err_msg"

sleep 5
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 -m2 -F -O '^huge_file' $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"

err_msg="Error: copying files form $tmp_mnt to $root_mnt failed"
cmd="cp -a $tmp_mnt/. $root_mnt/"
run_cmd "$cmd" "$err_msg"

50 changes: 50 additions & 0 deletions files/initramfs-tools/mke2fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/sh
#Part of the code is revised based on initramfs-tools/hooks/fsck and initramfs-tool is under GPL v2.

PREREQ=""

prereqs()
{
echo "$PREREQ"
}

case $1 in
prereqs)
prereqs
exit 0
;;
esac

. /usr/share/initramfs-tools/hook-functions

copy_exec /sbin/mke2fs
copy_exec /sbin/sfdisk
copy_exec /sbin/fdisk

fstypes="ext4"

for type in $fstypes; do
prog="/sbin/mkfs.${type}"
if [ -h "$prog" ]; then
link=$(readlink -f "$prog")
copy_exec "$link"
ln -s "$link" "${DESTDIR}/$prog"
elif [ -x "$prog" ] ; then
copy_exec "$prog"
else
echo "Warning: /sbin/mkfs.${type} doesn't exist, can't install to initramfs, ignoring."
fi
done

for type in $fstypes; do
prog="/sbin/fsck.${type}"
if [ -h "$prog" ]; then
link=$(readlink -f "$prog")
copy_exec "$link"
ln -s "$link" "${DESTDIR}/$prog"
elif [ -x "$prog" ] ; then
copy_exec "$prog"
else
echo "Warning: /sbin/fsck.${type} doesn't exist, can't install to initramfs, ignoring."
fi
done

0 comments on commit 6d8f576

Please sign in to comment.