Как синхронизировать PFLT_POST_OPERATION_CALLBACK и поток -
От: LimyKurn  
Дата: 13.09.18 22:22
Оценка:
Имеется исходник драйвера минифильтра, который ведет лог разных IRP-операций с файлами.
Архитектура довольно прикольная — своей простотой...

В PRE_OPERATION_CALLBACK ничего нет.

Есть POST_OPERATION_CALLBACK — он из операций и всяких собранных данных (вроде PID процесса) формирует готовые строки и добавляет их в "очередь" на логирование.
И есть отдельный поток, запущен он таким образом:
PsCreateSystemThread(hThread, (ACCESS_MASK)0,
NULL,
(HANDLE) 0,
NULL,
loggerThread,
NULL);
В потоке каждые 10 минут проверяется, не наполнилась ли "очередь", и если да, то она грузится в лог (лог — это файл, но там еще всякая обработка буфера, который в этом файл запишется — есть сжатие и еще что-то — все прямо здесь, в драйвере) и опустошается.

А "очередь" представляет собой не что иное, как простой PWCHAR (даже не UNICODE_STRING). Прямо так и объявлено, в глобальной области:
PWCHAR szLogQueue;

Резюмируя: каллбек аппендит данные в глобальный PWCHAR, а совершенно не зависящий от него поток каждые свои 10 минут проверяет PWCHAR, открывает-пишет-закрывает файл лога и заново allocatит PWCHAR (в NonPagedPool).

И вроде бы все это работает, да только код течёт. За несколько часов забивает все ОЗУ. Написал ускоренный тест — все подтвердилось.

И мне, еще очень начинающему в NT, нужно исправить это — проставив ExFreePoolWithTag везде, где нужно.
Делать что-либо радикальное, типа вынести логирование в юзермод или хотя бы переписать на UNICODE_STRING, я пока не могу. Код лапша, да и я не потяну.

Казалось бы, все просто. В потоке перед alloc ставим ExFreePoolWithTag. А чтобы не было такого, когда поток уже очистил, но не выделил заново, а тут к указателю обращается каллбак — для этого используем мьютексы, то есть и обращения из потока, и обращения из каллбака заворачиваем в lockи.

Только вот беда — согласно MSDN, POST_OPERATION_CALLBACK не должен сам по себе создавать мьютексы. Причем про ждать не сказано, а вот создавать — да.
Правда, тот же MSDN разрешает делать это через FltDoCompletionProcessingWhenSafe и FltQueueDeferredIoWorkItem.
Но уже в этих функциях написано, что в случае IRP_MJ_WRITE их опять же применять нельзя — а этому драйверу нужна и эта операция в том числе — он пишет число записанных байт и др.
В итоге имеем, что никаких lockов сюда вообще нельзя. И как тогда поступить?
Отредактировано 13.09.2018 22:23 LimyKurn . Предыдущая версия .
Re: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и поток -
От: okman Беларусь https://searchinform.ru/
Дата: 14.09.18 05:42
Оценка: 2 (1)
Здравствуйте, LimyKurn, Вы писали:

LK>Есть POST_OPERATION_CALLBACK — он из операций и всяких собранных данных (вроде PID процесса) формирует готовые строки и добавляет их в "очередь" на логирование.

LK>...
LK>В итоге имеем, что никаких lockов сюда вообще нельзя. И как тогда поступить?

POST_OPERATION_CALLBACK в общем случае может вызываться на DISPATCH_LEVEL. Поэтому никаких мьютексов и ожиданий,
здесь для синхронизации можно использовать только спинлок (потому что спинлок допустимо использовать на этом IRQL, а
другие объекты — нет). Очередь и память под ее объекты, соответственно, тоже должна использовать исключительно
NonPagedPool(Nx), иначе нарвемся на IRQL_NOT_LESS_OR_EQUAL. Здесь, кстати, нужна повышенная бдительность.
Например, имя файла, получаемое через FltGetFileNameInformation, выделяется из paged-пула, поэтому тупо взять его и
запихнуть в такую очередь нельзя, нужно сначала где-нибудь в безопасном месте, например, на pre-create или на
post-create (там всегда PASSIVE_LEVEL) сделать копию имени в nonpaged-памяти.

