Patch to fix bugcheck at exit for various TCP wielding apps. This puts in

a work item for socket shutdown that decouples the IRP cancel from the actual
(PASSIVE_LEVEL) tcp accounting chores.

Uses the CHEW static lib that I put in to gather workitem code into one nice
sane happy place.

It seems like doing the same to loopback.c is detrimental and I suspect that
it's due to nasty reentrancy issues in our code.  I'll likely adapt chew lib
so we can use it there too.

svn path=/trunk/; revision=20149
This commit is contained in:
Art Yerkes 2005-12-13 20:17:25 +00:00
parent bc49f0f151
commit 9f345c304d
7 changed files with 134 additions and 119 deletions

View file

@ -647,4 +647,34 @@ NTSTATUS TCPGetPeerAddress
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
VOID TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) {
PLIST_ENTRY Entry;
PLIST_ENTRY ListHead[4];
KIRQL OldIrql;
PTDI_BUCKET Bucket;
UINT i = 0;
ListHead[0] = &Endpoint->ReceiveRequest;
ListHead[1] = &Endpoint->ConnectRequest;
ListHead[2] = &Endpoint->ListenRequest;
ListHead[3] = 0;
TcpipAcquireSpinLock( &Endpoint->Lock, &OldIrql );
for( i = 0; ListHead[i]; i++ ) {
for( Entry = ListHead[i]->Flink;
Entry != ListHead[i];
Entry = Entry->Flink ) {
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
if( Bucket->Request.RequestContext == Irp ) {
RemoveEntryList( &Bucket->Entry );
break;
}
}
}
TcpipReleaseSpinLock( &Endpoint->Lock, OldIrql );
}
/* EOF */ /* EOF */

View file

