Calculate unmounted JFS size accurately (!50)

Create the smallest possible JFS (16 MiB) and GParted will report
1.2 MiB of unallocated space.  This is because the size of the Aggregate
Disk Map (dmap) was used as the size of the file system.  However after
reading the source code to mkfs.jfs, it separately accounts for the size
of the Log (Journal) and the FSCK Working Space.  The size of a JFS is
the sum of these 3 components added together.

Using the minimum 16 MiB JFS as an example:

    # jfs_debugfs /dev/sdb1
    jfs_debugfs version 1.1.15, 04-Mar-2011

    Aggregate Block Size: 4096

    > superblock
    [1] s_magic:            'JFS1'          [15] s_ait2.addr1:      0x00
    [2] s_version:          1               [16] s_ait2.addr2:      0x00000018
    [3] s_size:     0x0000000000007660           s_ait2.address:    24
    [4] s_bsize:            4096            [17] s_logdev:          0x00000000
    [5] s_l2bsize:          12              [18] s_logserial:       0x00000000
    [6] s_l2bfactor:        3               [19] s_logpxd.len:      256
    [7] s_pbsize:           512             [20] s_logpxd.addr1:    0x00
    [8] s_l2pbsize:         9               [21] s_logpxd.addr2:    0x00000f00
    [9] pad:                Not Displayed        s_logpxd.address:  3840
    [10] s_agsize:          0x00002000      [22] s_fsckpxd.len:     52
    [11] s_flag:            0x10200900      [23] s_fsckpxd.addr1:   0x00
                            JFS_LINUX       [24] s_fsckpxd.addr2:   0x00000ecc
            JFS_COMMIT      JFS_GROUPCOMMIT      s_fsckpxd.address: 3788
                            JFS_INLINELOG   [25] s_time.tv_sec:     0x5dbbdfa0
                                            [26] s_time.tv_nsec:    0x00000000
                                            [27] s_fpack:           'small_jfs'
    [12] s_state:           0x00000000
                 FM_CLEAN
    [13] s_compress:        0
    [14] s_ait2.len:        4

    display_super: [m]odify or e[x]it: x
    > dmap

    Block allocation map control page at block 16

    [1] dn_mapsize:         0x00000000ecc   [9] dn_agheigth:        0
    [2] dn_nfree:           0x00000000eaa   [10] dn_agwidth:        1
    [3] dn_l2nbperpage:     0               [11] dn_agstart:        341
    [4] dn_numag:           1               [12] dn_agl2size:       13
    [5] dn_maxlevel:        0               [13] dn_agfree:         type 'f'
    [6] dn_maxag:           0               [14] dn_agsize:         8192
    [7] dn_agpref:          0               [15] pad:               Not Displayed
    [8] dn_aglevel:         0
    display_dbmap: [m]odify, [f]ree count, [t]ree, e[x]it > x
    > quit

Values of interest:
    s_size        - Aggregate size in device (s_pbsize) blocks
    s_bsize       - Aggregate block (aka file system allocation) size in
                    bytes
    s_pbsize      - Physical (device) block size in bytes
    s_logpxd.len  - Log (Journal) size in Aggregate (s_bsize) blocks
    s_fsckpxd.len - FSCK Working Space in Aggregate (s_bsize) blocks
    dn_nfree      - Number of free (s_bsize) blocks in Aggregate

Calculation:
    file system size = s_size * s_pbsize
                     + s_logpxd.len * s_bsize
                     + s_fsckpxd.len * s_bsize
                     = 30304 * 512
                     + 256 * 4096
                     + 52 * 4096
                     =  16777216
                        (Exactly 16 MiB.  The size of the partition.)
    free space = dn_nfree * s_bsize
               = 3754 * 4096
               = 15376384

Rewrite JFS usage querying code to use this updated calculation.

[1] JFS Overview / How the Journaled File System cuts system restart
    times to the quick
    http://jfs.sourceforge.net/project/pub/jfs.pdf
[2] JFS Layout / How the Journaled File systems handles the on-disk
    layout
    http://jfs.sourceforge.net/project/pub/jfslayout.pdf
