Cleaning up miniport refs for child PDO

Hi guys,

I need a little bit of help here…I have a bus driver which creates a static child PDO, for which I install my miniport driver to (which has an NDIS upper edge). The two drivers talk to each other using a WDF Query Interface. It all works fine, except when I go to update the mp driver. Evidently, there’s a ref left around somewhere that I can’t pinpoint, and the mp driver doesn’t get unloaded. So, I see error code 38 in the device status window.

So, I have ensured that the ref count of my adapter object goes to zero in MPHalt(). MPHalt() is getting called, followed by MPUnload().

Both drivers are installed on the same stack, so with respect to registering the Query Interface functionality, I let the framework handle reference counting in this regard.

// Let the framework handle reference counting, since
// the TS_II_NDIS driver will be in the same stack:
tsiiBusNdisInterface.InterfaceHeader.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
tsiiBusNdisInterface.InterfaceHeader.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;

I have seen refs to using WdfPdoMarkMissing(), but I don’t think I need to do this, since I want the PDO created by the bus driver to remain around, so that I can install the new driver to it.

Just so I’m clear, I should be able to update the mp driver without having to destroy/recreate another PDO down in the bus driver, right?

Can anyone suggest other instances that I might be missing, or provide some useful debugging tips using WinDbg for tracking this down? Any help would be greatly appreciated!

Thanks!

Jason

>I have seen refs to using WdfPdoMarkMissing(), but I don’t think I need to do this, since I want the >PDO created by the bus driver to remain around, so that I can install the new driver to it.
I believe your bus driver should destroy PDO during the update and create it again when updated driver start.

Igor Sharovar

Not correct. the PDO can stay. This is how disable/enable or update driver works. You need to track down the leaked ref. !object (which is hidden from you by NDIS but available via an API) will tell you the current pointer count (as well as the handle count, but that is only relevant if there are open handles). What I would do is when the miniport handle is created and you can get a pdevobj, put a write breakpoint on the ref count. The ref count precedes the DEVICE_OBJECST structure (IIRC at -16 on x86) in memory, the easiest way to to find it is to dump the memory before the devobj pointer and find the DWORD with the right value and then add the breakpoint, something like this

ba w4 “k;dd l1;g”

which will break in on read or write, dump the stack, dump the value and then continue. This will slow things down significantly but you should be able to find the unmatched ref. you can also turn on Ob ref tracking, but I don’t have the instructions for that handy right now

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
Sent: Friday, May 07, 2010 9:47 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Cleaning up miniport refs for child PDO

>I have seen refs to using WdfPdoMarkMissing(), but I don’t think I need to do this, since I want the >PDO created by the bus driver to remain around, so that I can install the new driver to it.
I believe your bus driver should destroy PDO during the update and create it again when updated driver start.

Igor Sharovar


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars 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

Hi Igor,

Well, I could destroy the PDO in the bus driver, as the mp driver notifies it when it’s shutting down via Query Interface.

But, I don’t want to have to touch the bus driver to get it to create a new PDO if I don’t have to. Meaning, I don’t want to have to go through the driver update process for the bus driver (using devcon).

So, when would I create the new PDO? As soon as I destroyed the old one? My point is that there’s nothing currently to trigger the creation of a new PDO. It’s not like I’m pluggin a card in.

I guess creating a new PDO as soon as the old one is gone would work…I can give it a try anyway. :slight_smile: This seems to make sense, since I’ll have to re-register the Query Interface again as well.

Does this sound legitimate to everyone else, or is there a better way?

Thanks for your advice Igor!

Thanks Doron! I will try this! We were posting at the same time, so I didn’t see your post until after my last post. :slight_smile:

I was thinking that the PDO could stay, but now I know for sure! :slight_smile:

Thanks!

Jason

Do not destroy the PDO, it won’t solve the problem. The problem is that your miniport image is stuck in memory due to a dangling ref. when you create a new PDO, the Mm will try to load the image, just like it would on disable/enable, and fail because of that dangling ref. fix the dangling ref

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Friday, May 07, 2010 10:20 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Cleaning up miniport refs for child PDO

