Windows trì hoãn việc viết bảng FAT trên ổ USB nhỏ mặc dù loại bỏ nhanh chóng


10

Tôi đang thấy sự chậm trễ ghi vào FAT trên ổ flash USB có định dạng FAT (FAT12) dung lượng nhỏ mặc dù chính sách cho ổ đĩa được đặt thành "Loại bỏ nhanh". (Tôi tin rằng điều này có nghĩa là SurpriseRemovalOKcờ được đặt). Tôi đã bắt được các lệnh SCSI được gửi tới ổ đĩa qua USB: quá trình ghi tệp bị cắt xảy ra ngay lập tức, toàn bộ tệp (2 cung dài 512 byte) được ghi ngay sau đó, nhưng sau đó có độ trễ 20-90 giây trước FAT được cập nhật để phản ánh tập tin ghi.

Kích thước của ổ đĩa là đáng kể. Tôi đã thử nghiệm và thấy các sự cố trên hệ thống tệp FAT có kích thước 15MB và nhỏ hơn. Trên 16MB trở lên, việc ghi không bị trì hoãn. 16MB là điểm dừng tôi thấy giữa việc sử dụng FAT12 và FAT16 khi tôi định dạng ổ đĩa trong Windows. (Lưu ý thêm vào sau: Nhưng điểm dừng của FAT12 / FAT16 phụ thuộc vào số lượng cụm chứ không phải kích thước hệ thống tệp tuyệt đối).

Trên 16 MB và lớn hơn, Windows sẽ gửi các Prevent/Allow Medium Removallệnh SCSI trước khi ghi, yêu cầu không xóa thiết bị. Thanh USB thực sự trả về thất bại cho các yêu cầu này (vì nó không thể đảm bảo không loại bỏ), nhưng dù sao thì Windows vẫn cố gắng. Các dấu vết 15MB và nhỏ hơn cho thấy không có Prevent/Allow Medium Removal lệnh.

(Tôi đã phát hiện ra vấn đề này trong khi sử dụng bảng vi điều khiển hỗ trợ hệ thống tệp FAT nhỏ chứa mã Python. Khi vi điều khiển phát hiện ghi vào hệ thống tệp, nó đợi một chút để ghi hoàn thành rồi tự động khởi động lại và chạy mã Python mới được viết . Nhưng vi điều khiển đã thấy mã bị hỏng hoặc hệ thống tệp bị hỏng do ghi chậm.)

Tại sao việc ghi vào FAT bị trì hoãn quá lâu, mặc dù "Loại bỏ nhanh" được đặt? Tôi có thể buộc viết bằng cách thực hiện "Đẩy" trên ổ đĩa nhưng điều đó đánh bại lời hứa "Loại bỏ nhanh". Nếu tôi kéo ổ đĩa sớm, nó sẽ có một bảng FAT không chính xác. Điều này tin rằng tuyên bố trong ảnh chụp màn hình bên dưới về việc không phải sử dụng "Phần cứng loại bỏ an toàn". Đây có phải là một lỗi hoặc tôi đang thiếu một cái gì đó? Có cách nào để buộc tất cả các ghi được xảy ra ngay lập tức mà không có "Eject" thủ công không?

Ổ đĩa USB được đặt thành Loại bỏ nhanh

Đây là một trích xuất được cắt tỉa từ dấu vết Wireshark / USBPcap cho thấy vấn đề. Tôi cắt một tập tin hiện có và sau đó viết một bản sao mới của nó. Tôi đã thêm ý kiến ​​với ###. Hầu hết các lần ghi vào ổ USB diễn ra trong khoảng 5 giây vào dấu vết, nhưng lần ghi FAT cuối cùng không kéo dài đến 26 giây.

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

Tôi đã tạo ra các dấu vết như thế này bằng cách sử dụng ổ đĩa flash thông thường và với bảng vi điều khiển mô phỏng ổ USB USB nhỏ, trên cả Windows 7 và windows 10.

Nói rõ hơn, đây là một ổ đĩa có định dạng FAT12, chỉ được gọi là "FAT" trong công cụ định dạng Windows.


1
Bạn chỉ tò mò? Hay bạn đang phải đối mặt với một kịch bản mà bạn bắt buộc phải sử dụng hệ thống tập tin FAT16?
Tôi nói Phục hồi Monica

2
Tôi đang giúp kiểm tra một bảng vi điều khiển (Adaf nhung Feather M0 và có liên quan) đang chạy một biến thể của MicroPython (CircuitPython). Nó có một hệ thống tệp FAT nhỏ chứa mã Python. Để thuận tiện, bảng được thiết lập để tự động đặt lại và chạy main.pyhoặc các tệp tương tự khi phát hiện tệp đã được ghi. Nó trì hoãn một chút để ghi hoàn thành, nhưng không phải hàng chục giây. Chúng tôi có thể vô hiệu hóa tự động khởi động lại này, nhưng vẫn cần phải "Đẩy" ổ đĩa để đảm bảo việc ghi hoàn thành một cách kịp thời. Yêu cầu người dùng thực hiện Eject là một sự phiền toái; chúng tôi muốn tránh điều đó
Dan Halbert

Vui lòng xem xét chỉnh sửa vào đầu câu hỏi của bạn một lời giải thích ngắn gọn về điều này. Đó là bối cảnh nền tảng tốt để có.
Tôi nói Phục hồi Monica

Gợi ý tốt. Làm xong.
Dan Halbert

Câu trả lời:


4

Tôi có thể đã tìm thấy mã trình điều khiển Windows thực sự gây ra sự cố.

MS tình cờ bao gồm trình điều khiển hệ thống tập tin FAT trong một gói mã trình điều khiển mẫu. Có một vài vị trí trong trình điều khiển đó, nếu hệ thống tập tin là FAT12, trình điều khiển sẽ không bận tâm làm điều gì đó như đặt bit bẩn (có thể không có gì cho FAT12) hoặc xóa dữ liệu FAT.

https://github.com/Microsoft/Windows-do-samples/blob/master/filesys/fastfat/verfysup.c#L774 https://github.com/Microsoft/Windows-do-samples/blob/master/filesys /fastfat/cachesup.c#L1212 và có lẽ là quan trọng nhất: https://github.com/Microsoft/Windows- ấn-samples / blob / master / filesys / fastfat / clupup.c # L1101

Trong liên kết cuối cùng, trong cleanup.c, FAT không bị xóa nếu hệ thống tập tin là FAT12. Tôi nghĩ rằng điều này có thể gây ra chính xác hành vi tôi thấy:

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

Báo cáo cho Microsoft trong Trung tâm phản hồi của Windows tại https://aka.ms/btvdog (URL đặc biệt mở trong Trung tâm phản hồi).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.