Summary - Was Re: IoCancelFileOpen leaving handle open

IoCancelFileOpen. Badness. Avoid as plague.

“Neil Weicher” wrote in message news:xxxxx@ntfsd…
>I know this is very old-school, but sometimes I have to cancel an
>IRP_MJ_CREATE in the completion routine in my legacy FSFD. Fortunately it
>has only happened in testing but never “in the field”.
>
> IoCancelFileOpen appears to work. However, when I terminate the User
> process that was opening the file, and then start it again, it says that
> the file is already in use. Process Explorer does not show any process
> actually having it open.
>
> Somehow IoCancelFileOpen is not decrementing the use count. Do I need to
> do something more than simply call IoCancelFileOpen? Do I need to
> complete the Irp and/or set a specific status?
>
> Thanks.
>
>
>

“Lijun Wang” wrote in message news:xxxxx@ntfsd…
> Also, please check this out
> http://www.microsoft.com/whdc/driver/kernel/IRPs.mspx,
> “Handling IRPs: What Every Driver Writer Needs to Know” – it is a simple
> and
> essential white paper from MS on how to handle IRPs in general.

Thanks. Ok, I went over it several times. Also went over the corresponding
chaptors in the Nagar book.

Which brings up another question: why is my legacy FSFD seeing reads or
writes with Irp->MdlAddress == NULL? According to the document, neither
I/O uses MdlAddress.

> According to the document, neither I/O uses MdlAddress.

Neither I/O uses Irp->UserBuffer. If Irp->MdlAddress is filled in, it is because someone locked down the original buffer OR they have used an unmapped MDL and the address is really just an arbitrary value (paging I/O falls into this latter category - the MDL is NOT mapped and the UserVA associated with it is NOT necessarily valid - but Irp->UserBuffer must be the same as the UserVA in the MDL, otherwise the logic within the file systems fails to work properly when they build partial MDLs and associated IRPs.)

Tony
OSR

“Tony Mason” wrote in message news:xxxxx@ntfsd…
> Neither I/O uses Irp->UserBuffer.

Doh! Reading the wrong paragraph. Been looking at this problem too long.

Ok, so in my FSFD read dispatch routine, if MdlAddress is null and
UserBuffer is not null, I allocate & lock an Mdl and store it in
Irp->MdlAddress. Am I responsible for unlocking the pages in the completion
routine, or is that handled for me?

“Dopey” wrote in message news:xxxxx@ntfsd…
> IoCancelFileOpen. Badness. Avoid as plague.

Thanks - I think that is the way to go.

It is handled for you by the I/O Manager in the specific scenario that you described.

Tony
OSR

Dopey wrote:

IoCancelFileOpen. Badness. Avoid as plague.

OK, sorry for the late response, busy at plugfest.

There has been some misinformation on this topic.

IoCancelFileOpen() is far from bad … in the old days one had to
manually create and send an IRP_MJ_CLEANUP and IRP_MJ_CLOSE. If the
developer was not familiar with the workings of why each of these
requests are issued, then they could issue an IRP_MJ_CLOSE on a file
object which had caching initialized and MM still had a reference on the
file object. This would result in a crash at some point later.

IoCancelFileOpen() is not a simple wrapper around both of the above
Irps. It does issue an IRP_MJ_CLEANUP but conditionally sends the
IRP_MJ_CLOSE, depending on the state of the file object. If the file
object still has a reference then the IRP_MJ_CLOSE is not issued but
instead normal tear down of the file object ensues and the object
manager will perform cleanup when appropriate.

In the end, if you are careful to not initialize caching on a stack
based file object, because this WILL result in a crash, then calling
IoCancelFileOpen() in post create is fine.

Again, checks must be made to avoid stack based file objects, these are
bad. Short of this, IoCancelFileOpen() works as it should and is used by
many successfully.

Pete


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295

Following is the disassembly code of the IoCancelFileOpen in Xp:

From this I do not see it is doing much other than wrapping an IRP_MJ_CLEANUP.

