If you'd put the
/ partition at the end of
sda, you'd have a trivial upgrade process:
Shut the VM down, and resize the raw disk drive in the VM management interface.
Boot into single user mode, resize the last partition to extend over the new space.
Resize the filesystem.
Doing this to a partition sandwiched between two others is probably more trouble than it's worth.
Therefore, I recommend that you move part of the contents of your
/ partition to a new disk:
Shut the VM down, and add another virtual disk.
Size it to hold the existing contents of
/ that you want to move to the new disk, plus however much space you want left over. Say you're using 14 GiB of your 16 GiB
/, and you want to move only
/home, which is using 10 GiB. If you want double your current space, you'd make the new drive 20 GiB.
You don't want to move any core OS directories:
/root, most of
/usr... It's safe to move
/usr/local to other disks.
Boot back up, preferably into single-user mode. (It will make later things easier if you don't have lots of background stuff running.)
Then, figure out which
/dev node your new disk got. There are many ways to do this. It's most likely
/dev/sdb, but it might get
/dev/sdc to be put after a previously-mapped optical drive, for example.
/dev/sdb for the purposes of explanation here.
parted to partition this new virtual disk:
# parted /dev/sdb
(parted) mklabel gpt
(parted) mkpart ext2 1 -1
That takes over the entire virtual disk. This will allow you to use the much simpler resize process above if you run out of disk capacity again in the future.
If you plan on moving lots of unrelated directories (e.g.
/usr/local) it's best to create a separate virtual disk for each, rather than partition one big disk. Partitioning is a kind of hack we tolerate in the world of real disks. When you're dealing with VMs, you're freed from the costs of multiple independent hard disks.
Create and mount the new filesystem(s) in temporary locations. I typically call them things like
# mkfs.ext4 /dev/sdb1
# mkdir -m 400 /mnt/newhome
# mount /dev/sdb1 /mnt/newhome
Copy the current contents of the tree you want to transplant, being sure to copy permissions. There are several ways to do this:
# cd /home
# find . -print | cpio -pd /mnt/newhome
# cp -aR * /mnt/newhome
# rsync -a * /mnt/newhome
/mnt/newhome has plausible contents. Does
df -h show approximately the same value as
du -h /home, for example?
Boot into single-user mode, if you aren't already.
Move the old filesystem out of the way, then lay the new one over it:
# cd /
# mv home oldhome
# mkdir -m 400 home
# umount /mnt/newhome
# mount /dev/sdb1 /home
# chmod 755 home
# chown root.root home
The last two commands are just examples. Give the new mount point the same owner, group, and permissions as the old one. (Don't count on the copy command to get the permissions on this top-level directory right.)
exit at the single-user mode prompt to continue booting into multi-user mode. (Or,
init 5, if the normal runlevel is 5, for example.) Check that everything seems to be working with the new filesystem.
(Don't reboot to do this test! The new filesystem won't automatically mount yet.)
When you're satisfied that you've successfully moved that partition, adjust
/etc/fstab to point to the new partition.
(This is way outside the scope of this answer. The exact details vary even between Linuxes, and vary even more broadly among *ix in general.)
Reboot normally. Check again. Does it all still work? Be certain you've got the new filesystem mounted, not the old one.
When you're certain it's all moved and mounting correctly, free up the space taken by the old copy:
rm -rf /oldhome.
If you have multiple filesystems to move,
GOTO 2. :) (Or step 1, if you didn't add all the new virtual disks at once.)
If you're using a VM system that knows how to set up a sparse virtual disk (e.g. VMware) you don't have to worry about wasted space. Just follow its normal "shrink" process to reclaim the now-slack space.
There are other refinements. For example, you might want to give something like
-L /home to the
mkfs.ext4 command if your OS uses disk labels in
/etc/fstab instead of partition names or UUIDs.