@ -51,11 +51,6 @@ BOOLEAN ProtocolRegistered = FALSE;
LIST_ENTRY AdapterListHead; LIST_ENTRY AdapterListHead;
KSPIN_LOCK AdapterListLock; KSPIN_LOCK AdapterListLock;
/* Work around being called back into afd at Dpc level */
KSPIN_LOCK LanWorkLock;
LIST_ENTRY LanWorkList;
WORK_QUEUE_ITEM LanWorkItem;
/* Double complete protection */ /* Double complete protection */
KSPIN_LOCK LanSendCompleteLock; KSPIN_LOCK LanSendCompleteLock;
LIST_ENTRY LanSendCompleteList; LIST_ENTRY LanSendCompleteList;
@ -289,10 +284,9 @@ VOID STDCALL ProtocolSendComplete(
} }
} }
VOID STDCALL LanReceiveWorker( PVOID Context ) { VOID LanReceiveWorker( PVOID Context ) {
UINT PacketType; UINT PacketType;
PLIST_ENTRY ListEntry; PLAN_WQ_ITEM WorkItem = (PLAN_WQ_ITEM)Context;
PLAN_WQ_ITEM WorkItem;
PNDIS_PACKET Packet; PNDIS_PACKET Packet;
PLAN_ADAPTER Adapter; PLAN_ADAPTER Adapter;
UINT BytesTransferred; UINT BytesTransferred;
@ -301,60 +295,49 @@ VOID STDCALL LanReceiveWorker( PVOID Context ) {
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n")); TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
while( (ListEntry = Packet = WorkItem->Packet;
ExInterlockedRemoveHeadList( &LanWorkList, &LanWorkLock )) ) { Adapter = WorkItem->Adapter;
WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry); BytesTransferred = WorkItem->BytesTransferred;
TI_DbgPrint(DEBUG_DATALINK, ("WorkItem: %x\n", WorkItem)); IPPacket.NdisPacket = Packet;
Packet = WorkItem->Packet; NdisGetFirstBufferFromPacket(Packet,
Adapter = WorkItem->Adapter; &NdisBuffer,
BytesTransferred = WorkItem->BytesTransferred; &IPPacket.Header,
&IPPacket.ContigSize,
ExFreePool( WorkItem ); &IPPacket.TotalSize);
IPPacket.NdisPacket = Packet; IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
/* Determine which upper layer protocol that should receive
NdisGetFirstBufferFromPacket(Packet, this packet and pass it to the correct receive handler */
&NdisBuffer,
&IPPacket.Header, TI_DbgPrint(MID_TRACE,
&IPPacket.ContigSize, ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
&IPPacket.TotalSize); IPPacket.ContigSize, IPPacket.TotalSize,
BytesTransferred));
IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
/* Determine which upper layer protocol that should receive PacketType = PC(IPPacket.NdisPacket)->PacketType;
this packet and pass it to the correct receive handler */ IPPacket.Position = 0;
TI_DbgPrint(MID_TRACE, TI_DbgPrint
("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n", (DEBUG_DATALINK,
IPPacket.ContigSize, IPPacket.TotalSize, ("Ether Type = %x ContigSize = %d Total = %d\n",
BytesTransferred)); PacketType, IPPacket.ContigSize, IPPacket.TotalSize));
PacketType = PC(IPPacket.NdisPacket)->PacketType; switch (PacketType) {
IPPacket.Position = 0; case ETYPE_IPv4:
case ETYPE_IPv6:
TI_DbgPrint TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
(DEBUG_DATALINK, IPReceive(Adapter->Context, &IPPacket);
("Ether Type = %x ContigSize = %d Total = %d\n", break;
PacketType, IPPacket.ContigSize, IPPacket.TotalSize)); case ETYPE_ARP:
TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
switch (PacketType) { ARPReceive(Adapter->Context, &IPPacket);
case ETYPE_IPv4: default:
case ETYPE_IPv6: break;
TI_DbgPrint(MID_TRACE,("Received IP Packet\n"));
IPReceive(Adapter->Context, &IPPacket);
break;
case ETYPE_ARP:
TI_DbgPrint(MID_TRACE,("Received ARP Packet\n"));
ARPReceive(Adapter->Context, &IPPacket);
default:
break;
}
FreeNdisPacket( Packet );
} }
TI_DbgPrint(DEBUG_DATALINK, ("Leaving\n"));
LanReceiveWorkerBusy = FALSE; FreeNdisPacket( Packet );
} }
VOID LanSubmitReceiveWork( VOID LanSubmitReceiveWork(
@ -362,34 +345,19 @@ VOID LanSubmitReceiveWork(
PNDIS_PACKET Packet, PNDIS_PACKET Packet,
NDIS_STATUS Status, NDIS_STATUS Status,
UINT BytesTransferred) { UINT BytesTransferred) {
PLAN_WQ_ITEM WQItem; LAN_WQ_ITEM WQItem;
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
KIRQL OldIrql; PVOID LanWorkItem;
TI_DbgPrint(DEBUG_DATALINK,("called\n")); TI_DbgPrint(DEBUG_DATALINK,("called\n"));
TcpipAcquireSpinLock( &LanWorkLock, &OldIrql ); WQItem.Packet = Packet;
WQItem.Adapter = Adapter;
WQItem.BytesTransferred = BytesTransferred;
WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) ); if( !ChewCreate
if( !WQItem ) { ( &LanWorkItem, sizeof(LAN_WQ_ITEM), LanReceiveWorker, &WQItem ) )
TcpipReleaseSpinLock( &LanWorkLock, OldIrql ); ASSERT(0);
return;
}
WQItem->Packet = Packet;
WQItem->Adapter = Adapter;
WQItem->BytesTransferred = BytesTransferred;
InsertTailList( &LanWorkList, &WQItem->ListEntry );
if( !LanReceiveWorkerBusy ) {
LanReceiveWorkerBusy = TRUE;
ExQueueWorkItem( &LanWorkItem, CriticalWorkQueue );
TI_DbgPrint(DEBUG_DATALINK,
("Work item inserted %x %x\n", &LanWorkItem, WQItem));
} else {
TI_DbgPrint(DEBUG_DATALINK,
("LAN WORKER BUSY %x %x\n", &LanWorkItem, WQItem));
}
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
} }
VOID STDCALL ProtocolTransferDataComplete( VOID STDCALL ProtocolTransferDataComplete(
@ -452,7 +420,6 @@ NDIS_STATUS STDCALL ProtocolReceive(
PNDIS_PACKET NdisPacket; PNDIS_PACKET NdisPacket;
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer; PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
KIRQL OldIrql;
TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize)); TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
@ -490,12 +457,9 @@ NDIS_STATUS STDCALL ProtocolReceive(
TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n", TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
Adapter, Adapter->MTU)); Adapter, Adapter->MTU));
TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
PacketSize + HeaderBufferSize ); PacketSize + HeaderBufferSize );
if( NdisStatus != NDIS_STATUS_SUCCESS ) { if( NdisStatus != NDIS_STATUS_SUCCESS ) {
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
return NDIS_STATUS_NOT_ACCEPTED; return NDIS_STATUS_NOT_ACCEPTED;
} }
@ -534,7 +498,6 @@ NDIS_STATUS STDCALL ProtocolReceive(
BytesTransferred = 0; BytesTransferred = 0;
} }
} }
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n")); TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
if (NdisStatus != NDIS_STATUS_PENDING) if (NdisStatus != NDIS_STATUS_PENDING)
@ -1369,10 +1332,8 @@ VOID LANUnregisterProtocol(
} }
VOID LANStartup() { VOID LANStartup() {
InitializeListHead( &LanWorkList );
InitializeListHead( &LanSendCompleteList ); InitializeListHead( &LanSendCompleteList );
KeInitializeSpinLock( &LanSendCompleteLock ); KeInitializeSpinLock( &LanSendCompleteLock );
ExInitializeWorkItem( &LanWorkItem, LanReceiveWorker, NULL );
} }
VOID LANShutdown() { VOID LANShutdown() {
@ -1380,15 +1341,6 @@ VOID LANShutdown() {
PLAN_WQ_ITEM WorkItem; PLAN_WQ_ITEM WorkItem;
PLIST_ENTRY ListEntry; PLIST_ENTRY ListEntry;
TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
while( !IsListEmpty( &LanWorkList ) ) {
ListEntry = RemoveHeadList( &LanWorkList );
WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
FreeNdisPacket( WorkItem->Packet );
ExFreePool( WorkItem );
}
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql ); KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
while( !IsListEmpty( &LanSendCompleteList ) ) { while( !IsListEmpty( &LanSendCompleteList ) ) {
ListEntry = RemoveHeadList( &LanSendCompleteList ); ListEntry = RemoveHeadList( &LanSendCompleteList );

View file

@ -36,4 +36,4 @@
#include <ports.h> #include <ports.h>
#include <ipifcons.h> #include <ipifcons.h>
#include <ndk/ntndk.h> #include <ndk/ntndk.h>
#include <chew/chew.h>

View file

@ -176,4 +176,6 @@ NTSTATUS TCPStartup(
NTSTATUS TCPShutdown( NTSTATUS TCPShutdown(
VOID); VOID);
VOID TCPRemoveIRP( PCONNECTION_ENDPOINT Connection, PIRP Irp );
#endif /* __TCP_H */ #endif /* __TCP_H */

View file

@ -9,6 +9,7 @@
<library>oskittcp</library> <library>oskittcp</library>
<library>ndis</library> <library>ndis</library>
<library>pseh</library> <library>pseh</library>
<library>chew</library>
<library>ntoskrnl</library> <library>ntoskrnl</library>
<library>hal</library> <library>hal</library>
<directory name="include"> <directory name="include">

View file

@ -135,6 +135,30 @@ VOID DispDataRequestComplete(
TI_DbgPrint(DEBUG_IRP, ("Done Completing IRP\n")); TI_DbgPrint(DEBUG_IRP, ("Done Completing IRP\n"));
} }
typedef struct _DISCONNECT_TYPE {
UINT Type;
PVOID Context;
PIRP Irp;
PFILE_OBJECT FileObject;
} DISCONNECT_TYPE, *PDISCONNECT_TYPE;
VOID DispDoDisconnect( PVOID Data ) {
PDISCONNECT_TYPE DisType = (PDISCONNECT_TYPE)Data;
TI_DbgPrint(DEBUG_IRP, ("PostCancel: DoDisconnect\n"));
TCPDisconnect
( DisType->Context,
DisType->Type,
NULL,
NULL,
DispDataRequestComplete,
DisType->Irp );
TI_DbgPrint(DEBUG_IRP, ("PostCancel: DoDisconnect done\n"));
DispDataRequestComplete(DisType->Irp, STATUS_CANCELLED, 0);
DispCancelComplete(DisType->FileObject);
}
VOID DDKAPI DispCancelRequest( VOID DDKAPI DispCancelRequest(
PDEVICE_OBJECT Device, PDEVICE_OBJECT Device,
@ -150,6 +174,8 @@ VOID DDKAPI DispCancelRequest(
PTRANSPORT_CONTEXT TranContext; PTRANSPORT_CONTEXT TranContext;
PFILE_OBJECT FileObject; PFILE_OBJECT FileObject;
UCHAR MinorFunction; UCHAR MinorFunction;
DISCONNECT_TYPE DisType;
PVOID WorkItem;
/*NTSTATUS Status = STATUS_SUCCESS;*/ /*NTSTATUS Status = STATUS_SUCCESS;*/
TI_DbgPrint(DEBUG_IRP, ("Called.\n")); TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
@ -161,6 +187,8 @@ VOID DDKAPI DispCancelRequest(
TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X) MinorFunction (0x%X) IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp)); TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X) MinorFunction (0x%X) IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp));
Irp->IoStatus.Status = STATUS_PENDING;
#ifdef DBG #ifdef DBG
if (!Irp->Cancel) if (!Irp->Cancel)
TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n")); TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
@ -169,26 +197,22 @@ VOID DDKAPI DispCancelRequest(
/* Try canceling the request */ /* Try canceling the request */
switch(MinorFunction) { switch(MinorFunction) {
case TDI_SEND: case TDI_SEND:
TCPDisconnect
( TranContext->Handle.ConnectionContext,
TDI_DISCONNECT_RELEASE,
NULL,
NULL,
DispDataRequestComplete,
Irp );
break;
case TDI_RECEIVE: case TDI_RECEIVE:
TCPDisconnect DisType.Type = TDI_DISCONNECT_RELEASE |
( TranContext->Handle.ConnectionContext, ((MinorFunction == TDI_RECEIVE) ? TDI_DISCONNECT_ABORT : 0);
TDI_DISCONNECT_ABORT | TDI_DISCONNECT_RELEASE, DisType.Context = TranContext->Handle.ConnectionContext;
NULL, DisType.Irp = Irp;
NULL, DisType.FileObject = FileObject;
DispDataRequestComplete,
Irp ); TCPRemoveIRP( TranContext->Handle.ConnectionContext, Irp );
if( !ChewCreate( &WorkItem, sizeof(DISCONNECT_TYPE),
DispDoDisconnect, &DisType ) )
ASSERT(0);
break; break;
case TDI_SEND_DATAGRAM: case TDI_SEND_DATAGRAM:
Irp->IoStatus.Status = STATUS_CANCELLED;
if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) { if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n")); TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n"));
break; break;
@ -198,6 +222,7 @@ VOID DDKAPI DispCancelRequest(
break; break;
case TDI_RECEIVE_DATAGRAM: case TDI_RECEIVE_DATAGRAM:
Irp->IoStatus.Status = STATUS_CANCELLED;
if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) { if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n")); TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n"));
break; break;
@ -211,9 +236,10 @@ VOID DDKAPI DispCancelRequest(
break; break;
} }
IoReleaseCancelSpinLock(Irp->CancelIrql); if( Irp->IoStatus.Status == STATUS_PENDING )
IoMarkIrpPending(Irp);
DispCancelComplete(FileObject); IoReleaseCancelSpinLock(Irp->CancelIrql);
TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
} }

View file

@ -619,6 +619,8 @@ VOID STDCALL TiUnload(
} }
TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
#endif #endif
ChewShutdown();
/* Cancel timer */ /* Cancel timer */
KeCancelTimer(&IPTimer); KeCancelTimer(&IPTimer);
@ -734,6 +736,8 @@ DriverEntry(
return Status; return Status;
} }
ChewInit( IPDeviceObject );
/* Create RawIP device object */ /* Create RawIP device object */
Status = IoCreateDevice(DriverObject, 0, &strRawDeviceName, Status = IoCreateDevice(DriverObject, 0, &strRawDeviceName,
FILE_DEVICE_NETWORK, 0, FALSE, &RawIPDeviceObject); FILE_DEVICE_NETWORK, 0, FALSE, &RawIPDeviceObject);