7

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

4

2 回答 2

3

您可以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的文件系统中,并且位于支持此类文件的文件系统中。

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

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

于 2016-08-02T13:33:22.197 回答
1

这是一个非常简单的 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,这意味着创建了一个稀疏文件。

另请参阅:为什么 `du` 的输出通常与 `du -b` 如此不同

于 2019-04-04T10:53:24.623 回答