Использовать FltDoCompletionProcessingWhenSafe или FLT_PREOP_SYNCHRONIZE здесь тоже не стоит, это только ухудшит
производительность системы.
Re[2]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: LimyKurn  
Дата: 14.09.18 06:58
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, LimyKurn, Вы писали:


LK>>Есть POST_OPERATION_CALLBACK — он из операций и всяких собранных данных (вроде PID процесса) формирует готовые строки и добавляет их в "очередь" на логирование.

LK>>...
LK>>В итоге имеем, что никаких lockов сюда вообще нельзя. И как тогда поступить?

O>POST_OPERATION_CALLBACK в общем случае может вызываться на DISPATCH_LEVEL. Поэтому никаких мьютексов и ожиданий,

O>здесь для синхронизации можно использовать только спинлок (потому что спинлок допустимо использовать на этом IRQL, а
O>другие объекты — нет). Очередь и память под ее объекты, соответственно, тоже должна использовать исключительно
O>NonPagedPool(Nx), иначе нарвемся на IRQL_NOT_LESS_OR_EQUAL. Здесь, кстати, нужна повышенная бдительность.
O>Например, имя файла, получаемое через FltGetFileNameInformation, выделяется из paged-пула, поэтому тупо взять его и
O>запихнуть в такую очередь нельзя, нужно сначала где-нибудь в безопасном месте, например, на pre-create или на
O>post-create (там всегда PASSIVE_LEVEL) сделать копию имени в nonpaged-памяти.

O>Использовать FltDoCompletionProcessingWhenSafe или FLT_PREOP_SYNCHRONIZE здесь тоже не стоит, это только ухудшит

O>производительность системы.

А, кстати, что такое pre-create и post-create, у которых PASSIVE_LEVEL? FltGetFileNameInformation тут тоже используется. Проблем вроде BSODов не наблюдается никак. Однако меня больше интересует другое — раз там PASSIVE_LEVEL, то нельзя ли там синхронизировать? Но важно, чтобы решение поддерживало и IRP_MJ_WRITE.

> POST_OPERATION_CALLBACK в общем случае может вызываться на DISPATCH_LEVEL

А если просто отсечь случаи, когда он на нем вызывается? То можно ли будет использовать мьютексы и сможет ли система логировать все операции с файлами, в том числе IRP_MJ_WRITE и операции не только от usermode-приложений, но желательно и от других драйверов?

> здесь для синхронизации можно использовать только спинлок

Про них читал, что нельзя ждать дольше 24 микросекунд. Меня это привело в некоторое замешательство. А если процессор перегружен, и код, который укладывался в эти 24, больше не укладывается? Это требование связано только с быстродействием (в данном случае — чтобы в системе не тормозили операции создания файлов, записи в них и т.д.) или его нарушение может привести к ошибкам?

И что все-таки можно сделать? Я могу согласиться с тем, что решение делать такое жирное логирование в отдельном потоке драйвера — это плохое решение. Но само по себе использование отдельного потока, в который каждые N секунд\минут попадают данные из POST_OPERATION_CALLBACK, вроде бы не относится к такому — это может в некоторых случаях быть нужно. Поэтому хотя бы для общего развития хотелось бы найти решение.
(Ну а вообще я сам сторонник того, что у каждого драйвера, если это не драйвер устройства, должен быть свой сервис или приложение в usermode.)