kd> uf IoCancelFileOpen
nt!IoCancelFileOpen:
805693d0 8bff??? mov??? edi,edi
805693d2 55??? push??? ebp
805693d3 8bec??? mov??? ebp,esp
805693d5 83ec10??? sub??? esp,10h
805693d8 53??? push??? ebx
805693d9 8b5d0c??? mov??? ebx,dword ptr [ebp+0Ch] // ebx = fileObject
805693dc 8b432c??? mov??? eax,dword ptr [ebx+2Ch] // eax = fileObject->Flags
805693df a900000400??? test??? eax,40000h // fileObject->Flags & FO_HANDLE_CREATED
805693e4 56??? push??? esi
805693e5 57??? push??? edi
805693e6 7412??? je??? nt!IoCancelFileOpen+0x2a (805693fa)
// handle already created, this is not safe, crash!
nt!IoCancelFileOpen+0x18:
805693e8 6a00??? push??? 0
805693ea 6a00??? push??? 0
805693ec ff7508??? push??? dword ptr [ebp+8]
805693ef 53??? push??? ebx
805693f0 68e8000000??? push??? 0E8h
805693f5 e810f5f8ff??? call??? nt!KeBugCheckEx (804f890a)
//
nt!IoCancelFileOpen+0x2a:
805693fa 0d00002000??? or??? eax,200000h
805693ff 89432c??? mov??? dword ptr [ebx+2Ch],eax
80569402 8d45f8??? lea??? eax,[ebp-8]
80569405 8945fc??? mov??? dword ptr [ebp-4],eax
80569408 8945f8??? mov??? dword ptr [ebp-8],eax
8056940b 8b4508??? mov??? eax,dword ptr [ebp+8]
8056940e 33ff??? xor??? edi,edi
80569410 897b60??? mov??? dword ptr [ebx+60h],edi
80569413 0fbe4030??? movsx?? eax,byte ptr [eax+30h]
80569417 50??? push??? eax
80569418 c645f001??? mov??? byte ptr [ebp-10h],1
8056941c c645f204??? mov??? byte ptr [ebp-0Eh],4
80569420 897df4??? mov??? dword ptr [ebp-0Ch],edi
80569423 e8b89af8ff??? call??? nt!IopAllocateIrpMustSucceed (804f2ee0) // Allocate an IRP
80569428 8bf0??? mov??? esi,eax // irp

8056942a 895e64??? mov??? dword ptr [esi+64h],ebx //esi = IRP->Tail.Overlay.OriginalFileObject = fileObject
8056942d 64a124010000??? mov??? eax,dword ptr fs:[00000124h]
80569433 894650??? mov??? dword ptr [esi+50h],eax
80569436 8d45f0??? lea??? eax,[ebp-10h]
80569439 89462c??? mov??? dword ptr [esi+2Ch],eax
8056943c 8d4618??? lea??? eax,[esi+18h]
8056943f 894628??? mov??? dword ptr [esi+28h],eax
// nextStackLocation
80569442 8b4660??? mov??? eax,dword ptr [esi+60h]
80569445 83e824??? sub??? eax,24h
//
80569448 c6462000??? mov??? byte ptr [esi+20h],0
8056944c 897e30??? mov??? dword ptr [esi+30h],edi
8056944f c7460804040000? mov??? dword ptr [esi+8],404h
80569456 b101??? mov??? cl,1
80569458 c60012??? mov??? byte ptr [eax],12h // nextStackLocation->MajorFunction = IRP_MJ_CLEANUP
8056945b 895818??? mov??? dword ptr [eax+18h],ebx
8056945e ff15f4764d80??? call??? dword ptr [nt!_imp_KfRaiseIrql (804d76f4)]
80
569464 8b5650??? mov??? edx,dword ptr [esi+50h]
80569467 81c210020000??? add??? edx,210h
8056946d 8b0a??? mov??? ecx,dword ptr [edx]
8056946f 8d7e10??? lea??? edi,[esi+10h]
80569472 890f??? mov??? dword ptr [edi],ecx
80569474 895704??? mov??? dword ptr [edi+4],edx
80569477 897904??? mov??? dword ptr [ecx+4],edi
8056947a 8ac8??? mov??? cl,al
8056947c 893a??? mov??? dword ptr [edx],edi
8056947e ff151c774d80??? call??? dword ptr [nt!_imp_KfLowerIrql (804d771c)]
80569484 56??? push??? esi // irp
80569485 ff7508??? push??? dword ptr [ebp+8] // device
80569488 e8295df8ff??? call??? nt!IoCallDriver (804ef1b6) // send the cleanup

