Я выполняю много параллельных вызовов robocopy для копирования файлов из одного сетевого ресурса в один каталог. Поскольку файлы доступны только для чтения, я приказываю robocopy убрать атрибут только для чтения в целевом каталоге через / A-: R. Похоже, что на некоторых компьютерах (12 или более) целевой каталог! блокируется на срок до 16 секунд.
Эта проблема возникает, когда выполняются параллельные задачи MSBuild и задача CopyFile выполняется для файлов только для чтения. Это также происходит, когда выполняется robocopy для параллельной загрузки зависимостей для сборки TFS из общего сетевого ресурса. Поскольку все эти проблемы указывают на CopyFile kernel32 (или его частную реализацию), я подозреваю, что проблема связана с тем, как Windows копирует файлы.
Похоже, что это не является общей проблемой в ядре, поскольку временная папка основана на том факте, что параллельный доступ к каталогу должен быть возможен. Но реализация пользовательского режима внутри kernel32.dll в CopyFile кажется некорректной.
Обновление 2
С воспроизведением ниже это происходит независимо от того, доступен ли файл только для чтения или нет.
Обновление 3
Это воспроизведение также показывает ту же проблему в Windows 8.
Трассировки стека procmon действительно показывают, что магия происходит в kernel32.dll внутри
PrivCopyFileExW, который кажется довольно недокументированным. Там выдается IRP_MJ_CREATE , чтобы открыть каталог, а чуть позже каталог закрывается. По-видимому, это является основной причиной состояния гонки, когда многие параллельные процессы Robocopy пытаются скопировать файлы в один каталог.
Вот несколько выводов procmon о том, как выглядит эта проблема.
С какой стати PrivCopyFileExW удается заблокировать каталог? Файловая система должна поддерживать копирование файлов в один каталог. Я использую Windows Server 2008 R2 и некоторые новейшие многоядерные машины с RAID-массивами, твердотельными накопителями и тому подобным.
Похоже, это связано с сообщениями о проблемах с CopyFile в kernel32.dll , которые до сих пор не решены. Я могу исключить антивирусные сканеры, потому что это также происходит на компьютерах, которые не установлены.
Обновление 1
Кажется, что другой процесс robocopy пытается скопировать файл в каталог назначения, который открывает каталог
Date & Time: 20.03.2012 08:30:06
Event Class: File System
Operation: CreateFile
Result: SUCCESS
Path: C:\temp\dest
TID: 11672
Duration: 0.0000150
Desired Access: Read Data/List Directory, Write Data/Add File, Write EA, Read Attributes, Write Attributes, Delete, Synchronize
Disposition: OpenIf
Options: Directory, Synchronous IO Non-Alert, Open For Backup
Attributes: D
ShareMode: None <---- No sharing
AllocationSize: 0
OpenResult: Opened
0 fltmgr.sys FltpPerformPreCallbacks + 0x2f7 0xfffff88001045027 C:\Windows\system32\drivers\fltmgr.sys
1 fltmgr.sys FltpPassThroughInternal + 0x4a 0xfffff880010478ca C:\Windows\system32\drivers\fltmgr.sys
2 fltmgr.sys FltpCreate + 0x293 0xfffff880010652a3 C:\Windows\system32\drivers\fltmgr.sys
3 ntoskrnl.exe IopParseDevice + 0x5a7 0xfffff800031cb537 C:\Windows\system32\ntoskrnl.exe
4 ntoskrnl.exe ObpLookupObjectName + 0x585 0xfffff800031c1ba4 C:\Windows\system32\ntoskrnl.exe
5 ntoskrnl.exe ObOpenObjectByName + 0x1cd 0xfffff800031c6b7d C:\Windows\system32\ntoskrnl.exe
6 ntoskrnl.exe IopCreateFile + 0x2b7 0xfffff800031cd647 C:\Windows\system32\ntoskrnl.exe
7 ntoskrnl.exe NtCreateFile + 0x78 0xfffff800031d7398 C:\Windows\system32\ntoskrnl.exe
8 ntoskrnl.exe KiSystemServiceCopyEnd + 0x13 0xfffff80002eca813 C:\Windows\system32\ntoskrnl.exe
9 ntdll.dll NtCreateFile + 0xa 0x7718fc0a C:\Windows\System32\ntdll.dll
10 kernel32.dll BaseCopyStream + 0x11a9 0x77034b89 C:\Windows\System32\kernel32.dll
11 kernel32.dll BasepCopyFileExW + 0x545 0x77033d85 C:\Windows\System32\kernel32.dll
12 kernel32.dll PrivCopyFileExW + 0xb6 0x770b5296 C:\Windows\System32\kernel32.dll
13 Robocopy.exe CZDir::CopyData + 0xb5 0xff8623a9 C:\Windows\System32\Robocopy.exe
14 Robocopy.exe RoboCopyDir + 0xe4 0xff85af00 C:\Windows\System32\Robocopy.exe
15 Robocopy.exe Walk + 0x12a 0xff85c6b6 C:\Windows\System32\Robocopy.exe
16 Robocopy.exe wmain + 0x4f4 0xff85de78 C:\Windows\System32\Robocopy.exe
17 Robocopy.exe operator+ + 0x19b 0xff867be5 C:\Windows\System32\Robocopy.exe
18 kernel32.dll BaseThreadInitThunk + 0xd 0x7703f33d C:\Windows\System32\kernel32.dll
19 ntdll.dll RtlUserThreadStart + 0x1d 0x77172ca1 C:\Windows\System32\ntdll.dll
Другой robocopy хочет проверить, существует ли файл, и вызывает FindFirstFile, что также приводит к открытию каталога и полному совместному использованию.
Date & Time: 20.03.2012 08:30:06
Event Class: File System
Operation: CreateFile
Result: SHARING VIOLATION
Path: C:\temp\dest
TID: 8280
Duration: 0.0000099
Desired Access: Read Data/List Directory, Synchronize
Disposition: Open
Options: Directory, Synchronous IO Non-Alert
Attributes: n/a
ShareMode: Read, Write, Delete <----- Full sharing
AllocationSize: n/a
0 fltmgr.sys FltpPerformPreCallbacks + 0x2f7 0xfffff88001045027 C:\Windows\system32\drivers\fltmgr.sys
1 fltmgr.sys FltpPassThroughInternal + 0x4a 0xfffff880010478ca C:\Windows\system32\drivers\fltmgr.sys
2 fltmgr.sys FltpCreate + 0x293 0xfffff880010652a3 C:\Windows\system32\drivers\fltmgr.sys
3 ntoskrnl.exe IopParseDevice + 0x5a7 0xfffff800031cb537 C:\Windows\system32\ntoskrnl.exe
4 ntoskrnl.exe ObpLookupObjectName + 0x585 0xfffff800031c1ba4 C:\Windows\system32\ntoskrnl.exe
5 ntoskrnl.exe ObOpenObjectByName + 0x1cd 0xfffff800031c6b7d C:\Windows\system32\ntoskrnl.exe
6 ntoskrnl.exe IopCreateFile + 0x2b7 0xfffff800031cd647 C:\Windows\system32\ntoskrnl.exe
7 ntoskrnl.exe NtOpenFile + 0x58 0xfffff800031e64a8 C:\Windows\system32\ntoskrnl.exe
8 ntoskrnl.exe KiSystemServiceCopyEnd + 0x13 0xfffff80002eca813 C:\Windows\system32\ntoskrnl.exe
9 ntdll.dll NtOpenFile + 0xa 0x7718f9ea C:\Windows\System32\ntdll.dll
10 KernelBase.dll FindFirstFileExW + 0x1ee 0x7fefd3a560e C:\Windows\System32\KernelBase.dll
11 KernelBase.dll FindFirstFileW + 0x1c 0x7fefd3a58dc C:\Windows\System32\KernelBase.dll
12 Robocopy.exe CZDir::Exists + 0xf7 0xff861bb7 C:\Windows\System32\Robocopy.exe
13 Robocopy.exe RoboCopyDir + 0x58 0xff85ae74 C:\Windows\System32\Robocopy.exe
14 Robocopy.exe Walk + 0x12a 0xff85c6b6 C:\Windows\System32\Robocopy.exe
15 Robocopy.exe wmain + 0x4f4 0xff85de78 C:\Windows\System32\Robocopy.exe
16 Robocopy.exe operator+ + 0x19b 0xff867be5 C:\Windows\System32\Robocopy.exe
17 kernel32.dll BaseThreadInitThunk + 0xd 0x7703f33d C:\Windows\System32\kernel32.dll
18 ntdll.dll RtlUserThreadStart + 0x1d 0x77172ca1 C:\Windows\System32\ntdll.dll
Я могу легко воспроизвести это и в Windows 7. Вам нужно только скопировать файлы только для чтения из двух параллельных вызовов robocopy в один и тот же каталог в цикле и подождать, пока это произойдет (около 30 с).
for /L %i in (1,1,1000) do robocopy /E /XO /COPY:DAT /A-:R C:\ReadOnlySource1 c:\temp\dest
for /L %i in (1,1,1000) do robocopy /E /XO /COPY:DAT /A-:R C:\ReadOnlySource2 c:\temp\dest
Вы можете поместить только один файл только для чтения в исходные каталоги, чтобы получить быструю копию и много одновременных обращений к каталогам. Является ли это известным ограничением Windows, запрещающим доступ к каталогу во время копирования в него файла?
Мое необразованное мнение заключается в том, что это ошибка, и она может стать довольно неприятной, если вам нужен надежный параллельный доступ к файлам.