Стоит ли заменить на UNICODE_STRING? В идеале, конечно, хотелось бы нормальный контейнер, как std::vector в C++. На C++ можно писать целый месяц и ни разу ничего не очищать, т.к. ничего и не выделяешь. Сюда бы тоже такое. Кстати, там еще и список один самодельный заменить надо, а то тоже течет. Или быстродействие и другие проблемы помешают реализовать подобное?
Отредактировано 14.09.2018 7:05 LimyKurn . Предыдущая версия . Еще …
Отредактировано 14.09.2018 7:01 LimyKurn . Предыдущая версия .
Re[3]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: okman Беларусь https://searchinform.ru/
Дата: 14.09.18 07:26
Оценка: 2 (1)
> что такое pre-create и post-create, у которых PASSIVE_LEVEL?

pre- и post-калбэки для IRP_MJ_CREATE. Они всегда вызываются на PASSIVE_LEVEL (это есть в документации).

> А если просто отсечь случаи, когда он на нем [DISPATCH_LEVEL] вызывается? То можно ли будет использовать

> мьютексы и сможет ли система логировать все операции с файлами, в том числе IRP_MJ_WRITE и операции
> не только от usermode-приложений, но желательно и от других драйверов?

Отсечь — т.е. так вот:
if (KeGetCurrentIrql() < DISPATCH_LEVEL)
{
    addLogRecord(...);
}

Ну тогда надо быть готовым к тому, что какие-то операции в лог не попадут.
Вряд ли это то, что требуется. А так да, на IRQL < DISPATCH_LEVEL можно использовать
любые стандартные объекты синхронизации — fast_mutex, pushlock, eresource, etc.

> Про них [spinlocks] читал, что нельзя ждать дольше 24 микросекунд. Меня это привело в некоторое

> замешательство. А если процессор перегружен, и код, который укладывался в эти 24, больше не укладывается?

Захват спинлока — это, фактически, эксклюзивный захват процессора/ядра.
Пока захвачен спинлок, процессор выполняет код только одного потока, остальные потоки,
запланированные для выполнения на этом процессоре, выполняться не будут.
Потому наилучший сценарий использования спинлока — быстро захватить блокировку, выполнить
несколько коротких операций (в идеале — максимум несколько процессорных инструкций,
например, добавить элемент в linked list) и выйти.

> Это требование связано только с быстродействием (в данном случае — чтобы в системе не тормозили

> операции создания файлов, записи в них и т.д.) или его нарушение может привести к ошибкам?

Насколько я знаю, это может привести к BSOD DPC_WATCHDOG_VIOLATION, если спинлок захвачен слишком долго.

> И что все-таки можно сделать? Я могу согласиться с тем, что решение делать такое жирное

> логирование в отдельном потоке драйвера — это плохое решение.

Я не вижу здесь ничего ужасного. Минифильтр перехватывает некоторый файловый I/O и добавляет
информацию в очередь. Отдельный поток разбирает очередь и пишет, не торопять, на диск.
Вполне избитая схема. Максимум, над чем тут стоит подумать — это чтобы не выделять слишком
много nonpaged-памяти, так как это дорогой (и не масштабируемый) ресурс.

> Стоит ли заменить на UNICODE_STRING? В идеале, конечно, хотелось бы нормальный контейнер,

> как std::vector в C++. На C++ можно писать целый месяц и ни разу ничего не очищать, т.к. ничего и
> не выделяешь. Сюда бы тоже такое. Кстати, там еще и список один самодельный заменить надо, а
> то тоже течет. Или быстродействие и другие проблемы помешают реализовать подобное?

IMHO, сначала нужно добиться нормальной ровной работы драйвера, чтобы не текла память, чтобы он
не ронял систему в BSOD и работал штатно, без отклонений, а уже потом "вылизывать" и оптимизировать.
Еще советую сразу подключать Driver Verifier, так сразу наиболее грубые ошибки можно будет выловить
(например, обращение к paged-памяти на dispatch level).
Re: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и поток -
От: mike_rs Россия  
Дата: 14.09.18 08:36
Оценка:
Здравствуйте, LimyKurn, Вы писали:

LK>А "очередь" представляет собой не что иное, как простой PWCHAR (даже не UNICODE_STRING). Прямо так и объявлено, в глобальной области:

LK>PWCHAR szLogQueue;

..

LK>Только вот беда — согласно MSDN, POST_OPERATION_CALLBACK не должен сам по себе создавать мьютексы. Причем про ждать не сказано, а вот создавать — да.

LK>Правда, тот же MSDN разрешает делать это через FltDoCompletionProcessingWhenSafe и FltQueueDeferredIoWorkItem.
LK>Но уже в этих функциях написано, что в случае IRP_MJ_WRITE их опять же применять нельзя — а этому драйверу нужна и эта операция в том числе — он пишет число записанных байт и др.
LK>В итоге имеем, что никаких lockов сюда вообще нельзя. И как тогда поступить?

очередь — глобальный указатель, ок. Не надо никаких мьютексов, надо в потоке делать InterlockedExchange этого указателя, подсовывая ему новый пустой буфер. А тот, что получили после интерлока спокойно писать на диск и освобождать. все.
Re[4]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: LimyKurn  
Дата: 14.09.18 09:08
Оценка:
Здравствуйте, okman, Вы писали:

>> что такое pre-create и post-create, у которых PASSIVE_LEVEL?


O>pre- и post-калбэки для IRP_MJ_CREATE. Они всегда вызываются на PASSIVE_LEVEL (это есть в документации).


>> А если просто отсечь случаи, когда он на нем [DISPATCH_LEVEL] вызывается? То можно ли будет использовать

>> мьютексы и сможет ли система логировать все операции с файлами, в том числе IRP_MJ_WRITE и операции
>> не только от usermode-приложений, но желательно и от других драйверов?

O>Отсечь — т.е. так вот:

O>
O>if (KeGetCurrentIrql() < DISPATCH_LEVEL)
O>{
O>    addLogRecord(...);
O>}
O>

O>Ну тогда надо быть готовым к тому, что какие-то операции в лог не попадут.
O>Вряд ли это то, что требуется. А так да, на IRQL < DISPATCH_LEVEL можно использовать
O>любые стандартные объекты синхронизации — fast_mutex, pushlock, eresource, etc.

>> Про них [spinlocks] читал, что нельзя ждать дольше 24 микросекунд. Меня это привело в некоторое

>> замешательство. А если процессор перегружен, и код, который укладывался в эти 24, больше не укладывается?

O>Захват спинлока — это, фактически, эксклюзивный захват процессора/ядра.

O>Пока захвачен спинлок, процессор выполняет код только одного потока, остальные потоки,
O>запланированные для выполнения на этом процессоре, выполняться не будут.
O>Потому наилучший сценарий использования спинлока — быстро захватить блокировку, выполнить
O>несколько коротких операций (в идеале — максимум несколько процессорных инструкций,
O>например, добавить элемент в linked list) и выйти.

>> Это требование связано только с быстродействием (в данном случае — чтобы в системе не тормозили

>> операции создания файлов, записи в них и т.д.) или его нарушение может привести к ошибкам?

O>Насколько я знаю, это может привести к BSOD DPC_WATCHDOG_VIOLATION, если спинлок захвачен слишком долго.


>> И что все-таки можно сделать? Я могу согласиться с тем, что решение делать такое жирное

>> логирование в отдельном потоке драйвера — это плохое решение.

O>Я не вижу здесь ничего ужасного. Минифильтр перехватывает некоторый файловый I/O и добавляет

O>информацию в очередь. Отдельный поток разбирает очередь и пишет, не торопять, на диск.
O>Вполне избитая схема. Максимум, над чем тут стоит подумать — это чтобы не выделять слишком
O>много nonpaged-памяти, так как это дорогой (и не масштабируемый) ресурс.

>> Стоит ли заменить на UNICODE_STRING? В идеале, конечно, хотелось бы нормальный контейнер,

>> как std::vector в C++. На C++ можно писать целый месяц и ни разу ничего не очищать, т.к. ничего и
>> не выделяешь. Сюда бы тоже такое. Кстати, там еще и список один самодельный заменить надо, а
>> то тоже течет. Или быстродействие и другие проблемы помешают реализовать подобное?