8056948d 3d03010000??? cmp??? eax,103h // STATUS_PENDING
80569492 7510??? jne??? nt!IoCancelFileOpen+0xd4 (805694a4)
// if it is STATUS_PENDING, wait for it
nt!IoCancelFileOpen+0xc4:
80569494 33c0??? xor??? eax,eax
80569496 50??? push??? eax
80569497 50??? push??? eax
80569498 50??? push??? eax
80569499 6a06??? push??? 6
8056949b 8d45f0??? lea??? eax,[ebp-10h]
8056949e 50??? push??? eax
8056949f e85803f9ff??? call??? nt!KeWaitForSingleObject (804f97fc)
nt!IoCancelFileOpen+0xd4:
805694a4 b101??? mov??? cl,1
805694a6 ff15f4764d80??? call??? dword ptr [nt!_imp_KfRaiseIrql (804d76f4)]
805694ac 8b17??? mov??? edx,dword ptr [edi]
805694ae 8ac8??? mov??? cl,al
805694b0 8b4704??? mov??? eax,dword ptr [edi+4]
805694b3 8910??? mov??? dword ptr [eax],edx
805694b5 894204??? mov??? dword ptr [edx+4],eax
805694b8 897f04??? mov??? dword ptr [edi+4],edi
805694bb 893f??? mov??? dword ptr [edi],edi
805694bd ff151c774d80??? call??? dword ptr [nt!_imp_KfLowerIrql (804d771c)]
805694c3 56??? push??? esi
805694c4 e80b4cf8ff??? call??? nt!IoFreeIrp (804ee0d4) // free the IRP

805694c9 83636000??? and??? dword ptr [ebx+60h],0
805694cd 5f??? pop??? edi
805694ce 5e??? pop??? esi
805694cf 5b??? pop??? ebx
805694d0 c9??? leave
805694d1 c20800??? ret??? 8

?


From: Peter Scott
To: Windows File Systems Devs Interest List
Sent: Tue, January 26, 2010 12:43:21 PM
Subject: Re: [ntfsd] Summary - Was Re: IoCancelFileOpen leaving handle open

Dopey wrote:
> IoCancelFileOpen. Badness. Avoid as plague.
>

OK, sorry for the late response, busy at plugfest.

There has been some misinformation on this topic.

IoCancelFileOpen() is far from bad … in the old days one had to manually create and send an IRP_MJ_CLEANUP and IRP_MJ_CLOSE. If the developer was not familiar with the workings of why each of these requests are issued, then they could issue an IRP_MJ_CLOSE on a file object which had caching initialized and MM still had a reference on the file object. This would result in a crash at some point later.

IoCancelFileOpen() is not a simple wrapper around both of the above Irps. It does issue an IRP_MJ_CLEANUP but conditionally sends the IRP_MJ_CLOSE, depending on the state of the file object. If the file object still has a reference then the IRP_MJ_CLOSE is not issued but instead normal tear down of the file object ensues and the object manager will perform cleanup when appropriate.

In the end, if you are careful to not initialize caching on a stack based file object, because this WILL result in a crash, then calling IoCancelFileOpen() in post create is fine.

Again, checks must be made to avoid stack based file objects, these are bad. Short of this, IoCancelFileOpen() works as it should and is used by? many successfully.

Pete

– Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295


NTFSD is sponsored by OSR

For our schedule of debugging and file system seminars
(including our new fs mini-filter seminar) visit: http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Lijun Wang wrote:

Following is the disassembly code of the IoCancelFileOpen in Xp:

From this I do not see it is doing much other than wrapping an
IRP_MJ_CLEANUP.

Correct, my point is to address the inaccurate statement that it is a
wrapper on IRP_MJ_CLEANUP and IRP_MJ_CLOSE. The IRP_MJ_CLOSE will get
issued, not directly through this call but as a result of this call
dependent on the file object pointer count.

Pete


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com
866.263.9295