Hi Igor,

Well, I could destroy the PDO in the bus driver, as the mp driver notifies it when it’s shutting down via Query Interface.

But, I don’t want to have to touch the bus driver to get it to create a new PDO if I don’t have to. Meaning, I don’t want to have to go through the driver update process for the bus driver (using devcon).

So, when would I create the new PDO? As soon as I destroyed the old one? My point is that there’s nothing currently to trigger the creation of a new PDO. It’s not like I’m pluggin a card in.

I guess creating a new PDO as soon as the old one is gone would work…I can give it a try anyway. :slight_smile: This seems to make sense, since I’ll have to re-register the Query Interface again as well.

Does this sound legitimate to everyone else, or is there a better way?

Thanks for your advice Igor!


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars 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

Yep, it’s a dangling ref allright…check out the !object debug info pointer count:

// Before update(4 pointers to device object):
// =============================
0: kd> !object fc6f29d0
Object: fc6f29d0 Type: (fc991208) Device
ObjectHeader: fc6f29b8 (old version)
HandleCount: 0 PointerCount: 4
Directory Object: e1011670 Name: {1FD70F60-1F32-4919-8054-1BBEA4A45967}

// After update(1 pointers to device object):
// =============================
0: kd> !object fc6f29d0
Object: fc6f29d0 Type: (fc991208) Device
ObjectHeader: fc6f29b8 (old version)
HandleCount: 0 PointerCount: 1

Now to figure out whose keeping the ref…

Thanks Doron!

Doron,

I want to make sure I understand your suggestion above in finding the unmatched ref…

I now know that there’s 1 ref left around per my last post.

Now, I want to find out whose not freeing it. Per your breakpoint suggestion above, will I be able to find out whose leaving the ref behind, or will I just be able to find out what I already know?

If I can find out whose keeping the ref using your ‘ba’ suggestion, then which address do I need to use below, the device object?

Here’s a dump of the device stack and object info:

0: kd> !devstack fc884b80
!DevObj !DrvObj !DevExt ObjectName
fc6973f0 \Driver\TS_II_NDIS fc6974a8 {1FD70F60-1F32-4919-8054-1BBEA4A45967}

fc884b80 \Driver\TS_II_BUS fc83d210 00000081
!DevNode fc697ee8 :
DeviceInst is “{9cf7c715-2e6b-48b6-8495-4f1418782ab4}\TsiiNdis\5&27b65565&d”
ServiceName is “TS_II_NDIS”

0: kd> !devobj fc6973f0
Device object (fc6973f0) is for:
{1FD70F60-1F32-4919-8054-1BBEA4A45967} \Driver\TS_II_NDIS DriverObject fc8c3c50
Current Irp 00000000 RefCount 0 Type 00000017 Flags 00002050
Dacl e16a8794 DevExt fc6974a8 DevObjExt fc6979f0
ExtensionFlags (0000000000)
AttachedTo (Lower) fc884b80 \Driver\TS_II_BUS
Device queue is not busy.

Based on the devobj info above, would I use:

ba w4 0xfc6973f0 “k;dd fc6973f0 l1;g”

Thanks Doron!

Jason

The devobj pointer, but you need to find the offset of the pointer count before the devobj. The easiest way to do this is to run

!object and capture the pointer count
dd -0x30 and see which dword maps to the pointer count.
Verification: edit the memory which you think is the dword for the pointer count and change it to some big value like 0x10, rerun !object and see if it picks up the modified value (thus confirming you edited the right dword), change the value back to its original value
ba w4 “k;dd l1;g”

is going to be devobj-. The output is going to give you every ref and deref. You are going to have to comb through the output and find the missing deref on your own

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Friday, May 07, 2010 11:33 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Cleaning up miniport refs for child PDO

Doron,

I want to make sure I understand your suggestion above in finding the unmatched ref…

