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