HOWTO shrink your partition to make room for another

I already had experimented with [the heavy] partitioning stuff before with VMware, but this was the final stability test before I could write this HOWTO.

For a long time now, some tools exist that allow you to resize partitions without going through the hassle of backing up and recreating the partition table from scratch. Yet, they are very limited when it comes to Linux. Most only have ext2 and swap support. And then, they are only for Windows, or even DOS.

But since Linux distributers ship their own filesystem partitioning tools, you are not out of luck. On the contrary, I have managed to change a 40 GB FS (with a weird swap space scheme) into like 39 GB FS and a 512 MB good ol' swap partition. Without reformatting anything! And on top of that, it was my root partition. So here is the way how to go.

Right away, here is the stopper: shrinking is only supported by reiserfs(3), ext2 and ext3. This should not stop you from using filesystems like jfs oder xfs, though!

First, you will need a rescue CD or any means necessary to access your root partition (if applies) in an unmounted state. If it is not your root partition that you want to resize, you usually can do it in a running system. Just get the affected partitions unmounted. My setup before was as follows:

# fdisk -l /dev/hda

Disk /dev/hda: 40.0 GB, 40020664320 bytes
255 heads, 63 sectors/track, 4865 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot    Start       End    Blocks   Id  System
/dev/hda1   *         1      4865  39078081   83  Linux

Which is the one and only partition available (= base system and private data all on one). If you ask where the swap space was; well it was located in a plain file on the filesystem. That is not optimal (but possible under certain circumstances), and that is why I wanted to change it!

# cat /proc/swaps
Filename      Type  Size    Used  Priority
/boot/swapf0  file  131064  0     -1
(and of course, I deleted it afterwards to make it easier for resize_reiserfs)
# swapoff /boot/swapf0
# rm -f /boot/swapf0

In my case, I only needed to shrink the partition to make room for another on the end. (I have not tried moving a partition yet, but believe it is possible.) First, I shrank it using the resize_reiserfs tool (use the one appropriate for your FS):

# resize_reiserfs -s -1G /dev/hda1

This command reduced its size by 1 GB. Although the program says it is beta and that you should backup your data, I only backed up a small amount (the most recently-important, about 67 MB), even though it sounded like I should backup more. Well, I did not have the time, and even less the disk space to do so. Well then, gave it a blind shot.

The utility will move directories and files off the affected blocks to other free space on the partition. After this is done, it is time to create the new partition. I have gone a very unusual way, though I just did what repartitioning programs did. Just doing it by hand makes it look very dangerous.

In fdisk, delete necessary partitions and then create the new ones. Please know that deleting a partition with Linux's fdisk does not actually delete the content on the real disk, as a partition is merely a definition of two boundaries where a "partition" begins on the disk -- which is contiguous. So, deleting a partition and recreating it with different boundaries is the same as "changing the boundaries while keeping a partition intact".

You cannot move the start boundary, because that would involve to move the actual bytes within the partition. (Use some specialized tools for that.)

Command (m for help): d
Partition number (1-4): 1

Command (m for help): p

Disk /dev/hda: 40.0 GB, 40020664320 bytes
255 heads, 63 sectors/track, 4865 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

           Device Boot    Start       End    Blocks   Id  System

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-4865, default 1): 1
Last cylinder or +size or +sizeM or +sizeK (1-4865, default 4865): 4799

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 2
First cylinder (4800-4865, default 4800): 4800
Last cylinder or +size or +sizeM or +sizeK (4800-4865, default 4865): 4865

Command (m for help): t
Partition number (1-4): 2
(setting the partition type)
Hex code (type L to list codes): 82

Command (m for help): a
(activating the first partition for boot)
Partition number (1-4): 1

Command (m for help): p

Disk /dev/hda: 40.0 GB, 40020664320 bytes
255 heads, 63 sectors/track, 4865 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot    Start       End    Blocks   Id  System
/dev/hda1   *         1      4799  38547936   83  Linux
/dev/hda2          4800      4865    530145   82  Linux swap

Command (m for help): w
The partition table has been altered!
Calling ioctl() to re-read partition table.
Syncing disks.

You may need to experiment with the block boundaries, but if you calculate everything correctly, you will be fine too. Well, there goes my 512 MB (in fact 517 MB) partition.

If it was a root partition, you could already restart, as you can do the final steps in a running system, in case you are running a time-critical system where downtime is just not good. As the final step, we need to adjust the reiserfs on partition 1 to the actual size. (Remember, we took 1 GB off the FS, yet only 517 MB off the partition. Please always take more off the FS than what you have planned for your partition. Otherwise, you might just loose the last bytes of the FS to the swap partition, which is not what you want.) Rerun resize_reiserfs, but without any parameters (to automatically adjust to the size of the partition).

# resize_reiserfs /dev/hda1

(Running resize_reiserfs on mounted partitions only works when you are about to enlarge it. Shrinking must be done in unmounted state.) And finally create the swap partition:

# mkswap /dev/hda2
# swapon /dev/hda2

Edit /etc/fstab on the root partition and add hda2 so that it is automatically activated at boot-up.

Post notes

If you wanted to turn, for example, a [root=4GB] [data=10GB] [data2=10GB] [swap=128MB] into a [root=6GB] [data=18GB] [swap=512MB] setup (make a backup of data{,2} in this case), you could possibly (no guarantee here) do everything in the running system (except rewriting the partition table).