2016-07-11 24 views
2

Ich versuche, ioctl zu verwenden, um sicherzustellen, dass Änderungen direkt auf das Volume geschrieben werden. fsync() offensichtlich nicht in unformatierten Partition verfügbar. sync() ist zu schrecklich Lösung (um 64 MB zu spülen, i gesamte Lebensdauer müssen synchron warten)Wie man Festplattencache mit ioctl (rohe Partition) in Linux richtig flush

so .. hier ist das, was ich zu tun versucht - errno 25.

/dev bekommen/sda3 ist eine roh hängte Partition auf Solid State Laufwerk

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

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

Ubuntu 14.04, c

Hinweis:

hdparm -W 0 /dev/sda3 

schlägt fehl: Ungültige ioctl für Gerät.

Wie finde ich die geeignete Spülmethode für meine ssd?

+0

Verwendet direkte I/O oder/dev/rohe eine Option? –

+1

Was meinst du, * "fsync() offensichtlich nicht in rohen Partition" *? 'fsync (_fd)' und 'fdatasync (_fd)' sollten den Inhalt auf das zugrunde liegende Gerät übertragen, auch wenn '_fd' auf ein Block-Gerät verweist. Das eigentliche Flushing erfolgt durch [fs/block_dev.c: blkdev_fsync()] (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/block_dev.c# n368) (über [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(), dann blkdev_fsync() über die file_operations-Struktur). –

+0

@MarkPlotnick - Ich öffne/dev/sda3. nicht/dev/roh. Ich nahm eine andere Maschine, wo hdparam -W 0 arbeitete. Trotzdem schlägt ioctl mit errno = 25 fehl. Also meine Frage ist - kann ich ioctl BLKFLSHBUF auf/dev/sdxN verwenden? – Adi

Antwort

0

Ich kann nicht ioctl(fd, BLKFLSBUF) Fehler in Ubuntu 14.04.4 LTS auf x86_64 mit 4.2.0-42-generischen Kernel duplizieren.

Ich testete sowohl Vollblock-Geräte, und einzelne Partitionen auf ihnen. Könnten Sie das folgende minimale Testprogramm versuchen?

Speichern Sie das Folgende wie z. block 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; 
} 

kompilieren

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

verwenden und ausführen (root), in der die Partition (en) oder Block-Vorrichtung (en) in der Befehlszeile:

sudo ./block-flush /dev/sda3 

für mich gibt diese /dev/sdxN: Flushed. für post Partitionen sowie die Scheiben (/dev/sdx) selbst. (Auch das Hinzufügen von fdatasync(descriptor) vor dem ioctl() ändert nichts, und es gelingt auch ohne Fehler.)

Auch das habe ich zufällig mit einer externen USB-SATA-Dockingstation und einem "lauten" 3,5 "Laufwerk zu testen (Solche Docks benötigen externe Stromversorgung; die USB-Stromversorgung reicht für diese größeren Laufwerke mit rotierenden Platten nicht aus.) Ich könnte leicht hören, dass das ioctl() auf das physische Gerät zugreift, also kein No-Op ist (und wiederum das (Das minimale Testprogramm hat in meinen Tests keine Fehler gemeldet.) Nach dem Schließen des Deskriptors ist die Festplatte auch so lange inaktiv, bis die Festplatte oder die Partitionen für weitere Zugriffe geöffnet werden.Natürlich gelten diese Beobachtungen nur für USB-verbundene Festplatten auf dieser speziellen Kernel-und Hardware-Architektur, aber meiner Meinung nach, zeigt es, dass die ioctl(descriptor, BLKFLSBUF); sollte für unmounted partiti arbeiten Ons und Full-Block-Geräte, in der erwarteten Weise.