Доброго времени суток! Столкнулся со следующей проблемой. Есть драйвер фильтр файловой системы, в процедуре обработки IRP_MJ_WRITE используется функция FsRtlGetFileSize. Все работает замечательно пока не запустить MS Word. При открытии создается временный файл типа ~WRD0000.tmp. Если внести изменения в этот документ и нажать сохранить, то как и положено валится кучу запросов на запись, но в одном из последних при вызове FsRtlGetFileSize система подвисает. FileObject отправляется корректный (проверяю по ._type). Подвисает - это процес Worda висит и его нельзя завершить через диспетчер задач да и в принципе вся система начинает тормозить, спасает только жесткий reset. С ходу не нашел аналогов функции, чтобы по FileObject определять размер файла. Кто нить может подсказать по этой теме? Заранее спасибо
Пробовал отправлять irp напрямую как указывается в http://www.rsdn.ru/forum/asm/3433288.flat.aspx При простом копировании с диска на диск все ок, но с word такая же беда, зависает.
Есть подозрение, что это известная проблема дедлока в драйвере файловой системы (в частности, ntfs.sys частенько был за этим замечен). Покажи полный call stack в тот момент, когда FsRtlGetFileSize() вешает поток.
FsRtlGetFileSize не лочит файловый объект, соот-но дедлока не может быть. Скорее всего кривой код у топик стартера.
Файловая система в данном случае FAT32 По поводу кривого кода: отключаю использование этой функции и все идет свои чередом. зависший поток: отлаживаю процесс на виртуальной машине WInXP с использованием старого доброго SoftIce, мониторю поочередно каждый вызов FsRtlGetFileSize и на одном из них Ice после очередного F10 вылетает, в смысле не синий экран а система отмирает от отладки Softice при этом процесс word перестает отвечать. К сожалению отладчиком WinDBG мадо пользовался, сейчас возможно самое время. При использовании WinDBG больше шансов отловить ошибку?
Вроде разобрался с Call stack. Вот только скопировать текст из окна не получилось, прикрепил как скриншот во вложении
Символы некорректны, потому что вызов IoBuildPartialMdl() не может приводить к вызову твоего кода. В командную строку WinDbg добавь следующий параметр: Принудительно перезагрузить символы можно так: kd> .reload /f nt kd> .reload /f mydriver.sys kd> ... Используй следующую команду в отладчике: kd> kb 30
Обычно этого делать не требуется, ибо WinDbg умеет находить соответствующие .pdb-файлы по загруженным в ядро бинарникам, т.е. в данном случае, я так понимаю, либо символы просто тупо отсутствуют, либо не соответствуют бинарнику.
ну дык, там полный путь обычно присутствует в бинарнике. По которому и глядит WinDBG. Надо у ТСа узнать, куда он символы после компиляции дел.
Запускаю WinDBG c помощью батника @echo off set _NT_SYMBOL_PATH=srv*C:\SYMBOLS*http://msdl.microsoft.com/download/symbols;cache*C:\SYMBOLS start windbg -b -k com:pipe,port=\\.\pipe\com_1,resets=0 Удалил папку Symbols и запустил заново, подкачались заново символы. Новый стек во вложении. Командой "kb 30" не удается воспользоваться, так как после очередного вызова FsRtlGetFileSize отладчик переходит в состоянии Running, Также подгрузил символьные файлы своего драйвера PS извиняюсь за столь поздний свой ответ (были технические проблемы)
Вообще-то в этом стеке вызов FsRtlGetFileSize() отсутствует. Но если предположить, что проблема здесь в символах и этот вызов там всё таки есть, то это классический дедлок, связанный с менеджером кэша и драйвером файловой системы. Если кратко, то в своей MyDispatchWrite() ты должен проверять все приходящие пакеты запросов (IRP) на наличие флага IRP_PAGING_IO и/или IRP_SYNCHRONOUS_PAGING_IO. Если хотя бы один из флагов установлен, то такой запрос следует пропустить дальше без какой-либо обработки. Запросы эти инициирует менеджер кэша, при чём обычно он делает это не сам по себе, а в ответ на тот или иной вызов драйвера файловой системы. Короче говоря, может быть такая ситуация, что какое-то приложение запросило какую-либо файловую операцию (запись, к примеру), fastfat.sys залочил файловый объект и позвал один из сервисов кэша, тот зашедулил операцию в один из своих рабочих потоков (он всегда так делает...), который в свою очередь вызвал тебя. А ты что сделал? А ты сдуру взял да и позвал файловую систему опять, она поди да и захвати лок снова. Вот и висим. В этом случае нужно нажать Ctrl+Break, дать команду "!process 0 6 System". После чего нужно найти свой поток в списке, для этого можно воспользоваться окном поиска по Ctrl+F, в котором наберёшь что-то типа "mydrv!", нажмёшь Enter, потом несколько раз F3, это выведет тебя на нужный поток, его сразу узнаешь - там в стеке будет присутствовать твой злополучный вызов FsRtlGetFileSize(). Незаметно, подгрузи нормальные символы для своего драйвера, команда ".reload /f mydrv.sys". Это без разницы, это ж тебе надо, не нам.
С помощью вашей инструкции получил таки стек THREAD 819cb830 Cid 0004.0014 Teb: 00000000 Win32Thread: 00000000 WAIT: (Executive) KernelMode Non-Alertable 81828bf8 Semaphore Limit 0x7fffffff 819cb920 NotificationTimer Not impersonating DeviceMap e1006008 Owning Process 0 Image: <Unknown> Attached Process 819cc490 Image: System Wait Start TickCount 715734 Ticks: 186 (0:00:00:02.906) Context Switch Count 3509 UserTime 00:00:00.000 KernelTime 00:00:00.125 Start Address nt!ExpWorkerThread (0x80534082) Stack Init f9de0000 Current f9ddf8a0 Base f9de0000 Limit f9ddd000 Call 0 Priority 13 BasePriority 13 PriorityDecrement 0 DecrementCount 16 ChildEBP RetAddr Args to Child f9ddf8b8 8050049e 819cb8a0 819cb830 804f9cec nt!KiSwapContext+0x2e (FPO: [Uses EBP] [0,0,4]) f9ddf8c4 804f9cec 00000000 8188bef0 819cb830 nt!KiSwapThread+0x46 (FPO: [0,0,0]) f9ddf8ec 80531908 00000000 00000000 00000000 nt!KeWaitForSingleObject+0x1c2 (FPO: [5,5,4]) f9ddf928 80531e74 816b75b0 817a592c 00000000 nt!ExpWaitForResource+0xd2 (FPO: [0,5,0]) f9ddf93c f7c7c452 8188bef0 00000001 816b75b0 nt!ExAcquireResourceSharedLite+0xb2 (FPO: [2,0,4]) f9ddf980 80560a29 818e75d8 00000001 f9ddf9a8 Fastfat!FatFastQueryStdInfo+0x4d (FPO: [Non-Fpo]) f9ddf9d8 f792b58d 818e75d8 f9ddfa1c 00000000 nt!FsRtlGetFileSize+0x35 (FPO: [2,12,4]) WARNING: Stack unwind information not available. Following frames may be wrong. f9ddfad0 f792b75d 816b75b0 817a57c0 f9ddfafc mydrv+0x258d f9ddfb1c 804ee0ef 816b75b0 817a57c0 00000000 mydrv+0x275d f9ddfb2c 804ef3e7 f9ddfb68 f9ddfd40 00000000 nt!IopfCallDriver+0x31 (FPO: [0,0,0]) f9ddfb40 8050babd 818e7508 f9ddfb68 f9ddfbfc nt!IoSynchronousPageWrite+0xaf (FPO: [5,0,4]) f9ddfc24 8050c463 e1101008 e1101050 e1101050 nt!MiFlushSectionInternal+0x3bf (FPO: [6,47,4]) f9ddfc60 804e3872 8189a278 e1101008 00000000 nt!MmFlushSection+0x1b5 (FPO: [5,4,0]) f9ddfce8 804e3b94 00009000 00000000 00000001 nt!CcFlushCache+0x386 (FPO: [4,24,4]) f9ddfd2c 804e61be 819c5a78 8055a5a0 819cb830 nt!CcWriteBehind+0xdc (FPO: [0,8,4]) f9ddfd74 80534182 819c5a78 00000000 819cb830 nt!CcWorkerThread+0x126 (FPO: [Non-Fpo]) f9ddfdac 805c4fac 819c5a78 00000000 00000000 nt!ExpWorkerThread+0x100 (FPO: [1,8,0]) f9ddfddc 80541352 80534082 00000000 00000000 nt!PspSystemThreadStartup+0x34 (FPO: [Non-Fpo]) 00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16 Если пропускать все запросы с флагами IRP_PAGING_IO IRP_SYNCHRONOUS_PAGING_IO то смысл разработки моего драйвера теряется ( Кратко, драйвер-фильтр обрабатывает все запросы на запись и в случаи необходимости делает теневые копии. Если это классический дедлок, то почему он проявляется только с запуском word? Простое копирование файлов с диска на диск протестировано успешно. Саму процедуру записи теневой копии делаю с использованием мапинга файлов (ZwCreateSection, ZwMapViewOfSection) пример здесь ( в конце топика ) http://www.osronline.com/cf.cfm?PageURL=showThread.CFM?link=143839 Можете порекомендовать как обойти использование FsRtlGetFileSize
Да, хорошо, именно такой стек я и имел в виду. Да не, ну разумеется, обрабатывать можно любые запросы, вопрос только в том, насколько это соответствует задаче. В данном случае, похоже, что да, именно эти запросы тебе и нужны. Честно говоря, не вижу никакой связи между "классичностью" дедлока и частотой его воспроизведения. А проблема очевидно, в способе работы с файлами - через запросы ввода/вывода или через секции. Первый вариант, насколько я знаю, используется в стандартных Win32-функциях копирования файлов, а Word, вероятно, использует секции для работы со своими временными файлами. Перечитай внимательно, что пишет Tony Mason в сообщении #21. К мнению этого человека стоит прислушиваться. Посты Максима тоже игнорировать не стоит. Так или иначе, использовать секции здесь я бы не стал, лучше всего задействовать такие функции как IoCreateFileSpecifyDeviceObjectHint() и вообще обычный механизм I/O-запросов. Кроме того, я бы подумал в сторону отложенной записи в отдельном потоке, это также решило бы часть потенциальных проблем. А оно тебе там вообще надо? Зачем?
С самого начала пробовал реализовать систему отложенной записи в отдельном потоке, в тестовой среде при копировании 1-2 файлов еще работало куда ни шло, но в реальности получилось что очередь постоянно росла при активном копировании, сейчас уже не вспомню почему точно отказался от этой реализации, но были еще много подводных камней, не говоря уже о значительно более сложной схему реализации этого метода. Под обычным механизмом вы имеете ввиду вручную формировать irp IRP_MJ_WRITE? Проблему вроде решил отказом от использования FsRtlGetFileSize, при создании ZwCreateSection можно получить MaximumSize просто сложив смещение и размер буфера. (выровняв естественно по верхней границе)
Ну так и что? Бес попутал? Что значит "постоянно росла"? Попахивает кривизной рук, если честно. Да ну? И где же они? Сложность реализации не может быть аргументом, им может быть недостаточное кол-во бабла у заказчика. Да, во избежание рекурсии это будет самым правильным решением в данном случае. Это всё костыли. Я бы на твоём месте взял бы и переписал вообще всё по уму, - с отложенной записью, без секций и прочих потенциально опасных (да и не нужных) вещей.
По поводу более правильной схемы реализации спорить не буду. Скорее всего подниму старый проект с отложенной записью и попробую довести его до ума, но это будет уже отдельный топик наверное.