I now know that there’s 1 ref left around per my last post.

Now, I want to find out whose not freeing it. Per your breakpoint suggestion above, will I be able to find out whose leaving the ref behind, or will I just be able to find out what I already know?

If I can find out whose keeping the ref using your ‘ba’ suggestion, then which address do I need to use below, the device object?

Here’s a dump of the device stack and object info:

0: kd> !devstack fc884b80
!DevObj !DrvObj !DevExt ObjectName
fc6973f0 \Driver\TS_II_NDIS fc6974a8 {1FD70F60-1F32-4919-8054-1BBEA4A45967}
> fc884b80 \Driver\TS_II_BUS fc83d210 00000081
!DevNode fc697ee8 :
DeviceInst is “{9cf7c715-2e6b-48b6-8495-4f1418782ab4}\TsiiNdis\5&27b65565&d”
ServiceName is “TS_II_NDIS”

0: kd> !devobj fc6973f0
Device object (fc6973f0) is for:
{1FD70F60-1F32-4919-8054-1BBEA4A45967} \Driver\TS_II_NDIS DriverObject fc8c3c50 Current Irp 00000000 RefCount 0 Type 00000017 Flags 00002050 Dacl e16a8794 DevExt fc6974a8 DevObjExt fc6979f0 ExtensionFlags (0000000000) AttachedTo (Lower) fc884b80 \Driver\TS_II_BUS Device queue is not busy.

Based on the devobj info above, would I use:

ba w4 0xfc6973f0 “k;dd fc6973f0 l1;g”

Thanks Doron!

Jason


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars 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

Perfect! Thanks Doron! :slight_smile:

Have a great weekend!

Jason

> !object and capture the pointer count
> dd -0x30 and see which dword maps to the pointer count.
> Verification: edit the memory which you think is the dword for the
> pointer count and change it to some big value like 0x10,

There’s a faster way if you leverage the object header:

kd> !object 8172c3b8
Object: 8172c3b8 Type: (819b8788) Device
ObjectHeader: 8172c3a0 (old version)
HandleCount: 0 PointerCount: 2
Directory Object: e1006758 Name: Beep
kd> dt nt!_object_header 8172c3a0
+0x000 PointerCount : 2
+0x004 HandleCount : 0
+0x004 NextToFree : (null)
+0x008 Type : 0x819b8788 _OBJECT_TYPE
+0x00c NameInfoOffset : 0x10 ‘’
+0x00d HandleInfoOffset : 0 ‘’
+0x00e QuotaInfoOffset : 0 ‘’
+0x00f Flags : 0x12 ‘’
+0x010 ObjectCreateInfo : 0x00000001 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : 0x00000001 Void
+0x014 SecurityDescriptor : (null)
+0x018 Body : _QUAD
kd> ba w4 8172c3a0

Do this enough and you’ll learn that offset zero from the header is the
pointer count and offset four is the handle count, thus replacing yet
another childhood memory with random Windows trivia.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

