2016-07-11 2 views
2

J'essaie d'utiliser ioctl pour m'assurer que les changements écrits directement sur le volume touchent le disque. fsync() n'est évidemment pas disponible en partition brute. synchronisation() est une solution terrible aussi (pour rincer 64MB, je besoin de temps de vie à attendre la synchronisation)Comment vider correctement le cache disque en utilisant ioctl (partition brute) sous Linux

donc .. voici ce que je suis en train de faire - obtenir errno 25.

/dev/sda3 est un brut partition non montée sur SSD

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

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

Ubuntu 14,04, c

note:

hdparm -W 0 /dev/sda3 

échoue le: ioctl inapproprié pour l'appareil.

comment puis-je trouver la méthode de rinçage appropriée pour mon ssd?

+0

L'utilisation d'E/S directes ou/dev/raw est-elle une option? –

+1

Que voulez-vous dire, * "fsync() évidemment pas disponible dans la partition brute" *? 'fsync (_fd)' et 'fdatasync (_fd)' devraient vider le contenu du périphérique sous-jacent même si '_fd' fait référence à un périphérique bloc. Le vidage réel est effectué par [fs/block_dev.c: blkdev_fsync()] (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/block_dev.c# n368) (via [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(), puis blkdev_fsync() via la structure file_operations). –

+0

@MarkPlotnick - J'ouvre/dev/sda3. pas/dev/raw. J'ai pris une autre machine où hdparam -W 0 a travaillé. Encore ioctl échoue avec errno = 25. Donc ma question est - puis-je utiliser ioctl BLKFLSHBUF sur/dev/sdxN? – Adi

Répondre

0

Je ne peux pas reproduire les erreurs ioctl(fd, BLKFLSBUF) dans Ubuntu 14.04.4 LTS sur x86_64 en utilisant le noyau 4.2.0-42-generic.

J'ai testé à la fois les périphériques à bloc complet et les partitions individuelles. Pourriez-vous essayer le programme de test minimal suivant?

Conservez ce qui suit, par ex. bloc-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; 
} 

Compiler en utilisant

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

et l'exécuter (en root), en spécifiant la cloison (s) ou dispositif de bloc (s) à la ligne de commande:

sudo ./block-flush /dev/sda3 

pour moi, cette commande affiche /dev/sdxN: Flushed. pour les partitions non montées, ainsi que les disques (/dev/sdx) eux-mêmes. (En outre, ajouter fdatasync(descriptor) avant que l'ioctl() ne change rien, et il réussit aussi sans aucune erreur.)

Aussi, il m'est arrivé de tester cela en utilisant une station d'accueil USB SATA externe et un "fort" 3,5 "lecteur (ces docks ont besoin d'une alimentation externe, l'alimentation USB n'est pas suffisante pour ces disques plus grands avec des plateaux tournants.) Je pourrais facilement entendre que l'ioctl() accède au périphérique physique, donc ce n'est pas un no-op (et, programme de test minimal n'a jamais signalé d'échecs dans mes tests.) Après la fermeture du descripteur, le disque est également au repos jusqu'à ce que le disque ou les partitions soient ouverts pour d'autres accès.Bien entendu, ces observations ne sont valables que pour les disques durs USB connectés. sur ce noyau particulier et l'architecture matérielle, mais à mon avis, il indique que le ioctl(descriptor, BLKFLSBUF); devrait fonctionner pour partiti démonté ons on et full block devices, de la manière attendue.