O>IMHO, сначала нужно добиться нормальной ровной работы драйвера, чтобы не текла память, чтобы он

O>не ронял систему в BSOD и работал штатно, без отклонений, а уже потом "вылизывать" и оптимизировать.
O>Еще советую сразу подключать Driver Verifier, так сразу наиболее грубые ошибки можно будет выловить
O>(например, обращение к paged-памяти на dispatch level).

Так UNICODE_STRING я не просто так предлагаю, а для решения то самой проблемы.
В BSOD он вроде не роняет, но это пока. Однако нету очистки памяти. Поток после того как все запишет — просто заново выделяет этот глобальный PWCHAR через ExAllocatePoolWithTag.
Я пытаюсь это исправить, вызвав перед этим ExFreePoolWithTag. (есть и другие места с утечками, но это самое большое по размеру буфера, да и фиксить по-любому надо все места) Но это вот приводит к BSOD. Я полагаю, что именно из-за рассинхронизации: поток уже сделал ExFreePoolWithTag, но еще не сделал ExAllocatePoolWithTag, а в это время фильтр успевает обратиться к PWCHAR.
Вот другой чел советует InterlockedExchange.

Насчет UNICODE_STRING — я ее рассматривал по той причине, что она не хранится как указатель (указатель внутри нее, а не она сама).
Рассмотрим код: 2 одинаковых потока, один в бесконечном цикле создает глобально UNICODE_STRING (в т.ч. выделяя ее Buffer), другой в бесконечном цикле освобождает этот буфер. Синхронизации никакой нет. Однако BSOD не происходит
Теперь вместо UNICODE_STRING используем PWCHAR и переписываем код аналогично. BSOD — сразу.

Ну, а "что-то типа std::vector" вообще позволило бы не чистить память, т.к. оно само ее выделяет и чистит внутри себя, когда надо.

Про verifier — спасибо, гляну. А что именно он дает, в 2 словах?
Отредактировано 14.09.2018 9:25 LimyKurn . Предыдущая версия .
Re[5]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: okman Беларусь https://searchinform.ru/
Дата: 14.09.18 09:33
Оценка: 2 (1)
Здравствуйте, LimyKurn, Вы писали:

LK>Так UNICODE_STRING я не просто так предлагаю, а для решения то самой проблемы.


UNICODE_STRING, vector или просто wchar_t — это не важно. Пока у тебя не будет синхронизации доступа к
этой переменной, работать твой драйвер корректно не будет.

LK>Про verifier — спасибо, гляну. А что именно он дает, в 2 словах?


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

Ну например, ты обращаешься к paged-памяти на DISPATCH_LEVEL. В нормальных условиях это иногда
может работать месяцами и годами, не выпадая в BSOD, а затем вдруг начинает падать (как правило, в
самый неожиданный и неудачный момент).

Когда ты включаешь соответствующую проверку в Verifier, он принудительно сбрасывает paged-память на
диск при повышении IRQL, так что данная ошибка всплывает практически сразу.

Это лишь один из примеров.
Re[2]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и поток -
От: okman Беларусь https://searchinform.ru/
Дата: 14.09.18 09:35
Оценка:
Здравствуйте, mike_rs, Вы писали:

_>очередь — глобальный указатель, ок. Не надо никаких мьютексов, надо в потоке делать InterlockedExchange этого указателя, подсовывая ему новый пустой буфер. А тот, что получили после интерлока спокойно писать на диск и освобождать. все.


А добавлять данные в такую очередь как? Можно пример?
(учитываем, что minifilter callbacks могут вызываться одновременно в разных потоках и,
соответственно, конкурировать за доступ к очереди).
Re[6]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: LimyKurn  
Дата: 14.09.18 09:44
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, LimyKurn, Вы писали:


LK>>Так UNICODE_STRING я не просто так предлагаю, а для решения то самой проблемы.


