Shrink a Linux partition to create Swap space

I am an owner of a Utilite ARM computer. One of the issues I experienced with the default setup, is that there is no swap partition. That causes Firefox some memory hungry applications to perform badly.

Check for yourself, if swap is activated on your machine:

free
            total       used       free     shared    buffers     cached
Mem:       2006476     263752    1742724      20100      21428     107388
-/+ buffers/cache:     134936    1871540
Swap:            0          0          0

As you can see in the output, no swap space is used. So we are going to see how we can resize a linux ext2/ext3/ext4 partition to make space for a swap partition. We are then going to create a new swap partition and activate it on boot.

Prerequisites

Checking the current setup

After you boot using a removable medium, you can follow this procedure to check the current setup:
$ sudo fdisk -l /dev/sda

Disk /dev/sda: 29.8 GiB, 32017047552 bytes, 62533296 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xa5161f73

Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 206847 204800 100M c W95 FAT32 (LBA)
/dev/sda2 206848 62533295 62326448 29.7G 83 Linux

  • START_SECTOR = 206848
  • END_SECTOR = 62533295
  • TOTAL_SECTORS = 62326448
As you can see, the main root partition (sda2) has a size of 29.7GB. We will reduce it to 28GB and you the rest of the space (1.7GB) for swap. That should be more than enough.

Now in order to avoid tedious calculations, and make sure the filesystem on sda2 takes all available space on the partition we are going to use this trick:

  • Resize the sda2 filesystem to 27GB.
  • Resize the sda2 partition to 28GB.
  • Resize the sda2 filesystem to all available space of the sda2 partition (28GB).

Temporarily resize sda2

  1. First force check the filesystem for errors:
    $ sudo e2fsck -f /dev/sda2
    
    If it finishes without errors move to the next step
  2. Resize the filesystem to 27GB:
    $ sudo resize2fs /dev/sda2 27G
    
  3. Verify the result:
    $ sudo dumpe2fs  /dev/sda2 | grep Block | head -2
    dumpe2fs 1.42.12 (29-Aug-2014)
    Block count:              7077888
    Block size:               4096
    

    $ echo '(7077888 * 4096)/1024/1024/1024' | bc -l
    27.00000000000000000000


    Exactly 27GB.

Resize the sda2 partition

