about ExInitializeWorkItem

> your driver is still in memory

Driver is in memory? or the device object+extension are not deallocated yet?

Are you sure these are the same things?


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Er? AH, both, actually.

Peter
OSR

> Driver is in memory? or the device object+extension are not deallocated yet? Are you sure these are

the same things?

No, they are not, but as long as DEVICE_OBJECT’s refcount is nonzero its controlling driver module is not going to get unloaded from RAM…

Anton Bassov

> No, they are not, but as long as DEVICE_OBJECT’s refcount is nonzero

What of them?

Ob’s one?

Or DEVICE_OBJECT::ReferenceCount?

IIRC IoQueueWorkItem raises the first one, and it is the second one which suspends unload.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

If your point here is that there’s a bug in IoQueueWorkItem, it would be infinitely more clear – and more helpful I would think – if you just explain your point and say that, rather than posting a string of cryptic questions and making us all play “Guess What I Am Talking About.”

C’mon, Max…

Peter
OSR

> If your point here is that there’s a bug in IoQueueWorkItem

IIRC raising the Ob’s count of the device (ObReferenceObject on it) does NOT prevent the driver from unloading.

It only prevents the DO itself and its devext from deallocation.

What prevents the driver from unloading is DEVICE_OBJECT::ReferenceCount (and also existence of the DOs attached above this DO), at least it was so in NT4 when I have reverse-engineered this path.

So, there can be scenarios where the driver is unloaded, and the memory for the DOs is still not freed, the DOs still live (with junk dispatch table in the driver object).

Also, there can be scenarios when the driver unload path races with the work item. Yes, the devext memory is guaranteed to be valid by IoQueueWorkItem (and even this guarantee is not total - what if devext references some objects which were already destroyed?), but what about the code of the work item routine?

Am I correct? or wrong? was this fixed since NT4 times? is Ob’s “delete routine” (zero refcount) for type “Devi” actually used in the driver unload path?


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

While the Ob ref count being >0 does not prevent DriverUnload from being called, it does prevent the image itself from being unloaded from memory. so the Io work item routines guard against the scenario where the work item causes the ref count to go to zero, forces the image to unload and then when the kernel returns from the call to ObDeref, it executes garbage b/c the code is now gone. since the last obref is outside of the driver’s image in the io work item case, you are safe from unload while still needing to execute code.

d

>…at least it was so in NT4 when I have reverse-engineered this path.

Oh, I am afraid Jake would not be happy about it at all …

So, there can be scenarios where the driver is unloaded, and the memory for the DOs is still not freed,
the DOs still live (with junk dispatch table in the driver object).

IIRC, I had a discussion about it with Doron around 3 years ago (IIRC, it was also in context of discussing workitems). You can search the archives for more info …

Anton Bassov

Doron,

You just have made your post while I was typing mine - indeed, we had a pretty detailed discussion of this issue around 3 years ago, so that I referred Max to this discussion…

Anton Bassov

> While the Ob ref count being >0 does not prevent DriverUnload from being called, it does prevent the

image itself from being unloaded from memory.

Thanks, good to know.

What exactly will the Ob’s “delete” method for Device and Driver types do? any addref/release on the loaded module list’s entry?

And note another possibility: the work item is running over a PnP DO and touching some objects referenced by the devext (logical children of it).

Then assume that MN_REMOVE_DEVICE comes.

In this case, MN_REMOVE_DEVICE must be blocked till the work item will be done, otherwise a race can occur and work item will touch the killed (by remove path) objects parented by the devext. Yes, the devext’s memory itself will still be valid, but not its children.

Replacing ExQueueWorkItem with its Io counterpart does not help to solve this race. At all.

What really helps is a) remove lock acquired by the work item b) “self-managed IO” concept in KMDF.

Without these concepts, IoQueueWorkItem only does “let’s delay operator delete but not the destructor” type of thing, which is not enough to save from crashes.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Max actually makes quite a good observation: The driver image will persist in memory, but the effective destructor (unload or _REMOVE_DEVICE, for example) could still be called.

What IoQueueWorkItem appears to get you, then, is that your driver code COULD be properly written to handle this situation. Whereas, with ExQueueWorkItem there’s nothing you can do about it.

Of course, it remains to be see how many drivers really DO handle this situation… but you can say that about all SORTS of things driver-related, right?

Peter
OSR

this is why KMDF provides rundown support of the work item to let you wait on it executing and returning back to the framework. this is also why work items are descendants of the WDFDEVICE in the wdf object hierarchy. by being a child, kmdf will make sure the work item has returned and is disposed before you nuke the parent WDFDEVICE’s state/context.

d