|
|
1.1 ! root 1: /* ! 2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved. ! 3: ! 4: Governed by the TrueCrypt License 2.4 the full text of which is contained ! 5: in the file License.txt included in TrueCrypt binary and source code ! 6: distribution packages. ! 7: */ ! 8: ! 9: #include "TCdefs.h" ! 10: #include "Apidrvr.h" ! 11: #include "Ntdriver.h" ! 12: #include "EncryptedIoQueue.h" ! 13: ! 14: ! 15: static void DecrementOutstandingIoCount (EncryptedIoQueue *queue) ! 16: { ! 17: if (InterlockedDecrement (&queue->OutstandingIoCount) == 0 && (queue->SuspendPending || queue->StopPending)) ! 18: KeSetEvent (&queue->NoOutstandingIoEvent, 0, FALSE); ! 19: } ! 20: ! 21: ! 22: static void OnItemCompleted (EncryptedIoQueueItem *item) ! 23: { ! 24: DecrementOutstandingIoCount (item->Queue); ! 25: ! 26: if (item->Queue->IsFilterDevice) ! 27: IoReleaseRemoveLock (&item->Queue->RemoveLock, item->OriginalIrp); ! 28: ! 29: if (NT_SUCCESS (item->Status)) ! 30: { ! 31: if (item->Write) ! 32: item->Queue->TotalBytesWritten += item->OriginalLength; ! 33: else ! 34: item->Queue->TotalBytesRead += item->OriginalLength; ! 35: } ! 36: ! 37: TCfree (item); ! 38: } ! 39: ! 40: ! 41: static NTSTATUS CompleteOriginalIrp (EncryptedIoQueueItem *item, NTSTATUS status, ULONG_PTR information) ! 42: { ! 43: //Dump ("Queue comp offset=%I64d status=%x info=%p out=%d\n", item->OriginalOffset, status, information, item->Queue->OutstandingIoCount - 1); ! 44: TCCompleteDiskIrp (item->OriginalIrp, status, information); ! 45: OnItemCompleted (item); ! 46: return status; ! 47: } ! 48: ! 49: ! 50: static void AcquireFragmentBuffer (EncryptedIoQueue *queue, byte *buffer) ! 51: { ! 52: NTSTATUS status = STATUS_INVALID_PARAMETER; ! 53: ! 54: if (buffer == queue->FragmentBufferA) ! 55: { ! 56: status = KeWaitForSingleObject (&queue->FragmentBufferAFreeEvent, Executive, KernelMode, FALSE, NULL); ! 57: } ! 58: else if (buffer == queue->FragmentBufferB) ! 59: { ! 60: status = KeWaitForSingleObject (&queue->FragmentBufferBFreeEvent, Executive, KernelMode, FALSE, NULL); ! 61: } ! 62: ! 63: if (!NT_SUCCESS (status)) ! 64: TC_BUG_CHECK (status); ! 65: } ! 66: ! 67: ! 68: static void ReleaseFragmentBuffer (EncryptedIoQueue *queue, byte *buffer) ! 69: { ! 70: if (buffer == queue->FragmentBufferA) ! 71: { ! 72: KeSetEvent (&queue->FragmentBufferAFreeEvent, 0, FALSE); ! 73: } ! 74: else if (buffer == queue->FragmentBufferB) ! 75: { ! 76: KeSetEvent (&queue->FragmentBufferBFreeEvent, 0, FALSE); ! 77: } ! 78: else ! 79: { ! 80: TC_BUG_CHECK (STATUS_INVALID_PARAMETER); ! 81: } ! 82: } ! 83: ! 84: ! 85: static VOID CompletionThreadProc (PVOID threadArg) ! 86: { ! 87: EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg; ! 88: PLIST_ENTRY listEntry; ! 89: EncryptedIoRequest *request; ! 90: UINT64_STRUCT dataUnit; ! 91: ! 92: while (!queue->ThreadExitRequested) ! 93: { ! 94: if (!NT_SUCCESS (KeWaitForSingleObject (&queue->CompletionThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL))) ! 95: continue; ! 96: ! 97: if (queue->ThreadExitRequested) ! 98: break; ! 99: ! 100: while ((listEntry = ExInterlockedRemoveHeadList (&queue->CompletionThreadQueue, &queue->CompletionThreadQueueLock))) ! 101: { ! 102: request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, CompletionListEntry); ! 103: ! 104: if (request->EncryptedLength > 0) ! 105: { ! 106: ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length); ! 107: dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE; ! 108: DecryptDataUnits (request->Data + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo); ! 109: } ! 110: ! 111: if (request->CompleteOriginalIrp) ! 112: { ! 113: CompleteOriginalIrp (request->Item, request->Item->Status, ! 114: NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0); ! 115: } ! 116: ! 117: TCfree (request); ! 118: } ! 119: } ! 120: ! 121: PsTerminateSystemThread (STATUS_SUCCESS); ! 122: } ! 123: ! 124: ! 125: static VOID IoThreadProc (PVOID threadArg) ! 126: { ! 127: EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg; ! 128: PLIST_ENTRY listEntry; ! 129: EncryptedIoRequest *request; ! 130: ! 131: while (!queue->ThreadExitRequested) ! 132: { ! 133: if (!NT_SUCCESS (KeWaitForSingleObject (&queue->IoThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL))) ! 134: continue; ! 135: ! 136: if (queue->ThreadExitRequested) ! 137: break; ! 138: ! 139: while ((listEntry = ExInterlockedRemoveHeadList (&queue->IoThreadQueue, &queue->IoThreadQueueLock))) ! 140: { ! 141: request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, ListEntry); ! 142: ! 143: // IO request ! 144: if (queue->IsFilterDevice) ! 145: { ! 146: if (request->Item->Write) ! 147: request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, request->Data, request->Offset, request->Length); ! 148: else ! 149: request->Item->Status = TCReadDevice (queue->LowerDeviceObject, request->Data, request->Offset, request->Length); ! 150: } ! 151: else ! 152: { ! 153: IO_STATUS_BLOCK ioStatus; ! 154: ! 155: if (request->Item->Write) ! 156: request->Item->Status = ZwWriteFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, request->Data, request->Length, &request->Offset, NULL); ! 157: else ! 158: request->Item->Status = ZwReadFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, request->Data, request->Length, &request->Offset, NULL); ! 159: } ! 160: ! 161: if (!request->Item->Write && NT_SUCCESS (request->Item->Status)) ! 162: { ! 163: // Successful read completed ! 164: if (!request->CompleteOriginalIrp) ! 165: KeSetEvent (&request->Item->IoRequestCompletedEvent, 0, FALSE); ! 166: ! 167: // Copy fragment to original IRP buffer ! 168: memcpy (request->OrigDataBufferFragment, request->Data, request->Length); ! 169: ReleaseFragmentBuffer (queue, request->Data); ! 170: request->Data = request->OrigDataBufferFragment; ! 171: ! 172: // Queue decryption to completion thread ! 173: ExInterlockedInsertTailList (&queue->CompletionThreadQueue, &request->CompletionListEntry, &queue->CompletionThreadQueueLock); ! 174: KeSetEvent (&queue->CompletionThreadQueueNotEmptyEvent, 0, FALSE); ! 175: } ! 176: else ! 177: { ! 178: ReleaseFragmentBuffer (queue, request->Data); ! 179: ! 180: if (request->CompleteOriginalIrp) ! 181: { ! 182: CompleteOriginalIrp (request->Item, request->Item->Status, ! 183: NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0); ! 184: } ! 185: else ! 186: { ! 187: KeSetEvent (&request->Item->IoRequestCompletedEvent, 0, FALSE); ! 188: } ! 189: ! 190: TCfree (request); ! 191: } ! 192: } ! 193: } ! 194: ! 195: PsTerminateSystemThread (STATUS_SUCCESS); ! 196: } ! 197: ! 198: ! 199: static NTSTATUS OnPassedIrpCompleted (PDEVICE_OBJECT filterDeviceObject, PIRP irp, EncryptedIoQueueItem *item) ! 200: { ! 201: if (irp->PendingReturned) ! 202: IoMarkIrpPending (irp); ! 203: ! 204: OnItemCompleted (item); ! 205: return STATUS_CONTINUE_COMPLETION; ! 206: } ! 207: ! 208: ! 209: static VOID MainThreadProc (PVOID threadArg) ! 210: { ! 211: EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg; ! 212: PLIST_ENTRY listEntry; ! 213: EncryptedIoQueueItem *item; ! 214: NTSTATUS status; ! 215: ! 216: LARGE_INTEGER fragmentOffset; ! 217: ULONG dataRemaining; ! 218: PUCHAR activeFragmentBuffer = queue->FragmentBufferA; ! 219: PUCHAR dataBuffer; ! 220: EncryptedIoRequest *request; ! 221: uint64 intersectStart; ! 222: uint32 intersectLength; ! 223: ! 224: while (!queue->ThreadExitRequested) ! 225: { ! 226: if (!NT_SUCCESS (KeWaitForSingleObject (&queue->MainThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL))) ! 227: continue; ! 228: ! 229: while ((listEntry = ExInterlockedRemoveHeadList (&queue->MainThreadQueue, &queue->MainThreadQueueLock))) ! 230: { ! 231: item = CONTAINING_RECORD (listEntry, EncryptedIoQueueItem, ListEntry); ! 232: ! 233: if (queue->Suspended) ! 234: { ! 235: KeWaitForSingleObject (&queue->QueueResumedEvent, Executive, KernelMode, FALSE, NULL); ! 236: } ! 237: ! 238: IoSetCancelRoutine (item->OriginalIrp, NULL); ! 239: if (item->OriginalIrp->Cancel) ! 240: { ! 241: CompleteOriginalIrp (item, STATUS_CANCELLED, 0); ! 242: continue; ! 243: } ! 244: ! 245: // Pass the IRP if the drive is not encrypted ! 246: if (queue->IsFilterDevice && (queue->EncryptedAreaStart == -1 || queue->EncryptedAreaEnd == -1)) ! 247: { ! 248: ! 249: IoCopyCurrentIrpStackLocationToNext (item->OriginalIrp); ! 250: IoSetCompletionRoutine (item->OriginalIrp, OnPassedIrpCompleted, item, TRUE, TRUE, TRUE); ! 251: IoCallDriver (queue->LowerDeviceObject, item->OriginalIrp); ! 252: continue; ! 253: } ! 254: ! 255: //Dump ("--- Queue %c %I64d (%I64d) %d out=%d\n", item->Write ? 'W' : 'R', item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart / 1024 / 1024, item->OriginalLength, queue->OutstandingIoCount); ! 256: ! 257: // Validate offset and length ! 258: if (item->OriginalLength == 0 || (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) ! 259: || (!queue->IsFilterDevice && item->OriginalOffset.QuadPart + item->OriginalLength > queue->VirtualDeviceLength)) ! 260: { ! 261: CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0); ! 262: continue; ! 263: } ! 264: ! 265: if (!queue->IsFilterDevice) ! 266: { ! 267: // Hidden volume protection ! 268: if (item->Write && queue->CryptoInfo->bProtectHiddenVolume) ! 269: { ! 270: // If there has already been a write operation denied in order to protect the ! 271: // hidden volume (since the volume mount time) ! 272: if (queue->CryptoInfo->bHiddenVolProtectionAction) ! 273: { ! 274: // Do not allow writing to this volume anymore. This is to fake a complete volume ! 275: // or system failure (otherwise certain kinds of inconsistency within the file ! 276: // system could indicate that this volume has used hidden volume protection). ! 277: CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0); ! 278: continue; ! 279: } ! 280: ! 281: // Verify that no byte is going to be written to the hidden volume area ! 282: if (RegionsOverlap ((unsigned __int64) item->OriginalOffset.QuadPart + HEADER_SIZE, ! 283: (unsigned __int64) item->OriginalOffset.QuadPart + HEADER_SIZE + item->OriginalLength - 1, ! 284: queue->CryptoInfo->hiddenVolumeOffset, ! 285: (unsigned __int64) queue->VirtualDeviceLength + HEADER_SIZE - (HIDDEN_VOL_HEADER_OFFSET - HEADER_SIZE) - 1)) ! 286: { ! 287: queue->CryptoInfo->bHiddenVolProtectionAction = TRUE; ! 288: ! 289: // Deny this write operation to prevent the hidden volume from being overwritten ! 290: CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0); ! 291: continue; ! 292: } ! 293: } ! 294: ! 295: // Adjust the offset for host file or device ! 296: if (queue->CryptoInfo->hiddenVolume) ! 297: item->OriginalOffset.QuadPart += queue->CryptoInfo->hiddenVolumeOffset; ! 298: else ! 299: item->OriginalOffset.QuadPart += HEADER_SIZE; ! 300: } ! 301: ! 302: // Original IRP data buffer ! 303: dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (item->OriginalIrp->MdlAddress, HighPagePriority); ! 304: if (dataBuffer == NULL) ! 305: { ! 306: CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0); ! 307: continue; ! 308: } ! 309: ! 310: // Divide data block to fragments to enable efficient overlapping of encryption and IO operations ! 311: ! 312: dataRemaining = item->OriginalLength; ! 313: fragmentOffset = item->OriginalOffset; ! 314: ! 315: while (dataRemaining > 0) ! 316: { ! 317: BOOL isFirstFragment = fragmentOffset.QuadPart == item->OriginalOffset.QuadPart; ! 318: BOOL isLastFragment = dataRemaining <= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; ! 319: ! 320: ULONG dataFragmentLength = isLastFragment ? dataRemaining : TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; ! 321: activeFragmentBuffer = (activeFragmentBuffer == queue->FragmentBufferA ? queue->FragmentBufferB : queue->FragmentBufferA); ! 322: ! 323: // Create IO request ! 324: request = (EncryptedIoRequest *) TCalloc (sizeof (EncryptedIoRequest)); ! 325: if (!request) ! 326: { ! 327: CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0); ! 328: break; ! 329: } ! 330: ! 331: request->Item = item; ! 332: request->CompleteOriginalIrp = isLastFragment; ! 333: request->Offset = fragmentOffset; ! 334: request->Data = activeFragmentBuffer; ! 335: request->OrigDataBufferFragment = dataBuffer; ! 336: request->Length = dataFragmentLength; ! 337: ! 338: if (queue->IsFilterDevice) ! 339: { ! 340: // Get intersection of data fragment with encrypted area ! 341: GetIntersection (fragmentOffset.QuadPart, dataFragmentLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength); ! 342: ! 343: request->EncryptedOffset = intersectStart - fragmentOffset.QuadPart; ! 344: request->EncryptedLength = intersectLength; ! 345: } ! 346: else ! 347: { ! 348: request->EncryptedOffset = 0; ! 349: request->EncryptedLength = dataFragmentLength; ! 350: } ! 351: ! 352: AcquireFragmentBuffer (queue, activeFragmentBuffer); ! 353: ! 354: if (item->Write) ! 355: { ! 356: // Encrypt data ! 357: memcpy (activeFragmentBuffer, dataBuffer, dataFragmentLength); ! 358: ! 359: if (request->EncryptedLength > 0) ! 360: { ! 361: UINT64_STRUCT dataUnit; ! 362: ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length); ! 363: ! 364: dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE; ! 365: EncryptDataUnits (activeFragmentBuffer + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo); ! 366: } ! 367: } ! 368: ! 369: if (!isFirstFragment) ! 370: { ! 371: // Wait for completion of previous fragment IO ! 372: ! 373: status = KeWaitForSingleObject (&item->IoRequestCompletedEvent, Executive, KernelMode, FALSE, NULL); ! 374: if (!NT_SUCCESS (status)) ! 375: TC_BUG_CHECK (status); ! 376: ! 377: if (!NT_SUCCESS (item->Status)) ! 378: { ! 379: // If the previous fragment IO failed, stop processing remaining fragments and complete the IRP ! 380: ReleaseFragmentBuffer (queue, activeFragmentBuffer); ! 381: CompleteOriginalIrp (item, item->Status, 0); ! 382: break; ! 383: } ! 384: } ! 385: ! 386: // Queue IO request ! 387: ExInterlockedInsertTailList (&queue->IoThreadQueue, &request->ListEntry, &queue->IoThreadQueueLock); ! 388: KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, 0, FALSE); ! 389: ! 390: if (isLastFragment) ! 391: break; ! 392: ! 393: dataRemaining -= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; ! 394: dataBuffer += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; ! 395: fragmentOffset.QuadPart += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE; ! 396: } ! 397: } ! 398: } ! 399: ! 400: PsTerminateSystemThread (STATUS_SUCCESS); ! 401: } ! 402: ! 403: ! 404: NTSTATUS EncryptedIoQueueAddIrp (EncryptedIoQueue *queue, PIRP irp) ! 405: { ! 406: EncryptedIoQueueItem *item; ! 407: PIO_STACK_LOCATION origIrpSp = IoGetCurrentIrpStackLocation (irp); ! 408: NTSTATUS status; ! 409: ! 410: InterlockedIncrement (&queue->OutstandingIoCount); ! 411: if (queue->StopPending) ! 412: { ! 413: Dump ("STATUS_DEVICE_NOT_READY out=%d\n", queue->OutstandingIoCount); ! 414: status = STATUS_DEVICE_NOT_READY; ! 415: goto err; ! 416: } ! 417: ! 418: if (queue->IsFilterDevice) ! 419: { ! 420: status = IoAcquireRemoveLock (&queue->RemoveLock, irp); ! 421: if (!NT_SUCCESS (status)) ! 422: goto err; ! 423: } ! 424: ! 425: item = TCalloc (sizeof (EncryptedIoQueueItem)); ! 426: if (!item) ! 427: { ! 428: status = STATUS_INSUFFICIENT_RESOURCES; ! 429: goto err; ! 430: } ! 431: ! 432: memset (item, 0, sizeof (EncryptedIoQueueItem)); ! 433: ! 434: switch (origIrpSp->MajorFunction) ! 435: { ! 436: case IRP_MJ_READ: ! 437: item->Write = FALSE; ! 438: item->OriginalOffset = origIrpSp->Parameters.Read.ByteOffset; ! 439: item->OriginalLength = origIrpSp->Parameters.Read.Length; ! 440: break; ! 441: ! 442: case IRP_MJ_WRITE: ! 443: item->Write = TRUE; ! 444: item->OriginalOffset = origIrpSp->Parameters.Write.ByteOffset; ! 445: item->OriginalLength = origIrpSp->Parameters.Write.Length; ! 446: break; ! 447: ! 448: default: ! 449: TCfree (item); ! 450: status = STATUS_INVALID_PARAMETER; ! 451: goto err; ! 452: } ! 453: ! 454: item->Queue = queue; ! 455: item->OriginalIrp = irp; ! 456: KeInitializeEvent (&item->IoRequestCompletedEvent, SynchronizationEvent, FALSE); ! 457: ! 458: IoMarkIrpPending (irp); ! 459: ! 460: //Dump ("Queue add %I64d %I64d out=%d\n", item->OriginalOffset, item->OriginalLength, queue->OutstandingIoCount); ! 461: ! 462: ExInterlockedInsertTailList (&queue->MainThreadQueue, &item->ListEntry, &queue->MainThreadQueueLock); ! 463: KeSetEvent (&queue->MainThreadQueueNotEmptyEvent, 0, FALSE); ! 464: ! 465: return STATUS_PENDING; ! 466: ! 467: err: ! 468: DecrementOutstandingIoCount (queue); ! 469: return status; ! 470: } ! 471: ! 472: ! 473: NTSTATUS EncryptedIoQueueHoldWhenIdle (EncryptedIoQueue *queue, int64 timeout) ! 474: { ! 475: NTSTATUS status; ! 476: ASSERT (!queue->Suspended); ! 477: ! 478: queue->SuspendPending = TRUE; ! 479: ! 480: while (TRUE) ! 481: { ! 482: while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0) ! 483: { ! 484: LARGE_INTEGER waitTimeout; ! 485: ! 486: waitTimeout.QuadPart = timeout * -10000; ! 487: status = KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, timeout != 0 ? &waitTimeout : NULL); ! 488: ! 489: if (status == STATUS_TIMEOUT) ! 490: status = STATUS_UNSUCCESSFUL; ! 491: ! 492: if (!NT_SUCCESS (status)) ! 493: return status; ! 494: } ! 495: ! 496: KeClearEvent (&queue->QueueResumedEvent); ! 497: queue->Suspended = TRUE; ! 498: ! 499: if (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) == 0) ! 500: break; ! 501: ! 502: queue->Suspended = FALSE; ! 503: KeSetEvent (&queue->QueueResumedEvent, 0, FALSE); ! 504: ! 505: } ! 506: ! 507: queue->SuspendPending = FALSE; ! 508: //Dump ("Queue suspended out=%d\n", queue->OutstandingIoCount); ! 509: ! 510: return STATUS_SUCCESS; ! 511: } ! 512: ! 513: ! 514: BOOL EncryptedIoQueueIsSuspended (EncryptedIoQueue *queue) ! 515: { ! 516: return queue->Suspended; ! 517: } ! 518: ! 519: ! 520: BOOL EncryptedIoQueueIsRunning (EncryptedIoQueue *queue) ! 521: { ! 522: return !queue->StopPending; ! 523: } ! 524: ! 525: ! 526: NTSTATUS EncryptedIoQueueResumeFromHold (EncryptedIoQueue *queue) ! 527: { ! 528: ASSERT (queue->Suspended); ! 529: ! 530: queue->Suspended = FALSE; ! 531: KeSetEvent (&queue->QueueResumedEvent, 0, FALSE); ! 532: ! 533: //Dump ("Queue resumed out=%d\n", queue->OutstandingIoCount); ! 534: ! 535: return STATUS_SUCCESS; ! 536: } ! 537: ! 538: ! 539: NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue) ! 540: { ! 541: NTSTATUS status; ! 542: queue->ThreadExitRequested = FALSE; ! 543: ! 544: KeInitializeEvent (&queue->NoOutstandingIoEvent, SynchronizationEvent, FALSE); ! 545: KeInitializeEvent (&queue->QueueResumedEvent, SynchronizationEvent, FALSE); ! 546: ! 547: queue->FragmentBufferA = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE); ! 548: if (!queue->FragmentBufferA) ! 549: goto noMemory; ! 550: ! 551: queue->FragmentBufferB = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE); ! 552: if (!queue->FragmentBufferB) ! 553: goto noMemory; ! 554: ! 555: KeInitializeEvent (&queue->FragmentBufferAFreeEvent, SynchronizationEvent, TRUE); ! 556: KeInitializeEvent (&queue->FragmentBufferBFreeEvent, SynchronizationEvent, TRUE); ! 557: ! 558: // Main thread ! 559: InitializeListHead (&queue->MainThreadQueue); ! 560: KeInitializeSpinLock (&queue->MainThreadQueueLock); ! 561: KeInitializeEvent (&queue->MainThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE); ! 562: ! 563: status = TCStartThread (MainThreadProc, queue, &queue->MainThread); ! 564: if (!NT_SUCCESS (status)) ! 565: goto err; ! 566: ! 567: // IO thread ! 568: InitializeListHead (&queue->IoThreadQueue); ! 569: KeInitializeSpinLock (&queue->IoThreadQueueLock); ! 570: KeInitializeEvent (&queue->IoThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE); ! 571: ! 572: status = TCStartThread (IoThreadProc, queue, &queue->IoThread); ! 573: if (!NT_SUCCESS (status)) ! 574: { ! 575: queue->ThreadExitRequested = TRUE; ! 576: TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent); ! 577: goto err; ! 578: } ! 579: ! 580: // Completion thread ! 581: InitializeListHead (&queue->CompletionThreadQueue); ! 582: KeInitializeSpinLock (&queue->CompletionThreadQueueLock); ! 583: KeInitializeEvent (&queue->CompletionThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE); ! 584: ! 585: status = TCStartThread (CompletionThreadProc, queue, &queue->CompletionThread); ! 586: if (!NT_SUCCESS (status)) ! 587: { ! 588: queue->ThreadExitRequested = TRUE; ! 589: TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent); ! 590: TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent); ! 591: goto err; ! 592: } ! 593: ! 594: queue->StopPending = FALSE; ! 595: Dump ("Queue started\n"); ! 596: return STATUS_SUCCESS; ! 597: ! 598: noMemory: ! 599: status = STATUS_INSUFFICIENT_RESOURCES; ! 600: ! 601: err: ! 602: if (queue->FragmentBufferA) ! 603: TCfree (queue->FragmentBufferA); ! 604: if (queue->FragmentBufferB) ! 605: TCfree (queue->FragmentBufferB); ! 606: ! 607: return status; ! 608: } ! 609: ! 610: ! 611: NTSTATUS EncryptedIoQueueStop (EncryptedIoQueue *queue) ! 612: { ! 613: ASSERT (!queue->StopPending); ! 614: queue->StopPending = TRUE; ! 615: ! 616: while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0) ! 617: { ! 618: KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, NULL); ! 619: } ! 620: ! 621: Dump ("Queue stopping out=%d\n", queue->OutstandingIoCount); ! 622: ! 623: queue->ThreadExitRequested = TRUE; ! 624: ! 625: TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent); ! 626: TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent); ! 627: TCStopThread (queue->CompletionThread, &queue->CompletionThreadQueueNotEmptyEvent); ! 628: ! 629: TCfree (queue->FragmentBufferA); ! 630: TCfree (queue->FragmentBufferB); ! 631: ! 632: Dump ("Queue stopped out=%d\n", queue->OutstandingIoCount); ! 633: return STATUS_SUCCESS; ! 634: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.