Windows задерживает запись таблицы FAT на маленький USB-накопитель, несмотря на «быстрое удаление»

10

Я вижу отложенные записи в FAT на USB-флэш-накопителе с малой емкостью FAT (FAT12), даже если для политики задано «Быстрое удаление». (Я считаю, что это означает, что SurpriseRemovalOKфлаг установлен). Я перехватил команды SCSI, отправленные на накопитель через USB: запись усечения файла происходит немедленно, весь файл (2 512-байтовых секторов) записывается сразу после этого, но затем перед FAT происходит задержка в 20-90 секунд обновляется, чтобы отразить запись файла.

Размер диска значительный. Я проверил и вижу проблемы на файловых системах FAT размером 15 МБ и меньше. На 16 МБ и выше запись не задерживается. 16 МБ - это точка останова между использованием FAT12 и FAT16 при форматировании диска в Windows. (Примечание добавлено позже: Но точка останова FAT12 / FAT16 зависит от количества кластеров, а не от абсолютного размера файловой системы).

На 16 МБ и больше Windows отправляет Prevent/Allow Medium Removalкоманды SCSI перед записью, прося не удалять устройство. USB-накопитель фактически возвращает ошибку при этих запросах (потому что не может гарантировать удаление), но Windows все равно пытается. Следы размером 15 МБ и меньше не показывают Prevent/Allow Medium Removalкоманд.

(Я обнаружил эту проблему при использовании платы микроконтроллера, которая поддерживает крошечную файловую систему FAT, содержащую код Python. Когда микроконтроллер обнаруживает запись в файловую систему, он немного ожидает завершения записи, а затем автоматически перезапускает и запускает вновь написанный код Python Но микроконтроллер обнаружил поврежденный код или поврежденную файловую систему из-за отложенной записи.)

Почему запись в FAT задерживается так долго, несмотря на установленное «Быстрое удаление»? Я могу форсировать запись, выполнив «Извлечение» на диске, но это противоречит обещанию «Быстрое удаление». Если бы я выдернул диск раньше, у него была бы неправильная таблица FAT. Это противоречит утверждению на снимке экрана ниже о том, что не нужно использовать «Безопасное извлечение устройства». Это ошибка или я что-то упустил? Есть ли способ заставить все записи происходить немедленно без ручного «извлечения»?

USB-накопитель настроен на быстрое удаление

Вот сокращенная выдержка из трассировки Wireshark / USBPcap, показывающая проблему. Я обрезаю существующий файл и затем пишу новую копию. Я добавил комментарии с ###. Большинство операций записи на USB-накопитель происходит примерно через 5 секунд, но окончательная запись в FAT происходит только через 26 секунд.

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

Подобные следы я генерировал, используя обычную флешку, а также с платой микроконтроллера, которая эмулирует крошечный USB MSC-накопитель, как в Windows 7, так и в Windows 10.

Просто чтобы быть понятным, это диск в формате FAT12, просто называемый «FAT» в средстве форматирования Windows.

Дэн Халберт
источник
1
Вам просто любопытно? Или вы сталкиваетесь со сценарием, когда вам необходимо использовать файловую систему FAT16?
Я говорю: восстанови Монику
2
Я помогаю протестировать плату микроконтроллера (Adafruit Feather M0 и связанные с ней) под управлением варианта MicroPython (CircuitPython). Он имеет крошечную файловую систему FAT, содержащую код Python. Для удобства на плате настроен автоматический сброс и запуск main.pyили аналогичные файлы, когда он обнаруживает, что файл записан. Задержка записи завершается, но не на десятки секунд. Мы можем отключить этот автоматический перезапуск, но все равно необходимо «извлечь» диск, чтобы убедиться, что запись завершена своевременно. Требование пользователя сделать Eject является неприятностью; мы хотели бы избежать этого.
Дэн Халберт,
Пожалуйста, рассмотрите возможность редактирования в начале вашего вопроса краткого объяснения этого. Это хороший фоновый контекст.
Я говорю: восстанови Монику
Хорошее предложение. Выполнено.
Дэн Халберт,

Ответы:

4

Возможно, я нашел фактический код драйвера Windows, который вызывает проблему.

MS включает драйвер файловой системы FAT в пакет примера кода драйвера. В этом драйвере есть несколько мест, где, если файловая система FAT12, драйвер не потрудится сделать что-то вроде установки грязного бита (возможно, его нет для FAT12) или сброса данных 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 и, возможно, наиболее критично: https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/cleanup.c#L1101

В последней ссылке в cleanup.cFAT не сбрасывается, если файловая система FAT12. Я думаю, что это может быть причиной именно того поведения, которое я вижу:

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

Об этом сообщает Microsoft в Windows Feedback Hub по адресу https://aka.ms/btvdog (специальный URL, который открывается в Feedback Hub).

Дэн Халберт
источник