12

Recently i shrinked an ext4 filesystem size to 500GB

df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda2       493G   64G  404G  14% /

now i want to shrink the partition size to fit exactly to the filesystem size.

I tried to used parted and the resizepart command. The problem is when parted asks for the new size. If i choose 500GB the resulting partition is smaller from 500GB and as a result the underlying filesystem cannot fit on this partition. Any hint on how to do the correct size calculations?

1
  • 2
    IMO, you're doing this backwards. Shrink your file system below your target partition size, shrink the partition, then resize the filesystem to fill the partition.. You don't need to calculate anything, the default is to use all the space available in the partition in resize2fs. The partition size dictates the max filesystem size, not the other way around.
    – user143703
    Commented Aug 14, 2016 at 20:04

2 Answers 2

12

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 print the table to get the start sector and logical sector size. Divide the total size in bytes from above by the sector size. Round up to the nearest multiple of 2048 and resize to this number of sectors (end sector = size in sectors + start sector - 1).

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)
2
  • Arg! Was looking sooo good, until: Error: The resize command has been removed in parted 3.0
    – dsz
    Commented Aug 23, 2021 at 22:52
  • @dsz it's resizepart these days
    – pschichtel
    Commented Mar 11, 2023 at 20:45
14

Here is an example of the whole process.

This is the hard disk:

root@debian:~# 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

Note: "/dev/loop0" is a loopback device, a virtual hard disk based on a file container. A physical hard disk would be named "/dev/sda".

The disk contains a single partition (/dev/loop0p1) that is 4.7GB in size.

This is the file system on the partition:

root@debian:~# 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 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. resize2fs only works with ext file systems, for others you would have to find an equivalent program with this functionality.

root@debian:~# resize2fs -M /dev/loop0p1

The file system looks now like this:

root@debian:~# 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 new filesystem size. The dumpe2fs tool is very useful for that, it shows detailed information about a file system.

root@debian:~# 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 bytes sector size = 4527600 sectors

Because the partition does not start at sector 0, we need to add the start sector from the fdisk output above, then subtract one because the sector count begins at zero:

4527600 + 8192 (start sector) - 1 = 4535791

This is the new end sector for our partition.

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.

root@debian:~# parted
GNU Parted 3.2
Using /dev/sda

(parted) select /dev/loop0   
                                         
Using /dev/loop0

(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 4535791  
                                       
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  4535791s  4527600s  primary  ext4

It gives us a warning about potential data loss, but there should be no data in the sectors to be cut off. We now have a 2.1GB partition with a 2.1GB filesystem that's 100% occupied.

4
  • 4
    I like this answer very much but not the added 10 sectors "to play it safe". Either the calculations and methods are correct and I don't need the 10 sectors or there is something missing. Including this just raises concerns about the correctness of the answer. Commented Nov 24, 2021 at 8:37
  • 1
    @ChristopherGertz Agreed, but the basic procedure is correct. Note that the calculation of end sector is not correct, it needs to be start + new_size - 1, the answer uses start + new_size. I followed this answer's procedure with this correct end sector exact calculation, and it worked fine. So, good answer, just with a few small tweaks.
    – Bogatyr
    Commented Mar 14, 2023 at 5:46
  • Thanks for your suggestions. I had verified the data before and after the shrinking process to make sure there was no data loss. But my end sector calculation was indeed incorrect, it was 1 sector too large as pointed out by @Bogatyr. I have verified this and updated my answer accordingly. If an additional sector is removed (start + new_size -2), the partition becomes corrupted. Commented Mar 19, 2023 at 7:24
  • Years later, and this comprehensive answer still saves the day. Thank you so much for the in-depth! Commented Sep 6, 2023 at 15:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .