When installing Linux by unpacking .tar files into empty boot and root file system partitions, you get to decide how the partitions will lay out. When extracting Linux from a raw image file, the partition table is already defined and may not fit your needs and likely does not utilize all space available on the microSD card. For example, the Ubuntu 12.10 .img file available for the BeagleBone Black is sized exactly at 1832MB so it is able to precisely fit into the BeagleBone Black’s internal eMMC storage.
If you are extracting this image to a microSD card, you will likely have a significant amount of unused space available. With many inexpensive microSD cards sporting capacities of 4GB to 8GB (or more), the afore mentioned 1.8GB partition layout leaves us with some additional work to be done. Fortunately, it is not difficult to take advantage of all available space. I am going to review two different methods for achieving this goal.
The first method may not be immediately obvious, but we can create an additional third partition and mount it into the filesystem at boot time. There are a few compelling reasons for selecting this method. If you are planning to install a graphical desktop you will want to create a swap partition and you should set aside space for this. Additionally, if you are intending to allow external sources to upload information via a web browser or FTP, it is possible to have a volume run out of space. Having a dedicated upload and logging var
volume will prevent uploads or excessive logging from utilizing more than a predetermined amount of space. Similar benefits can be realized buy mounting the home
directory this way as well.
The second technique takes advantage of Linux’s ability to expand a partition in-place on a booted system so long as no data exists beyond the end of that partition. Afterward, the ext2, ext3, or ext4 filesystem can be expanded using resize2fs
to use this new available space at the end of the volume.
Adding a Partition
In this case we are going to dump all extra space into a single storage
volume where we can mount from /etc/fstab
as desired. The example is generic enough to be adapted for specific use cases.
Step 1: Start fdisk
# fdisk /dev/mmcblk0
Command (m for help): p
Disk /dev/mmcblk0: 15.7 GB, 15719727104 bytes
4 heads, 16 sectors/track, 479728 cylinders, total 30702592 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
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/mmcblk0p1 * 63 65598 32768 c W95 FAT32 (LBA)
/dev/mmcblk0p2 65599 3751935 1843168+ 83 Linux
Command (m for help):
In this case notice that the prepackaged 1.8GB image has been expanded onto a 16GB microSD card (notice the 15.7 GB
at the top). To make a new /dev/mmcblk0p3
parition we type ‘n’ for new ‘p’ for primary (the default), 3 for the 3rd partition (the default), select the default first sector (3751936 in my case) and the default value for the last sector to use all remaining space. Don’t worry about mistakes yet, <ctrl> + c or ‘q’ for quit will exit the program leaving your microSD unchanged.
Command (m for help): n
Partition type:
p primary (2 primary, 0 extended, 2 free)
e extended
Select (default p):
Using default response p
Partition number (1-4, default 3):
Using default value 3
First sector (3751936-30702591, default 3751936):
Using default value 3751936
Last sector, +sectors or +size{K,M,G} (3751936-30702591, default 30702591):
Using default value 30702591
Command (m for help):
If you want to save space for a swap partition, use the +size notation for the end value. For example +12G
for a 12GB partition. At this point it is wise to review your work before committing changes by using the ‘p’ command to print the current configuration choices. When all looks correct, ‘w’ will commit your changes to disk and exit.
At this point we should be able to see the new partition as a device.
# ls -l /dev/mmcblk0*
brw-rw---- 1 root disk 179, 0 Apr 30 02:21 /dev/mmcblk0
brw-rw---- 1 root disk 179, 1 Apr 28 23:47 /dev/mmcblk0p1
brw-rw---- 1 root disk 179, 2 Apr 28 23:47 /dev/mmcblk0p2
brw-rw---- 1 root disk 179, 3 Apr 30 02:22 /dev/mmcblk0p3
We now have a partition ready for a filesystem.
Step 2: Format the Partition
To format as an ext4 volume, use mkfs.ext4
. Likewise, to format as an ext3 volume, use mkfs.ext3
. Note that the -L
option sets the volume label and is optional.
# mkfs.ext4 -L "storage" /dev/mmcblk0p3
mke2fs 1.42.5 (29-Jul-2012)
Discarding device blocks: done
Filesystem label=storage
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
843776 inodes, 3368832 blocks
168441 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=3451912192
103 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
Step 3: Mount the Volume
The next step is to create a location in the filesystem to mount the new volume. Create a /mnt/storage
directory for this purpose and mount the volume.
# mkdir /mnt/storage
# mount /dev/mmcblk0p3 /mnt/storage
# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mmcblk0p2 1781432 541188 1148088 33% /
udev 252780 4 252776 1% /dev
tmpfs 101648 248 101400 1% /run
none 5120 0 5120 0% /run/lock
none 254112 0 254112 0% /run/shm
none 102400 0 102400 0% /run/user
/dev/mmcblk0p1 32686 6134 26552 19% /boot/uboot
/dev/mmcblk0p3 13132408 32904 12425740 1% /mnt/storage
Place an entry in /etc/fstab
auto-mount the new volume at boot time.
proc /proc proc defaults 0 0
/dev/mmcblk0p2 / auto errors=remount-ro 0 1
/dev/mmcblk0p1 /boot/uboot auto defaults 0 0
/dev/mmcblk0p3 /mnt/storage auto defaults 0 0
Each time the BeagleBone Black is booted, it will auto-mount the new volume.
Step 4: Additional Mount Points Using Bind Mounts
Having a heap of storage sitting off at /mnt/storage
isn’t the most useful thing in the world. We want to have meaningful subdirectories of the filesystem using this store. For this we use bind mounts. This allows us to move the users’ /home
directory to the new storage partition. Notice we create a new empty /home
directory for the one we move.
# mv /home /mnt/storage
# mkdir /home
Add the bind mount to /etc/fstab
.
proc /proc proc defaults 0 0
/dev/mmcblk0p2 / auto errors=remount-ro 0 1
/dev/mmcblk0p1 /boot/uboot auto defaults 0 0
/dev/mmcblk0p3 /mnt/storage auto defaults 0 0
/mnt/storage/home /home none defaults,bind 0 0
To see the bind mounts specify the -a
option for df
.
# df -a
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mmcblk0p2 1781432 541108 1148168 33% /
proc 0 0 0 - /proc
sysfs 0 0 0 - /sys
none 0 0 0 - /sys/fs/fuse/connections
none 0 0 0 - /sys/kernel/debug
none 0 0 0 - /sys/kernel/security
udev 252780 4 252776 1% /dev
devpts 0 0 0 - /dev/pts
tmpfs 101648 220 101428 1% /run
none 5120 0 5120 0% /run/lock
none 254112 0 254112 0% /run/shm
none 102400 0 102400 0% /run/user
/dev/mmcblk0p1 32686 6134 26552 19% /boot/uboot
/dev/mmcblk0p3 1969936 3032 1865172 1% /mnt/storage
/mnt/storage/home 1969936 3032 1865172 1% /home
This can be done for other directories such as /tmp
and /var
as well.
In Part 2 of this article, I show how to expand the existing /dev/mmcblk0p2
volume in-place to achieve similar results.