Files winaoe-0.97g/bin/aoe.exe and winaoe-0.97g.deadlock_fix.1/bin/aoe.exe differ Files winaoe-0.97g/bin/aoe32.sys and winaoe-0.97g.deadlock_fix.1/bin/aoe32.sys differ Files winaoe-0.97g/bin/aoe64.sys and winaoe-0.97g.deadlock_fix.1/bin/aoe64.sys differ diff -ru winaoe-0.97g/src/aoe.c winaoe-0.97g.deadlock_fix.1/src/aoe.c --- winaoe-0.97g/src/aoe.c 2008-03-12 00:23:04.000000000 -0500 +++ winaoe-0.97g.deadlock_fix.1/src/aoe.c 2008-12-09 14:29:05.112016000 -0600 @@ -111,14 +111,20 @@ } DISKSEARCH, *PDISKSEARCH; BOOLEAN Stop = FALSE; -KSPIN_LOCK SpinLock; +static KSPIN_LOCK SpinLock; +static KSPIN_LOCK ReplySpinLock; KEVENT ThreadSignalEvent; PTAG TagList = NULL; PTAG TagListLast = NULL; PTAG ProbeTag = NULL; +PTAG ReplyTagListLast = NULL; +PTAG ReplyTagListHead = NULL; PDISKSEARCH DiskSearchList = NULL; LONG OutstandingTags = 0; HANDLE ThreadHandle; +UCHAR GlobalSourceMac[6]; + + NTSTATUS STDCALL AoEStart() { NTSTATUS Status; @@ -145,6 +151,7 @@ ProbeTag->PacketData->Count = 1; KeInitializeSpinLock(&SpinLock); + KeInitializeSpinLock(&ReplySpinLock); KeInitializeEvent(&ThreadSignalEvent, SynchronizationEvent, FALSE); InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); @@ -240,7 +247,7 @@ Timeout.QuadPart = -500000LL; // 500.000 * 100ns = 50.000.000 ns = 50ms KeWaitForSingleObject(&DeviceExtension->Disk.SearchEvent, Executive, KernelMode, FALSE, &Timeout); if (Stop) { - DbgPrint("AoESearchBootDrive cancled\n"); + DbgPrint("AoESearchBootDrive canceled\n"); return FALSE; } @@ -513,27 +520,81 @@ return STATUS_PENDING; } -NTSTATUS STDCALL AoEReply(IN PUCHAR SourceMac, IN PUCHAR DestinationMac, IN PUCHAR Data, IN UINT DataSize) { + + + +// Call from protocolReceive/NDIS to add packets to receive queue +NTSTATUS STDCALL AoEReplyQueue(IN PUCHAR SourceMac, IN PUCHAR DestinationMac, IN PUCHAR Data, IN UINT DataSize) { PAOE Reply = (PAOE)Data; LONGLONG LBASize; - PTAG Tag; + PTAG ReplyTag; KIRQL Irql; - BOOLEAN Found = FALSE; - LARGE_INTEGER CurrentTime; if (!Reply->ResponseFlag) return STATUS_SUCCESS; + + // Special case for AoE probe response if (ProbeTag->Id == Reply->Tag) { RtlCopyMemory(&LBASize, &Reply->Data[200], sizeof(LONGLONG)); BusAddTarget(DestinationMac, SourceMac, ntohs(Reply->Major), Reply->Minor, LBASize); return STATUS_SUCCESS; } + + // allocate storage + if ((ReplyTag = (PTAG)ExAllocatePool(NonPagedPool, sizeof(TAG))) == NULL) { + DbgPrint("AoERequest ExAllocatePool ReplyTag\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlZeroMemory(ReplyTag, sizeof(TAG)); + // - not using all the TAG fields, just PacketData, PacketSize, Next, and Previous + ReplyTag->PacketSize = DataSize; + if ((ReplyTag->PacketData = (PAOE)ExAllocatePool(NonPagedPool, ReplyTag->PacketSize)) == NULL) { + DbgPrint("AoERequest ExAllocatePool ReplyTag->PacketData\n"); + ExFreePool(ReplyTag); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // copy packet data to list item + RtlCopyMemory(ReplyTag->PacketData, Reply, ReplyTag->PacketSize); + + // AoEProcessReply needs the SourceMac, so save it + RtlCopyMemory(GlobalSourceMac, SourceMac, 6); + + // add to the end of the reply list + KeAcquireSpinLock(&ReplySpinLock, &Irql); + if (ReplyTagListLast == NULL) { + ReplyTagListHead = ReplyTag; + } else { + ReplyTagListLast->Next = ReplyTag; + ReplyTag->Previous = ReplyTagListLast; + ReplyTag->Next = NULL; + } + ReplyTagListLast = ReplyTag; + KeReleaseSpinLock(&ReplySpinLock, Irql); + + // tell Thread we have a reply + KeSetEvent(&ThreadSignalEvent, 0, FALSE); + return STATUS_SUCCESS; +} + + +// changed this to process receive list; call from Thread before processing sends +NTSTATUS STDCALL AoEProcessReply(IN PUCHAR Data, IN UINT DataSize) { + PAOE Reply = (PAOE) Data; + LONGLONG LBASize; + PTAG Tag; + KIRQL Irql; + BOOLEAN Found = FALSE; + LARGE_INTEGER CurrentTime; + + KeAcquireSpinLock(&SpinLock, &Irql); if (TagList == NULL) { KeReleaseSpinLock(&SpinLock, Irql); return STATUS_SUCCESS; } + // see if we need this packet Tag = TagList; while (Tag != NULL) { if ((Tag->Id == Reply->Tag) && (Tag->PacketData->Major == Reply->Major) && (Tag->PacketData->Minor == Reply->Minor)) { @@ -546,24 +607,29 @@ KeReleaseSpinLock(&SpinLock, Irql); return STATUS_SUCCESS; } else { + // we need this packet, remove from TagList, and decrement count if (Tag->Previous == NULL) TagList = Tag->Next; else Tag->Previous->Next = Tag->Next; if (Tag->Next == NULL) TagListLast = Tag->Previous; else Tag->Next->Previous = Tag->Previous; OutstandingTags--; if (OutstandingTags < 0) DbgPrint("!!OutstandingTags < 0 (AoEReply)!!\n"); - KeSetEvent(&ThreadSignalEvent, 0, FALSE); } KeReleaseSpinLock(&SpinLock, Irql); + // get MAC from a global if (RtlCompareMemory(Tag->DeviceExtension->Disk.ServerMac, "\xff\xff\xff\xff\xff\xff", 6) == 6) { - RtlCopyMemory(Tag->DeviceExtension->Disk.ServerMac, SourceMac, 6); - DbgPrint("Major: %d minor: %d found on server %02x:%02x:%02x:%02x:%02x:%02x\n", Tag->DeviceExtension->Disk.Major, Tag->DeviceExtension->Disk.Minor, SourceMac[0], SourceMac[1], SourceMac[2], SourceMac[3], SourceMac[4], SourceMac[5]); + RtlCopyMemory(Tag->DeviceExtension->Disk.ServerMac, GlobalSourceMac, 6); + DbgPrint("Major: %d minor: %d found on server %02x:%02x:%02x:%02x:%02x:%02x\n", Tag->DeviceExtension->Disk.Major, Tag->DeviceExtension->Disk.Minor, + GlobalSourceMac[0], GlobalSourceMac[1], GlobalSourceMac[2], GlobalSourceMac[3], GlobalSourceMac[4], GlobalSourceMac[5]); } KeQuerySystemTime(&CurrentTime); + // timeout -= (timeout - delta time) / 1024 Tag->DeviceExtension->Disk.Timeout -= (ULONG)((Tag->DeviceExtension->Disk.Timeout - (CurrentTime.QuadPart - Tag->FirstSendTime.QuadPart)) / 1024); if (Tag->DeviceExtension->Disk.Timeout > 100000000) Tag->DeviceExtension->Disk.Timeout = 100000000; + // min timeout = 7 msec + //if (Tag->DeviceExtension->Disk.Timeout < 70000) Tag->DeviceExtension->Disk.Timeout = 70000; switch (Tag->Type) { case SearchDriveType: @@ -615,7 +681,6 @@ break; } - KeSetEvent(&ThreadSignalEvent, 0, FALSE); ExFreePool(Tag->PacketData); ExFreePool(Tag); return STATUS_SUCCESS; @@ -629,14 +694,15 @@ LARGE_INTEGER Timeout, CurrentTime, ProbeTime, ReportTime; ULONG NextTagId = 1; PTAG Tag; - KIRQL Irql; + PTAG Next=NULL; + KIRQL Irql, Irq2; ULONG Sends = 0; ULONG Resends = 0; ULONG ResendFails = 0; ULONG Fails = 0; ULONG RequestTimeout = 0; - DbgPrint("Thread\n"); + DbgPrint("Thread - entry\n"); ReportTime.QuadPart = 0LL; ProbeTime.QuadPart = 0LL; @@ -652,7 +718,7 @@ KeQuerySystemTime(&CurrentTime); if (CurrentTime.QuadPart > (ReportTime.QuadPart + 10000000LL)) { -// DbgPrint("Sends: %d Resends: %d ResendFails: %d Fails: %d OutstandingTags: %d RequestTimeout: %d\n", Sends, Resends, ResendFails, Fails, OutstandingTags, RequestTimeout); + DbgPrint("Sends: %d Resends: %d ResendFails: %d Fails: %d OutstandingTags: %d RequestTimeout: %d\n", Sends, Resends, ResendFails, Fails, OutstandingTags, RequestTimeout); Sends = 0; Resends = 0; ResendFails = 0; @@ -660,6 +726,7 @@ KeQuerySystemTime(&ReportTime); } + // send the probe every 100 seconds if (CurrentTime.QuadPart > (ProbeTag->SendTime.QuadPart + 100000000LL)) { ProbeTag->Id = NextTagId++; if (NextTagId == 0) NextTagId++; @@ -668,6 +735,21 @@ KeQuerySystemTime(&ProbeTag->SendTime); } + + // process the reply list, deleting each item after processing + KeAcquireSpinLock(&ReplySpinLock, &Irq2); + for (Tag = ReplyTagListHead; Tag != NULL; Tag=Next) { + AoEProcessReply ((PUCHAR) Tag->PacketData, Tag->PacketSize); + Next= Tag->Next; + ExFreePool (Tag->PacketData); + ExFreePool(Tag); + } + ReplyTagListHead = NULL; + ReplyTagListLast = NULL; + KeReleaseSpinLock(&ReplySpinLock, Irq2); + + + // process the Tag list KeAcquireSpinLock(&SpinLock, &Irql); if (TagList == NULL) { KeReleaseSpinLock(&SpinLock, Irql); @@ -676,6 +758,7 @@ Tag = TagList; while (Tag != NULL) { RequestTimeout = Tag->DeviceExtension->Disk.Timeout; + // if this is a new packet to send if (Tag->Id == 0) { if (OutstandingTags <= 64) { //if (OutstandingTags <= 102400) { @@ -687,20 +770,25 @@ KeQuerySystemTime(&Tag->FirstSendTime); KeQuerySystemTime(&Tag->SendTime); OutstandingTags++; - Sends++; + Sends++; } else { Fails++; Tag->Id = 0; break; } } + // else this is a previously sent packet; see if we need to re-send it } else { KeQuerySystemTime(&CurrentTime); + // if we've waited longer than the 2*timeout, resend packet, and raise the timeout value a little if (CurrentTime.QuadPart > (Tag->SendTime.QuadPart + (LONGLONG)(Tag->DeviceExtension->Disk.Timeout * 2))) { if (ProtocolSend(Tag->DeviceExtension->Disk.ClientMac, Tag->DeviceExtension->Disk.ServerMac, (PUCHAR)Tag->PacketData, Tag->PacketSize, Tag)) { KeQuerySystemTime(&Tag->SendTime); + // timeout += timeout/1000 Tag->DeviceExtension->Disk.Timeout += Tag->DeviceExtension->Disk.Timeout / 1000; if (Tag->DeviceExtension->Disk.Timeout > 100000000) Tag->DeviceExtension->Disk.Timeout = 100000000; + // min timeout = 7 msec + //if (Tag->DeviceExtension->Disk.Timeout < 70000) Tag->DeviceExtension->Disk.Timeout = 70000; Resends++; } else { ResendFails++; diff -ru winaoe-0.97g/src/aoe.h winaoe-0.97g.deadlock_fix.1/src/aoe.h --- winaoe-0.97g/src/aoe.h 2008-02-19 08:46:08.000000000 -0600 +++ winaoe-0.97g.deadlock_fix.1/src/aoe.h 2008-12-04 17:50:30.376059800 -0600 @@ -23,6 +23,7 @@ #include "portable.h" #include "driver.h" + #define htons(x) (USHORT)((((x) << 8) & 0xff00) | (((x) >> 8) & 0xff)) #define ntohs(x) (USHORT)((((x) << 8) & 0xff00) | (((x) >> 8) & 0xff)) @@ -30,7 +31,8 @@ BOOLEAN STDCALL AoESearchDrive(IN PDEVICEEXTENSION DeviceExtension); NTSTATUS STDCALL AoERequest(IN PDEVICEEXTENSION DeviceExtension, IN REQUESTMODE Mode, IN LONGLONG StartSector, IN ULONG SectorCount, IN PUCHAR Buffer, IN PIRP Irp); -NTSTATUS STDCALL AoEReply(IN PUCHAR SourceMac, IN PUCHAR DestinationMac, IN PUCHAR Data, IN UINT DataSize); +NTSTATUS STDCALL AoEReplyQueue(IN PUCHAR SourceMac, IN PUCHAR DestinationMac, IN PUCHAR Data, IN UINT DataSize); +NTSTATUS STDCALL AoEProcessReply(IN PUCHAR Data, IN UINT DataSize); VOID STDCALL AoEResetProbe(); #endif diff -ru winaoe-0.97g/src/debug.c winaoe-0.97g.deadlock_fix.1/src/debug.c --- winaoe-0.97g/src/debug.c 2008-02-19 08:46:08.000000000 -0600 +++ winaoe-0.97g.deadlock_fix.1/src/debug.c 2008-12-03 12:51:37.992681100 -0600 @@ -38,7 +38,7 @@ } IRPLIST, *PIRPLIST; PIRPLIST IrpList = NULL; -KSPIN_LOCK SpinLock; +static KSPIN_LOCK SpinLock; ULONG Number = 0; extern int sprintf(char*, const char *, ...); diff -ru winaoe-0.97g/src/protocol.c winaoe-0.97g.deadlock_fix.1/src/protocol.c --- winaoe-0.97g/src/protocol.c 2008-02-19 08:46:08.000000000 -0600 +++ winaoe-0.97g.deadlock_fix.1/src/protocol.c 2008-12-04 17:55:02.874315800 -0600 @@ -71,7 +71,7 @@ } BINDINGCONTEXT, *PBINDINGCONTEXT; KEVENT ProtocolStopEvent; -KSPIN_LOCK SpinLock; +static KSPIN_LOCK SpinLock; PBINDINGCONTEXT BindingContextList = NULL; NDIS_HANDLE ProtocolHandle = NULL; @@ -259,7 +259,7 @@ } else { DbgPrint("ProtocolTransferDataComplete Header (back) Buffer == NULL\n"); } - if (Header != NULL && Data != NULL) AoEReply(Header->SourceMac, Header->DestinationMac, Data, DataSize); + if (Header != NULL && Data != NULL) AoEReplyQueue(Header->SourceMac, Header->DestinationMac, Data, DataSize); if (Header != NULL) ExFreePool(Header); if (Data != NULL) ExFreePool(Data); NdisFreePacket(Packet); @@ -303,7 +303,7 @@ if (ntohs(Header->Protocol) != AOEPROTOCOLID) return NDIS_STATUS_NOT_ACCEPTED; if (LookaheadBufferSize == PacketSize) { - AoEReply(Header->SourceMac, Header->DestinationMac, LookAheadBuffer, PacketSize); + AoEReplyQueue(Header->SourceMac, Header->DestinationMac, LookAheadBuffer, PacketSize); return NDIS_STATUS_SUCCESS; }