O>UNICODE_STRING, vector или просто wchar_t — это не важно. Пока у тебя не будет синхронизации доступа к

O>этой переменной, работать твой драйвер корректно не будет.

LK>>Про verifier — спасибо, гляну. А что именно он дает, в 2 словах?


O>Verifier позволяет быстрее обнаруживать различные скрытые ошибки, которые в нормальных условиях обычно

O>не проявляются сразу или проявляются спустя долгое время, когда программа уже в релизе.

O>Ну например, ты обращаешься к paged-памяти на DISPATCH_LEVEL. В нормальных условиях это иногда

O>может работать месяцами и годами, не выпадая в BSOD, а затем вдруг начинает падать (как правило, в
O>самый неожиданный и неудачный момент).

O>Когда ты включаешь соответствующую проверку в Verifier, он принудительно сбрасывает paged-память на

O>диск при повышении IRQL, так что данная ошибка всплывает практически сразу.

O>Это лишь один из примеров.


Спасибо за verifier, а вот по синхронизации надо либо что-то делать, либо все-таки счесть данную архитектуру чем-то ужасным (пусть она и избитая в юзермоде, но здесь не та обстановка. Но правда если переделывать архитектуру, то мы получим гемор — делать службу не вариант, т.к. ее нет, совсем — гемор по ее созданию слишком большой. А если перенести логирование в минифильтры, то это гемор поменьше, но придется его оптимизировать по быстродействию, что ли, к тому же логирование создает файл — от рекурсии защищаться придется). Но и спинлоки как вариант "что-то делать" — не нравятся.
Отредактировано 14.09.2018 10:13 LimyKurn . Предыдущая версия .
Re[7]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: okman Беларусь https://searchinform.ru/
Дата: 16.09.18 17:44
Оценка:
Здравствуйте, LimyKurn, Вы писали:

LK>Спасибо за verifier, а вот по синхронизации надо либо что-то делать, либо все-таки счесть данную архитектуру чем-то ужасным


Если задача заключается в том, чтобы собирать какие-то данные на post operation callback и записывать в файл,
то вряд ли есть что-то лучше, чем отдельный поток, который это делает. Не вижу резона гонять эти данные в user mode и
писать в файл оттуда, это никаких выгод не даст, получится только лишнее усложнение на ровном месте.

Очередь можно сделать на базе linked list и засинхронизировать доступ к ней, как я уже писал, через спинлоки.
Рабочий поток будет ждать (KeWaitForXxx) на событии и при его сигналинге выгребать данные из очереди и сбрасывать их на диск.
То же самое делать можно и по таймауту (например, когда KeWaitForXxx вернула STATUS_TIMEOUT).

LK>А если перенести логирование в минифильтры, то это гемор поменьше, но придется его оптимизировать по быстродействию, что ли, к тому же логирование создает файл — от рекурсии защищаться придется).


Там рекурсии неоткуда возникнуть.

LK>Но и спинлоки как вариант "что-то делать" — не нравятся.


Почему?
Re[8]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: LimyKurn  
Дата: 16.09.18 21:20
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, LimyKurn, Вы писали:


LK>>Спасибо за verifier, а вот по синхронизации надо либо что-то делать, либо все-таки счесть данную архитектуру чем-то ужасным


O>Если задача заключается в том, чтобы собирать какие-то данные на post operation callback и записывать в файл,

O>то вряд ли есть что-то лучше, чем отдельный поток, который это делает. Не вижу резона гонять эти данные в user mode и
O>писать в файл оттуда, это никаких выгод не даст, получится только лишнее усложнение на ровном месте.

O>Очередь можно сделать на базе linked list и засинхронизировать доступ к ней, как я уже писал, через спинлоки.

O>Рабочий поток будет ждать (KeWaitForXxx) на событии и при его сигналинге выгребать данные из очереди и сбрасывать их на диск.
O>То же самое делать можно и по таймауту (например, когда KeWaitForXxx вернула STATUS_TIMEOUT).

