2016-07-30 3 views
4

Моя проблема состоит в том, чтобы иметь дело с разреженным чтением файлов и понимать, где экстенты файла должны выполнять некоторую логику вокруг него.Как использовать ioctl с FS_IOC_FIEMAP

Поскольку нет прямого вызова API, чтобы определить эти данные, я решил использовать ioctl api для этого. Я понял, как команда cp занимается проблемами копирования более разреженных файлов, просматривая их код и заканчивая тем, что видит это.

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

Итак, я попытался сделать то же самое в моей программе образца работает в пользовательском пространстве, и оно ошибка вне с «недопустимым аргументом». Я не уверен, что мне не хватает или это возможно даже из пользовательского пространства. Я запускаю ubuntu 14.04 в файловой системе ext4. Это может быть проблема с драйвером устройства, поддерживающим эти режимы запроса ниже?

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

ответ

3

Как вы не правильно настроек fiemap_buf.f параметров перед вызовом ioctl(), вполне вероятно, что EINVAL исходит из fiemap недействительного содержания, чем от самой поддержки идентификатора FS_IOC_FIEMAP запроса.

Например, ioctl_fiemap() (от ядра) будет оценивать fiemap.fm_extent_count для того, чтобы определить, если он больше, чем FIEMAP_MAX_EXTENTS и возвращение -EINVAL в этом случае. Так как сброс памяти и параметризация не выполняется на fiemap, это, скорее всего, является основной причиной проблемы.

Обратите внимание, что из 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; 
+1

Инициализация fiemap работала! Большое спасибо! – Aila

1

Примечание fiemap не рекомендуется, так как вы должны быть уверены, чтобы пройти FIEMAP_FLAG_SYNC, который имеет побочные эффекты. Интерфейсы lseek(), SEEK_DATA и SEEK_HOLE рекомендуются, хотя обратите внимание, что в зависимости от файловой системы будут отображаться неписанные экстенты (выделенные нули) в виде отверстий.

+0

Спасибо за предложение. Мы попытались использовать SEEK_DATA и SEEK_HOLE с lseek, но похоже, что он поддерживается только с более высокой версией ядра Linux для файловой системы xfs, чем тот, на котором мы находимся. Итак, нам пришлось прибегнуть к ioctl. Я как бы новичок в этом низкоуровневом программировании, не могли бы вы посоветовать, какие могут быть побочные эффекты с флагом FIEMAP_FLAG_SYNC? – Aila

+0

Синхронизация может иметь большие последствия для производительности, и ее следует избегать, когда это возможно – pixelbeat

Смежные вопросы