Shrink and grow filesystems and partitions in Linux
These example scripts try to show how filesystems and partitions can be shrunk and grown if a partition has become too little to accomodate for larger files.
We're going to create a few partitions, most of the 10 M in size. The goal will be to grow the third partition to 15 M. In order to be able to that, the fourth partition needs to be shrank to 5 MB and then moved »to the right«.
Variables
First, we need to define a few variables.
device is the harddisk on which these examples are to be run. If you run the following code, please make sure that you choose a hard disk with no important data on it!
exec_parted is how parted is to be executed. It contains a reference to $device to make sure that we're not accidentally going to destroy the data on /dev/sda.
mountdir specifies the directory where we're going to mount the filesystems on.
Finally, part_n_start define, in bytes, where a partition starts on $device. The last partition also needs part_7_end.
#
# Specify the device on which we're going to run the examples.
#
device=sdb
#
# Where is parted located:
#
parted_executable=/sbin/parted
if [[ ! -x $parted_executable ]]; then
echo "$parted_executable not executable, exiting"
exit
fi
#
# How parted is to be executed.
# The -s flag is for non-interactive (scripted) mode. So
# no questions will be asked from parted.
#
exec_parted="sudo $parted_executable -s /dev/$device"
#
# The directory into which the partitions/devices will be
# mounted.
#
mount_dir=./mountpoints/
part_1_start=$(( 17 * 1024 ))
part_2_start=$(( 512 * 1024 ))
part_3_start=$(( 10 * 1024 * 1024 ))
part_4_start=$(( 10 * 1024 * 1024 + $part_3_start ))
part_5_start=$(( 10 * 1024 * 1024 + $part_4_start ))
part_6_start=$(( 10 * 1024 * 1024 + $part_5_start ))
part_7_start=$(( 10 * 1024 * 1024 + $part_6_start ))
part_7_end=$(( 10 * 1024 * 1024 + $part_7_start - 1 ))
In order to start with the example, we remove each partition on the hard disk.
I believe this is technically not really necessary because in the next step we're going to create a partition table anyway. But it shows how to use the rm command of parted.
#
# Remove each partition
#
for part_nr in $($exec_parted print | awk '/^ / {print $1}'); do
echo "removing $part_nr on $device"
$exec_parted rm ${part_nr}
done
Before we can create the partitions we need to initialise the hard disk with a partition table.
I probably could choose the partition typemsdos, but I go with the more modern gpt.
However, before I create the partition table, I really (and possibly paranoidly) want to erase evertything that reminds me of the past of the hard disk.
So, I use dd to erase the start (and thus the old partition table) of the hard disk.
#
# Create a GPT partition table.
# ( Other possible values would be:
# aix, amiga, bsd, dvh, loop, mac, msdos, pc98, sun )
#
sudo dd if=/dev/zero of=/dev/$device bs=1024 count=$(( $part_7_end / 1024 ))
$exec_parted mklabel gpt
Note especially partition 4 (/dev/${device}4) where I create two 4M files.
After creating those huge files, I create a rather smallisch readme.txt file. This file is placed at the »end« of the file system (because the two 4M files occupy most of the file system.
Then I drop one of the 4M files to make room when we're going to shrink this filesystem
echo "This is the second partition" > ${mount_dir}${device}2/readme.txt
echo "This is the third partition" > ${mount_dir}${device}3/readme.txt
# Create two 4 M file on the fourth partition
dd if=/dev/zero of=${mount_dir}{$device}4/4M.1 bs=1024 count=1024
dd if=/dev/zero of=${mount_dir}{$device}4/4M.2 bs=1024 count=1024
# Then write a file to the fourth partition
echo "This is the fourth partition" > ${mount_dir}${device}4/readme.txt
# Remove the 1st of the 4M files again:
rm ${mount_dir}${device}4/4M1
echo "This is the fifth partition" > ${mount_dir}${device}5/readme.txt
echo "This is the sixth partition" > ${mount_dir}${device}6/readme.txt
The fourth partition is not actually shrunk in one step: it is first deleted entierly (rm) and then recreated with a different start and the same end as it previously had.
#
# First, we define a new variable to store
# the start of the shrunk filesystem's new
# start:
#
part_4_start_new=$(( $part_4_start + 5*1024*1024 ))
#
# Then, we use parted again to remove and
# recreate the partition with a different size:
#
$exec_parted rm 4
$exec_parted mkpart --align cylinder nm_four_resized ext4 $(( $part_4_start_new ))b $(( $part_5_start - 1 ))b
After moving the fourth partition up, we have enough room for the third partition go grow.
Again, we first delete it entirely and resize it.
Note: removing the partition does no harm to the filesystem that is stored in it. Since the filesystem will physically reside in the same place on the harddisk after recreating the partition, there is no need to take an image file.
$exec_parted rm 3
$exec_parted mkpart --align cylinder nm_three_resized $(( $part_3_start ))b $(( $part_4_start_new -1 ))b
#
# Check file system three.
# Apparently, we have to give the system some time to recognize the new
# partition:
#
sleep 0.1
sudo e2fsck -f -y -C 0 /dev/${device}3
Let's check if the files are still valid and intact and if the 12 M file is indeed that size.
cat ${mount_dir}${device}3/readme.txt
cat ${mount_dir}${device}4/readme.txt
#
# Verify that the size is of 12.MiB
# is indeed 12 MB:
#
ls -l ${mount_dir}${device}3/12.MiB