正确地将 statvfs 转换为可用百分比
我有一个非常简单的测试程序,可以打印出以下数字。
ie
int main(int argc, char* argv[])
struct statvfs vfs;
statvfs(argv[1], &vfs);
printf("f_bsize (block size): %lu\n"
"f_frsize (fragment size): %lu\n"
"f_blocks (size of fs in f_frsize units): %lu\n"
"f_bfree (free blocks): %lu\n"
"f_bavail free blocks for unprivileged users): %lu\n"
"f_files (inodes): %lu\n"
"f_ffree (free inodes): %lu\n"
"f_favail (free inodes for unprivileged users): %lu\n"
"f_fsid (file system ID): %lu\n"
"f_flag (mount flags): %lu\n"
"f_namemax (maximum filename length)%lu\n",
vfs.f_bsize,
vfs.f_frsize,
vfs.f_blocks,
vfs.f_bfree,
vfs.f_bavail,
vfs.f_files,
vfs.f_ffree,
vfs.f_favail,
vfs.f_fsid,
vfs.f_flag,
vfs.f_namemax);
return 0;
}
打印出:
f_bsize (block size): 4096
f_frsize (fragment size): 4096
f_blocks (size of fs in f_frsize units): 10534466
f_bfree (free blocks): 6994546
f_bavail free blocks for unprivileged users): 6459417
f_files (inodes): 2678784
f_ffree (free inodes): 2402069
f_favail (free inodes for unprivileged users): 2402069
f_fsid (file system ID): 12719298601114463092
f_flag (mount flags): 4096
f_namemax (maximum filename length)255
df 打印出根 fs:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 42137864 14159676 25837672 36% /
但这是我感到困惑的地方。
25837672+14159676!= 42137846(实际上是39997348)
因此,如果我要进行计算 14159676 / 42137864 * 100 我得到 33% 而不是 36% 作为 df 打印。
但如果我计算
14159676 / 39997348 * 100 我得到 35%。
为什么会出现这些差异? df 从哪里得到 42137864 这个数字?这是否与 1k 块与实际系统块大小(4k)的转换有关?
这将集成到我的缓存应用程序中,告诉我驱动器何时处于某个阈值...例如,在我开始释放大小为 2^n 大小的固定大小块之前的 90%。 所以我想要的是一个能够给我一个相当准确的 %used 的函数。
编辑: 我现在可以匹配 df 打印的内容。除了 %Used 之外。这让我们想知道这一切有多准确。碎片大小是多少?
unsigned long total = vfs.f_blocks * vfs.f_frsize / 1024;
unsigned long available = vfs.f_bavail * vfs.f_frsize / 1024;
unsigned long free = vfs.f_bfree * vfs.f_frsize / 1024;
printf("Total: %luK\n", total);
printf("Available: %luK\n", available);
printf("Used: %luK\n", total - free);
EDIT2:
unsigned long total = vfs.f_blocks * vfs.f_frsize / 1024;
unsigned long available = vfs.f_bavail * vfs.f_frsize / 1024;
unsigned long free = vfs.f_bfree * vfs.f_frsize / 1024;
unsigned long used = total - free;
printf("Total: %luK\n", total);
printf("Available: %luK\n", available);
printf("Used: %luK\n", used);
printf("Free: %luK\n", free);
// Calculate % used based on f_bavail not f_bfree. This is still giving out a different answer to df???
printf("Use%%: %f%%\n", (vfs.f_blocks - vfs.f_bavail) / (double)(vfs.f_blocks) * 100.0);
f_bsize (block size): 4096
f_frsize (fragment size): 4096
f_blocks (size of fs in f_frsize units): 10534466
f_bfree (free blocks): 6994182
f_bavail (free blocks for unprivileged users): 6459053
f_files (inodes): 2678784
f_ffree (free inodes): 2402056
f_favail (free inodes for unprivileged users): 2402056
f_fsid (file system ID): 12719298601114463092
f_flag (mount flags): 4096
f_namemax (maximum filename length)255
Total: 42137864K
Available: 25836212K
Used: 14161136K
Free: 27976728K
Use%: 38.686470%
matth@kubuntu:~/dev$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 42137864 14161136 25836212 36% /
我得到 38% 而不是 36。如果由 f_bfree 计算,我得到 33%。 df 是错误的还是这永远不会准确?如果是这样的话,那么我想倾向于保守。
I have a terribly uncomplicated test program that prints out the following numbers.
i.e.
int main(int argc, char* argv[])
struct statvfs vfs;
statvfs(argv[1], &vfs);
printf("f_bsize (block size): %lu\n"
"f_frsize (fragment size): %lu\n"
"f_blocks (size of fs in f_frsize units): %lu\n"
"f_bfree (free blocks): %lu\n"
"f_bavail free blocks for unprivileged users): %lu\n"
"f_files (inodes): %lu\n"
"f_ffree (free inodes): %lu\n"
"f_favail (free inodes for unprivileged users): %lu\n"
"f_fsid (file system ID): %lu\n"
"f_flag (mount flags): %lu\n"
"f_namemax (maximum filename length)%lu\n",
vfs.f_bsize,
vfs.f_frsize,
vfs.f_blocks,
vfs.f_bfree,
vfs.f_bavail,
vfs.f_files,
vfs.f_ffree,
vfs.f_favail,
vfs.f_fsid,
vfs.f_flag,
vfs.f_namemax);
return 0;
}
Prints out:
f_bsize (block size): 4096
f_frsize (fragment size): 4096
f_blocks (size of fs in f_frsize units): 10534466
f_bfree (free blocks): 6994546
f_bavail free blocks for unprivileged users): 6459417
f_files (inodes): 2678784
f_ffree (free inodes): 2402069
f_favail (free inodes for unprivileged users): 2402069
f_fsid (file system ID): 12719298601114463092
f_flag (mount flags): 4096
f_namemax (maximum filename length)255
df prints out for the root fs:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 42137864 14159676 25837672 36% /
But here is where I'm confused.
25837672+14159676 != 42137846 (actually 39997348)
Therefore if I were to do the calc 14159676 / 42137864 * 100 I get 33% not 36% as df prints.
But if I calc
14159676 / 39997348 * 100 I get 35%.
Why all the discrepencies and where is df getting the number 42137864? Is it related to some conversion to 1k blocks vs the actual system block size which is 4k?
This will be integrated into my caching app to tell me when the drive is at some threshold... e.g. 90% before I start freeing fixed size blocks that are sized in 2^n sizing.
So what I'm after is a function that gives me a reasonably accurate %used.
EDIT:
I can now match what df prints. Except for the %Used. It makes we wonder how accurate all this is. What is the fragment size?
unsigned long total = vfs.f_blocks * vfs.f_frsize / 1024;
unsigned long available = vfs.f_bavail * vfs.f_frsize / 1024;
unsigned long free = vfs.f_bfree * vfs.f_frsize / 1024;
printf("Total: %luK\n", total);
printf("Available: %luK\n", available);
printf("Used: %luK\n", total - free);
EDIT2:
unsigned long total = vfs.f_blocks * vfs.f_frsize / 1024;
unsigned long available = vfs.f_bavail * vfs.f_frsize / 1024;
unsigned long free = vfs.f_bfree * vfs.f_frsize / 1024;
unsigned long used = total - free;
printf("Total: %luK\n", total);
printf("Available: %luK\n", available);
printf("Used: %luK\n", used);
printf("Free: %luK\n", free);
// Calculate % used based on f_bavail not f_bfree. This is still giving out a different answer to df???
printf("Use%%: %f%%\n", (vfs.f_blocks - vfs.f_bavail) / (double)(vfs.f_blocks) * 100.0);
f_bsize (block size): 4096
f_frsize (fragment size): 4096
f_blocks (size of fs in f_frsize units): 10534466
f_bfree (free blocks): 6994182
f_bavail (free blocks for unprivileged users): 6459053
f_files (inodes): 2678784
f_ffree (free inodes): 2402056
f_favail (free inodes for unprivileged users): 2402056
f_fsid (file system ID): 12719298601114463092
f_flag (mount flags): 4096
f_namemax (maximum filename length)255
Total: 42137864K
Available: 25836212K
Used: 14161136K
Free: 27976728K
Use%: 38.686470%
matth@kubuntu:~/dev$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 42137864 14161136 25836212 36% /
I get 38% not 36. If calculated by f_bfree I get 33%. Is df wrong or is this just never going to be accurate? If this is the case then I want to lean on the side of being conservative.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
df
的数据可能基于f_bavail
,而不是f_bfree
。您可能会发现查看 df 源代码 了解它是如何工作的会很有帮助。它需要处理许多边缘情况(例如,当已用空间超过非 root 用户可用的空间量时),但正常情况的相关代码在这里:换句话说,
100 * 已使用/(已使用 + 可用)
,四舍五入。代入 df 输出中的值,得到100 * 14159676 / (14159676 + 25837672) = 35.4015371
,四舍五入为 36%,正如df
的计算结果一样。df
's data may be based onf_bavail
, notf_bfree
. You may find it helpful to look at the source code to df to see how it does things. It has a number of edge cases it needs to deal with (eg, when the used space exceeds the amount of space available to non-root users), but the relevant code for the normal case is here:In other words,
100 * used / (used + available)
, rounded up. Plugging in the values from your df output gives100 * 14159676 / (14159676 + 25837672) = 35.4015371
, which rounded up is 36%, just asdf
calculated.在编辑 #2 上,Usage% 计算需要更新为此以匹配 df 输出:
推理:
使用 = f_blocks - f_bfree
可用 = f_bavail
df % = 已使用 / (已使用 + 可用)
On your Edit #2, the Usage% calculation needs to be updated to this to match df output:
Reasoning:
Used = f_blocks - f_bfree
Avail = f_bavail
df % = Used / (Used + Avail)
这是我最接近的匹配 df -h 输出的已用百分比:
This is the closest I've got to matching the output of
df -h
for used percentage:statvfs 指标有点令人困惑。您可以使用 psutil 源代码作为示例,了解如何获取有意义的字节值: https://github.com/giampaolo/psutil/blob/f4734c80203023458cb05b1499db611ed4916af2/psutil/_psposix.py#L119
statvfs metrics are kinda confusing. You can use psutil source code as an example on how to get meaningful values in bytes: https://github.com/giampaolo/psutil/blob/f4734c80203023458cb05b1499db611ed4916af2/psutil/_psposix.py#L119
这是一个模仿
df
:例如,它可能返回
39.623889
,而df
输出40%
(四舍五入值)。Here is an implementation that mimics the behavior of
df
:E.g. it may return
39.623889
whiledf
outputs40%
(rounded value).每当我处理这个问题时,我似乎都会感到困惑。我希望以下 C 代码对寻找已用空间百分比的人有所帮助:
It seems I get confused whenever I deal with this issue. I hope the following C code is helpful to someone looking for percentage of used space: