statfs example

  • The statfs() system call returns information about a mounted filesystem.
    • int statfs(const char path, struct statfs buf);
    • path is the pathname of any file within the mounted filesystem.
           struct statfs {
               __fsword_t f_type;    /* Type of filesystem (see below) */
               __fsword_t f_bsize;   /* Optimal transfer block size */
               fsblkcnt_t f_blocks;  /* Total data blocks in filesystem */
               fsblkcnt_t f_bfree;   /* Free blocks in filesystem */
               fsblkcnt_t f_bavail;  /* Free blocks available to
                                        unprivileged user */
               fsfilcnt_t f_files;   /* Total file nodes in filesystem */
               fsfilcnt_t f_ffree;   /* Free file nodes in filesystem */
               fsid_t     f_fsid;    /* Filesystem ID */
               __fsword_t f_namelen; /* Maximum length of filenames */
               __fsword_t f_frsize;  /* Fragment size (since Linux 2.6) */
               __fsword_t f_flags;   /* Mount flags of filesystem
                                        (since Linux 2.6.36) */
               __fsword_t f_spare[xxx];
                               /* Padding bytes reserved for future use */
           };

f_bsize: Optimal transfer block size
f_blocks:Total data blocks in filesystem
f_bfree: Free blocks in filesystem
f_bavail:ree blocks available to unprivileged user


example 320GB

  • 此顆HDD (320GB),切成/dev/sda1及/dev/sda2
  • 硬碟HDD SZIE定義 320GB = 320 x 1000000000 byte = 298Gbyte
  • /dev/sda1可使用的大小為 319.5GB (319558778880 byte = 304755 Mbyte = 297.6 Gbyte)
  • 319558778880大小同fdisk -l /dev/sda1大小
  • dumpe2fs /dev/sda1 得到大小 319558778880 byte (78017280 * 4096),此為實際可以用的block空間
  • parted /dev/sda 得到size 320GB = 320x1000000000 byte = 298Gbyte

swap 512Mbyte = 536870912 byte

parted 及 fdisk

# parted -s /dev/sda print free
Model: ATA MAXTOR STM332082 (scsi)
Disk /dev/sda: 320GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

Number  Start   End     Size    File system     Name        Flags
        17.4kB  1049kB  1031kB  Free Space
 1      1049kB  320GB   320GB   ext4            primary
 2      320GB   320GB   513MB   linux-swap(v1)  linux-swap
        320GB   320GB   335kB   Free Space
# fdisk -l /dev/sda

Disk /dev/sda: 320.0 GB, 320072933376 bytes
255 heads, 63 sectors/track, 38913 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks  Id System
/dev/sda1               1       38914   312571223+ ee EFI GPT
# fdisk -l /dev/sda1

Disk /dev/sda1: 319.5 GB, 319558778880 bytes
255 heads, 63 sectors/track, 38850 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Disk /dev/sda1 doesn't contain a valid partition table
  • statfs 得到total size 319459942400 (77993150 * 4096) = 304660.7Mbyte = 297.5Gbyte
  • 比dumpe2fs得到size 少了 98836480 (94.25Mbyte)
  • statfs 得到free size 32232423424

df算法

Total data blocks in filesystem
(f_blocks*f_bsize + 512) / 1024 
= 311972600.5 Kbyte (1K-blocks) 全部的量297.5Gbyte

Total data blocks in filesystem - Free blocks in filesystem =使用量
((f_blocks - f_bfree)*f_bsize + 512 ) / 1024 
= 280495624.5 Kbyte (Used) 全部使用的量 267.5Gbyte

由於bavial為非root量會比較少
Free blocks available to unprivileged user
(f_bavail*f_bsize+512)/1024 
= 15873520 Kbyte  (Available)剩下可使用量15.13Gbyte

