Windows retarde l'écriture de la table FAT sur une petite clé USB malgré un «retrait rapide»

10

Je constate des écritures différées dans le FAT sur un lecteur flash USB formaté FAT (FAT12) de petite capacité, même si la politique du lecteur est définie sur «Suppression rapide». (Je crois que cela signifie que le SurpriseRemovalOKdrapeau est réglé). J'ai capturé les commandes SCSI envoyées au lecteur via USB: les écritures de troncature de fichier se produisent immédiatement, le fichier entier (2 secteurs de 512 octets de long) est écrit immédiatement après cela, mais il y a ensuite un délai de 20 à 90 secondes avant le FAT est mis à jour pour refléter l'écriture du fichier.

La taille du disque est importante. J'ai testé avec et je vois des problèmes sur les systèmes de fichiers FAT de taille 15 Mo et moins. Sur 16 Mo et plus, les écritures ne sont pas retardées. 16 Mo est le point d'arrêt que je vois entre l'utilisation de FAT12 et FAT16 lorsque je formate un lecteur sous Windows. (Remarque ajoutée plus tard: mais le point d'arrêt FAT12 / FAT16 dépend du nombre de clusters, et non de la taille absolue du système de fichiers).

Sur 16 Mo et plus, Windows envoie des Prevent/Allow Medium Removalcommandes SCSI avant les écritures, demandant que le périphérique ne soit pas supprimé. La clé USB renvoie en fait un échec à ces demandes (car elle ne peut garantir aucune suppression), mais Windows essaie quand même. Les 15 Mo et les traces plus petites ne montrent aucunePrevent/Allow Medium Removal commande.

(J'ai découvert ce problème en utilisant une carte de microcontrôleur qui prend en charge un petit système de fichiers FAT contenant du code Python. Lorsque le microcontrôleur détecte une écriture dans le système de fichiers, il attend un peu que l'écriture se termine, puis redémarre automatiquement et exécute le code Python nouvellement écrit Mais le microcontrôleur voyait du code corrompu ou un système de fichiers corrompu en raison de l'écriture retardée.)

Pourquoi l'écriture dans le FAT est-elle retardée si longtemps, malgré le "retrait rapide" défini? Je peux forcer les écritures en faisant un "Eject" sur le lecteur mais cela va à l'encontre de la promesse de "Quick Removal". Si je tirais le disque tôt, il y aurait une table FAT incorrecte. Cela dément la déclaration de la capture d'écran ci-dessous à propos de ne pas avoir à utiliser "Retirer le matériel en toute sécurité". Est-ce un bug ou est-ce que je manque quelque chose? Existe-t-il un moyen de forcer toutes les écritures à se produire immédiatement sans "éjection" manuelle?

Clé USB définie sur Retrait rapide

Voici un extrait élagué d'une trace Wireshark / USBPcap montrant le problème. Je tronque un fichier existant, puis j'en écris une nouvelle copie. J'ai ajouté des commentaires avec ###. La plupart des écritures sur la clé USB ont lieu environ 5 secondes après la trace, mais l'écriture finale en FAT ne dure que 26 secondes.

No.    Time  Source       Destination  Protocol  Length  Info
    ### write directory entry to truncate file
13 5.225586    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x00000041, Len: 8)
14 5.225838    host         1.2.2        USB      4123   URB_BULK out
    ### write FAT entries to truncate file
16 5.230488    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x0000003b, Len: 1)
17 5.230707    host         1.2.2        USB      539    URB_BULK out
19 5.235110    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x0000003e, Len: 1)
20 5.235329    host         1.2.2        USB      539    URB_BULK out
    ### write directory entry for 
22 5.252672    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x00000041, Len: 8)
23 5.252825    host         1.2.2        USB      4123   URB_BULK out
    ### write out file data (2 sectors of 512 bytes)
25 5.257416    host         1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x000000c1, Len: 2)
26 5.257572    host         1.2.2        USB      1051   URB_BULK out
    ### 20 second delay
    ### finally, write FAT entries to indicate used sectors
79 26.559964      host      1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x0000003b, Len: 1)
80 26.560191      host      1.2.2        USB      539    URB_BULK out
82 26.560834      host      1.2.2        USBMS    58     SCSI: Write(10) LUN: 0x00 (LBA: 0x0000003e, Len: 1)
83 26.560936      host      1.2.2        USB      539    URB_BULK out

J'ai généré des traces comme celle-ci à l'aide d'un lecteur flash standard et également avec une carte microcontrôleur qui émule un minuscule lecteur USB MSC, à la fois sur Windows 7 et Windows 10.

Juste pour être clair, il s'agit d'un lecteur au format FAT12, juste appelé "FAT" dans l'outil de formatage Windows.

Dan Halbert
la source
1
Êtes-vous simplement curieux? Ou êtes-vous confronté à un scénario dans lequel vous devez utiliser un système de fichiers FAT16?
Je dis Rétablir Monica le
2
J'aide à tester une carte microcontrôleur (Adafruit Feather M0 et apparenté) exécutant une variante de MicroPython (CircuitPython). Il possède un petit système de fichiers FAT contenant du code Python. Pour plus de commodité, la carte est configurée pour se réinitialiser automatiquement et exécuter main.pydes fichiers similaires lorsqu'elle détecte que le fichier a été écrit. Cela retarde un peu la fin de l'écriture, mais pas des dizaines de secondes. Nous pouvons désactiver ce redémarrage automatique, mais il est toujours nécessaire d '"éjecter" le lecteur pour vous assurer que l'écriture se termine en temps opportun. Obliger l'utilisateur à effectuer une éjection est une nuisance; nous aimerions éviter cela.
Dan Halbert
Veuillez envisager d'éditer au début de votre question une brève explication à ce sujet. C'est un bon contexte de base.
Je dis Reinstate Monica
Bonne suggestion. Terminé.
Dan Halbert

Réponses:

4

J'ai peut-être trouvé le code de pilote Windows réel à l'origine du problème.

Il se trouve que MS inclut le pilote du système de fichiers FAT dans un package d'exemple de code de pilote. Il y a plusieurs endroits dans ce pilote où, si le système de fichiers est FAT12, le pilote ne prendra pas la peine de faire quelque chose comme définir le bit sale (peut-être il n'y en a pas pour FAT12) ou vider les données FAT.

https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/verfysup.c#L774 https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys /fastfat/cachesup.c#L1212 et peut-être le plus critique: https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/cleanup.c#L1101

Dans le dernier lien, dans cleanup.c, le FAT n'est pas vidé si le système de fichiers est FAT12. Je pense que cela peut être à l'origine du comportement que je vois:

    //
    //  If that worked ok,  then see if we should flush the FAT as well.
    //

    if (NT_SUCCESS(Status) && Fcb && !FatIsFat12( Vcb) && 
        FlagOn( Fcb->FcbState, FCB_STATE_FLUSH_FAT)) {

        Status = FatFlushFat( IrpContext, Vcb);

Signalé à Microsoft dans Windows Feedback Hub à https://aka.ms/btvdog (URL spéciale qui s'ouvre dans Feedback Hub).

Dan Halbert
la source