System Windows opóźnia pisanie tabeli FAT na małym dysku USB pomimo „szybkiego usuwania”

10

Widzę opóźnione zapisy w systemie FAT na sformatowanym dysku flash USB o małej pojemności (FAT12), mimo że dla tego dysku wybrano ustawienie „Szybkie usuwanie”. (Wierzę, że to oznacza, że SurpriseRemovalOKflaga jest ustawiona). Przechwyciłem polecenia SCSI wysyłane na dysk przez USB: zapisy obcinania plików odbywają się natychmiast, cały plik (długość 2 512 bajtów sektorów) jest zapisywany natychmiast po tym, ale potem jest FAT o 20-90 sekund jest aktualizowany, aby odzwierciedlić zapis pliku.

Rozmiar dysku jest znaczący. Testowałem i widzę problemy z systemami plików FAT o rozmiarze 15 MB i mniejszym. Przy 16 MB i więcej zapisy nie są opóźniane. 16 MB to punkt przerwania, który widzę między użyciem FAT12 i FAT16 podczas formatowania dysku w systemie Windows. (Uwaga dodana później: Ale punkt przerwania FAT12 / FAT16 zależy od liczby klastrów, a nie od absolutnego rozmiaru systemu plików).

W wersjach 16 MB i większych system Windows wysyła Prevent/Allow Medium Removalpolecenia SCSI przed zapisem, prosząc, aby urządzenie nie zostało usunięte. Pamięć USB faktycznie zwraca błąd w przypadku tych żądań (ponieważ nie może zagwarantować braku usunięcia), ale system Windows mimo to próbuje. Ślady 15 MB i mniejsze nie pokazują Prevent/Allow Medium Removalpoleceń.

(Odkryłem ten problem podczas korzystania z płytki mikrokontrolera, która obsługuje mały system plików FAT zawierający kod Python. Gdy mikrokontroler wykryje zapis w systemie plików, czeka trochę na zakończenie zapisu, a następnie automatycznie uruchamia się ponownie i uruchamia nowo napisany kod Python Ale mikrokontroler widział uszkodzony kod lub uszkodzony system plików z powodu opóźnionego zapisu.)

Dlaczego zapis do FAT jest tak opóźniony pomimo ustawienia „Szybkie usuwanie”? Mogę wymusić zapisy, wykonując polecenie „Wysuń” na dysku, ale to obala obietnicę „Szybkie usunięcie”. Gdybym wcześniej wyciągnął dysk, miałby on niepoprawną tabelę FAT. To zaprzecza stwierdzeniu na zrzucie ekranu poniżej, że nie trzeba używać „Bezpiecznego usuwania sprzętu”. Czy to błąd, czy coś brakuje? Czy istnieje sposób, aby zmusić wszystkie zapisy do natychmiastowego wykonania bez ręcznego „Wysuń”?

Napęd USB ustawiony na Szybkie usuwanie

Oto przycięty fragment ze śladu Wireshark / USBPcap pokazujący problem. Obcinam istniejący plik, a następnie zapisuję jego nową kopię. Dodałem komentarze do ###. Większość zapisów na dysku USB odbywa się w ciągu około 5 sekund, ale ostateczny zapis FAT trwa dopiero po 26 sekundach.

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

Generowałem takie ślady za pomocą zwykłego dysku flash, a także płytki mikrokontrolera, która emuluje mały dysk USB MSC, zarówno w systemie Windows 7, jak i Windows 10.

Dla jasności jest to dysk sformatowany w systemie FAT12, zwany po prostu „FAT” w narzędziu formatującym Windows.

Dan Halbert
źródło
1
Czy jesteś po prostu ciekawy? A może czeka Cię scenariusz, w którym musisz korzystać z systemu plików FAT16?
Mówię: Przywróć Monikę
2
Pomagam przetestować płytę mikrokontrolera (Adafruit Feather M0 i powiązane) z uruchomionym wariantem MicroPython (CircuitPython). Ma mały system plików FAT zawierający kod Pythona. Dla wygody płyta jest skonfigurowana do automatycznego resetowania i uruchamiania main.pylub podobnych plików po wykryciu, że plik został zapisany. Trwa trochę opóźnienie zapisu, ale nie kilkadziesiąt sekund. Możemy wyłączyć to automatyczne restartowanie, ale nadal konieczne jest „wysunięcie” napędu, aby mieć pewność, że zapis zostanie zakończony w odpowiednim czasie. Wymaganie od użytkownika wysunięcia jest uciążliwe; chcielibyśmy tego uniknąć.
Dan Halbert,
Proszę rozważyć edytowanie na początku pytania krótkiego wyjaśnienia tego. To dobry kontekst tła.
Mówię: Przywróć Monikę
Dobry pomysł. Gotowy.
Dan Halbert,

Odpowiedzi:

4

Mogłem znaleźć rzeczywisty kod sterownika Windows, który powoduje problem.

Zdarza się, że MS dołącza sterownik systemu plików FAT do pakietu przykładowego kodu sterownika. W tym sterowniku jest kilka miejsc, w których jeśli systemem plików jest FAT12, sterownik nie będzie się starał robić czegoś takiego jak ustawienie brudnego bitu (być może nie ma FAT12) lub opróżnianie danych 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 i może najbardziej krytycznie: https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/cleanup.c#L1101

W ostatnim łączu cleanup.cwewnątrz FAT nie jest opróżniany, jeśli systemem plików jest FAT12. Myślę, że może to powodować dokładnie takie zachowanie, jakie widzę:

    //
    //  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);

Zgłoszone do Microsoft w Centrum opinii Windows na https://aka.ms/btvdog (specjalny adres URL, który otwiera się w Centrum opinii).

Dan Halbert
źródło