used %
block_used = (f_blocks - f_bfree)     = 70123906 (x4K = 
block_total = (block_used + f_bavail) = 74092286 (x4K = 296369144Kbyte = 282.6Gbyte )
# df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/root                18432     13332      5100  72% /
devtmpfs                295904         4    295900   0% /dev
tmpfs                   295996      1324    294672   0% /tmp
tmpfs                   295996         0    295996   0% /dev/shm
/dev/mtdblock6           29624     29624         0 100% /usr
/dev/mtdblock8            5120      3496      1624  68% /opt/dvr_rdk/dvr_board
/dev/mtdblock9            2048       224      1824  11% /mnt/nand
/dev/mtdblock10           2048       196      1852  10% /mnt/log
/dev/sda1            311972600 280495624  15873520  95% /media/sda1

# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root                18.0M     13.0M      5.0M  72% /
devtmpfs                289.0M      4.0K    289.0M   0% /dev
tmpfs                   289.1M      1.3M    287.8M   0% /tmp
tmpfs                   289.1M         0    289.1M   0% /dev/shm
/dev/mtdblock6           28.9M     28.9M         0 100% /usr
/dev/mtdblock8            5.0M      3.4M      1.6M  68% /opt/dvr_rdk/dvr_board
/dev/mtdblock9            2.0M    224.0K      1.8M  11% /mnt/nand
/dev/mtdblock10           2.0M    196.0K      1.8M  10% /mnt/log
/dev/sda1               297.5G    267.5G     15.1G  95% /media/sda1
  • f_blocks : Total data blocks in filesystem
  • f_bavail :Free blocks available to unprivileged user
  • f_bfree :Free blocks in filesystem

f_bfree比f_bavail多,但只有f_bavail才是能使用量

# ./test-statfs 
mount_path:/media/sda1
dev_path:/dev/sda1
f_blocks :077993150
f_bsize  :000004096
f_bavail :003968380
f_bfree  :007869244
Filesystem           4K-blocks      Used Available Use% Mounted on
/dev/sda1            311972600 280495624  15873520  95% /media/sda1
  • dumpe2fs
Block count:              78017280
Reserved block count:     3900864
Free blocks:              57976020
Free inodes:              303839

dumpe2fs

# ./dumpe2fs 
dumpe2fs 1.41.11 (14-Mar-2010)
Usage: ./dumpe2fs [-bfhixV] [-o superblock=<num>] [-o blocksize=<num>] device
# ./dumpe2fs /dev/sda1
dumpe2fs 1.41.11 (14-Mar-2010)
Filesystem volume name:   <none>
Last mounted on:          /media/sda1
Filesystem UUID:          27f84dc8-e61a-4c12-80e9-b17813a87891
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         unsigned_directory_hash 
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              304768
Block count:              78017280
Reserved block count:     3900864
Free blocks:              57976020
Free inodes:              303839
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      1005
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         128
Inode blocks per group:   8
Flex block group size:    16
Filesystem created:       Fri Dec 11 18:43:08 2015
Last mount time:          Thu Jan  1 00:00:48 1970
Last write time:          Thu Jan  1 00:00:48 1970
Mount count:              4
Maximum mount count:      24
Last checked:             Fri Dec 11 18:43:08 2015
Check interval:           15552000 (6 months)
Next check after:         Wed Jun  8 18:43:08 2016
Lifetime writes:          77 GB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      04e4fbde-8a6f-4a63-a5ae-37d10975ac73
Journal backup:           inode blocks
Journal features:         (none)
Journal size:             128M
Journal length:           32768
Journal sequence:         0x0000c1d2
Journal start:            61

320G 試算

# mkfs.ext4 -q -T largefile /dev/sda1
# 
# df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/root                18432     13348      5084  72% /
devtmpfs                295904         4    295900   0% /dev
tmpfs                   295996      1652    294344   1% /tmp
tmpfs                   295996         0    295996   0% /dev/shm
/dev/mtdblock6           29624     29624         0 100% /usr
/dev/mtdblock8            5120      3496      1624  68% /opt/dvr_rdk/dvr_board
/dev/mtdblock9            2048       228      1820  11% /mnt/nand
/dev/mtdblock10           2048       196      1852  10% /mnt/log
/dev/sda1            311972600    195416 296173728   0% /media/sda1
# df -h 
Filesystem                Size      Used Available Use% Mounted on
/dev/root                18.0M     13.0M      5.0M  72% /
devtmpfs                289.0M      4.0K    289.0M   0% /dev
tmpfs                   289.1M      1.6M    287.4M   1% /tmp
tmpfs                   289.1M         0    289.1M   0% /dev/shm
/dev/mtdblock6           28.9M     28.9M         0 100% /usr
/dev/mtdblock8            5.0M      3.4M      1.6M  68% /opt/dvr_rdk/dvr_board
/dev/mtdblock9            2.0M    228.0K      1.8M  11% /mnt/nand
/dev/mtdblock10           2.0M    196.0K      1.8M  10% /mnt/log
/dev/sda1               297.5G    190.8M    282.5G   0% /media/sda1
  • dumpe2fs
# ./dumpe2fs /dev/sda1
dumpe2fs 1.41.11 (14-Mar-2010)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          875b5629-d22e-4036-b1ed-2bfb7bf39e7d
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         unsigned_directory_hash 
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              304768
Block count:              78017280
Reserved block count:     3900864
Free blocks:              77944296
Free inodes:              304757
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      1005
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         128
Inode blocks per group:   8
Flex block group size:    16

f_blocks size: 77993150 x 4096 = 297.52 Gbyte
f_bfree size : 77944296 x 4096 = 297.33 Gbyte f_bavail size: 74043432 x 4096 = 282.45 Gbyte

# ./test-statfs /media/sda1
mount_path:/media/sda1
dev_path:/dev/sda1
f_blocks :077993150
f_bsize  :000004096
f_bavail :074043432
f_bfree  :077944296
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1            311972600    195416 296173728   0% /media/sda1

BKT 計算

  • 320G會開啟456個bkt
    • f_blocks (297.52 Gbyte ) / 600M = 507.7 Bkt
    • --bkt (506.7BKT)
    • bkt-= BKT_RESERVE_IDX_SPACE_BKT_NUM (50) (456BKT)
  • 456BKT錄滿會佔 267.42Gbyte
    • (600M + 557K) * 456 = 267.42Gbyte

used % = ( block_used*100 + 0.5xblock_total) / block_total
block_used = (f_blocks - f_bfree)
block_total = (block_used + f_bavail)

item 格化式之後 錄滿 變量
f_blocks 77993150 (297.52 Gbyte) 77993150 (297.52 Gbyte) 相同
f_bfree 77944296 (297.33 Gbyte) 7869244 ( 30.01 Gbyte) 減少 267.32Gbyte
f_bavail 74043432 (282.45 Gbyte) 3968380 ( 15.13 Gbyte) 減少 267.32Gbyte
used 0.19 Gbyte 267.51 Gbyte 增加 267.32Gbyte
total 282.64 Gbyte 282.64 Gbyte 相同
used % 0% 95% 增加95%, 268.5Gbyte

增加的量為 BKT寫滿量 (267.42GByte)

used % = (19 + 141.32) / 282.64 = 0.56 % = 0%
used % = (26751 + 141.32) / 282.64 = 0.56 % = 95.14%

顯示滿100%算法

282.64 - 267.51 = 15.13 (Gbyte)

total -= 15.13 => 267.51 Gbyte

used % = (19 + 133.75) / 267.51 = 0.57 % = 0%
used % = (26751 + 133.75) / 267.51 = 100.4 % = 100%


2TB HDD example

  • 2TB HDD = 21000100010001000 byte = 1862.645149230957 Gbyte = 1.81Tbyte
  • dumpe2fs size (488253184 * 4096 = 1999885041664 = 1862.53Gbyte)
  • dumpe2fs Free blocks: 488051925 (同statfs f_bfree)
  • dumpe2fs block 488253184 比 statfs 488101932 多了 151252個block (多了590Mbyte)
  • statfs f_block size 1861Gbyte ( 488101932 x 4096 = 1999265513472 byte )

當未建立bkt時 f_bfree等於 dumpe2fs free block量

dumpe2fs

Block count:              488253184
Reserved block count:     24412659
Free blocks:              488051925
Block size:               4096
  • f_blocks: 488101932 (1861.96Gbyte)
  • f_bavail: 463639266 (1768.6Gbyte)
  • f_bfree: 488051925 (1861.7Gbyte)
  • 總HDD BLOCK空間 1861.96Gbyte,,有1861.7G的free ,但只有 1768.6G可以使用 (少了93.3Gbyte)
# mkfs.ext4 -q -T largefile /dev/sda1
# mount /dev/sda1 /media/sda1
# ./test-statfs 
mount_path:/media/sda1
dev_path:/dev/sda1
f_blocks :488101932
f_bsize  :000004096
f_bavail :463639266
f_bfree  :488051925
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1            1952407728    200028 1854557064   0% /media/sda1
#
# df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/root                18432     13324      5108  72% /
devtmpfs                295904         4    295900   0% /dev
tmpfs                   295996      1296    294700   0% /tmp
tmpfs                   295996         0    295996   0% /dev/shm
/dev/mtdblock6           29616     29616         0 100% /usr
/dev/mtdblock7            5120      3492      1628  68% /opt/dvr_rdk/dvr_board
/dev/mtdblock9            2048       224      1824  11% /mnt/nand
/dev/mtdblock10           2048       196      1852  10% /mnt/log
/dev/sda1            1952407728    200028 1854557064   0% /media/sda1
# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root                18.0M     13.0M      5.0M  72% /
devtmpfs                289.0M      4.0K    289.0M   0% /dev
tmpfs                   289.1M      1.3M    287.8M   0% /tmp
tmpfs                   289.1M         0    289.1M   0% /dev/shm
/dev/mtdblock6           28.9M     28.9M         0 100% /usr
/dev/mtdblock7            5.0M      3.4M      1.6M  68% /opt/dvr_rdk/dvr_board
/dev/mtdblock9            2.0M    224.0K      1.8M  11% /mnt/nand
/dev/mtdblock10           2.0M    196.0K      1.8M  10% /mnt/log
/dev/sda1                 1.8T    195.3M      1.7T   0% /media/sda1
#
  • 建立bkt之後
  • f_blocks不變
  • f_bavail 少了 3498 block (463639266 - 463635768) (13992Kbyte)
  • f_bfree 少了 3498 block (488051925 - 488048427 )
  • df下的 used 增加 13992Kbyte (214020 - 200028) ,等於f_bavail 及 f_bfree的量
-rw-r--r--    1 root     root     629145600 Dec  9 16:18 00003176.bkt
-rw-r--r--    1 root     root             0 Dec  9 16:18 00003176.idx
-rw-r--r--    1 root     root       1117976 Dec  9 16:18 bktmgr.udf
drwxr-xr-x    3 root     root          4096 Dec  9 17:36 cfg
drwx------    2 root     root         16384 Dec  9 16:18 lost+found
-rw-r--r--    1 root     root            88 Dec 15 11:06 topmgr.udf
# df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/root                18432     13320      5112  72% /
devtmpfs                295904         4    295900   0% /dev
tmpfs                   295996      1284    294712   0% /tmp
tmpfs                   295996         0    295996   0% /dev/shm
/dev/mtdblock6           29616     29616         0 100% /usr
/dev/mtdblock7            5120      3492      1628  68% /opt/dvr_rdk/dvr_board
/dev/mtdblock9            2048       224      1824  11% /mnt/nand
/dev/mtdblock10           2048       196      1852  10% /mnt/log
/dev/sda1            1952407728    214020 1854543072   0% /media/sda1

# ./test-statfs 
mount_path:/media/sda1
dev_path:/dev/sda1
f_blocks :488101932
f_bsize  :000004096
f_bavail :463635768
f_bfree  :488048427
  • 2TB dumpe2fs
# 
# ./dumpe2fs /dev/sda1
dumpe2fs 1.41.11 (14-Mar-2010)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          6aa991cc-8cc4-482e-8ace-e5d42e95433b
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         unsigned_directory_hash 
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              1907328
Block count:              488253184
Reserved block count:     24412659
Free blocks:              488051925
Free inodes:              1907317
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      907
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         128
Inode blocks per group:   8
Flex block group size:    16
Filesystem created:       Tue Dec 15 14:03:00 2015
Last mount time:          Tue Dec 15 14:03:47 2015
Last write time:          Tue Dec 15 14:03:47 2015
Mount count:              1
Maximum mount count:      24
Last checked:             Tue Dec 15 14:03:00 2015
Check interval:           15552000 (6 months)
Next check after:         Sun Jun 12 14:03:00 2016
Lifetime writes:          610 MB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   half_md4
Directory Hash Seed:      ad8fc829-1efe-4487-819d-1f4a2ac1eac4
Journal backup:           inode blocks
Journal features:         (none)
Journal size:             128M
Journal length:           32768
Journal sequence:         0x00000001
Journal start:            0

example source

參考 busybox 的df.c修改過來

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/vfs.h>

#define SIZE_KB         1024
#define SIZE_MB         (SIZE_KB*SIZE_KB)

static unsigned long kscale(unsigned long b, unsigned long bs)
{
    return (b * (unsigned long long) bs + 1024/2) / 1024;
}

void bkt_1(char *mount_point,char *dev_path){
    struct statfs s;
    unsigned long blocks_used;
    unsigned blocks_percent_used;

    if(statfs(mount_point,&s) != 0){
        printf("fail statfs");
        return;
    }

    printf("f_blocks :%09lu\n",(unsigned long)s.f_blocks);
    printf("f_bsize  :%09lu\n",(unsigned long)s.f_bsize);
    printf("f_bavail :%09lu\n",(unsigned long)s.f_bavail);
    printf("f_bfree  :%09lu\n",(unsigned long)s.f_bfree);

    printf("Filesystem           %-15sUsed Available %s Mounted on\n",
                        "1K-blocks", "Use%");

    blocks_used = s.f_blocks - s.f_bfree;
    blocks_percent_used = 0;
    if (blocks_used + s.f_bavail) {
        blocks_percent_used = (blocks_used * 100ULL + (blocks_used + s.f_bavail)/2) / (blocks_used + s.f_bavail);
    }

    printf("\n%-20s" + 1, dev_path);
    printf(" %9lu %9lu %9lu %3u%% %s\n",
        kscale(s.f_blocks, s.f_bsize),
        kscale(s.f_blocks - s.f_bfree, s.f_bsize),
        kscale(s.f_bavail, s.f_bsize),
        blocks_percent_used, mount_point);
}

int main(void){
    char mount_path[128];
    char dev_path[128];
    snprintf(mount_path,sizeof(mount_path),"%s","/media/sda1");
    printf("mount_path:%s\n",mount_path);
    snprintf(dev_path,sizeof(dev_path),"%s","/dev/sda1");
    printf("dev_path:%s\n",dev_path);
    bkt_1(mount_path,dev_path);
    return 0;
}

格式化問題

# umount -l /media/sda1
# mount
rootfs on / type rootfs (rw)
/dev/root on / type jffs2 (rw,relatime)
devtmpfs on /dev type devtmpfs (rw,relatime,size=295904k,nr_inodes=73976,mode=755)
proc on /proc type proc (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
tmpfs on /tmp type tmpfs (rw,relatime)
tmpfs on /dev/shm type tmpfs (rw,relatime,mode=777)
devpts on /dev/pts type devpts (rw,relatime,gid=5,mode=620)
/dev/mtdblock6 on /usr type cramfs (ro,relatime)
/dev/mtdblock8 on /opt/dvr_rdk/dvr_board type jffs2 (ro,relatime)
/dev/mtdblock9 on /mnt/nand type jffs2 (rw,relatime)
/dev/mtdblock10 on /mnt/log type jffs2 (rw,relatime)
# mkfs.ext4 -q -T largefile /dev/sda1
/dev/sda1 is apparently in use by the system; will not make a filesystem here!
#
即使umoun成功且無swapoff,也是無法format,,
 2529 root         0 SW   [kworker/0:0]
 3232 root         0 SW   [kworker/0:2]
 3233 root         0 SW   [flush-mtd-unmap]
 3240 root      161m S    /opt/dvr_rdk/dvr_board/bin/media
 3293 root      3180 S    -sh
 3296 root         0 SW   [flush-8:0]
 3299 root         0 Z    [telnetd]
 3300 root      3508 S    telnetd
 3303 root      3180 S    -sh
 3305 root      3180 R    ps
# /bin/busybox fuser -m /dev/sda1
3303 3300 3293 3240 676 11 
# kill 3240
# kill 676
# /bin/busybox fuser -m /dev/sda1
3303 3300 3293 11 
# mkfs.ext4 -q -T largefile /dev/sda1
#
kill 相關的process (media , upgrade , boa , dvrmain, ..等),就可以format
  • fuser
 /bin/busybox fuser -v
fuser: invalid option -- 'v'
BusyBox v1.16.1 (2013-07-17 17:28:26 CST) multi-call binary.

Usage: fuser [OPTIONS] FILE or PORT/PROTO

Find processes which use FILEs or PORTs

Options:
        -m      Find processes which use same fs as FILEs
        -4      Search only IPv4 space
        -6      Search only IPv6 space
        -s      Silent: just exit with 0 if any processes are found
        -k      Kill found processes (otherwise display PIDs)
        -SIGNAL Signal to send (default: TERM)