“Doron Holan” wrote in message
news:xxxxx@ntdev…
> The devobj pointer, but you need to find the offset of the pointer count
> before the devobj. The easiest way to do this is to run
>
> !object and capture the pointer count
> dd -0x30 and see which dword maps to the pointer count.
> Verification: edit the memory which you think is the dword for the
> pointer count and change it to some big value like 0x10, rerun !object
> and see if it picks up the modified value (thus confirming you
> edited the right dword), change the value back to its original value
> ba w4 “k;dd
> l1;g”
>
> is going to be
> devobj-. The output is going to give you every ref and
> deref. You are going to have to comb through the output and find the
> missing deref on your own
>
> d
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of
> xxxxx@gmail.com
> Sent: Friday, May 07, 2010 11:33 AM
> To: Windows System Software Devs Interest List
> Subject: RE:[ntdev] Cleaning up miniport refs for child PDO
>
> Doron,
>
> I want to make sure I understand your suggestion above in finding the
> unmatched ref…
>
> I now know that there’s 1 ref left around per my last post.
>
> Now, I want to find out whose not freeing it. Per your breakpoint
> suggestion above, will I be able to find out whose leaving the ref behind,
> or will I just be able to find out what I already know?
>
> If I can find out whose keeping the ref using your ‘ba’ suggestion, then
> which address do I need to use below, the device object?
>
> Here’s a dump of the device stack and object info:
>
> 0: kd> !devstack fc884b80
> !DevObj !DrvObj !DevExt ObjectName
> fc6973f0 \Driver\TS_II_NDIS fc6974a8
> {1FD70F60-1F32-4919-8054-1BBEA4A45967}
>> fc884b80 \Driver\TS_II_BUS fc83d210 00000081
> !DevNode fc697ee8 :
> DeviceInst is
> “{9cf7c715-2e6b-48b6-8495-4f1418782ab4}\TsiiNdis\5&27b65565&d”
> ServiceName is “TS_II_NDIS”
>
> 0: kd> !devobj fc6973f0
> Device object (fc6973f0) is for:
> {1FD70F60-1F32-4919-8054-1BBEA4A45967} \Driver\TS_II_NDIS DriverObject
> fc8c3c50 Current Irp 00000000 RefCount 0 Type 00000017 Flags 00002050 Dacl
> e16a8794 DevExt fc6974a8 DevObjExt fc6979f0 ExtensionFlags (0000000000)
> AttachedTo (Lower) fc884b80 \Driver\TS_II_BUS Device queue is not busy.
>
> Based on the devobj info above, would I use:
>
> ba w4 0xfc6973f0 “k;dd fc6973f0 l1;g”
>
> Thanks Doron!
>
> Jason
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars 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
>
>

Did not know if the header type was available or not :wink:

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Scott Noone
Sent: Friday, May 07, 2010 12:30 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Cleaning up miniport refs for child PDO

!object and capture the pointer count dd -0x30 and
> see which dword maps to the pointer count.
> Verification: edit the memory which you think is the dword for the
> pointer count and change it to some big value like 0x10,

There’s a faster way if you leverage the object header:

kd> !object 8172c3b8
Object: 8172c3b8 Type: (819b8788) Device
ObjectHeader: 8172c3a0 (old version)
HandleCount: 0 PointerCount: 2
Directory Object: e1006758 Name: Beep
kd> dt nt!_object_header 8172c3a0
+0x000 PointerCount : 2
+0x004 HandleCount : 0
+0x004 NextToFree : (null)
+0x008 Type : 0x819b8788 _OBJECT_TYPE
+0x00c NameInfoOffset : 0x10 ‘’
+0x00d HandleInfoOffset : 0 ‘’
+0x00e QuotaInfoOffset : 0 ‘’
+0x00f Flags : 0x12 ‘’
+0x010 ObjectCreateInfo : 0x00000001 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : 0x00000001 Void
+0x014 SecurityDescriptor : (null)
+0x018 Body : _QUAD
kd> ba w4 8172c3a0

Do this enough and you’ll learn that offset zero from the header is the pointer count and offset four is the handle count, thus replacing yet another childhood memory with random Windows trivia.

-scott


Scott Noone
Consulting Associate
OSR Open Systems Resources, Inc.
http://www.osronline.com

