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

526
Dan Halbert

Я вижу отложенные записи в 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 drive set to Quick Removal

Вот сокращенная выдержка из трассировки 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.

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

1 ответ на вопрос

2
Dan Halbert

Возможно, я нашел фактический код драйвера 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).