Packet Filter Driver issues Re: DPC routines

I’m currently in the process of writing a packet filter (firewall) driver
for NT/2K. Everything is working great EXCEPT for the occasional:

A wait operation, attach process, or yield was attempted from a DPC routine.

I’ve investigated all the code that I’ve inserted to do the packet filtering
and in it I have no calls that would block except for spin locks. I guess
the first question I have is:

Can NDIS spin locks can be executed at irql <= dispatch? It seems to me
that they should, and also should be allowed to block. Kind of a paradox.

If the answer is yes, then why would it cause some sort of blue screen? (as
it’s the only operation in my code that could/might block).
If the answer is no, what else could it possibly be if I have no other code
that would cause the driver to block while running at dispatch level?

Here are a couple of details on the blue screen:

  1. The stack trace tells me that it KeBugCheck’s in my MiniportSend
    function. The code that it bugcheck’s around is:

---- begin cut ----

if ((pktfilterIsEnabled()) &&
(!pktfilterCheckPacket(Packet))) // if we aren’t going to allow this packet through, drop it.
return NDIS_STATUS_FAILURE;

/* this seems to be causing blue screens.
NdisAcquireSpinLock(&posFirewall.statusSpinLock);
*/
posFirewall.status.sendPackets++;
/*
NdisReleaseSpinLock(&posFirewall.statusSpinLock);
*/

----- end cut -----

I originally had the sendPackets incrementing inside the acquistion/release
of the spin lock, but commented it out for testing.

  1. The only spin locks that could block are the ruleset spinlock (for user
    defined rules) and the status spin lock (for packet counting).
  2. The driver is based on Microsoft’s passthru driver.

Please let me know if anyone needs more information. Any help is
appreciated.

-Steve


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

> Can NDIS spin locks can be executed at irql <= dispatch? It seems to me

that they should, and also should be allowed to block. Kind of a paradox.

Any code holding any spinlock runs on >= DISPATCH_LEVEL (> if and only if the spinlock is the interrupt spinlock) and thus not
allowed to block.

Max


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

This may reflect a basic misunderstanding of mine, which would explain a lot… If I have a function that I know will be called at dispatch_level, and it requires access to a shared resource, what do I do? Can I use anything that would block (presumably including spinlocks)? Can I have a spinlock that has the possibility of being acquired by multiple different dispatch_level threads? That would imply that one or more of them are blocking…

The specific case here is that I’m trying to protect a shared data structure between the protocol side and the miniport side of an NDIS IM driver.

I guess that also begs another basic question that I thought I understood before this mess: can a thread at >= dispatch_level hold multiple spinlocks at one time? The second one might block, and the first one will already be held. I’d swear I’ve used nested spinlocks before, and I always pay attention to acquisition/release ordering too.

Sorry for the basic questions…

-sd

On Sun, Oct 07, 2001 at 04:14:15AM +0400, Maxim S. Shatskih wrote:

> Can NDIS spin locks can be executed at irql <= dispatch? It seems to me
> that they should, and also should be allowed to block. Kind of a paradox.

Any code holding any spinlock runs on >= DISPATCH_LEVEL (> if and only if the spinlock is the interrupt spinlock) and thus not
allowed to block.

Max


You are currently subscribed to ntdev as: xxxxx@positivenetworks.net
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

>function that I know will be called at dispatch_level, and it requires access to a shared

resource, what do I do?

What kind of resource? Only spinlocks are allowed to acquire from such routines.

Can I use anything that would block (presumably including spinlocks)?

Spinlocks are not “block”. Block is causing reschedule in the dispatcher, spinlocks do not do this.

block, and the first one will already be held. I’d swear I’ve used nested spinlocks before, and
I always pay attention to acquisition/release ordering too.

You can, if you maintain the order.

Max


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

>This may reflect a basic misunderstanding of mine, which would explain a

lot… If I have a function that I know will be called at dispatch_level,
and it requires access to a shared resource, what do I do? Can I use
anything that would block (presumably including spinlocks)? Can I have a
spinlock that has the possibility of being acquired by multiple different
dispatch_level threads? That would imply that one or more of them are
blocking…

The specific case here is that I’m trying to protect a shared data
structure between the protocol side and the miniport side of an NDIS IM
driver.

I guess that also begs another basic question that I thought I understood
before this mess: can a thread at >= dispatch_level hold multiple
spinlocks at one time? The second one might block, and the first one will
already be held. I’d swear I’ve used nested spinlocks before, and I
always pay attention to acquisition/release ordering too.

First, I’d like to clarify how I use some terminology. When I think of
execution “blocking”, I think of a thread switch happening. I should also
define “thread” to means a stack plus an “execution context”. An execution
context (any suggestion of better terminology?) is not related to which
stack your on, and means the state of the processor registers at the
moment. When code is interrupted, it’s execution context changes, but it’s
stack doesn’t. Interrupts and returns MUST occur in LIFO order, thread
preemption can resume execution on ANY runnable thread

DISPATCH_LEVEL code (and above) preempts PASSIVE_LEVEL code, and executes
on an arbitrary thread stack, possible resuming a different piece of
PASSIVE_LEVEL code when it returns from DISPATCH_LEVEL. Code at
DISPATCH_LEVEL and above, can be interrupted, but not preempted. There can
be only one execution context for DISPATCH_LEVEL per processor, so your
scenario above simple can’t happen, as there aren’t different
DISPATCH_LEVEL threads a processor. On a single processor system, it’s not
possible for you to be running code at DISPATCH_LEVEL, and acquire a
spinlock, and then be preempted by some other piece of DISPATCH_LEVEL code
which tries to acquire the same spinlock. In SMP systems, you may go to
acquire the spinlock and find it’s locked, and that processor will just
spin at DISPATCH_LEVEL, still being interruptible. Spinning on a spinlock
does NOT give the processor to other code at DISPATCH_LEVEL., it’s
essentially stuck at the spinlock until it’s released.

You can hold multiple spin locks at DISPATCH_LEVEL, and you have to be
careful about ordering, which you seem to know already. The danger is some
other processor acquires the spin locks in a different order, you may
create deadlock because processor 1 has spinlock a and is waiting on
spinlock b, and processor 2 has spinlock b and is waiting on spinlock a.

Choosing the IRQL level for a spinlock is important, as it must be acquired
at the highest IRQL level of any code that might acquire it. For example,
say you have data you access in your DPC at DISPATCH_LEVEL, and the same
data is accessed at a higher IRQL in the interrupt service routine. If you
acquire the spinlock in the DPC at DISPATCH_LEVEL, the ISR may come along,
interrupt the DPC, and attempt to acquire the same spinlock at the DIRQL.
Since the DPC already holds the spinlock, the ISR will get stuck waiting on
the spinlock and your system is mostly frozen. The correct thing to do is
for the DPC to acquire the spinlock at the IRQL level that the ISR would
acquire it at, which assures you will not be interrupted by the ISR while
the spinlock is held. If you get an interrupt on another processor, it may
enter the ISR, and spin on the spinlock held by the DPC, until the DPC is
done with the spinlock.

Hope this make this clearer.

  • Jan

You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com