KERNEL_SECURITY_CHECK_FAILURE in Work Item waiting on a mutex

I have a work item routine. It is guarded by a mutex which also guards all the dispatch routines in order to serialize them.
The sequence of things is…
Thread A:

  1. dispatch routine acquires the mutex.
  2. queues a DPC
  3. releases the mutex.
    Thread B:
  4. The DPC does some stuff and queues a Work Item.
    Thread C (system thread):
  5. The Work Item acquires the same mutex.
  6. The Work Item does some stuff.

I know that the user app has issued only the one IRP, so there’s no issue of another IRP competing for the same mutex.
However, it’s possible that 4. and 5. happen before 3. All the code is running on the same CPU (I think), so the DPC may well get dispatched immediately. Likewise, the Work Item may well get dispatched immediately. Both of these would preempt thread A
In that case, I would expect that 5. will go into a wait state, then the mutex will be released by 3., then 6. will proceed.
However…
I got a KERNEL_SECURITY_CHECK_FAILURE bugcheck.
The stack shows
00 : nt!KeBugCheckEx
01 : nt!KiBugCheckDispatch+0x69
02 : nt!KiFastFailDispatch+0xd0
03 : nt!KiRaiseSecurityCheckFailure+0x2df
04 : nt!KeWaitForSingleObject+0x14eb44
05 : nt!ViKeWaitForSingleObjectCommon+0x98
06 : nt!VerifierKeWaitForSingleObject+0x1e
07 : IbsOps!Drivers::ExtBase::lockCall+0x43
08 : nt!IopProcessWorkItem+0x12c
It also shows current IRQL = 2! I _assume _this is the IRQL when 00 is running, not 07 (which should be at IRQL 0), and that some routine on the stack raised the IRQL.

Is there a problem with the wait in step 5. , being that it is running in a system thread, at least in the case that the Mutex is currently owned by the thread in 1. ?

And just what is a KERNEL_SECURITY_CHECK_FAILURE anyway? Windbg tells me that “A LIST_ENTRY has been corrupted (i.e. double remove).”

Are Work Items just a poor solution? Do I want to go to the trouble of setting up my own thread pool? Some earlier discussions on OSR have suggested that.