Shrink partition to exactly fit the underlying filesystem size
Sizes reported by
df will be incorrect as they account only for data blocks and miss blocks used internally by the filesystem as well as the reserved blocks.
The easy way is to shrink your filesystem to be smaller than you want by at least 10%. Resize the partition to the size you want then grow the filesystem with resize2fs.
If you want to calculate it by hand you have to know how large the filesystem is internally. Check this with
tune2fs -l /dev/sda2 and multiply the Block count by the Block size. When resizing the partition in parted switch the units to sectors with
unit s and
Equation (runable in python just fill in the first 4 values):
block_count = N block_size = N sector_size = N start_sector = N fs_size = block_count * block_size fs_sectors = fs_size/sector_size part_sectors = ((fs_sectors-1)/2048+1)*2048 end_sector = start_sector + part_sectors - 1 print "Partition start: %d end: %d size: %d"%(start_sector,end_sector,part_sectors) print "Resize in parted with: \nresizepart <number> %ds"%(end_sector)
Here is an example of the whole process.
This is our hard disk:
[email protected]:~# fdisk /dev/loop0 Command (m for help): p Disk /dev/loop0: 4,9 GiB, 5243928576 bytes, 10242048 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: 0xc5127fad Device Boot Start End Sectors Size Id Type /dev/loop0p1 8192 9765625 9757434 4,7G 83 Linux
it contains a single partition (/dev/loop0p1) that is 4.7GB in size. This is the file system on the partition:
[email protected]:~# df -h /dev/loop0p1 4,7G 2,1G 0 45% /mnt
By default, it has the same size as the partition (4.7GB). But only 2.1GB (45%) of the filesystem is used. This means we could potentially shrink the filesystem and partition to just 2.1 GB without losing any data.
The first step is to use resize2fs with the -M switch on the partition. Similar to a disk defragmenter, this command will attempt to move all files to the beginning of the file system to form one contiguous block. This then allows to shrink the file system to its smallest possible size.
[email protected]:~# resize2fs -M /dev/loop0p1
The file system looks now like this:
[email protected]:~# df -h /dev/loop0p1 2,1G 2,1G 0 100% /mnt
The hard disk now contains a 4.7GB partition with a 2.1GB file system in it that is 100% used. The next step is to shrink the partition size to fit the smaller file system.
For that, we need to calculate the filesystem size. The dumpe2fs tool is very useful for that, it shows detailed information about a file system.
[email protected]:~# dumpe2fs -h /dev/loop0p1 dumpe2fs 1.43.4 (31-Jan-2017) Filesystem volume name: <none> Last mounted on: / Filesystem UUID: 7d5ec9a4-cc65-4433-95e2-6536e4fd56d6 Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file dir_nlink extra_isize Filesystem flags: signed_directory_hash Default mount options: journal_data_writeback user_xattr acl Filesystem state: clean Errors behavior: Continue Filesystem OS type: Linux Inode count: 139392 Block count: 565950 Reserved block count: 7825 Free blocks: 8611 Free inodes: 2296 First block: 0 Block size: 4096
This tells us that there are 565950 blocks and the block size is 4096 bytes. This allows us to calculate the filesystem size:
565950 blocks * 4096 bytes = 2318131200 bytes
From that, we can calculate the filesystem size in sectors. From the fdisk output above, we know that the hard disk sector size is 512 bytes:
2318131200 bytes / 512 = 4527600 sectors
Because the partition does not start at sector 0, we need to add the start sector from the fdisk output:
4527600 + 8192 (start sector) = 4535792
This is the new end sector for our partition. Just to play it safe, add 10 sectors (about 5 KB) to that number: 4535802
Now we can use parted to shrink the partition to this new end sector. The "unit s" command is used to switch the units to sectors.
[email protected]:~# parted GNU Parted 3.2 Using /dev/sda (parted) select /dev/loop0 Using /dev/loop0 (parted) p Model: Loopback device (loopback) Disk /dev/loop0: 5244MB Sector size (logical/physical): 512B/512B Partition Table: msdos Disk Flags: Number Start End Size Type File system Flags 1 4194kB 5000MB 4996MB primary ext4 (parted) unit s (parted) p Model: Loopback device (loopback) Disk /dev/loop0: 10242048s Sector size (logical/physical): 512B/512B Partition Table: msdos Disk Flags: Number Start End Size Type File system Flags 1 8192s 9765625s 9757434s primary ext4 (parted) resizepart 1 4535802 Warning: Shrinking a partition can cause data loss, are you sure you want to continue? Yes/No? yes (parted) p Model: Loopback device (loopback) Disk /dev/loop0: 10242048s Sector size (logical/physical): 512B/512B Partition Table: msdos Disk Flags: Number Start End Size Type File system Flags 1 8192s 4535802s 4527611s primary ext4
It gives us a warning about potential data loss, but because we moved all data to the beginning of the partition before, this can safely be ignored. Done! We now have a 2.1GB partition with a 2.1GB filesystem that's 100% occupied.