Deadlock due to TopLevelIrp not null when calling FltQueryInformationFile() for UNC files, how can I fix it?

Hello,

I am a minifilter and wanting to collect the file metadata so calling FltQueryInformationFile() but its always (90% of the times) failing the check for TopLevelIrp(). If I dont check for TopLevelIrp(), it expectedly always leads to deadlock due to the FCB lock synchronization between RDBSS and other similar routines. What can I do to fix this issue? I also pasted the offending call stack below.

    pFileInfo->AllocationSize = stdInfo.AllocationSize;
    pFileInfo->ChangeTime = basicInfo.ChangeTime;
    pFileInfo->CreationTime = basicInfo.CreationTime;
    pFileInfo->EndOfFile = stdInfo.EndOfFile;
    pFileInfo->FileAttributes = basicInfo.FileAttributes;
    pFileInfo->LastAccessTime = basicInfo.LastAccessTime;
    pFileInfo->LastWriteTime = basicInfo.LastWriteTime;

///////////

if (KeGetCurrentIrql() != PASSIVE_LEVEL) {
// Do not call FltQueryInformationFile
}

if (IoGetTopLevelIrp() != NULL) { <============== fails here
// Do not call FltQueryInformationFile here
}

if (KeAreAllApcsDisabled()) {
// Do not call FltQueryInformationFile
}

/////////////////////

03 nt!KeWaitForSingleObject
04 nt!ExpWaitForResource
05 nt!ExpAcquireResourceSharedLite
06 nt!ExAcquireResourceSharedLite
07 rdbss!RxWaitForStableLViewOnFcbAndAcquireRundown
08 rdbss!RxFsdCommonDispatch
09 rdbss!RxFsdDispatch
0a mrxsmb!MRxSmbFsdDispatch
0b nt!IopfCallDriver
0c nt!IofCallDriver
0d mup!MupStateMachine
0e mup!MupFsdIrpPassThrough
0f nt!IopfCallDriver
10 nt!IofCallDriver
11 FLTMGR!FltpLegacyProcessingAfterPreCallbacksCompleted
12 FLTMGR!FltPerformSynchronousIo
13 FLTMGR!FltQueryInformationFile <===========================
14 myminifilter <=========================
15 myminifilter <===================================
16 FLTMGR!FltpPerformPostCallbacksWorker
17 FLTMGR!FltpProcessIoCompletion
18 FLTMGR!FltpPassThroughCompletionWorker
19 FLTMGR!FltpPassThroughCompletion
1a nt!IopfCompleteRequest
1b nt!IofCompleteRequest
1c mup!MupiIoPostProcess
1d mup!MupStateMachine
1e mup!MupStateMachineWorker
1f mup!MupiUncProviderCompletion
20 nt!IopfCompleteRequest
21 nt!IofCompleteRequest
22 rdbss!RxCompleteRequestEx
23 rdbss!RxLowIoCompletionTail
24 rdbss!RxLowIoCompletion
25 mrxsmb20!Smb2Read_Finalize
26 mrxsmb!SmbCepFinalizeExchangeWorker
27 rdbss!RxpProcessWorkItem
28 nt!ExpWorkerThread

0: kd> dt nt!_ethread ffff9f89843e3400 t*
   +0x000 Tcb : _KTHREAD
   +0x4e8 TerminationPort : (null) 
   +0x550 TopLevelIrp : 0xffff8788`f475aa48

0: kd> dps 0xffff8788f475aa48
ffff8788`f475aa48  00000000`4c547852
ffff8788`f475aa50  ffff9f89`793e7040
ffff8788`f475aa58  ffff9f89`8e73b7c0
ffff8788`f475aa60  ffff9f89`8f758310 <========= IRP
ffff8788`f475aa68  00000000`00000000

0: kd> !irp ffff9f89`8f758310
Irp is active with 4 stacks 2 is current (= 0xffff9f898f758428)
 No Mdl: System buffer=ffff8788f475b0c8: Thread ffff9f89843e3400:  Irp stack trace.  
     cmd  flg cl Device   File     Completion-Context
 [N/A(0), N/A(0)]
            0  0 00000000 00000000 00000000-00000000    

			Args: 00000000 00000000 00000000 00000000
>[IRP_MJ_QUERY_INFORMATION(5), N/A(0)]
            0 e0 ffff9f89793e7040 ffff9f8992653150 fffff800319d1b90-ffff9f89943813d0 Success Error Cancel 
	       \FileSystem\mrxsmb	mup!MupiUncProviderCompletion
			Args: 00000038 00000022 00000000 00000000
 [IRP_MJ_QUERY_INFORMATION(5), N/A(0)]
            0 e0 ffff9f89739c9ce0 ffff9f8992653150 fffff8002f2b48a0-ffff9f8994bd4550 Success Error Cancel 
	       \FileSystem\Mup	FLTMGR!FltpSynchronizedOperationCompletion
			Args: 00000038 00000022 00000000 00000000
 [IRP_MJ_QUERY_INFORMATION(5), N/A(0)]
            0  0 ffff9f8973b25790 ffff9f8992653150 00000000-00000000    
	       \FileSystem\FltMgr
			Args: 00000038 00000022 00000000 00000000

I am collecting the metadata info as part of certain pre and post callbacks.

PostCreate
PreRead
PostRead
PreWrite
PreSetInfo
PreCleanup
PreClose
PreSetSecurity

@Neal_Christiansen Can you please look into this and suggest? you have been instrumental in the past so tagging u here again, sorry..

This is the main purpose of checking the Top-Level IRP. The Top-Level IRP is a concept used to tell file system drivers (and filters) where the original request started. The request may have originated from a user operation, such as when an application calls the ReadFile API. However, some requests are initiated by the Memory Manager when an application accesses a virtual address that is mapped to file content. Requests may also be initiated by the Cache Manager during a flush or by the Lazy Writer thread.

Depending on the original requester, there are lock‑acquisition rules that file system drivers must follow to maintain the correct locking hierarchy. That is why filter drivers are not allowed to submit certain additional requests when the Top-Level IRP is not NULL. Some requests may attempt to acquire file system locks again, which can cause system deadlocks.

Refer to the book Windows NT File System Internals, Chapter 10: “I/O Revisited: Who Called?”. You may need to move the metadata collection to another point, or it may be irrelevant depending on who is calling the file system at that moment.

1 Like