“Doron Holan” wrote in message
news:xxxxx@ntdev…
> The devobj pointer, but you need to find the offset of the pointer count
> before the devobj. The easiest way to do this is to run
>
> !object and capture the pointer count
> dd -0x30 and see which dword maps to the pointer count.
> Verification: edit the memory which you think is the dword for the
> pointer count and change it to some big value like 0x10, rerun !object
> and see if it picks up the modified value (thus confirming you
> edited the right dword), change the value back to its original value
> ba w4 “k;dd
> l1;g”
>
> is going to be
> devobj-. The output is going to give you every ref and
> deref. You are going to have to comb through the output and find the
> missing deref on your own
>
> d
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com] On Behalf Of
> xxxxx@gmail.com
> Sent: Friday, May 07, 2010 11:33 AM
> To: Windows System Software Devs Interest List
> Subject: RE:[ntdev] Cleaning up miniport refs for child PDO
>
> Doron,
>
> I want to make sure I understand your suggestion above in finding the
> unmatched ref…
>
> I now know that there’s 1 ref left around per my last post.
>
> Now, I want to find out whose not freeing it. Per your breakpoint
> suggestion above, will I be able to find out whose leaving the ref behind,
> or will I just be able to find out what I already know?
>
> If I can find out whose keeping the ref using your ‘ba’ suggestion, then
> which address do I need to use below, the device object?
>
> Here’s a dump of the device stack and object info:
>
> 0: kd> !devstack fc884b80
> !DevObj !DrvObj !DevExt ObjectName
> fc6973f0 \Driver\TS_II_NDIS fc6974a8
> {1FD70F60-1F32-4919-8054-1BBEA4A45967}
>> fc884b80 \Driver\TS_II_BUS fc83d210 00000081
> !DevNode fc697ee8 :
> DeviceInst is
> “{9cf7c715-2e6b-48b6-8495-4f1418782ab4}\TsiiNdis\5&27b65565&d”
> ServiceName is “TS_II_NDIS”
>
> 0: kd> !devobj fc6973f0
> Device object (fc6973f0) is for:
> {1FD70F60-1F32-4919-8054-1BBEA4A45967} \Driver\TS_II_NDIS DriverObject
> fc8c3c50 Current Irp 00000000 RefCount 0 Type 00000017 Flags 00002050 Dacl
> e16a8794 DevExt fc6974a8 DevObjExt fc6979f0 ExtensionFlags (0000000000)
> AttachedTo (Lower) fc884b80 \Driver\TS_II_BUS Device queue is not busy.
>
> Based on the devobj info above, would I use:
>
> ba w4 0xfc6973f0 “k;dd fc6973f0 l1;g”
>
> Thanks Doron!
>
> Jason
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars 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
>
>


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars 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

Scott,

Yep, and for others needing to debug driver unload / leaked reference problems:

http://msdn.microsoft.com/en-us/library/ff540608(VS.85).aspx

which reiterates what you said! :slight_smile:

I’m combing through my debug output now…hopefully I’ll find the missing ref soon.

Thanks guys!

Jason

Well, it must be an extra ref taken out during initialization, because I don’t see any unmatched object refs (except that the very last entry still has a ref of 1 - expected).

So, if I could just get WinDbg to break in DriverEntry(), I can get the devobj pointer, and see all the refs/derefs from the beginning…but WinDbg is being a PITA with respect to my symbols, and hitting the breakpoints! Arrrgghhhh.

>So, if I could just get WinDbg to break in DriverEntry(), I can get the devobj pointer, and see all the >refs/derefs from the beginning…but WinDbg is being a PITA with respect to my symbols, and hitting >the breakpoints! Arrrgghhhh.
Put DbgBreakPoint() in your DriverEntry. WinDbg will stop at this function.

Igor Sharovar

Ahhh…sweet Igor! :slight_smile: Thanks!

Jason

Found it!!!

I was making a call to WdfDriverCreate() in DriverEntry(), and not making a call to WdfDriverMiniportUnload() from within MPUnload(). Hence that one ref was left around, which was held *I’m guessing* by the WDF framework?

Thanks for everyone’s help! I’m now able to cleanly update my ndis mp driver now!

Using Doron’s and Scott’s ref count debugging techniques above, I was able to see that one ref was left around, and that ref was taken out somewhere within DriverEntry(). I then went through every call, making sure that there was a corresponding cleanup call (if neccessary) in MPUnload(). I was able to see using the PPT link below that I wasn’t calling WdfDriverMiniportUnload()!

For those developing mp drivers using KMDF, this powerpoint presentation was a huge help:

http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DDE-T685_DDC08.pptx

Best Regards!

Jason Summerour