LK>>А если перенести логирование в минифильтры, то это гемор поменьше, но придется его оптимизировать по быстродействию, что ли, к тому же логирование создает файл — от рекурсии защищаться придется).


O>Там рекурсии неоткуда возникнуть.


LK>>Но и спинлоки как вариант "что-то делать" — не нравятся.


O>Почему?


Ты только сейчас появился, а у меня дедлайн послезавтра) Хотя посплю всего 2 часа, но все равно похоже придется временно оставить вопрос с этой проблемой и заняться другими моментами драйвера собственно которые меня просили сделать. Ну или применить InterlockedExchange (хочу применить в рабочем потоке призамене указателя, а в каллбаках просто ничего не менять — там же нет ни очистки, ни выделения памяти. Какие проблемы?)

А спинлоки не нравятся тем, что в 24 мксек можно не уложиться из-за тормозов процессора тех же — и будет БСОД.
Отредактировано 16.09.2018 21:21 LimyKurn . Предыдущая версия .
Re[9]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: okman Беларусь https://searchinform.ru/
Дата: 17.09.18 06:53
Оценка:
Здравствуйте, LimyKurn, Вы писали:

LK>А спинлоки не нравятся тем, что в 24 мксек можно не уложиться из-за тормозов процессора тех же — и будет БСОД.


Если под спинлоком выполнять только простейшие операции, например вставку или удаление элемента из списка,
то про ограничение в 25 мкс можно смело забыть. Инфа 100%.

Проблемы возникают тогда, когда захватив спинлок, начинают вызывать другие функции в большом количестве.
Но и даже в таком варианте надо очень постараться, чтобы выйти за лимит.
Re[10]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: LimyKurn  
Дата: 17.09.18 08:17
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, LimyKurn, Вы писали:


LK>>А спинлоки не нравятся тем, что в 24 мксек можно не уложиться из-за тормозов процессора тех же — и будет БСОД.


O>Если под спинлоком выполнять только простейшие операции, например вставку или удаление элемента из списка,

O>то про ограничение в 25 мкс можно смело забыть. Инфа 100%.

O>Проблемы возникают тогда, когда захватив спинлок, начинают вызывать другие функции в большом количестве.

O>Но и даже в таком варианте надо очень постараться, чтобы выйти за лимит.

Спасибо. Но и сам понимаешь — решение довольно сложное со спинлоком. Учитывая, что я вообще впервые с ним знакомлюсь.
Re[3]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и поток -
От: -prus-  
Дата: 17.09.18 12:53
Оценка:
O>А добавлять данные в такую очередь как? Можно пример?
O>(учитываем, что minifilter callbacks могут вызываться одновременно в разных потоках и,
O>соответственно, конкурировать за доступ к очереди).

А всякие там Singly and Doubly Linked Lists, LIST_ENTRY, ExInterlockedInsertHeadList ну и остальные интерлокед функциидля работы со списками разве не прокатят при условии выделения памяти из NonPagedPool'a?
С уважением,
Евгений
Re[4]: Как синхронизировать PFLT_POST_OPERATION_CALLBACK и п
От: LimyKurn  
Дата: 04.10.18 04:55
Оценка:
Здравствуйте, okman, Вы писали:

O>Я не вижу здесь ничего ужасного. Минифильтр перехватывает некоторый файловый I/O и добавляет

O>информацию в очередь. Отдельный поток разбирает очередь и пишет, не торопять, на диск.
O>Вполне избитая схема. Максимум, над чем тут стоит подумать — это чтобы не выделять слишком
O>много nonpaged-памяти, так как это дорогой (и не масштабируемый) ресурс.

Есть еще одно решение, которое никто не предложил.
В каллбеке создавать каждый раз новый поток и передавать все параметры. А в нем уже делать что хочешь. Если нет цели прерывать операцию (но разве POST-каллбеки умеют прерывать?), то в целом сойдет, хотя громоздко и непонятно зачем нужно, когда таки есть нормальное решение.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.