How to use ioctl with FS_IOC_FIEMAP

My problem is to deal with sparse file reading and understand where the extents of the file should perform some logic around it.

Since there is no direct API call to determine this data, I decided to use the ioctl api for this. I realized how the cp team deals with the problems of copying more sparse files, looking at their code and ending with seeing it.

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

So, I tried to do the same in my sample program running in user space, and he made a mistake with "Invalid argument". I'm not sure what I am missing or is it possible even from user space. I am running ubuntu 14.04 on an ext4 file system. Could this be a problem with a device driver that supports these request modes below?

    #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
source share
2 answers

As you do not correctly set the parameters fiemap_buf.fbefore the call ioctl(), it is likely that it EINVALcomes from invalid content fiemapthan from the support of the request identifier itself FS_IOC_FIEMAP.

, ioctl_fiemap() ( ) fiemap.fm_extent_count, , , FIEMAP_MAX_EXTENTS -EINVAL . fiemap reset , , , .

, coreutils, , fiemap ioctl():

  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;
+3

. fiemap , FIEMAP_FLAG_SYNC, . lseek(), SEEK_DATA SEEK_HOLE , , ( ) .

+1

Source: https://habr.com/ru/post/1649602/


All Articles