Помогите, как сделать правильно блокировки.

Тема в разделе "WASM.NT.KERNEL", создана пользователем Igi, 2 ноя 2007.

  1. Igi

    Igi New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2005
    Сообщения:
    35
    Уважаемые мастера! Написал несколько процедур для организации списка файлов. Ниже привожу исходный код:

    fileslist.h
    Код (Text):
    1. #define MAX_PATH          260
    2.  
    3. typedef struct _FNAME_STRUCTURE
    4. {
    5.     LIST_ENTRY   ListEntry;
    6.     WCHAR FileName[MAX_PATH];
    7.     ULONG        Length;
    8. } FNAME_STRUCTURE, *PFNAME_STRUCTURE;
    9.  
    10. typedef struct _FILES_LIST
    11. {
    12.     PPAGED_LOOKASIDE_LIST pPagedLookasideList;
    13.     LIST_ENTRY ListHead;
    14.     ULONG Count;
    15. } FILES_LIST, *PFILES_LIST;
    16.  
    17. // Создание нового списка файлов
    18. PFILES_LIST     NewFilesList(void);
    19. void            FreeFilesList(PFILES_LIST FilesList);
    20. void            AddFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength);
    21. BOOLEAN         DelFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength);
    22. void            DelEntry(IN PFILES_LIST FilesList);
    23. BOOLEAN         IsAddedFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength);
    и fileslist.cpp

    Код (Text):
    1. #include "StdAfx.h"
    2.  
    3. // Создание нового списка файлов
    4. PFILES_LIST NewFilesList(void)
    5. {
    6.     PFILES_LIST FilesList = (PFILES_LIST)ExAllocatePool(NonPagedPool, sizeof(FILES_LIST));
    7.     FilesList->Count = 0;
    8.     FilesList->pPagedLookasideList = (PPAGED_LOOKASIDE_LIST)ExAllocatePool(NonPagedPool, sizeof(PAGED_LOOKASIDE_LIST));
    9.     ExInitializePagedLookasideList(FilesList->pPagedLookasideList, NULL, NULL, 0, sizeof(FNAME_STRUCTURE), 0, 0);
    10.     InitializeListHead(&FilesList->ListHead);
    11.     return FilesList;
    12. }
    13.  
    14. void FreeFilesList(PFILES_LIST FilesList){
    15.     // Удаляем все элементы списка
    16.         while (TRUE){
    17.             DelEntry(FilesList);
    18.             if (IsListEmpty(&FilesList->ListHead))
    19.                 break;
    20.         }
    21.     // Удаляем сам ассоциативный список
    22.     ExDeletePagedLookasideList(FilesList->pPagedLookasideList);
    23.     //освобождаем неподкачиваемую память, занятую под структуру PAGED_LOOKASIDE_LIST.
    24.     ExFreePool(FilesList->pPagedLookasideList);
    25.     //освобождаем сам список NEWFILES_LIST
    26.     ExFreePool(FilesList);
    27.     return;
    28. }
    29.  
    30. //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    31. //                                         AddFilesList                                                  
    32. //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    33. void AddFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength)
    34. {
    35.     //получаем указатель на новый блок памяти и сохраняем его в added
    36.     PFNAME_STRUCTURE NewItem = (PFNAME_STRUCTURE)ExAllocateFromPagedLookasideList(FilesList->pPagedLookasideList);
    37.     if (NewItem != NULL){
    38.         RtlZeroMemory(NewItem, sizeof(FNAME_STRUCTURE));
    39.         // Добавить в голову списка
    40.         InsertHeadList(&FilesList->ListHead, &NewItem->ListEntry);
    41.         if (NameLength > sizeof(NewItem->FileName)) NameLength = sizeof(NewItem->FileName);
    42.         RtlCopyMemory(&NewItem->FileName, FileName, NameLength * sizeof(WCHAR));
    43.        
    44.         FilesList->Count++;
    45.         NewItem->Length = NameLength;
    46.        
    47.         DPRINT("FILES_LIST: + File %ws added. Length: %d", NewItem->FileName, NewItem->Length);
    48.     }else{
    49.         DPRINT("FILES_LIST: Very bad. Couldn't allocate from lookaside list");
    50.     }
    51.     return;
    52. }
    53.  
    54. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    55. //                                       DelEntry                                                
    56. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    57. void DelEntry(IN PFILES_LIST FilesList)
    58. // Удалить с конца один элемент
    59. {
    60.     if (!IsListEmpty(&FilesList->ListHead)){
    61.         PLIST_ENTRY tmplistentry = RemoveHeadList(&FilesList->ListHead);
    62.         PFNAME_STRUCTURE fname_struc = CONTAINING_RECORD(tmplistentry, FNAME_STRUCTURE, ListEntry);
    63.         DPRINT("FILES_LIST: - File %ws deleted", fname_struc->FileName);
    64.         ExFreeToPagedLookasideList(FilesList->pPagedLookasideList, fname_struc);
    65.     }else{
    66.         DPRINT("FILES_LIST: An attempt was made to remove entry from empty lookaside list");
    67.     }
    68.     return;
    69. }
    70.  
    71. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    72. //                                       DelFilesList                                                
    73. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    74. BOOLEAN DelFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength)
    75. // Удалить с конца один элемент
    76. {
    77.     if (!IsListEmpty(&FilesList->ListHead)){
    78.         PFNAME_STRUCTURE fname_struc = (PFNAME_STRUCTURE)(FilesList->ListHead.Flink);
    79.         while(TRUE){
    80.             if (&fname_struc->ListEntry == &FilesList->ListHead)
    81.                 break;
    82.             if (fname_struc->Length == NameLength) // Если совпадает длина символа
    83.                 if (_wcsnicmp(fname_struc->FileName, FileName, NameLength) == 0) // Если совпадает имя файла
    84.                 {
    85.                     DPRINT("DelFilesList: - File %ws deleted", fname_struc->FileName);
    86.                     RemoveEntryList(&fname_struc->ListEntry);
    87.                     ExFreeToPagedLookasideList(FilesList->pPagedLookasideList, fname_struc);
    88.                     return TRUE;
    89.                 }
    90.             fname_struc = (PFNAME_STRUCTURE)fname_struc->ListEntry.Flink; // Переходим к следуюзему списку
    91.         }
    92.     }else{
    93.         DPRINT("FILES_LIST: An attempt was made to remove entry from empty lookaside list");
    94.     }
    95.     return FALSE;
    96. }
    97.  
    98. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    99. //                                       IsAddedFilesList                                                
    100. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    101. BOOLEAN         IsAddedFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength)
    102. {
    103.     // Если список пустой - то отменяем нафиг
    104.     if (IsListEmpty(&FilesList->ListHead))
    105.         return FALSE;
    106.     // Указатель на первый элемент
    107.     PFNAME_STRUCTURE fname_struc = (PFNAME_STRUCTURE)(FilesList->ListHead.Flink);
    108.     while(TRUE){
    109.         if (&fname_struc->ListEntry == &FilesList->ListHead)
    110.             break;
    111.         if (fname_struc->Length == NameLength) // Если совпадает длина символа
    112.             if (_wcsnicmp(fname_struc->FileName, FileName, NameLength) == 0) // Если совпадает имя файла
    113.                 return TRUE;
    114.         fname_struc = (PFNAME_STRUCTURE)fname_struc->ListEntry.Flink; // Переходим к следуюзему списку
    115.     }
    116.     return FALSE;
    117. }
    Работает все отлично, но как я понял, для надежности надо делать блокировки. Например чтобы во время выполнения функции IsAddedFilesList удалялся элемент ничего не зависло. Подскажите пожалуйста, все ли я правильно сделал и где нужно добавить чтобы драйвер не падал в синий экран.

    Использую этот код для хранения списка скрываемых файлов путем перехвата NTQueryDerectoryFile
     
  2. ya

    ya New Member

    Публикаций:
    0
    Регистрация:
    31 окт 2007
    Сообщения:
    8
    Я не смотрел правильная ли у тебя работа со списками,
    но советую сипользовать ERESOURCE,
    если речь идет о ядре, а не найтив приложении.
    ExInitializeResourceLite,
    ExDeleteResourceLite
    ExAcquireResourceExclusiveLite захват на запись
    ExAcquireResourceSharedLite на чтение
    ExReleaseResourceLite освобождение

    короче эти функции реализовывают RWlock, что это такое - поищи в гугле.
     
  3. mathio

    mathio New Member

    Публикаций:
    0
    Регистрация:
    16 июн 2007
    Сообщения:
    110
    Вот начал смореть сорцы и первое, за что зацепился взгляд.
    Объясните, как при таких разношерстных структурах
    Код (Text):
    1. typedef struct _FNAME_STRUCTURE
    2. {
    3.   LIST_ENTRY   ListEntry;
    4.   WCHAR FileName[MAX_PATH];
    5.   ULONG      Length;
    6. } FNAME_STRUCTURE, *PFNAME_STRUCTURE;
    7.  
    8. typedef struct _FILES_LIST
    9. {
    10.   PPAGED_LOOKASIDE_LIST pPagedLookasideList;
    11.   LIST_ENTRY ListHead;
    12.   ULONG Count;
    13. } FILES_LIST, *PFILES_LIST;
    возможно вообще срабатывание break'a вот здесь
    Код (Text):
    1. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    2. //                                       DelFilesList                                                
    3. //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    4. BOOLEAN DelFilesList(IN PFILES_LIST FilesList, PWCHAR FileName, ULONG NameLength)
    5. // Удалить с конца один элемент
    6. {
    7.     if (!IsListEmpty(&FilesList->ListHead)){
    8.         PFNAME_STRUCTURE fname_struc = (PFNAME_STRUCTURE)(FilesList->ListHead.Flink);
    9.         while(TRUE){
    10.             if (&fname_struc->ListEntry == &FilesList->ListHead) break; // здесь
    больше код не стал глядеть, ибо по-сути все ясно.
     
  4. Igi

    Igi New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2005
    Сообщения:
    35
    mathio
    Все работает.
    Делал по статье four-f, я так понял FilesList->ListHead - голова списка структур FNAME_STRUCTURE
    FilesList->ListHead.flink - это первая запись в списке
    FilesList->ListHead.blink - это последняя запись в списке

    &fname_struc->ListEntry == &FilesList->ListHead

    Здесь я проверяю, прошел ли круг, т.е. текущая структура fname_struc->ListEntry находится ли она между первым и последним элементом, т.е. равна ли она ListHead. Это я просто два указателя сравниваю.
     
  5. mathio

    mathio New Member

    Публикаций:
    0
    Регистрация:
    16 июн 2007
    Сообщения:
    110
    Вы меня не поняли.
    Я имею ввиду то, что если fname_struc - есть указатель на валидную структуру типа FNAME_STRUCTURE, а FilesList - есть указатель на валидную структуру типа FILES_LIST, то адреса их элементов с типом LIST_ENTRY никак не могут быть равны друг другу, хотя бы потому, что в структуре FNAME_STRUCTURE элемент типа LIST_ENTRY находится по нулевому смещению, а в структуре типа FILES_LIST элемент, имеющий тип LIST_ENTRY, находится по смещению отличному от нуля. Прояснилось?
     
  6. Igi

    Igi New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2005
    Сообщения:
    35
    FILES_LIST - это просто что-то вроде объекта. Где поля:
    PPAGED_LOOKASIDE_LIST pPagedLookasideList - так и не понял зачем, вроде для выделения памяти под элементы списка
    LIST_ENTRY ListHead - указатель на первый и последний элемент списка файлов
    ULONG Count - количество элементов в списке

    FNAME_STRUCTURE - это уже сам элемент списка файлов. Содержит имя файла, количество символов (для более быстрого поиска) и указатель на предыдущий/следующую структуру.

    В общем запутался я сам уже, код ведь полностью работает.
     
  7. Igi

    Igi New Member

    Публикаций:
    0
    Регистрация:
    7 дек 2005
    Сообщения:
    35
    ya
    Большое спасибо.
    Я сделал так: если функция которая только читает данные из списка, например
    IsAddedFilesList
    Тогда вначале вызвать
    ExAcquireResourceSharedLite(&FilesList->Resource, TRUE);
    А перед завершением
    ExReleaseResourceLite(&FilesList->Resource);

    Ну а если же функция которая изменяет данные, то в начале соответственно вызываю
    ExAcquireResourceExclusiveLite(&FilesList->Resource, TRUE);
    А в конце освобождаю этот ресурс.

    Я все правильно понял?
    Т.е. в этом случае читать данные смогут сколько угодно потоков паралельно, но как только начнется запись в них - никто читать не сможет. Да, запись также не начнется - пока все потоки не завершат чтение.
     
  8. Cock

    Cock New Member

    Публикаций:
    0
    Регистрация:
    9 фев 2007
    Сообщения:
    148
    Igi
    правильно
     
  9. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Код (Text):
    1. typedef struct _FNAME_STRUCTURE
    2. {
    3.     LIST_ENTRY ListEntry;
    4.     WCHAR FileName[MAX_PATH];
    5.     ULONG Length;
    6. } FNAME_STRUCTURE, *PFNAME_STRUCTURE;
    7.  
    8. typedef struct _FILES_LIST
    9. {
    10.     PPAGED_LOOKASIDE_LIST pPagedLookasideList;
    11.     LIST_ENTRY ListHead;
    12.     ULONG Count;
    13. } FILES_LIST, *PFILES_LIST;
    Код не смотрел - только структуры - бросилось в глаза следующее:

    1. Длина имени файла в 99,99% случаев значительно меньше MAX_PATH, т.е. бОшьшая часть памяти будет расходоваться впустую.
    2. Использовать LookasideList имеет смысл только там где скорость очень критична. В данном случае это, видимо, не так. Но проблема даже не в этом, а в том, что поиск, в данном случае, можно вести только путем тупого обхода списка и сравнения строк, что невероятно медленно. Так что используй или не используй LookasideList - ничего не измениться. Всё равно будет тормозно и чем длиннее список, тем больше тормоза.
    3. Я бы не плодил новые структуры, а использовал готовые, например, FILE_NAME_INFORMATION.

    Вобщем, советую глянуть IFSKit\src\filesys\filter\filespy\filter\fspyHash.c начиная с комментария "FileName cache routines", где имена файлов хешируются, что значительно эффективнее как по скорости работы, так и по расходу памяти.
     
  10. Cock

    Cock New Member

    Публикаций:
    0
    Регистрация:
    9 фев 2007
    Сообщения:
    148
    Таки прав Дмитрий, лучше искать сравнивая хеши, чем строки:)
    + списки хорошо, можно использовать бинарные деревья скажем, функции для работы с ними реализованы даже в Rtlxxx, но не могу уточнить в какой версии винды они уже есть.
    Для полной совместимости лучше реализовать свои функции, если деревья сложно - можно использовать хеш таблицы с заголовком списка в узлах каждой, или еще какие-то другие виды асд