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