阅读:7160回复:17
CcPurgeCacheSection清空cache求救
在osronline看到如下代码,是用来清空cache的,但是测试之后发现有死锁,大侠指点指点该怎么做才能 解决死锁问题,谢谢!!
//for example :filename is L"\\??\\E:\\test.txt"; BOOLEAN PurgeFile (WCHAR * filename ) { UNICODE_STRING fileNameUnicodeString; OBJECT_ATTRIBUTES objectAttributes; PFILE_OBJECT fileObject; HANDLE ntFileHandle; PFSRTL_COMMON_FCB_HEADER Fcb; BOOLEAN result = TRUE, IoPagingRelease = FALSE, MainResRelease = FALSE; NTSTATUS status; IO_STATUS_BLOCK ioStatus; //Open file RtlInitUnicodeString( &fileNameUnicodeString, filename ); InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwCreateFile( &ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS, &objectAttributes, &ioStatus, NULL, 0, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE, NULL, 0 ); if( !NT_SUCCESS( status ) ) { KdPrint(("sfilter!PurgeFile: !NT_SUCCESS( status )\n")); return FALSE; } // Find file-object it refers to KdPrint(("sfilter!PurgeFile: Find file-object it refers to\n")); status = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA, NULL, KernelMode, (PVOID*)&fileObject, NULL ); if( !NT_SUCCESS( status )) { KdPrint(("sfilter!PurgeFile: ZwClose( ntFileHandle );\n")); ZwClose( ntFileHandle ); return FALSE; } Fcb = (PFSRTL_COMMON_FCB_HEADER)(fileObject->FsContext); if (Fcb==NULL) { KdPrint(("sfilter!PurgeFile: Fcb==NULL\n")); return FALSE; } if (!ExAcquireResourceExclusive(Fcb->Resource, TRUE )) { KdPrint(("sfilter!PurgeFile: !ExAcquireResourceExclusive(Fcb->Resource, TRUE )\n")); result = FALSE; } else { MainResRelease = TRUE; } if (!ExAcquireResourceExclusive( Fcb->PagingIoResource , TRUE )) result = FALSE ; else IoPagingRelease = TRUE; //Yes,result must be TRUE KdPrint(("sfilter!PurgeFile: Yes,result must be TRUE\n")); if (result && (fileObject->SectionObjectPointer->ImageSectionObject != NULL)) if (!MmFlushImageSection(fileObject->SectionObjectPointer, MmFlushForWrite )) result = FALSE; if (result &&(fileObject->SectionObjectPointer->DataSectionObject != NULL)) { //GOD!!!!!!!DeadLock occurs When Call CcPurgeCacheSection KdPrint(("sfilter!PurgeFile: GOD!!!!!!!DeadLock occurs When Call CcPurgeCacheSection\n")); if (!CcPurgeCacheSection( fileObject->SectionObjectPointer, NULL, 0, FALSE ) ) result = FALSE; } if (IoPagingRelease) ExReleaseResource(Fcb->PagingIoResource); if (MainResRelease) ExReleaseResource(Fcb->Resource); ZwClose( ntFileHandle ); ObDereferenceObject( fileObject ); KdPrint(("sfilter!PurgeFile: !success!!\n")); return result; } 背景知识: 1) CcPurgeCacheSection The CcPurgeCacheSection routine purges all or a portion of a cached file from the system cache. BOOLEAN CcPurgeCacheSection( IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN PLARGE_INTEGER FileOffset OPTIONAL, IN ULONG Length, IN BOOLEAN UninitializeCacheMaps ); Parameters SectionObjectPointer Pointer to a structure containing the file object's section object pointers. FileOffset Pointer to a variable that specifies the starting byte offset within the cached file where the data is to be purged. If FileOffset is NULL, the entire file is purged from the cache. If FileOffset is not NULL, only the byte range specified by FileOffset and Length is purged. Length Length of the byte range to purge, starting at FileOffset. If Length is zero, the range from FileOffset to the end of the file is purged. If FileOffset is NULL, Length is ignored. UninitializeCacheMaps Set to TRUE to uninitialize any private cache maps for the file before purging the file data. Headers Declared in ntifs.h. Include ntifs.h. Return Value CcPurgeCacheSection returns TRUE if the cached file data was successfully purged, FALSE otherwise. Comments File systems call CcPurgeCacheSection to purge stale data from the cache. For example, when a file is truncated but not deleted, CcPurgeCacheSection should be called to purge any cached data that is no longer part of the file. CcPurgeCacheSection will not purge mapped files. Before calling CcPurgeCacheSection, the caller must acquire the file exclusively and ensure that no thread, including the caller, has mapped or pinned any byte range in the file. Callers of CcPurgeCacheSection must be running at IRQL < DISPATCH_LEVEL. 2) about Purge the file cache I have read A notes: >This works for me: >1. Lock the FCB Resource exclusive (after checking for non-NULL). >2. Lock the FCB PagingIoResource exclusive (after checking for non-NULL >and in a polling loop to prevent deadlocks, since different filesystems >will apparently acquire these two locks in different orders). >3. If fobj->SectionObjectPointer is non-NULL then: >3a. do a CcFlushCache for the entire file >3b. do a MmFlushImageSection for write if >fobj->SectionObjectPointer->ImageSectionObject is >non-NULL <...excess quoted lines suppressed...> I according to it,make the code below,but It will deadlock when calling CcPurgeCacheSection. God,it puzzled me.please help me. If your code can work fine,please...thanks you very much. perhaps,the reason is I don't understand the sentence: >and in a polling loop to prevent deadlocks, since different filesystems >will apparently acquire these two locks in different orders this is my code,the function is used at IRP_MJ_CREATE dispatch and IRP_MJ_CLOSE dispatch routine.ah,I filter it. Addtional,In my code,when I filter the Paging Read/Write,I roll a IRP to below device(Query file name). Yes,sometimes deadlock when calling CcPurgeCacheSection. when I delete the code about rolling a IRP to Query file name,That's OK(perhaps,I just can't find deadlock in test for a long period). But I'm not sure that's key. OK,this is my code: |
|
沙发#
发布于:2007-01-05 00:11
osronline上几位牛人的回答,但小牛愚笨,不太理解,牛牛们发发话,指点指点,最好能把这个函数做得比较通用.
1)Alexei Jelvis When you get a deadlock you need to check what the current thread is waiting for and find the other thread that is holding this resource. You can use !locks command to enumerate all locks that are acquired in the system and check if there is a loop in waiting threads. Alternatively, you can dump all threads using !process 0 7 and check if there are threads in which you filter is on the stack. If there is such thread you need to check if it is holding the resource the first thread is waiting for. I would suggest not to query name at paging io dispatch routine. When paging IO occurs some resources are already acquired and sending query information IRP may cause a deadlock. Hodling paging IO will cause CcPurgeCacheSection to wait. Also calling this function from IRP_MJ_CLOSE dispatch routine is not a good idea. This IRP comes when ObDereferenceObject is invoked which may happen when arbitrary set of resources is acquired by the calling thread. IRP_MJ_CLOSE may be generated from CcPurgeCacheSection so it is also potential cause of deadlock. I would suggest not to query name at paging io dispatch routine. When paging IO occurs some resources are already acquired and sending query information IRP may cause a deadlock. Hodling paging IO will cause CcPurgeCacheSection to wait. Also calling this function from IRP_MJ_CLOSE dispatch routine is not a good idea. This IRP comes when ObDereferenceObject is invoked which may happen when arbitrary set of resources is acquired by the calling thread. IRP_MJ_CLOSE may be generated from CcPurgeCacheSection so it is also potential cause of deadlock. Alexei. 2)Nick Ryan (MVP for DDK) Resources can be acquired recursively by the same thread as described in the DDK docs for the ExAcquire* functions. The deadlock comes when you try to acquire main and paging in one order, while the FSD may try to take them in the reverse order in another thread. You can prevent a deadlock here by take one lock, then testing if the other is currently held. If no, take it, and you've got both locks. If yes, release the first lock, pause for 50 ms or so, and repeat. |
|
板凳#
发布于:2007-03-08 09:16
根据最后一句解释,写了如下代码,:-) :
BOOLEAN ffdrv_puge_file_cache(PFILE_OBJECT FileObject) { PFSRTL_COMMON_FCB_HEADER Fcb = NULL; LARGE_INTEGER Interval = {0}; BOOLEAN result = TRUE, IoPagingRelease = FALSE, MainResRelease = FALSE; Fcb = (PFSRTL_COMMON_FCB_HEADER)(FileObject->FsContext); if(Fcb == NULL) { return FALSE; } Interval.QuadPart = -1 * (LONGLONG)50; for(; (Fcb->Resource != NULL) || (Fcb->PagingIoResource != NULL); ) { if( (Fcb->Resource == NULL) || ExAcquireResourceExclusive(Fcb->Resource, TRUE) ) { MainResRelease = TRUE; } else { MainResRelease = FALSE; } if(Fcb->PagingIoResource != NULL) { if( !( (Fcb->PagingIoResource->Flag & ResourceOwnedExclusive) && (Fcb->PagingIoResource->OwnerThreads[0].OwnerThread == ExGetCurrentResourceThread()) ) ) { if( ExAcquireResourceExclusive(Fcb->PagingIoResource, TRUE) ) { IoPagingRelease = TRUE; } else { IoPagingRelease = FALSE; } } } else { IoPagingRelease = TRUE; } if(MainResRelease && IoPagingRelease) { break; } if(Fcb->Resource != NULL) { ExReleaseResource(Fcb->Resource); } MainResRelease = FALSE; KeDelayExecutionThread(KernelMode, FALSE, &Interval); } if( FileObject->SectionObjectPointer->DataSectionObject != NULL ) { result = CcPurgeCacheSection(FileObject->SectionObjectPointer, NULL, 0, FALSE); } if(IoPagingRelease && Fcb->PagingIoResource != NULL) { ExReleaseResource(Fcb->PagingIoResource); } if(MainResRelease && Fcb->Resource != NULL) { ExReleaseResource(Fcb->Resource); } return result; } |
|
|
地板#
发布于:2007-03-08 09:43
大家可以验证一下执行后FILE_OBJECT的SectionObjectPointe的内容。
|
|
|
地下室#
发布于:2007-03-08 15:18
这样的代码无法清除内存映射的缓存,它缺少一条关键的代码,纵然解决了死锁也枉然。
|
|
5楼#
发布于:2007-03-09 13:22
引用第4楼yaolixing于2007-03-08 15:18发表的“”: If there are no mapped views of the image section。 MmFlushImageSection destroys the image section and returns any used pages to the free list. 所以首先要将已有的Mapped section unmap! |
|
|
6楼#
发布于:2007-03-09 15:51
俺只是简单翻译,批判就是最大的进步,:-)
|
|
|
7楼#
发布于:2007-03-10 14:58
先谢谢楼上的
文档上说CcPurgeCacheSection will not purge mapped files,要如何解决 |
|
8楼#
发布于:2007-03-10 18:41
我写了一个函数,不知对否?贴出来给大家看看。
还有请问yaolixing,要清除内存映射的缓存,是不是要调用MmFlushImageSection(pFileObject->SectionObjectPointer, MmFlushForDelete); 注意还没测过。 void ManageFileCache(PFILE_OBJECT pFileObject, BOOL bClearOrFlush) { PFSRTL_COMMON_FCB_HEADER pFcb; LARGE_INTEGER liInterval; BOOL bNeedReleaseResource = FALSE; BOOL bNeedReleasePagingIoResource = FALSE; KIRQL irql; pFcb = (PFSRTL_COMMON_FCB_HEADER)pFileObject->FsContext; if(pFcb == NULL) { return; } irql = KeGetCurrentIrql(); if (irql >= DISPATCH_LEVEL) { return; } liInterval.QuadPart = -1 * (LONGLONG)50; while (TRUE) { BOOL bBreak = TRUE; BOOL bLockedResource = FALSE; BOOL bLockedPagingIoResource = FALSE; bNeedReleaseResource = FALSE; bNeedReleasePagingIoResource = FALSE; if (pFcb->PagingIoResource) { bLockedPagingIoResource = ExIsResourceAcquiredExclusiveLite(pFcb->PagingIoResource); } if (pFcb->Resource) { bLockedResource = TRUE; if (ExIsResourceAcquiredExclusiveLite(pFcb->Resource) == FALSE) { bNeedReleaseResource = TRUE; if (bLockedPagingIoResource) { if (ExAcquireResourceExclusiveLite(pFcb->Resource, FALSE) == FALSE) { bBreak = FALSE; bNeedReleaseResource = FALSE; bLockedResource = FALSE; } } else { ExAcquireResourceExclusiveLite(pFcb->Resource, TRUE); } } } //if (bBreak) if (bLockedPagingIoResource == FALSE) { if (pFcb->PagingIoResource) { bLockedPagingIoResource = TRUE; bNeedReleasePagingIoResource = TRUE; if (bLockedResource) { if (ExAcquireResourceExclusiveLite(pFcb->PagingIoResource, FALSE) == FALSE) { bBreak = FALSE; bLockedPagingIoResource = FALSE; bNeedReleasePagingIoResource = FALSE; } } else { ExAcquireResourceExclusiveLite(pFcb->PagingIoResource, TRUE); } } } if (bBreak) { break; } if (bNeedReleasePagingIoResource) { ExReleaseResourceLite(pFcb->PagingIoResource); } if (bNeedReleaseResource) { ExReleaseResourceLite(pFcb->Resource); } if (irql == PASSIVE_LEVEL) { KeDelayExecutionThread(KernelMode, FALSE, &liInterval); } else { KEVENT waitEvent; KeInitializeEvent(&waitEvent, NotificationEvent, FALSE); KeWaitForSingleObject(&waitEvent, Executive, KernelMode, FALSE, &liInterval); } } //加锁完毕 if (pFileObject->SectionObjectPointer) { if (bClearOrFlush == FALSE) { IO_STATUS_BLOCK ioStatus; CcFlushCache(pFileObject->SectionObjectPointer, NULL, 0, &ioStatus); if (pFileObject->SectionObjectPointer->ImageSectionObject) { MmFlushImageSection(pFileObject->SectionObjectPointer, MmFlushForWrite);//MmFlushForDelete } } CcPurgeCacheSection(pFileObject->SectionObjectPointer, NULL, 0, FALSE); } if (bNeedReleasePagingIoResource) { ExReleaseResourceLite(pFcb->PagingIoResource); } if (bNeedReleaseResource) { ExReleaseResourceLite(pFcb->Resource); } } |
|
9楼#
发布于:2007-03-13 16:43
1 CcFlushCache
2 MmFlushImageSection 3 CcPurgeCacheSection |
|
10楼#
发布于:2007-03-23 13:58
这个函数可以用的,基本上尝试一两次就可以获lock
sfilter!SfRead: Decrypt 开始读新的IRP包 E:\lsx\fff.txt sfilter!SfRead: Decrypt 开始解密文件头 E:\lsx\fff.txt CompletionCtx->Length = 4096 IrpSp->Parameters.Read.ByteOffset.LowPart = 0 sfilter!SfRead: 发现加密标记 Decrypt E:\lsx\fff.txt SFilter!SioctlDeviceControl 解压前长度 UnCompressDataLen = 38 SFilter!SioctlDeviceControl 解压后长度 UnCompressDataLen = 509 lsx KeClearEvent gpEventDeCode sussfully! sfilter!SfRead: 解压成功 Decrypt E:\lsx\fff.txt UnCompressData = 1111112sd1111111111123sdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd11111112sd1111111111123sdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd11111112sd1111111111123sdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd11111112sd1111111111123sdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd sfilter!SfRead: Decrypt 结束读新的IRP包 E:\lsx\fff.txt sfilter!SfRead: Decrypt 开始读新的IRP包 E:\lsx\fff.txt sfilter!SfRead: Decrypt 开始解密文件头 E:\lsx\fff.txt CompletionCtx->Length = 20480 IrpSp->Parameters.Read.ByteOffset.LowPart = 4096 sfilter!SfRead: Decrypt 结束读新的IRP包 E:\lsx\fff.txt sfilter!SfClose: 开始关闭 E:\lsx\fff.txt sfilter!SfClose: 开始清空cache sfilter!ffdrv_puge_file_cache 失败 sfilter!SfWrite: Encrypt 开始写新的IRP包 E:\lsx\fff.txt lsx UnCompressWaitEvent sussfully! SFilter!SioctlDeviceControl 压缩前长度 CompressDataLen = 509 SFilter!SioctlDeviceControl 压缩后长度 CompressDataLen = 38 lsx KeClearEvent gpEventObject sussfully! sfilter!SfWrite: 开始添加加密标记 Encrypt E:\lsx\fff.txt need compress! sfilter!SfWrite: Encrypt 加密文件头成功 E:\lsx\fff.txt Length = 24576 IrpSp->Parameters.Read.ByteOffset.LowPart = 0 sfilter!SfWrite: Encrypt 结束写新的IRP包 E:\lsx\fff.txt lsx CompressWaitEvent sussfully! sfilter!ffdrv_puge_file_cache 成功 sfilter!SfRead: Decrypt 开始读新的IRP包 E:\lsx\fff.txt sfilter!SfRead: Decrypt 开始解密文件头 E:\lsx\fff.txt CompletionCtx->Length = 4096 IrpSp->Parameters.Read.ByteOffset.LowPart = 0 sfilter!SfRead: Decrypt 结束读新的IRP包 E:\lsx\fff.txt sfilter!SfRead: Decrypt 开始读新的IRP包 E:\lsx\fff.txt sfilter!SfRead: Decrypt 开始解密文件头 E:\lsx\fff.txt CompletionCtx->Length = 20480 IrpSp->Parameters.Read.ByteOffset.LowPart = 4096 sfilter!SfRead: Decrypt 结束读新的IRP包 E:\lsx\fff.txt sfilter!SfClose: 开始关闭 E:\lsx\fff.txt sfilter!SfClose: 开始清空cache sfilter!ffdrv_puge_file_cache 失败 sfilter!ffdrv_puge_file_cache 成功 sfilter!SfRead: Decrypt 开始读新的IRP包 E:\lsx\fff.txt sfilter!SfRead: Decrypt 开始解密文件头 E:\lsx\fff.txt CompletionCtx->Length = 4096 IrpSp->Parameters.Read.ByteOffset.LowPart = 0 sfilter!SfRead: Decrypt 结束读新的IRP包 E:\lsx\fff.txt sfilter!SfRead: Decrypt 开始读新的IRP包 E:\lsx\fff.txt sfilter!SfRead: Decrypt 开始解密文件头 E:\lsx\fff.txt CompletionCtx-> |
|
11楼#
发布于:2007-03-23 16:23
void ManageFileCache(PFILE_OBJECT pFileObject, BOOL bClearOrFlush)
符合下面的流程 OK the previous message got completely garbled, let's have another go at it: This works for me: 1. Lock the FCB Resource exclusive (after checking for non-NULL). 2. Lock the FCB PagingIoResource exclusive (after checking for non-NULL and in a polling loop to prevent deadlocks, since different filesystems will apparently acquire these two locks in different orders). 3. If fobj->SectionObjectPointer is non-NULL then: 3a. do a CcFlushCache for the entire file 3b. do a MmFlushImageSection for write if fobj->SectionObjectPointer->ImageSectionObject is non-NULL 3c. do a CcPurgeCacheSection (last param FALSE) if fobj->SectionObjectPointer->DataSectionObject is non-NULL 4. Unlock the FCB PagingIoResource if you locked it. 5. Unlock the FCB Resource if you locked it. |
|
12楼#
发布于:2007-03-24 09:31
你确信可以用?
我在IRP_MJ_CLOSE中调用还是会死锁。好象除非我不加锁,要不然都有死锁的可能。 |
|
13楼#
发布于:2007-03-24 15:16
我也是 在IRP_MJ_CLOSE中调用的,不过我不是对所有的close历程都做处理,只是对加密过的文件处理,目前测试过的没有出现过死锁的现象.
|
|
14楼#
发布于:2007-03-26 22:41
我也是 在IRP_MJ_CLOSE中调用,只是对加密过的文件处理
void ManageFileCache(PFILE_OBJECT pFileObject, BOOL bClearOrFlush) BOOLEAN ffdrv_puge_file_cache(PFILE_OBJECT FileObject) 这两个,我都试过了,都会deadlock 不知道是哪儿的问题,晕...我是xp,ntfs |
|
15楼#
发布于:2007-03-27 08:28
不加锁
|
|
16楼#
发布于:2007-07-23 17:39
CcPurgeCacheSection 请问一下 这个函数会不会在通过pageio的形式来请求pFcb->PagingIoResource啊?如果是的话,在前面已经取到了这个lock,那后面的acquire肯定会deadlock了吧
|
|
17楼#
发布于:2007-07-23 18:17
咱们处理的nocache,应该不会deadlock出现,只要在前面判断一下是否是自己的加解密文件即可,我也测试过上面的代码,ok的。。。
|
|