4

我的问题是处理稀疏文件读取并了解文件的范围在哪里围绕它执行一些逻辑。

由于没有直接的 API 调用来解决这些问题,我决定使用 ioctl api 来执行此操作。我从 cp 命令如何通过查看他们的代码来处理复制稀疏文件的问题得到了这个想法,并最终看到了这一点。

https://github.com/coreutils/coreutils/blob/df88fce71651afb2c3456967a142db0ae4bf9906/src/extent-scan.c#L112

因此,我尝试在用户空间中运行的示例程序中执行相同的操作,但出现“无效参数”错误。我不确定我错过了什么,或者这是否可能来自用户空间。我在 ext4 文件系统上的 ubuntu 14.04 上运行。这可能是设备驱动程序在下面支持这些请求模式的问题吗?

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/fcntl.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <linux/fs.h>
    #include "fiemap.h" //This is from https://github.com/coreutils/coreutils/blob/df88fce71651afb2c3456967a142db0ae4bf9906/src/fiemap.h

    int main(int argc, char* argv[]) {

        int input_fd;

        if(argc != 2){
            printf ("Usage: ioctl file1");
            return 1;
        }

        /* Create input file descriptor */
        input_fd = open (argv [1], O_RDWR);
        if (input_fd < 0) {
                perror ("open");
                return 2;
        }

        union { struct fiemap f; char c[4096]; } fiemap_buf;
        struct fiemap *fiemap = &fiemap_buf.f;
        int s = ioctl(input_fd, FS_IOC_FIEMAP, fiemap);

        if (s == 0) {
            printf("ioctl success\n");
        } else {
            printf("ioctl failure\n");
            char * errmsg = strerror(errno);
            printf("error: %d %s\n", errno, errmsg);
        }

        /* Close file descriptors */
        close (input_fd);

        return s;
    }
4

2 回答 2

3

由于您fiemap_buf.f在调用之前没有正确设置参数ioctl(),因此很可能EINVAL来自fiemap无效内容,而不是来自FS_IOC_FIEMAP请求标识符支持本身。

例如,ioctl_fiemap()(来自内核)将评估fiemap.fm_extent_count以确定它是否大于FIEMAP_MAX_EXTENTS-EINVAL在这种情况下返回。由于没有在 上执行内存重置或参数化fiemap,这很可能是问题的根本原因。

请注意,从您引用的代码中,它在调用之前coreutils执行了正确的参数化:fiemapioctl()

  fiemap->fm_start = scan->scan_start;
  fiemap->fm_flags = scan->fm_flags;
  fiemap->fm_extent_count = count;
  fiemap->fm_length = FIEMAP_MAX_OFFSET - scan->scan_start;
于 2016-07-30T02:05:11.630 回答
1

注意 fiemap 不推荐,因为您必须确保传递具有副作用的 FIEMAP_FLAG_SYNC。lseek()、SEEK_DATA 和 SEEK_HOLE 接口是推荐的接口,但请注意,根据文件系统,将未写入的范围(分配的零)表示为孔。

于 2016-07-30T19:39:27.633 回答