[3] mkfs.jfs source code
    http://jfs.sourceforge.net/project/pub/jfsutils-1.1.15.tar.gz
    mkfs/mkfs.c
    Selected lines from mkfs/mkfs.c
        create_aggregate(..., number_of_blocks, ..., logsize, ...)
            number_of_blocks -= fsck_wspace_length;
            aggr_superblock.s_size = number_of_blocks * (aggr_block_size / phys_block_size);
            aggr_superblock.s_bsize = aggr_block_size;
            aggr_superblock.s_pbsize = phys_block_size;
            PXDlength(&aggr_superblock.s_logpxd, logsize);
            PXDlength(&aggr_superblock.s_fsckpxd, fsck_wspace_length);
        main()
            number_of_bytes = bytes_on_device;
            number_of_blocks = number_of_bytes / agg_block_size;
            logsize = logsize_in_bytes / aggr_block_size;
            number_of_blocks -= logsize;
            create_aggregate(..., number_of_blocks, ..., logsize, ...);

Closes !50 - Calculate JFS size accurately
This commit is contained in:
Mike Fleetwood 2019-11-05 11:32:05 +00:00 committed by Curtis Gedak
parent 7be6d0967a
commit e55d10b919
1 changed files with 56 additions and 33 deletions

View File

@ -78,47 +78,70 @@ FS jfs::get_filesystem_support()
return fs ;
}
void jfs::set_used_sectors( Partition & partition )
{
const Glib::ustring jfs_debug_cmd = "jfs_debugfs " + Glib::shell_quote( partition.get_path() );
if (! Utils::execute_command(jfs_debug_cmd, "dmap\nx\nquit\n", output, error, true))
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)
{
//blocksize
Glib::ustring::size_type index = output.find( "Block Size:" );
if ( index >= output .length() ||
sscanf( output.substr( index ).c_str(), "Block Size: %lld", &S ) != 1 )
S = -1 ;
//total blocks
index = output .find( "dn_mapsize:" ) ;
if ( index >= output .length() ||
sscanf( output.substr( index ).c_str(), "dn_mapsize: %llx", &T ) != 1 )
T = -1 ;
//free blocks
index = output .find( "dn_nfree:" ) ;
if ( index >= output .length() ||
sscanf( output.substr( index ).c_str(), "dn_nfree: %llx", &N ) != 1 )
N = -1 ;
if ( T > -1 && N > -1 && S > -1 )
{
T = Utils::round( T * ( S / double(partition .sector_size) ) ) ;
N = Utils::round( N * ( S / double(partition .sector_size) ) ) ;
partition .set_sector_usage( T, N ) ;
partition.fs_block_size = S;
}
if (! output.empty())
partition.push_back_message(output);
if (! error.empty())
partition.push_back_message(error);
return;
}
else
// s_size - Aggregate size in device (s_pbsize) blocks
long long agg_size = -1;
Glib::ustring::size_type index = output.find("s_size:");
if (index < output.length())
sscanf(output.substr(index).c_str(), "s_size: %llx", &agg_size);
// s_bsize - Aggregate block (aka file system allocation) size in bytes
long long agg_block_size = -1;
index = output.find("s_bsize:");
if (index < output.length())
sscanf(output.substr(index).c_str(), "s_bsize: %lld", &agg_block_size);
// s_pbsize - Physical (device) block size in bytes
long long phys_block_size = -1;
index = output.find("s_pbsize:");
if (index < output.length())
sscanf(output.substr(index).c_str(), "s_pbsize: %lld", &phys_block_size);
// s_logpxd.len - Log (Journal) size in Aggregate (s_bsize) blocks
long long log_len = -1;
index = output.find("s_logpxd.len:");
if (index < output.length())
sscanf(output.substr(index).c_str(), "s_logpxd.len: %lld", &log_len);
// s_fsckpxd.len - FSCK Working Space in Aggregate (s_bsize) blocks
long long fsck_len = -1;
index = output.find("s_fsckpxd.len:");
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);
if (agg_size > -1 && agg_block_size > -1 && phys_block_size > -1 &&
log_len > -1 && fsck_len > -1 && free_blocks > -1 )
{
if ( ! output .empty() )
partition.push_back_message( output );
if ( ! error .empty() )
partition.push_back_message( error );
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;
partition.set_sector_usage(fs_size_sectors, fs_free_sectors);
partition.fs_block_size = agg_block_size;
}
}
void jfs::read_label( Partition & partition )
{
if ( ! Utils::execute_command( "jfs_tune -l " + Glib::shell_quote( partition.get_path() ),