Use resize2fs -P to get minimum EXT2/3/4 FS size (#8)

A user reported GParted failed to shrink an EXT4 file system because
GParted tried to shrink it smaller than resize2fs reported minimum size.
Operation details were:

    Shrink /dev/sdc1 from 931.51 GiB to 605.00 GiB             (ERROR)
      calibrate /dev/sdc1                                      (SUCCESS)
        path: /dev/sdc1 (partition)
        start: 63
        end: 1953520064
        size: 1953520002 (931.51 GiB)
      check file system on /dev/sdc1 for errors and (if poss...(SUCCESS)
        e2fsck -f -y -v -C 0 '/dev/sdc1'                       (SUCCESS)
          ...
          158165624 blocks are used (64.77% of 244190000)
          ...
      shrink file system                                       (ERROR)
        resize2fs -p '/dev/sdc1' 634389176K                    (ERROR)
          resize2fs 1.44.2 (14-May-2018)
          resize2fs: New size smaller than minimum (171882113)

The GParted figures:
 *  Partition size    = 1953520064 (512b sectors) = 976760032 KiB
 *  FS size           = 244190000 (4K blocks)     = 976760000 KiB
 *  Used FS size      = 158165624 (4K blocks)     = 632662496 KiB
 *  Requested FS size                             = 634389176 KiB
The resize2fs figure:
 *  Minimum FS size   = 171882113 (4K blocks)     = 687528452 KiB

GParted uses the number of free blocks in the file system to determine
the minimum size it can shrink a file system to.  However resize2fs uses
it's own internally calculated minimum size and won't shrink a file
system below that size, as seen in the above details.  Resize2fs does
have a force flag, (-f) which overrides some safety checks which are
normally enforced, to allow it to try to shrink a file system smaller
than it's calculated minimum.  GParted currently doesn't use the force
flag and it seems unwise for it to start to do so.

So for unmounted EXT2/3/4 file systems, change GParted to use
'resize2fs -P' to get the minimum file system size, rather than using
the number of free blocks direct from the super block, as reported by
'dumpe2fs -h'.

Mounted file systems still use statvfs() to provide file system usage.
As mounted EXT2/3/4 file systems can't be shrunk the fact that statvfs()
produces different, possibly smaller than minimum, figures than those
from 'resize2fs -P' doesn't matter.

Closes #8 - Shrinking an EXT4 partition does not respect resize2fs
            limits
This commit is contained in:
Mike Fleetwood 2018-07-19 10:33:42 +01:00
parent ef8dbe8f4e
commit fe83f6290f
1 changed files with 17 additions and 9 deletions

View File

@ -142,11 +142,11 @@ FS ext2::get_filesystem_support()
void ext2::set_used_sectors( Partition & partition )
{
//Called when file system is unmounted *and* when mounted. Always read
// the file system size from the on disk superblock using dumpe2fs to
// avoid overhead subtraction. Read the free space from the kernel via
// the statvfs() system call when mounted and from the superblock when
// unmounted.
// Called when file system is unmounted *and* when mounted. Always read
// the file system size from the on disk superblock using dumpe2fs to
// avoid overhead subtraction. When mounted read the free space from
// the kernel via the statvfs() system call. When unmounted read the
// free space using resize2fs itself.
if ( ! Utils::execute_command( "dumpe2fs -h " + Glib::shell_quote( partition.get_path() ),
output, error, true ) )
{
@ -177,10 +177,18 @@ void ext2::set_used_sectors( Partition & partition )
}
else
{
index = output .find( "Free blocks:" ) ;
if ( index >= output .length() ||
sscanf( output.substr( index ).c_str(), "Free blocks: %lld", &N ) != 1 )
N = -1 ;
// Resize2fs won't shrink a file system smaller than it's own
// estimated minimum size, so use that to derive the free space.
N = -1;
if ( ! Utils::execute_command( "resize2fs -P " + Glib::shell_quote( partition.get_path() ),
output, error, true ) )
{
if ( sscanf( output.c_str(), "Estimated minimum size of the filesystem: %lld", &N ) == 1 )
N = T - N;
}
if ( N == -1 && ! error.empty() )
partition.push_back_message( error );
}
if ( T > -1 && N > -1 && S > -1 )