[gparted] Calculate mounted JFS size accurately (!50)



commit 2c0572e29668aae86ed1e7e7c96cf99b5d6eafca
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Fri Nov 8 14:01:11 2019 +0000

    Calculate mounted JFS size accurately (!50)
    
    With the same minimum sized 16 MiB JFS used in the previous commit, now
    mounted, GParted once again reports 1.20 MiB of unallocated space.  This
    is because the kernel JFS driver is also just reporting the size of the
    Aggregate Disk Map (dmap) as the size of the file system [1].
    
    Fix by reading the on disk JFS superblock to calculate the size of the
    file system, but query the free space from the kernel using statvfs().
    Need to query mounted JFS free space from the kernel because the on disk
    dmap is not updated immediately so doesn't reflect recently used or
    freed disk space.
    
    For example, start with the 16 MiB JFS empty and mounted.
    
        # echo -e 'dmap\nx\nquit' | jfs_debugfs /dev/sdb1 | fgrep dn_nfree
        [2] dn_nfree:           0x00000000eaa   [10] dn_agwidth:        1
        # df -k /mnt/1
        Filesystem     1K-blocks  Used Available Use% Mounted on
        /dev/sdb1          15152   136     15016   1% /mnt/1
    
    Write 10 MiB of data to it:
    
        # dd if=/dev/zero bs=1M count=10 of=/mnt/1/file_10M
        10+0 records in
        10+0 records out
        1048760 bytes (10 MB, 10 MiB) copied, 0.0415676 s, 252 MB/s
    
    Query the file system free space from the kernel and by reading the on
    disk dmap figure:
    
        # df -k /mnt/1
        Filesystem     1K-blocks  Used Available Use% Mounted on
        /dev/sdb1          15152 10376      4776  69% /mnt/1
        # echo -e 'dmap\nx\nquit' | jfs_debugfs /dev/sdb1 | fgrep dn_nfree
        [2] dn_nfree:           0x00000000eaa   [10] dn_agwidth:        1
    
        # sync
        # echo -e 'dmap\nx\nquit' | jfs_debugfs /dev/sdb1 | fgrep dn_nfree
        [2] dn_nfree:           0x00000000eaa   [10] dn_agwidth:        1
    
        # umount /mnt/1
        # echo -e 'dmap\nx\nquit' | jfs_debugfs /dev/sdb1 | fgrep dn_nfree
        [2] dn_nfree:           0x000000004aa   [10] dn_agwidth:        1
    
    The kernel reports the updated usage straight away, but the on disk dmap
    record doesn't get updated even by sync, only after unmounting.
    
    This is the same fix as was previously done for EXT2/3/4 [2].
    
    [1] Linux jfs_statfs() function
        https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/jfs/super.c?h=v3.10#n142
    
    [2] 3828019030f981cc5b3411badc40704f5525fdb3
        Read file system size for mounted ext2/3/4 from superblock (#683255)
    
    Closes !50 - Calculate JFS size accurately

 src/jfs.cc | 52 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 12 deletions(-)
---
diff --git a/src/jfs.cc b/src/jfs.cc
index 309832be..fa773b9d 100644
--- a/src/jfs.cc
+++ b/src/jfs.cc
@@ -34,6 +34,7 @@ FS jfs::get_filesystem_support()
 
        if ( ! Glib::find_program_in_path( "jfs_debugfs" ) .empty() ) {
                fs.read = FS::EXTERNAL;
+               fs.online_read = FS::EXTERNAL;
        }
 
        if ( ! Glib::find_program_in_path( "jfs_tune" ) .empty() ) {
@@ -67,7 +68,6 @@ FS jfs::get_filesystem_support()
                fs.copy = FS::GPARTED;
        }
 
-       fs .online_read = FS::GPARTED ;
 #ifdef ENABLE_ONLINE_RESIZE
        if ( Utils::kernel_version_at_least( 3, 6, 0 ) )
                fs .online_grow = fs .grow ;
@@ -81,6 +81,11 @@ FS jfs::get_filesystem_support()
 
 void jfs::set_used_sectors( Partition & partition ) 
 {
+       // Called when the file system is unmounted *and* when mounted.  Always reads the
+       // on disk superblock using jfs_debugfs to accurately calculate the overall size
+       // of the file system.  Read free space from the kernel via statvfs() when mounted
+       // for the up to date figure, and from the on disk Aggregate Disk Map (dmap) when
+       // unmounted.
        exit_status = Utils::execute_command("jfs_debugfs " + Glib::shell_quote(partition.get_path()),
                                             "superblock\nx\ndmap\nx\nquit\n", output, error, true);
        if (exit_status != 0)
@@ -122,20 +127,43 @@ void jfs::set_used_sectors( Partition & partition )
        if (index < output.length())
                sscanf(output.substr(index).c_str(), "s_fsckpxd.len: %lld", &fsck_len);
 
-       // dn_nfree - Number of free (s_bsize) blocks in Aggregate
-       long long free_blocks = -1;
-       index = output.find("dn_nfree:");
-       if (index < output.length())
-               sscanf(output.substr(index).c_str(), "dn_nfree: %llx", &free_blocks);
+       Sector fs_size_sectors = -1;
+       if (agg_size > -1 && agg_block_size > -1 && phys_block_size > -1 && log_len > -1 && fsck_len > -1)
+       {
+               fs_size_sectors = (  agg_size * phys_block_size
+                                  + log_len  * agg_block_size
+                                  + fsck_len * agg_block_size) / partition.sector_size;
+       }
 
-       if (agg_size > -1 && agg_block_size > -1 && phys_block_size > -1 &&
-           log_len  > -1 && fsck_len       > -1 && free_blocks     > -1   )
+       Sector fs_free_sectors = -1;
+       if (partition.busy)
        {
-               Sector fs_size_sectors = (  agg_size * phys_block_size
-                                         + log_len  * agg_block_size
-                                         + fsck_len * agg_block_size) / partition.sector_size;
-               Sector fs_free_sectors = free_blocks * agg_block_size / partition.sector_size;
+               Byte_Value ignored;
+               Byte_Value fs_free_bytes;
+               if (Utils::get_mounted_filesystem_usage(partition.get_mountpoint(), ignored, fs_free_bytes, 
error) != 0)
+               {
+                       partition.push_back_message(error);
+                       return;
+               }
 
+               fs_free_sectors = fs_free_bytes / partition.sector_size;
+       }
+       else // (! partition.busy)
+       {
+               // dn_nfree - Number of free (s_bsize) blocks in Aggregate
+               long long free_blocks = -1;
+               index = output.find("dn_nfree:");
+               if (index < output.length())
+                       sscanf(output.substr(index).c_str(), "dn_nfree: %llx", &free_blocks);
+
+               if (agg_block_size && free_blocks > -1)
+               {
+                       fs_free_sectors = free_blocks * agg_block_size / partition.sector_size;
+               }
+       }
+
+       if (fs_size_sectors > -1 && fs_free_sectors > -1 && agg_block_size > -1)
+       {
                partition.set_sector_usage(fs_size_sectors, fs_free_sectors);
                partition.fs_block_size = agg_block_size;
        }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]