2016-07-11 6 views
2

Я пытаюсь использовать ioctl, чтобы изменения, записанные непосредственно на том, попали на диск. fsync(), очевидно, недоступен в необработанном разделе. синхронизации() является ужасным решением слишком (для того, чтобы избавиться 64Мбами, мне нужно все время жизни ждать в синхронизации)Как правильно очистить кеш диска с помощью ioctl (raw partition) в linux

так .. вот что я пытаюсь сделать - получение Errno 25.

/Dev/sda3 является сырья демонтирована раздел на диске SSD

open(_fd, "/dev/sda3", ...) 
pwritev(_fd, ...) 

ioctl(_fd, BLKFLSBUF, 0) <== errno = 25. 

Ubuntu 14.04, с

Примечание:

hdparm -W 0 /dev/sda3 

не работает: неудобно ioctl для устройства.

Как я могу найти подходящий метод мойки для моего ssd?

+0

Использует прямой ввод-вывод или/dev/raw вариант? –

+1

Что вы имеете в виду, * «fsync(), очевидно, недоступен в сыром разделе» *? 'fsync (_fd)' и 'fdatasync (_fd)' должны очищать содержимое до базового устройства, даже если '_fd' относится к блочному устройству. Фактическая промывка выполняется с помощью [fs/block_dev.c: blkdev_fsync()] (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/block_dev.c# n368) (через [fs/sync.c: fdatasync()] (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/sync.C# n230) → do_fsync() → vfs_fsync() → vfs_fsync_range(), затем blkdev_fsync() через структуру file_operations). –

+0

@MarkPlotnick - я открываю/dev/sda3. not/dev/raw. Я взял другую машину, где работал hdparam -W 0. Тем не менее ioctl не работает с errno = 25. Поэтому мой вопрос: могу ли я использовать ioctl BLKFLSHBUF на/dev/sdxN? – Adi

ответ

0

Я не могу дублировать ioctl(fd, BLKFLSBUF) ошибки в Ubuntu 14.04.4 LTS на x86_64 с использованием ядра 4.2.0-42.

Я тестировал как полноразмерные устройства, так и отдельные разделы на них. Не могли бы вы попробовать следующую минимальную тестовую программу?

Сохраните следующее, например. блок-flush.c:

#include <stdlib.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <sys/ioctl.h> 
#include <linux/fs.h> 
#include <string.h> 
#include <errno.h> 
#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
    int arg, descriptor, result; 

    if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 
     fprintf(stderr, "\n"); 
     fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]); 
     fprintf(stderr, "  %s BLOCK-DEVICE-OR-PARTITION ...\n", argv[0]); 
     fprintf(stderr, "\n"); 
     return EXIT_FAILURE; 
    } 

    for (arg = 1; arg < argc; arg++) { 

     do { 
      descriptor = open(argv[arg], O_RDWR); 
     } while (descriptor == -1 && errno == EINTR); 
     if (descriptor == -1) { 
      const int cause = errno; 
      fprintf(stderr, "%s: Cannot open device: %s [%d].\n", argv[arg], strerror(cause), cause); 
      return EXIT_FAILURE; 
     } 

     errno = 0; 
     result = ioctl(descriptor, BLKFLSBUF); 
     if (result && errno) { 
      const int cause = errno; 
      fprintf(stderr, "%s: Cannot flush device: %s [%d].\n", argv[arg], strerror(cause), cause); 
      return EXIT_FAILURE; 
     } else 
     if (result) 
      fprintf(stderr, "%s: Flush returned %d.\n", argv[arg], result); 
     else 
     if (errno) { 
      const int cause = errno; 
      fprintf(stderr, "%s: Flush returned zero, but with error: %s [%d]. Ignored.\n", argv[arg], strerror(cause), cause); 
     } 

     result = close(descriptor); 
     if (result == -1) { 
      const int cause = errno; 
      fprintf(stderr, "%s: Error closing device: %s [%d].\n", argv[arg], strerror(cause), cause); 
      return EXIT_FAILURE; 
     } 

     fprintf(stderr, "%s: Flushed.\n", argv[arg]); 
    } 

    return EXIT_SUCCESS; 
} 

Скомпилируйте его с помощью

gcc -Wall -O2 block-flush.c -o block-flush 

и запустить его (как корень), указывающий раздел (ы) или блочное устройство (ы) в командной строке:

sudo ./block-flush /dev/sda3 

для меня это выводит /dev/sdxN: Flushed. для немонтированных перегородок, а также дисков (/dev/sdx) сами. (Кроме того, добавление fdatasync(descriptor) до того, как ioctl() ничего не изменит, и он тоже успешно прошел без каких-либо ошибок.)

Кроме того, мне довелось проверить это с помощью внешней док-станции USB SATA и «громкого» 3,5-дюймового диска (такие доки, которые требуют внешнего питания, USB-мощность недостаточна для этих больших дисков с вращающимися планшетами). Я легко мог слышать, что ioctl() действительно имеет доступ к физическому устройству, поэтому он не является no-op (и, опять же, минимальная тестовая программа никогда не сообщала о каких-либо сбоях в моих тестах). После закрытия дескриптора диск также находится в состоянии покоя, пока диск или разделы не будут открыты для дальнейшего доступа. Конечно, эти наблюдения действительны только для жестких дисков, подключенных к USB, и только на эту конкретную ядерную и аппаратную архитектуру, но, на мой взгляд, это указывает на то, что ioctl(descriptor, BLKFLSBUF); должен работать для размонтированных partiti так и полноблочных устройств.