|
|
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.