Windows atrasa a gravação da tabela FAT em uma pequena unidade USB, apesar da "Remoção rápida"

10

Estou vendo gravações atrasadas no FAT em uma unidade flash USB formatada por FAT (FAT12) de pequena capacidade, mesmo que a política da unidade esteja definida como "Remoção rápida". (Eu acredito que isso significa que a SurpriseRemovalOKbandeira está definida). Capturei os comandos SCSI enviados para a unidade via USB: a gravação do truncamento de arquivos acontece imediatamente, o arquivo inteiro (2 setores de 512 bytes) é gravado imediatamente depois disso, mas há um atraso de 20 a 90 segundos antes do FAT é atualizado para refletir a gravação do arquivo.

O tamanho da unidade é significativo. Eu testei e vejo problemas em sistemas de arquivos FAT de tamanho 15 MB e menor. Nos 16 MB e acima, as gravações não são atrasadas. 16 MB é o ponto de interrupção que vejo entre o uso do FAT12 e do FAT16 ao formatar uma unidade no Windows. (Observação adicionada posteriormente: mas o ponto de interrupção do FAT12 / FAT16 depende do número de clusters, não do tamanho absoluto do sistema de arquivos).

Em 16 MB ou mais, o Windows envia Prevent/Allow Medium Removalcomandos SCSI antes da gravação, solicitando que o dispositivo não seja removido. O pendrive USB realmente retorna a falha nessas solicitações (porque não pode garantir nenhuma remoção), mas o Windows tenta assim mesmo. Os rastreamentos de 15 MB e menores não mostram Prevent/Allow Medium Removalcomandos.

(Descobri esse problema ao usar uma placa de microcontrolador que suporta um pequeno sistema de arquivos FAT contendo código Python. Quando o microcontrolador detecta uma gravação no sistema de arquivos, ele espera um pouco para que a gravação seja concluída e, em seguida, reinicia automaticamente e executa o código Python recém-gravado. Mas o microcontrolador estava vendo código corrompido ou um sistema de arquivos corrompido devido à gravação atrasada.)

Por que a gravação no FAT está atrasada há tanto tempo, apesar de a "Remoção rápida" estar definida? Eu posso forçar as gravações fazendo um "Ejetar" na unidade, mas isso anula a promessa de "Remoção rápida". Se eu puxasse a unidade mais cedo, haveria uma tabela FAT incorreta. Isso esconde a declaração na captura de tela abaixo sobre não ter que usar "Remover hardware com segurança". Isso é um bug ou estou faltando alguma coisa? Existe alguma maneira de forçar todas as gravações a ocorrer imediatamente sem um "Ejetar" manual?

Unidade USB definida como Remoção rápida

Aqui está uma extração removida de um rastreamento do Wireshark / USBPcap mostrando o problema. Trunco ​​um arquivo existente e, em seguida, escrevo uma nova cópia dele. Adicionei comentários com ###. A maioria das gravações na unidade USB ocorre em torno de 5 segundos no rastreamento, mas a gravação final em FAT não ocorre até 26 segundos.

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

Criei traços como esse usando uma unidade flash comum e também com uma placa de microcontrolador que emula uma pequena unidade USB MSC, no Windows 7 e no Windows 10.

Só para esclarecer, esta é uma unidade formatada em FAT12, chamada apenas "FAT" na ferramenta de formatação do Windows.

Dan Halbert
fonte
11
Você está apenas curioso? Ou você está enfrentando um cenário em que precisa usar um sistema de arquivos FAT16?
Eu digo Reinstate Monica
2
Estou ajudando a testar uma placa de microcontrolador (Adafruit Feather M0 e afins) executando uma variante do MicroPython (CircuitPython). Possui um pequeno sistema de arquivos FAT contendo código Python. Por conveniência, o quadro é configurado para redefinir automaticamente e executar main.pyarquivos semelhantes quando detectar que o arquivo foi gravado. Atrasa um pouco a conclusão da gravação, mas não dezenas de segundos. Podemos desativar essa reinicialização automática, mas ainda é necessário "Ejetar" a unidade para garantir que a gravação seja concluída em tempo hábil. Exigir que o usuário faça uma Ejeção é um incômodo; nós gostaríamos de evitar isso.
quer
Considere editar no início da sua pergunta uma breve explicação sobre isso. É um bom contexto para ter.
Eu digo Restabelecer Monica
Boa sugestão. Feito.
quer

Respostas:

4

Talvez eu tenha encontrado o código do driver real do Windows que está causando o problema.

A Microsoft inclui o driver do sistema de arquivos FAT em um pacote de código de driver de amostra. Existem vários locais nesse driver em que, se o sistema de arquivos for FAT12, o driver não se preocupará em fazer algo como definir o bit sujo (talvez não exista nenhum para o FAT12) ou liberar os dados do 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 e talvez o mais crítico: https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/cleanup.c#L1101

No último link, em cleanup.c, o FAT não será liberado se o sistema de arquivos for FAT12. Eu acho que isso pode estar causando exatamente o comportamento que vejo:

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

Relatado à Microsoft no Windows Feedback Hub em https://aka.ms/btvdog (URL especial que é aberta no Feedback Hub).

Dan Halbert
fonte