【问题标题】:How to test if sparse file is supported如何测试是否支持稀疏文件
【发布时间】:2016-08-02 11:12:55
【问题描述】:

给定一个文件描述符或文件名,我如何知道是否可以写入任意位置而无需等待中间部分在磁盘上显式归零?

【问题讨论】:

    标签: unix io filesystems posix sparse-file


    【解决方案1】:

    您可以stat()文件获取文件大小和磁盘块数,在文件末尾寻找相对少量的磁盘块,写入已知块数,然后再次统计文件。将磁盘块的原始数量与最终数量进行比较。如果文件系统不支持稀疏文件,那么几个磁盘块的写入时间应该不会太长。

    给定磁盘块的原始和最终数量,然后尝试确定文件系统是否支持稀疏文件。我说“尝试”是因为某些文件系统会使这变得困难 - 例如,启用压缩的 ZFS。

    类似这样的:

    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    
    int check( const char *filename )
    {
        struct stat sb;
        long blocksize;
        off_t filesize;
        blkcnt_t origblocks;
        char *buffer;
        int fd;
    
        fd = open( filename, O_CREAT | O_RDWR, 0644 );
    
        fstat( fd, &sb );
        blocksize = sb.st_blksize;
        filesize = sb.st_size;
        origblocks = sb.st_blocks;
    
        lseek( fd, 16UL * blocksize, SEEK_END );
    
        buffer = malloc( blocksize );
        memset( buffer, 0xAA, blocksize );
    
        write( fd, buffer, blocksize );
        fsync( fd );
    
        free( buffer );
    
        // kludge to give ZFS time to update metadata
        for ( ;; )
        {
            stat( filename, &sb );
            if ( sb.st_blocks != origblocks )
            {
                break;
            }
        }
    
        printf( "file: %s\n filesystem: %s\n blocksize: %d\n size: %zd\n"
            " blocks: %zd\n orig blocks: %zd\n disk space: %zd\n",
            filename, sb.st_fstype, blocksize, sb.st_size,
            ( size_t ) sb.st_blocks, ( size_t ) origblocks,
            ( size_t ) ( 512UL * sb.st_blocks ) );
    
        // return file to original size
        ftruncate( fd, filesize );
        return( 0 );
    }
    
    int main( int argc, char **argv )
    {
        for ( int ii = 1; ii < argc; ii++ )
        {
            check( argv[ ii ] );
        }
    
        return( 0 );
    }
    

    (为清楚起见省略了错误检查)

    启用压缩的 ZFS 似乎无法快速更新文件元数据,因此会等待更改出现。

    当在带有文件asdf(ZFS 文件系统,启用压缩)/tmp/asdf(tmpfs 文件系统)和/var/tmp/asdf(ZFS,无压缩)的 Solaris 11 机器上运行时,该代码会产生以下输出:

    file: asdf
     filesystem: zfs
     blocksize: 131072
     size: 2228224
     blocks: 10
     orig blocks: 1
     disk space: 5120
    file: /tmp/asdf
     filesystem: tmpfs
     blocksize: 4096
     size: 69632
     blocks: 136
     orig blocks: 0
     disk space: 69632
    file: /var/tmp/asdf
     filesystem: zfs
     blocksize: 131072
     size: 2228224
     blocks: 257
     orig blocks: 1
     disk space: 131584
    

    从该输出中,很明显/tmp/asdf 位于不支持稀疏文件的文件系统中,而/var/tmp/asdf 位于支持此类文件的文件系统中。

    而普通的asdf 则完全是另一回事,其中写入 128 kB 的数据会添加所有 9 512 字节的磁盘块。由此,您可以推断出文件系统中正在进行某种压缩。顺便说一句,我怀疑假设任何支持这种本机压缩的文件系统也将支持稀疏文件是非常安全的。

    在给出文件名或打开文件描述符时确定文件系统是否支持稀疏文件的最快方法是在文件名上调用 stat() 或在文件描述符上调用 fstat(),从 @ 获取 st_fstype 字段987654333@,并将文件的文件系统类型与一组已知支持稀疏文件的文件系统类型字符串进行比较。

    【讨论】:

      【解决方案2】:

      这是一个非常简单的 CLI 交互式测试,但如果 dudu --apparent 不同,您可以非常确定文件系统支持稀疏文件。

      例如在 ext4 分区上,当我这样做时:

      dd seek=1G if=/dev/zero of=f bs=1 count=1 status=none
      du --block-size=1 f
      du --block-size=1 --apparent f
      

      它给了我:

      8192    f
      1073741825      f
      

      所以 1GB 表观大小的文件实际上只占用了 8KB,这意味着创建了一个稀疏文件。

      另请参阅:why is the output of `du` often so different from `du -b`

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-05
        • 1970-01-01
        • 2020-06-18
        • 2013-01-07
        • 1970-01-01
        • 2018-04-13
        • 2018-05-26
        • 2011-04-02
        相关资源
        最近更新 更多