To resize the sda2 partition we will delete it temporarily and recreate it using the same START_SECTOR but a different END_SECTOR.
  1. To calculate the new end sector you can use this formula:NEW_END_SECTOR = START_SECTOR + TOTAL_SECTORS * 28 / 29.7
    $ echo "206848+62326448*28/29.7" | bc -l
    58965788.87542087542087542087
    
    We can round up the NEW_END_SECTOR to 58965789.
  2. Use fdisk to resize the partition:
    • Delete the sda2 partition:
      $ sudo fdisk /dev/sda
      Changes will remain in memory only, until you decide to write them.
      Be careful before using the write command.
      

      Command (m for help): d
      Partition number (1,2, default 2): 2

      Partition 2 has been deleted.


      Verify that sda2 is deleted:

      Command (m for help): p
      Disk /dev/sda: 29,8 GiB, 32017047552 bytes, 62533296 sectors
      Units: sectors of 1 * 512 = 512 bytes
      Sector size (logical/physical): 512 bytes / 512 bytes
      I/O size (minimum/optimal): 512 bytes / 512 bytes
      Disklabel type: dos
      Disk identifier: 0xa5161f73
      
      Device     Boot Start    End Sectors  Size Id Type
      /dev/sda1  *     2048 206847  204800  100M  c W95 FAT32 (LBA)
      

      It is deleted, but not really until you issue the write command.


    • Create a smaller sda2 partition:

      Command (m for help): n
      Partition type
         p   primary (1 primary, 0 extended, 3 free)
         e   extended (container for logical partitions)
      Select (default p): p
      Partition number (2-4, default 2): 
      First sector (206848-62533295, default 206848): 
      Last sector, +sectors or +size{K,M,G,T,P} (206848-62533295, default 62533295): 58965789
      
      Created a new partition 2 of type 'Linux' and of size 28 GiB.      
      

      For the end sector we use the value of the NEW_END_SECTOR we have calculated earlier. Now let’s verify the new partition:

      Command (m for help): p
      Disk /dev/sda: 29,8 GiB, 32017047552 bytes, 62533296 sectors
      Units: sectors of 1 * 512 = 512 bytes
      Sector size (logical/physical): 512 bytes / 512 bytes
      I/O size (minimum/optimal): 512 bytes / 512 bytes
      Disklabel type: dos
      Disk identifier: 0xa5161f73
      
      Device     Boot  Start      End  Sectors  Size Id Type
      /dev/sda1  *      2048   206847   204800  100M  c W95 FAT32 (LBA)
      /dev/sda2       206848 58965789 58758942   28G 83 Linux
      
    • Create a new partition of type swap:
      Command (m for help): n
      Partition type
         p   primary (2 primary, 0 extended, 2 free)
         e   extended (container for logical partitions)
      Select (default p): p
      Partition number (3,4, default 3): 
      First sector (58965790-62533295, default 58966016): 
      Last sector, +sectors or +size{K,M,G,T,P} (58966016-62533295, default 62533295): 
      

      Created a new partition 3 of type 'Linux' and of size 1,7 GiB.

      Command (m for help): t
      Partition number (1-3, default 3): 3
      Partition type (type L to list all types): 82

      Changed type of partition 'Linux' to 'Linux swap / Solaris'.


      Verify that the new partition is created:

      Command (m for help): p
      Disk /dev/sda: 29,8 GiB, 32017047552 bytes, 62533296 sectors
      Units: sectors of 1 * 512 = 512 bytes
      Sector size (logical/physical): 512 bytes / 512 bytes
      I/O size (minimum/optimal): 512 bytes / 512 bytes
      Disklabel type: dos
      Disk identifier: 0xa5161f73
      
      Device     Boot    Start      End  Sectors  Size Id Type
      /dev/sda1  *        2048   206847   204800  100M  c W95 FAT32 (LBA)
      /dev/sda2         206848 58965789 58758942   28G 83 Linux
      /dev/sda3       58966016 62533295  3567280  1,7G 82 Linux swap / Solaris
      

      Seems OK.


    • Write changes and exit:

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

      Remember that nothing is changed unless you issue the write command. If you make a mistake, just hit Ctrl+c and no harm done.

  3. Resize the filesystem to the full size of the partition:
    • Force check the filesystem
      $ sudo e2fsck -f /dev/sda2
      
    • Resize the filesystem to occupy all the available space in the partition:
      $ sudo resize2fs /dev/sda2
      
      Running resize2fs without a size definition, extends the size of the filesystem to the size of the partition.
    • Verify the new filesystem size:
      $ sudo dumpe2fs  /dev/sda2 | grep Block | head -2
      dumpe2fs 1.42.13 (17-May-2015)
      Block count:              7344867
      Block size:               4096
      
      The size in bytes is BLOCK_COUNT * BLOCK_SIZE i.e. 7344867 * 4096 = 30084575232. The size in GB is:
      $ echo '(7344867 * 4096)/1024/1024/1024' | bc -l
      28.01844406127929687500
      

Restart into your internal drive

At this point we need to restart into the Operating System installed on the internal SATA device and check if everything works:
$ sudo fdisk -l /dev/sda
Disk /dev/sda: 29,8 GiB, 32017047552 bytes, 62533296 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xa5161f73

Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 206847 204800 100M c W95 FAT32 (LBA)
/dev/sda2 206848 58965789 58758942 28G 83 Linux
/dev/sda3 58966016 62533295 3567280 1,7G 82 Linux swap / Solaris


The partition table appears to be correct. But we haven’t formatted the swap partition yet:

$ free
            total       used       free     shared    buffers     cached
Mem:       2006476     264380    1742096      20100      21568     107800
-/+ buffers/cache:     135012    1871464
Swap:            0          0          0

We need to format the swap partition before we can use it.

Setup the swap partition

  1. Format the swap partition:
    $ sudo mkswap /dev/sda3
    mkswap: /dev/sda3: warning: wiping old swap signature.
    Setting up swapspace version 1, size = 1,7 GiB (1826443264 bytes)
    no label, UUID=fa1e99ff-a9ab-4fd7-ba81-e5020f4e604b
    
    Take a note of the UUID: fa1e99ff-a9ab-4fd7-ba81-e5020f4e604b
  2. Activate swap:
    $ sudo swapon /dev/sda3
    
  3. Verify swap (in human readable form this time):
    $ free -m
                total       used       free     shared    buffers     cached
    Mem:          1959        259       1700         19         21        105
    -/+ buffers/cache:        132       1826
    Swap:         1741          0       1741
    
    So we have a total of 1741MB of swap space.
  4. Setup persistent swap.To have swap activated persistently across reboots, we need to set it up in /etc/fstab:
    # echo 'UUID="fa1e99ff-a9ab-4fd7-ba81-e5020f4e604b" none swap defaults 0 0' >> /etc/fstab
    
    You need to run the above command as root.
Now after you reboot you can check with free to see if the swap space is activated.