Драйвер фильтр и FsRtlGetFileSize

Тема в разделе "WASM.NT.KERNEL", создана пользователем Marik, 25 ноя 2009.

  1. Marik

    Marik New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2006
    Сообщения:
    166
    Адрес:
    Russia
    Доброго времени суток!
    Столкнулся со следующей проблемой. Есть драйвер фильтр файловой системы, в процедуре обработки IRP_MJ_WRITE используется функция FsRtlGetFileSize. Все работает замечательно пока не запустить MS Word. При открытии создается временный файл типа ~WRD0000.tmp. Если внести изменения в этот документ и нажать сохранить, то как и положено валится кучу запросов на запись, но в одном из последних при вызове FsRtlGetFileSize система подвисает. FileObject отправляется корректный (проверяю по ._type). Подвисает - это процес Worda висит и его нельзя завершить через диспетчер задач да и в принципе вся система начинает тормозить, спасает только жесткий reset.
    С ходу не нашел аналогов функции, чтобы по FileObject определять размер файла. Кто нить может подсказать по этой теме? Заранее спасибо
     
  2. Marik

    Marik New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2006
    Сообщения:
    166
    Адрес:
    Russia
    Пробовал отправлять irp напрямую как указывается в http://www.rsdn.ru/forum/asm/3433288.flat.aspx
    При простом копировании с диска на диск все ок, но с word такая же беда, зависает.
     
  3. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Есть подозрение, что это известная проблема дедлока в драйвере файловой системы (в частности, ntfs.sys частенько был за этим замечен). Покажи полный call stack в тот момент, когда FsRtlGetFileSize() вешает поток.
     
  4. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    FsRtlGetFileSize не лочит файловый объект, соот-но дедлока не может быть. Скорее всего кривой код у топик стартера.
     
  5. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Речь не о блокировке файлового объекта, проблема не в FsRtlGetFileSize().
     
  6. Marik

    Marik New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2006
    Сообщения:
    166
    Адрес:
    Russia
    Файловая система в данном случае FAT32
    По поводу кривого кода: отключаю использование этой функции и все идет свои чередом.
    зависший поток: отлаживаю процесс на виртуальной машине WInXP с использованием старого доброго SoftIce, мониторю поочередно каждый вызов FsRtlGetFileSize и на одном из них Ice после очередного F10 вылетает, в смысле не синий экран а система отмирает от отладки Softice при этом процесс word перестает отвечать. К сожалению отладчиком WinDBG мадо пользовался, сейчас возможно самое время. При использовании WinDBG больше шансов отловить ошибку?
     
  7. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Не важно, покажи мне call stack зависшего потока.

    С этим сюда.
     
  8. Marik

    Marik New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2006
    Сообщения:
    166
    Адрес:
    Russia
    Вроде разобрался с Call stack. Вот только скопировать текст из окна не получилось, прикрепил как скриншот во вложении
     
  9. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Символы некорректны, потому что вызов IoBuildPartialMdl() не может приводить к вызову твоего кода. В командную строку WinDbg добавь следующий параметр:

    Принудительно перезагрузить символы можно так:

    kd> .reload /f nt
    kd> .reload /f mydriver.sys
    kd> ...

    Используй следующую команду в отладчике:

    kd> kb 30
     
  10. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    как видим из скрина, пути к символам его драйвера не прописаны, их тоже нужно добавить.
     
  11. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Обычно этого делать не требуется, ибо WinDbg умеет находить соответствующие .pdb-файлы по загруженным в ядро бинарникам, т.е. в данном случае, я так понимаю, либо символы просто тупо отсутствуют, либо не соответствуют бинарнику.
     
  12. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    ну дык, там полный путь обычно присутствует в бинарнике. По которому и глядит WinDBG.
    Надо у ТСа узнать, куда он символы после компиляции дел.
     
  13. Marik

    Marik New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2006
    Сообщения:
    166
    Адрес:
    Russia
    Запускаю 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 извиняюсь за столь поздний свой ответ (были технические проблемы)
     
  14. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Вообще-то в этом стеке вызов 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".

    Это без разницы, это ж тебе надо, не нам.
     
  15. Marik

    Marik New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2006
    Сообщения:
    166
    Адрес:
    Russia
    С помощью вашей инструкции получил таки стек

    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 то смысл разработки моего драйвера теряется :dntknw:( Кратко, драйвер-фильтр обрабатывает все запросы на запись и в случаи необходимости делает теневые копии. Если это классический дедлок, то почему он проявляется только с запуском word? Простое копирование файлов с диска на диск протестировано успешно.
    Саму процедуру записи теневой копии делаю с использованием мапинга файлов (ZwCreateSection, ZwMapViewOfSection) пример здесь ( в конце топика )
    http://www.osronline.com/cf.cfm?PageURL=showThread.CFM?link=143839

    Можете порекомендовать как обойти использование FsRtlGetFileSize
     
  16. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Да, хорошо, именно такой стек я и имел в виду.

    Да не, ну разумеется, обрабатывать можно любые запросы, вопрос только в том, насколько это соответствует задаче. В данном случае, похоже, что да, именно эти запросы тебе и нужны.

    Честно говоря, не вижу никакой связи между "классичностью" дедлока и частотой его воспроизведения. А проблема очевидно, в способе работы с файлами - через запросы ввода/вывода или через секции. Первый вариант, насколько я знаю, используется в стандартных Win32-функциях копирования файлов, а Word, вероятно, использует секции для работы со своими временными файлами.

    Перечитай внимательно, что пишет Tony Mason в сообщении #21. К мнению этого человека стоит прислушиваться. Посты Максима тоже игнорировать не стоит. Так или иначе, использовать секции здесь я бы не стал, лучше всего задействовать такие функции как IoCreateFileSpecifyDeviceObjectHint() и вообще обычный механизм I/O-запросов. Кроме того, я бы подумал в сторону отложенной записи в отдельном потоке, это также решило бы часть потенциальных проблем.

    А оно тебе там вообще надо? Зачем?
     
  17. Marik

    Marik New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2006
    Сообщения:
    166
    Адрес:
    Russia
    С самого начала пробовал реализовать систему отложенной записи в отдельном потоке, в тестовой среде при копировании 1-2 файлов еще работало куда ни шло, но в реальности получилось что очередь постоянно росла при активном копировании, сейчас уже не вспомню почему точно отказался от этой реализации, но были еще много подводных камней, не говоря уже о значительно более сложной схему реализации этого метода.
    Под обычным механизмом вы имеете ввиду вручную формировать irp IRP_MJ_WRITE?

    Проблему вроде решил отказом от использования FsRtlGetFileSize, при создании ZwCreateSection можно получить MaximumSize просто сложив смещение и размер буфера. (выровняв естественно по верхней границе)
     
  18. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Ну так и что? Бес попутал?

    Что значит "постоянно росла"? Попахивает кривизной рук, если честно.

    Да ну? И где же они?

    Сложность реализации не может быть аргументом, им может быть недостаточное кол-во бабла у заказчика.

    Да, во избежание рекурсии это будет самым правильным решением в данном случае.

    Это всё костыли. Я бы на твоём месте взял бы и переписал вообще всё по уму, - с отложенной записью, без секций и прочих потенциально опасных (да и не нужных) вещей.
     
  19. Marik

    Marik New Member

    Публикаций:
    0
    Регистрация:
    21 июн 2006
    Сообщения:
    166
    Адрес:
    Russia
    По поводу более правильной схемы реализации спорить не буду. :) Скорее всего подниму старый проект с отложенной записью и попробую довести его до ума, но это будет уже отдельный топик наверное. :)