当文件系统不覆盖整个分区时,如何才能find文件系统在块设备上实际占用了多less空间?
考虑演示核心问题的基本示例:
dd if=/dev/zero bs=1024 count=20480 of=something.img losetup -f $PWD/something.img mke2fs /dev/loop0 mount /dev/loop0 /mnt
但是df -k /mnt
给出了这个输出:
Filesystem 1K-blocks Used Available Use% Mounted on /dev/loop0 19827 172 18631 1% /mnt
我创build了一个精确2048KB的设备,但statvfs()
系统调用(和上面显示的df
类似)报告文件系统仅占用19827KB。
看来, statvfs()
仅报告用户可用的块,但不报告文件系统的全部实际大小。
到目前为止,我只能find一个ext2 / 3/4特定的hacky 解决scheme : tune2fs -l /dev/loop0 | grep 'Block count:'
tune2fs -l /dev/loop0 | grep 'Block count:'
或者dumpe2fs -h /dev/loop0 | grep 'Block count:'
dumpe2fs -h /dev/loop0 | grep 'Block count:'
。 更清洁一点是使用libext2fs
库( e2fprogs
包的一部分)来读取超级块,但是我更喜欢文件系统中立的系统调用(如果可用的话)。
如果你正在寻找一个POSIX系统调用来检索设备级别的信息,我相信没有。
对于文件系统级别的信息(便携式)调用,据我所知,您将能够检索data blocks
的总数,而不是剩余的开销 (如inode tables
等)。
。
statvfs(2)
和fstatvfs(2)
将检索“可用”(又名data blocks
)文件系统级别信息(例如, vfat
, ext2
, ext3
…),而不是基础设备级别信息(例如/dev/loop0
, /dev/sda
,…)。
。
[ 编辑3 ]:不是什么操作系统正在寻找(这只是设备级信息,并不包括文件系统不映射整个设备的大小的情况下)。
在Linux下(假定是相对较新的内核版本),可以使用ioctl(2)
以字节为单位检索设备大小( blockdev(8)
执行的相同方法):
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <linux/fs.h> int main(void) { int fd = 0; unsigned long long size = 0; if (getuid() != 0) { puts("You need to be root."); exit(EXIT_FAILURE); } if ((fd = open("/dev/loop0", O_RDONLY)) < 0) { printf("open(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } if (ioctl(fd, BLKGETSIZE64, &size) < 0) { printf("ioctl(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } printf("%llu\n", size); return 0; }
编辑 :
正如评论中所讨论的那样,这是
device level information
,所以如果文件系统没有映射整个设备的大小,它不会解决问题(我们仍然不知道文件系统在设备中占用的总大小)。
。
恐怕你真的需要一切手工 一步一步来做。
你需要知道确切的文件系统,了解它的结构,并做所有的数学。 例如,在你的例子中,你正在使用一个20MiB的Ext2文件系统。 所以,结构看起来像这样(为了这个例子简化):
方块0 :
- 引导记录和额外引导记录数据: 1个块 (2 * 512字节)
。
块组0 :
超级块 : 1块 (1024字节)
块组描述符表,块位图和Inode位图: 3个块
Inode表: 214个块
数据块…
。
块组1 :
超级块 (备份): 1块
块组描述符表(备份),块位图和Inode位图: 3个块
Inode表: 214个块
数据块…
。
座组2 :
块位图和Inode位图: 2个块
Inode表: 214个块
数据块…
。
现在做数学 :
- 1 + 1 + 3 + 214 + 1 + 3 + 214 + 2 + 214 == 653
总和653到19827 (你可以用
statvfs(2)
检索):
- 653 + 19827 == 20480块
编辑2 :
正如在注释中所讨论的那样,ext2超级block count
已经包含了文件系统占用的块 (不仅像我以前认为的那样是可用的块)。 一个简单的测试来观察它(跳过错误检查简单的例子):
#include <stdio.h> #include <string.h> #include <inttypes.h> #include <sys/types.h> #include <unistd.h> #include <sys/types.h> #include <fcntl.h> struct ext2_super_block { uint32_t s_inodes_count; uint32_t s_blocks_count; uint32_t s_r_blocks_count; uint32_t s_free_blocks_count; uint32_t s_free_inodes_count; uint32_t s_first_data_block; uint32_t s_log_block_size; uint32_t s_dummy3[7]; unsigned char s_magic[2]; uint16_t s_state; uint32_t s_dummy5[8]; uint32_t s_feature_compat; uint32_t s_feature_incompat; uint32_t s_feature_ro_compat; unsigned char s_uuid[16]; char s_volume_name[16]; char s_last_mounted[64]; uint32_t s_algorithm_usage_bitmap; uint8_t s_prealloc_blocks; uint8_t s_prealloc_dir_blocks; uint16_t s_reserved_gdt_blocks; uint8_t s_journal_uuid[16]; uint32_t s_journal_inum; uint32_t s_journal_dev; uint32_t s_last_orphan; uint32_t s_hash_seed[4]; uint8_t s_def_hash_version; uint8_t s_jnl_backup_type; uint16_t s_reserved_word_pad; uint32_t s_default_mount_opts; uint32_t s_first_meta_bg; uint32_t s_mkfs_time; uint32_t s_jnl_blocks[17]; uint32_t s_blocks_count_hi; uint32_t s_r_blocks_count_hi; uint32_t s_free_blocks_hi; uint16_t s_min_extra_isize; uint16_t s_want_extra_isize; uint32_t s_flags; uint16_t s_raid_stride; uint16_t s_mmp_interval; uint64_t s_mmp_block; uint32_t s_raid_stripe_width; uint32_t s_reserved[163]; }; int main(void) { int fd = 0; struct ext2_super_block sb; /* Reset sb memory */ memset(&sb, 0, sizeof(struct ext2_super_block)); /* * /tmp/loop.img created with: * * dd if=/dev/zero bs=1024 count=20480 of=/tmp/loop.img * * ... and the ext2 file system maps the entire device. * */ fd = open("/tmp/loop.img", O_RDONLY); /* Jump to superblock */ lseek(fd, 1024, SEEK_SET); /* Read the superblock */ read(fd, &sb, sizeof(struct ext2_super_block)); /* Print the total block count */ printf("s_blocks_count: %" PRIu32 "\n", sb.s_blocks_count); /* Prints 20480 */ return 0; }
。
blockdev --getsize64 /dev/loop0
[ 编辑2 ]:这是设备级别的信息,这不是问题所指的。 dumpe2fs
, tune2fs
和类似的。