文件系统占用的全部空间

时间:2016-07-04 15:13:14

标签: linux filesystems posix

当文件系统没有覆盖整个分区时,如何找到文件系统在块设备上实际占用的空间?

考虑演示核心问题的基本示例:

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

我创建了一个精确为2048KB的设备,但是statvfs()系统调用(以及上面显示的类似df)报告文件系统只需要19827KB。

似乎statvfs()仅报告可供用户使用的块,但不报告文件系统的完整实际大小。

到目前为止,我只能找到特定于ext2 / 3/4的 hacky 解决方案tune2fs -l /dev/loop0 | grep 'Block count:'dumpe2fs -h /dev/loop0 | grep 'Block count:'。更清洁的是使用libext2fs库(e2fprogs包的一部分)来读取超级块,但我更喜欢文件系统中立系统调用(如果可用)。

1 个答案:

答案 0 :(得分:1)

如果您正在寻找POSIX系统调用来检索设备级信息,我相信没有。

对于文件系统级信息[便携式]通话,据我所知,您可以检索data blocks的总数,但不能检索剩余的开销 (例如inode tables等)。

问题

statvfs(2)fstatvfs(2)将检索"可用" (又名data blocks)文件系统级信息(例如vfatext2ext3 ...),而不是底层设备级信息(例如/dev/loop0 },/dev/sda,...)。

[部分/可能]非便携式解决方案

  

[编辑3 ]:不是OP正在寻找的(这是设备级别   仅供参考,不包括文件系统的情况   不映射整个设备大小。)

在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;
}

最后一些想法

  • 亲手操作只是疯了,IMO(你必须有一个非常非常好的理由这样做:))[编辑2 ]:它比我之前想象的要简单,[可能]所有文件系统超级块[可能]包含总块数(参见相关讨论的答案评论)。
  • 如果我是你,我会评估该代码应该运行多少个不同的操作系统,并且只使用非便携式调用实现设备级信息收集器(即它们)每个操作系统提供的直接系统调用[如果有的话]或库实现。然后,构建过程将能够确定和配置代码以在目标机器上正确编译[ EDIT 2 ]:这仍然是最好的方法(利用相应的文件系统库)。
  • 如果您真的不想(或需要)编写任何代码,而您只是在寻找特定于Linux的命令行工具来检索此类数据(在设备级别),请使用:{ {1}} [编辑2 ]:这是设备级信息,而不是问题所指的内容。
  • [编辑]否则,如果设备级别信息不够(在文件系统仅映射部分设备大小的情况下),你已经得到了答案:blockdev --getsize64 /dev/loop0dumpe2fs等等。