Annotation of truecrypt/driver/encryptedioqueue.c, revision 1.1.1.9

1.1       root        1: /*
1.1.1.8   root        2:  Copyright (c) 2008-2009 TrueCrypt Foundation. All rights reserved.
1.1       root        3: 
1.1.1.9 ! root        4:  Governed by the TrueCrypt License 2.7 the full text of which is contained
1.1       root        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"
1.1.1.6   root       12: #include "DriveFilter.h"
1.1       root       13: #include "EncryptedIoQueue.h"
1.1.1.5   root       14: #include "EncryptionThreadPool.h"
                     15: #include "Volumes.h"
1.1       root       16: 
                     17: 
1.1.1.8   root       18: static void AcquireBufferPoolMutex (EncryptedIoQueue *queue)
                     19: {
                     20:        NTSTATUS status;
                     21: 
                     22:        status = KeWaitForMutexObject (&queue->BufferPoolMutex, Executive, KernelMode, FALSE, NULL);
                     23:        if (!NT_SUCCESS (status))
                     24:                TC_BUG_CHECK (status);
                     25: }
                     26: 
                     27: 
                     28: static void ReleaseBufferPoolMutex (EncryptedIoQueue *queue)
                     29: {
                     30:        KeReleaseMutex (&queue->BufferPoolMutex, FALSE);
                     31: }
                     32: 
                     33: 
                     34: static void *GetPoolBuffer (EncryptedIoQueue *queue, ULONG requestedSize)
                     35: {
                     36:        EncryptedIoQueueBuffer *buffer;
                     37:        void *bufferAddress = NULL;
                     38:        BOOL requestedSizePresentInPool = FALSE;
                     39: 
                     40:        while (TRUE)
                     41:        {
                     42:                AcquireBufferPoolMutex (queue);
                     43: 
                     44:                for (buffer = queue->FirstPoolBuffer; ; buffer = buffer->NextBuffer)
                     45:                {
                     46:                        if (buffer && buffer->Size == requestedSize)
                     47:                        {
                     48:                                requestedSizePresentInPool = TRUE;
                     49: 
                     50:                                if (!buffer->InUse)
                     51:                                {
                     52:                                        // Reuse a free buffer
                     53:                                        buffer->InUse = TRUE;
                     54:                                        bufferAddress = buffer->Address;
                     55:                                        break;
                     56:                                }
                     57:                        }
                     58: 
                     59:                        if (!buffer || !buffer->NextBuffer)
                     60:                        {
1.1.1.9 ! root       61:                                EncryptedIoQueueBuffer *newBuffer;
        !            62: 
        !            63:                                if (requestedSizePresentInPool && !queue->StartPending)
        !            64:                                        break;
        !            65: 
1.1.1.8   root       66:                                // Allocate a new buffer
1.1.1.9 ! root       67:                                newBuffer = TCalloc (sizeof (EncryptedIoQueueBuffer));
1.1.1.8   root       68:                                if (!newBuffer)
                     69:                                {
                     70:                                        bufferAddress = NULL;
                     71:                                        break;
                     72:                                }
                     73: 
                     74:                                bufferAddress = TCalloc (requestedSize);
                     75:                                if (bufferAddress)
                     76:                                {
                     77:                                        newBuffer->NextBuffer = NULL;
                     78:                                        newBuffer->Address = bufferAddress;
                     79:                                        newBuffer->Size = requestedSize;
                     80:                                        newBuffer->InUse = TRUE;
                     81: 
                     82:                                        if (!buffer)
                     83:                                                queue->FirstPoolBuffer = newBuffer;
                     84:                                        else
                     85:                                                buffer->NextBuffer = newBuffer;
                     86:                                }
                     87:                                else
                     88:                                        TCfree (newBuffer);
                     89: 
                     90:                                break;
                     91:                        }
                     92:                }
                     93: 
                     94:                ReleaseBufferPoolMutex (queue);
                     95: 
                     96:                if (bufferAddress || !requestedSizePresentInPool || queue->StartPending)
                     97:                        break;
                     98: 
1.1.1.9 ! root       99:                KeWaitForSingleObject (&queue->PoolBufferFreeEvent, Executive, KernelMode, FALSE, NULL);
1.1.1.8   root      100:        }
                    101: 
                    102:        return bufferAddress;
                    103: }
                    104: 
                    105: 
                    106: static void ReleasePoolBuffer (EncryptedIoQueue *queue, void *address)
                    107: {
                    108:        EncryptedIoQueueBuffer *buffer;
                    109:        AcquireBufferPoolMutex (queue);
                    110:        
                    111:        for (buffer = queue->FirstPoolBuffer; buffer != NULL; buffer = buffer->NextBuffer)
                    112:        {
                    113:                if (buffer->Address == address)
                    114:                {
                    115:                        ASSERT (buffer->InUse);
                    116: 
                    117:                        buffer->InUse = FALSE;
                    118:                        break;
                    119:                }
                    120:        }
                    121: 
                    122:        ReleaseBufferPoolMutex (queue);
1.1.1.9 ! root      123:        KeSetEvent (&queue->PoolBufferFreeEvent, IO_DISK_INCREMENT, FALSE);
1.1.1.8   root      124: }
                    125: 
                    126: 
                    127: static void FreePoolBuffers (EncryptedIoQueue *queue)
                    128: {
                    129:        EncryptedIoQueueBuffer *buffer;
                    130:        AcquireBufferPoolMutex (queue);
                    131: 
                    132:        for (buffer = queue->FirstPoolBuffer; buffer != NULL; )
                    133:        {
                    134:                EncryptedIoQueueBuffer *nextBuffer = buffer->NextBuffer;
                    135: 
                    136:                ASSERT (!buffer->InUse);
                    137: 
                    138:                TCfree (buffer->Address);
                    139:                TCfree (buffer);
                    140: 
                    141:                buffer = nextBuffer;
                    142:        }
                    143: 
                    144:        queue->FirstPoolBuffer = NULL;
                    145:        ReleaseBufferPoolMutex (queue);
                    146: }
                    147: 
                    148: 
1.1       root      149: static void DecrementOutstandingIoCount (EncryptedIoQueue *queue)
                    150: {
                    151:        if (InterlockedDecrement (&queue->OutstandingIoCount) == 0 && (queue->SuspendPending || queue->StopPending))
1.1.1.3   root      152:                KeSetEvent (&queue->NoOutstandingIoEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      153: }
                    154: 
                    155: 
1.1.1.5   root      156: static void OnItemCompleted (EncryptedIoQueueItem *item, BOOL freeItem)
1.1       root      157: {
                    158:        DecrementOutstandingIoCount (item->Queue);
                    159:        
                    160:        if (item->Queue->IsFilterDevice)
                    161:                IoReleaseRemoveLock (&item->Queue->RemoveLock, item->OriginalIrp);
                    162: 
                    163:        if (NT_SUCCESS (item->Status))
                    164:        {
                    165:                if (item->Write)
                    166:                        item->Queue->TotalBytesWritten += item->OriginalLength;
                    167:                else
                    168:                        item->Queue->TotalBytesRead += item->OriginalLength;
                    169:        }
                    170: 
1.1.1.5   root      171:        if (freeItem)
1.1.1.8   root      172:                ReleasePoolBuffer (item->Queue, item);
1.1       root      173: }
                    174: 
                    175: 
                    176: static NTSTATUS CompleteOriginalIrp (EncryptedIoQueueItem *item, NTSTATUS status, ULONG_PTR information)
                    177: {
1.1.1.8   root      178: #ifdef TC_TRACE_IO_QUEUE
                    179:        Dump ("< %I64d [%I64d] %c status=%x info=%I64d\n", item->OriginalIrpOffset, GetElapsedTime (&item->Queue->LastPerformanceCounter), item->Write ? 'W' : 'R', status, (int64) information);
                    180: #endif
                    181: 
1.1       root      182:        TCCompleteDiskIrp (item->OriginalIrp, status, information);
1.1.1.5   root      183: 
                    184:        item->Status = status;
                    185:        OnItemCompleted (item, TRUE);
                    186: 
1.1       root      187:        return status;
                    188: }
                    189: 
                    190: 
                    191: static void AcquireFragmentBuffer (EncryptedIoQueue *queue, byte *buffer)
                    192: {
                    193:        NTSTATUS status = STATUS_INVALID_PARAMETER;
                    194: 
                    195:        if (buffer == queue->FragmentBufferA)
                    196:        {
                    197:                status = KeWaitForSingleObject (&queue->FragmentBufferAFreeEvent, Executive, KernelMode, FALSE, NULL);
                    198:        }
                    199:        else if (buffer == queue->FragmentBufferB)
                    200:        {
                    201:                status = KeWaitForSingleObject (&queue->FragmentBufferBFreeEvent, Executive, KernelMode, FALSE, NULL);
                    202:        }
                    203: 
                    204:        if (!NT_SUCCESS (status))
                    205:                TC_BUG_CHECK (status);
                    206: }
                    207: 
                    208: 
                    209: static void ReleaseFragmentBuffer (EncryptedIoQueue *queue, byte *buffer)
                    210: {
                    211:        if (buffer == queue->FragmentBufferA)
                    212:        {
1.1.1.3   root      213:                KeSetEvent (&queue->FragmentBufferAFreeEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      214:        }
                    215:        else if (buffer == queue->FragmentBufferB)
                    216:        {
1.1.1.3   root      217:                KeSetEvent (&queue->FragmentBufferBFreeEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      218:        }
                    219:        else
                    220:        {
                    221:                TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
                    222:        }
                    223: }
                    224: 
                    225: 
                    226: static VOID CompletionThreadProc (PVOID threadArg)
                    227: {
                    228:        EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
                    229:        PLIST_ENTRY listEntry;
                    230:        EncryptedIoRequest *request;
                    231:        UINT64_STRUCT dataUnit;
                    232: 
1.1.1.5   root      233:        if (IsEncryptionThreadPoolRunning())
                    234:                KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
                    235: 
1.1       root      236:        while (!queue->ThreadExitRequested)
                    237:        {
                    238:                if (!NT_SUCCESS (KeWaitForSingleObject (&queue->CompletionThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
                    239:                        continue;
                    240: 
                    241:                if (queue->ThreadExitRequested)
                    242:                        break;
                    243: 
                    244:                while ((listEntry = ExInterlockedRemoveHeadList (&queue->CompletionThreadQueue, &queue->CompletionThreadQueueLock)))
                    245:                {
                    246:                        request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, CompletionListEntry);
                    247: 
1.1.1.3   root      248:                        if (request->EncryptedLength > 0 && NT_SUCCESS (request->Item->Status))
1.1       root      249:                        {
                    250:                                ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length);
                    251:                                dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE;
1.1.1.3   root      252: 
                    253:                                if (queue->CryptoInfo->bPartitionInInactiveSysEncScope)
                    254:                                        dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value;
1.1.1.5   root      255:                                else if (queue->RemapEncryptedArea)
                    256:                                        dataUnit.Value += queue->RemappedAreaDataUnitOffset;
1.1.1.3   root      257: 
1.1       root      258:                                DecryptDataUnits (request->Data + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
                    259:                        }
                    260: 
                    261:                        if (request->CompleteOriginalIrp)
                    262:                        {
                    263:                                CompleteOriginalIrp (request->Item, request->Item->Status,
                    264:                                        NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0);
                    265:                        }
1.1.1.3   root      266:                        else
                    267:                        {
                    268:                                InterlockedDecrement (&request->Item->OutstandingRequestCount);
                    269:                                KeSetEvent (&queue->RequestCompletedEvent, IO_DISK_INCREMENT, FALSE);
                    270:                        }
1.1       root      271: 
1.1.1.8   root      272:                        ReleasePoolBuffer (queue, request);
1.1       root      273:                }
                    274:        }
                    275: 
                    276:        PsTerminateSystemThread (STATUS_SUCCESS);
                    277: }
                    278: 
                    279: 
1.1.1.8   root      280: static NTSTATUS TCCachedRead (EncryptedIoQueue *queue, IO_STATUS_BLOCK *ioStatus, PVOID buffer, LARGE_INTEGER offset, ULONG length)
                    281: {
                    282:        queue->LastReadOffset = offset;
                    283:        queue->LastReadLength = length;
                    284: 
                    285:        if (queue->ReadAheadBufferValid && queue->ReadAheadOffset.QuadPart == offset.QuadPart && queue->ReadAheadLength >= length)
                    286:        {
                    287:                memcpy (buffer, queue->ReadAheadBuffer, length);
                    288: 
                    289:                if (!queue->IsFilterDevice)
                    290:                {
                    291:                        ioStatus->Information = length;
                    292:                        ioStatus->Status = STATUS_SUCCESS;
                    293:                }
                    294: 
                    295:                return STATUS_SUCCESS;
                    296:        }
                    297: 
                    298:        if (queue->IsFilterDevice)
                    299:                return TCReadDevice (queue->LowerDeviceObject, buffer, offset, length);
                    300: 
                    301:        return ZwReadFile (queue->HostFileHandle, NULL, NULL, NULL, ioStatus, buffer, length, &offset, NULL);
                    302: }
                    303: 
                    304: 
1.1       root      305: static VOID IoThreadProc (PVOID threadArg)
                    306: {
                    307:        EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
                    308:        PLIST_ENTRY listEntry;
                    309:        EncryptedIoRequest *request;
                    310: 
1.1.1.4   root      311:        KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
                    312: 
1.1.1.6   root      313:        if (!queue->IsFilterDevice && queue->SecurityClientContext)
                    314:        {
                    315: #ifdef DEBUG
                    316:                NTSTATUS status =
                    317: #endif
                    318:                SeImpersonateClientEx (queue->SecurityClientContext, NULL);
                    319:                ASSERT (NT_SUCCESS (status));
                    320:        }
                    321: 
1.1       root      322:        while (!queue->ThreadExitRequested)
                    323:        {
                    324:                if (!NT_SUCCESS (KeWaitForSingleObject (&queue->IoThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
                    325:                        continue;
                    326: 
                    327:                if (queue->ThreadExitRequested)
                    328:                        break;
                    329: 
                    330:                while ((listEntry = ExInterlockedRemoveHeadList (&queue->IoThreadQueue, &queue->IoThreadQueueLock)))
                    331:                {
1.1.1.8   root      332:                        InterlockedDecrement (&queue->IoThreadPendingRequestCount);
1.1       root      333:                        request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, ListEntry);
1.1.1.3   root      334:                        
1.1.1.8   root      335: #ifdef TC_TRACE_IO_QUEUE
                    336:                        Dump ("%c   %I64d [%I64d] roff=%I64d rlen=%d\n", request->Item->Write ? 'W' : 'R', request->Item->OriginalIrpOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), request->Offset.QuadPart, request->Length);
                    337: #endif
                    338: 
1.1.1.3   root      339:                        // Perform IO request if no preceding request of the item failed
                    340:                        if (NT_SUCCESS (request->Item->Status))
1.1       root      341:                        {
1.1.1.3   root      342:                                if (queue->IsFilterDevice)
                    343:                                {
1.1.1.5   root      344:                                        if (queue->RemapEncryptedArea && request->EncryptedLength > 0)
                    345:                                        {
                    346:                                                if (request->EncryptedLength != request->Length)
                    347:                                                {
                    348:                                                        // Up to three subfragments may be required to handle a partially remapped fragment
                    349:                                                        int subFragment;
                    350:                                                        byte *subFragmentData = request->Data;
                    351: 
                    352:                                                        for (subFragment = 0 ; subFragment < 3; ++subFragment)
                    353:                                                        {
                    354:                                                                LARGE_INTEGER subFragmentOffset;
                    355:                                                                ULONG subFragmentLength;
                    356:                                                                subFragmentOffset.QuadPart = request->Offset.QuadPart;
                    357: 
                    358:                                                                switch (subFragment)
                    359:                                                                {
                    360:                                                                case 0:
                    361:                                                                        subFragmentLength = (ULONG) request->EncryptedOffset;
                    362:                                                                        break;
                    363: 
                    364:                                                                case 1:
                    365:                                                                        subFragmentOffset.QuadPart += request->EncryptedOffset + queue->RemappedAreaOffset;
                    366:                                                                        subFragmentLength = request->EncryptedLength;
                    367:                                                                        break;
                    368: 
                    369:                                                                case 2:
                    370:                                                                        subFragmentOffset.QuadPart += request->EncryptedOffset + request->EncryptedLength;
                    371:                                                                        subFragmentLength = (ULONG) (request->Length - (request->EncryptedOffset + request->EncryptedLength));
                    372:                                                                        break;
                    373:                                                                }
                    374: 
                    375:                                                                if (subFragmentLength > 0)
                    376:                                                                {
                    377:                                                                        if (request->Item->Write)
                    378:                                                                                request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, subFragmentData, subFragmentOffset, subFragmentLength);
                    379:                                                                        else
1.1.1.8   root      380:                                                                                request->Item->Status = TCCachedRead (queue, NULL, subFragmentData, subFragmentOffset, subFragmentLength);
1.1.1.5   root      381: 
                    382:                                                                        subFragmentData += subFragmentLength;
                    383:                                                                }
                    384:                                                        }
                    385:                                                }
                    386:                                                else
                    387:                                                {
                    388:                                                        // Remap the fragment
                    389:                                                        LARGE_INTEGER remappedOffset;
                    390:                                                        remappedOffset.QuadPart = request->Offset.QuadPart + queue->RemappedAreaOffset;
                    391: 
                    392:                                                        if (request->Item->Write)
                    393:                                                                request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, request->Data, remappedOffset, request->Length);
                    394:                                                        else
1.1.1.8   root      395:                                                                request->Item->Status = TCCachedRead (queue, NULL, request->Data, remappedOffset, request->Length);
1.1.1.5   root      396:                                                }
                    397:                                        }
1.1.1.3   root      398:                                        else
1.1.1.5   root      399:                                        {
                    400:                                                if (request->Item->Write)
                    401:                                                        request->Item->Status = TCWriteDevice (queue->LowerDeviceObject, request->Data, request->Offset, request->Length);
                    402:                                                else
1.1.1.8   root      403:                                                        request->Item->Status = TCCachedRead (queue, NULL, request->Data, request->Offset, request->Length);
1.1.1.5   root      404:                                        }
1.1.1.3   root      405:                                }
1.1       root      406:                                else
1.1.1.3   root      407:                                {
                    408:                                        IO_STATUS_BLOCK ioStatus;
1.1       root      409: 
1.1.1.3   root      410:                                        if (request->Item->Write)
                    411:                                                request->Item->Status = ZwWriteFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, request->Data, request->Length, &request->Offset, NULL);
                    412:                                        else
1.1.1.8   root      413:                                                request->Item->Status = TCCachedRead (queue, &ioStatus, request->Data, request->Offset, request->Length);
1.1.1.5   root      414: 
                    415:                                        if (NT_SUCCESS (request->Item->Status) && ioStatus.Information != request->Length)
                    416:                                                request->Item->Status = STATUS_END_OF_FILE;
1.1.1.3   root      417:                                }
1.1       root      418:                        }
                    419: 
1.1.1.3   root      420:                        if (request->Item->Write)
1.1       root      421:                        {
1.1.1.8   root      422:                                queue->ReadAheadBufferValid = FALSE;
                    423: 
1.1       root      424:                                ReleaseFragmentBuffer (queue, request->Data);
                    425: 
                    426:                                if (request->CompleteOriginalIrp)
                    427:                                {
                    428:                                        CompleteOriginalIrp (request->Item, request->Item->Status,
                    429:                                                NT_SUCCESS (request->Item->Status) ? request->Item->OriginalLength : 0);
                    430:                                }
                    431:                                else
                    432:                                {
1.1.1.3   root      433:                                        InterlockedDecrement (&request->Item->OutstandingRequestCount);
                    434:                                        KeSetEvent (&queue->RequestCompletedEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      435:                                }
                    436: 
1.1.1.8   root      437:                                ReleasePoolBuffer (queue, request);
1.1       root      438:                        }
1.1.1.3   root      439:                        else
                    440:                        {
1.1.1.8   root      441:                                BOOL readAhead = FALSE;
                    442: 
1.1.1.3   root      443:                                if (NT_SUCCESS (request->Item->Status))
                    444:                                        memcpy (request->OrigDataBufferFragment, request->Data, request->Length);
                    445: 
                    446:                                ReleaseFragmentBuffer (queue, request->Data);
                    447:                                request->Data = request->OrigDataBufferFragment;
                    448: 
1.1.1.8   root      449:                                if (request->CompleteOriginalIrp
                    450:                                        && queue->LastReadLength > 0
                    451:                                        && NT_SUCCESS (request->Item->Status)
                    452:                                        && InterlockedExchangeAdd (&queue->IoThreadPendingRequestCount, 0) == 0)
                    453:                                {
                    454:                                        readAhead = TRUE;
                    455:                                        InterlockedIncrement (&queue->OutstandingIoCount);
                    456:                                }
                    457: 
1.1.1.3   root      458:                                ExInterlockedInsertTailList (&queue->CompletionThreadQueue, &request->CompletionListEntry, &queue->CompletionThreadQueueLock);
                    459:                                KeSetEvent (&queue->CompletionThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
1.1.1.8   root      460: 
                    461:                                if (readAhead)
                    462:                                {
                    463:                                        queue->ReadAheadBufferValid = FALSE;
                    464:                                        queue->ReadAheadOffset.QuadPart = queue->LastReadOffset.QuadPart + queue->LastReadLength;
                    465:                                        queue->ReadAheadLength = queue->LastReadLength;
                    466: 
                    467: #ifdef TC_TRACE_IO_QUEUE
                    468:                                        Dump ("A   %I64d [%I64d] roff=%I64d rlen=%d\n", request->Item->OriginalIrpOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), queue->ReadAheadOffset, queue->ReadAheadLength);
                    469: #endif
                    470: 
                    471:                                        if (queue->ReadAheadOffset.QuadPart + queue->ReadAheadLength <= queue->MaxReadAheadOffset.QuadPart)
                    472:                                        {
                    473:                                                if (queue->IsFilterDevice)
                    474:                                                {
                    475:                                                        queue->ReadAheadBufferValid = NT_SUCCESS (TCReadDevice (queue->LowerDeviceObject, queue->ReadAheadBuffer, queue->ReadAheadOffset, queue->ReadAheadLength));
                    476:                                                }
                    477:                                                else
                    478:                                                {
                    479:                                                        IO_STATUS_BLOCK ioStatus;
                    480:                                                        queue->ReadAheadBufferValid = NT_SUCCESS (ZwReadFile (queue->HostFileHandle, NULL, NULL, NULL, &ioStatus, queue->ReadAheadBuffer, queue->ReadAheadLength, &queue->ReadAheadOffset, NULL));
                    481:                                                        queue->ReadAheadLength = (ULONG) ioStatus.Information;
                    482:                                                }
                    483:                                        }
                    484: 
                    485:                                        DecrementOutstandingIoCount (queue);
                    486:                                }
1.1.1.3   root      487:                        }
1.1       root      488:                }
                    489:        }
                    490: 
                    491:        PsTerminateSystemThread (STATUS_SUCCESS);
                    492: }
                    493: 
                    494: 
                    495: static VOID MainThreadProc (PVOID threadArg)
                    496: {
                    497:        EncryptedIoQueue *queue = (EncryptedIoQueue *) threadArg;
                    498:        PLIST_ENTRY listEntry;
                    499:        EncryptedIoQueueItem *item;
                    500: 
                    501:        LARGE_INTEGER fragmentOffset;
                    502:        ULONG dataRemaining;
                    503:        PUCHAR activeFragmentBuffer = queue->FragmentBufferA;
                    504:        PUCHAR dataBuffer;
                    505:        EncryptedIoRequest *request;
                    506:        uint64 intersectStart;
                    507:        uint32 intersectLength;
                    508: 
1.1.1.8   root      509:        int64 mdlWaitTime;
                    510:        LARGE_INTEGER mdlWaitPerfCounter;
1.1.1.5   root      511: 
                    512:        if (IsEncryptionThreadPoolRunning())
                    513:                KeSetPriorityThread (KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
                    514: 
1.1       root      515:        while (!queue->ThreadExitRequested)
                    516:        {
                    517:                if (!NT_SUCCESS (KeWaitForSingleObject (&queue->MainThreadQueueNotEmptyEvent, Executive, KernelMode, FALSE, NULL)))
                    518:                        continue;
                    519: 
                    520:                while ((listEntry = ExInterlockedRemoveHeadList (&queue->MainThreadQueue, &queue->MainThreadQueueLock)))
                    521:                {
1.1.1.5   root      522:                        PIRP irp = CONTAINING_RECORD (listEntry, IRP, Tail.Overlay.ListEntry);
                    523:                        PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
                    524:                        
1.1       root      525:                        if (queue->Suspended)
                    526:                                KeWaitForSingleObject (&queue->QueueResumedEvent, Executive, KernelMode, FALSE, NULL);
1.1.1.5   root      527: 
1.1.1.8   root      528:                        item = GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem));
1.1.1.5   root      529:                        if (!item)
                    530:                        {
                    531:                                EncryptedIoQueueItem stackItem;
                    532:                                stackItem.Queue = queue;
                    533:                                stackItem.OriginalIrp = irp;
                    534:                                stackItem.Status = STATUS_INSUFFICIENT_RESOURCES;
                    535: 
                    536:                                TCCompleteDiskIrp (irp, STATUS_INSUFFICIENT_RESOURCES, 0);
                    537:                                OnItemCompleted (&stackItem, FALSE);
                    538:                                continue;
1.1       root      539:                        }
1.1.1.5   root      540: 
                    541:                        item->Queue = queue;
                    542:                        item->OriginalIrp = irp;
                    543:                        item->OutstandingRequestCount = 0;
                    544:                        item->Status = STATUS_SUCCESS;
                    545: 
                    546:                        IoSetCancelRoutine (irp, NULL);
                    547:                        if (irp->Cancel)
1.1       root      548:                        {
                    549:                                CompleteOriginalIrp (item, STATUS_CANCELLED, 0);
                    550:                                continue;
                    551:                        }
                    552: 
1.1.1.5   root      553:                        switch (irpSp->MajorFunction)
                    554:                        {
                    555:                        case IRP_MJ_READ:
                    556:                                item->Write = FALSE;
                    557:                                item->OriginalOffset = irpSp->Parameters.Read.ByteOffset;
                    558:                                item->OriginalLength = irpSp->Parameters.Read.Length;
                    559:                                break;
                    560: 
                    561:                        case IRP_MJ_WRITE:
                    562:                                item->Write = TRUE;
                    563:                                item->OriginalOffset = irpSp->Parameters.Write.ByteOffset;
                    564:                                item->OriginalLength = irpSp->Parameters.Write.Length;
                    565:                                break;
                    566: 
                    567:                        default:
                    568:                                CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
                    569:                                continue;
                    570:                        }
                    571: 
1.1.1.8   root      572: #ifdef TC_TRACE_IO_QUEUE
                    573:                        item->OriginalIrpOffset = item->OriginalOffset;
                    574: #endif
1.1       root      575: 
1.1.1.8   root      576:                        // Handle misaligned read operations to work around a bug in Windows System Assessment Tool which does not follow FILE_FLAG_NO_BUFFERING requirements when benchmarking disk devices
1.1.1.7   root      577:                        if (queue->IsFilterDevice
                    578:                                && !item->Write
                    579:                                && item->OriginalLength > 0
                    580:                                && (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) == 0
                    581:                                && (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0)
                    582:                        {
                    583:                                byte *buffer;
                    584:                                ULONG alignedLength = item->OriginalLength + ENCRYPTION_DATA_UNIT_SIZE;
                    585:                                LARGE_INTEGER alignedOffset;
                    586:                                alignedOffset.QuadPart = item->OriginalOffset.QuadPart & ~((LONGLONG) ENCRYPTION_DATA_UNIT_SIZE - 1);
                    587: 
                    588:                                buffer = TCalloc (alignedLength);
                    589:                                if (!buffer)
                    590:                                {
                    591:                                        CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
                    592:                                        continue;
                    593:                                }
                    594: 
                    595:                                item->Status = TCReadDevice (queue->LowerDeviceObject, buffer, alignedOffset, alignedLength);
                    596: 
                    597:                                if (NT_SUCCESS (item->Status))
                    598:                                {
                    599:                                        UINT64_STRUCT dataUnit;
                    600: 
                    601:                                        dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority);
                    602:                                        if (!dataBuffer)
                    603:                                        {
                    604:                                                TCfree (buffer);
                    605:                                                CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
                    606:                                                continue;
                    607:                                        }
                    608: 
1.1.1.8   root      609:                                        if (queue->EncryptedAreaStart != -1 && queue->EncryptedAreaEnd != -1)
1.1.1.7   root      610:                                        {
1.1.1.8   root      611:                                                GetIntersection (alignedOffset.QuadPart, alignedLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength);
                    612:                                                if (intersectLength > 0)
                    613:                                                {
                    614:                                                        dataUnit.Value = intersectStart / ENCRYPTION_DATA_UNIT_SIZE;
                    615:                                                        DecryptDataUnits (buffer + (intersectStart - alignedOffset.QuadPart), &dataUnit, intersectLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
                    616:                                                }
1.1.1.7   root      617:                                        }
                    618: 
                    619:                                        memcpy (dataBuffer, buffer + (item->OriginalOffset.LowPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)), item->OriginalLength);
                    620:                                }
                    621: 
                    622:                                TCfree (buffer);
                    623:                                CompleteOriginalIrp (item, item->Status, NT_SUCCESS (item->Status) ? item->OriginalLength : 0);
                    624:                                continue;
                    625:                        }
                    626: 
1.1       root      627:                        // Validate offset and length
1.1.1.3   root      628:                        if (item->OriginalLength == 0
                    629:                                || (item->OriginalLength & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
                    630:                                || (item->OriginalOffset.QuadPart & (ENCRYPTION_DATA_UNIT_SIZE - 1)) != 0
1.1       root      631:                                || (!queue->IsFilterDevice && item->OriginalOffset.QuadPart + item->OriginalLength > queue->VirtualDeviceLength))
                    632:                        {
                    633:                                CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
                    634:                                continue;
                    635:                        }
                    636: 
1.1.1.8   root      637: #ifdef TC_TRACE_IO_QUEUE
                    638:                        Dump ("Q  %I64d [%I64d] %c len=%d\n", item->OriginalOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), item->Write ? 'W' : 'R', item->OriginalLength);
                    639: #endif
1.1.1.5   root      640: 
1.1       root      641:                        if (!queue->IsFilterDevice)
                    642:                        {
1.1.1.3   root      643:                                // Adjust the offset for host file or device
                    644:                                if (queue->CryptoInfo->hiddenVolume)
                    645:                                        item->OriginalOffset.QuadPart += queue->CryptoInfo->hiddenVolumeOffset;
                    646:                                else
                    647:                                        item->OriginalOffset.QuadPart += queue->CryptoInfo->volDataAreaOffset; 
                    648: 
1.1       root      649:                                // Hidden volume protection
                    650:                                if (item->Write && queue->CryptoInfo->bProtectHiddenVolume)
                    651:                                {
                    652:                                        // If there has already been a write operation denied in order to protect the
                    653:                                        // hidden volume (since the volume mount time)
                    654:                                        if (queue->CryptoInfo->bHiddenVolProtectionAction)      
                    655:                                        {
                    656:                                                // Do not allow writing to this volume anymore. This is to fake a complete volume
                    657:                                                // or system failure (otherwise certain kinds of inconsistency within the file
                    658:                                                // system could indicate that this volume has used hidden volume protection).
                    659:                                                CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
                    660:                                                continue;
                    661:                                        }
                    662: 
                    663:                                        // Verify that no byte is going to be written to the hidden volume area
1.1.1.3   root      664:                                        if (RegionsOverlap ((unsigned __int64) item->OriginalOffset.QuadPart,
                    665:                                                (unsigned __int64) item->OriginalOffset.QuadPart + item->OriginalLength - 1,
1.1       root      666:                                                queue->CryptoInfo->hiddenVolumeOffset,
1.1.1.5   root      667:                                                (unsigned __int64) queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1))
1.1       root      668:                                        {
1.1.1.5   root      669:                                                Dump ("Hidden volume protection triggered: write %I64d-%I64d (protected %I64d-%I64d)\n", item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, queue->CryptoInfo->hiddenVolumeOffset, queue->CryptoInfo->hiddenVolumeOffset + queue->CryptoInfo->hiddenVolumeProtectedSize - 1);
1.1       root      670:                                                queue->CryptoInfo->bHiddenVolProtectionAction = TRUE;
                    671: 
                    672:                                                // Deny this write operation to prevent the hidden volume from being overwritten
                    673:                                                CompleteOriginalIrp (item, STATUS_INVALID_PARAMETER, 0);
                    674:                                                continue;
                    675:                                        }
                    676:                                }
                    677:                        }
1.1.1.6   root      678:                        else if (item->Write && IsHiddenSystemRunning()
                    679:                                && (RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, SECTOR_SIZE, TC_BOOT_LOADER_AREA_SECTOR_COUNT * SECTOR_SIZE - 1)
                    680:                                 || RegionsOverlap (item->OriginalOffset.QuadPart, item->OriginalOffset.QuadPart + item->OriginalLength - 1, GetBootDriveLength(), _I64_MAX)))
                    681:                        {
                    682:                                Dump ("Preventing write to boot loader or host protected area\n");
                    683:                                CompleteOriginalIrp (item, STATUS_MEDIA_WRITE_PROTECTED, 0);
                    684:                                continue;
                    685:                        }
1.1       root      686: 
                    687:                        // Original IRP data buffer
1.1.1.5   root      688:                        mdlWaitTime = 0;
1.1.1.8   root      689:                        mdlWaitPerfCounter.QuadPart = 0;
1.1.1.5   root      690:                        while (TRUE)
                    691:                        {
                    692:                                dataBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe (irp->MdlAddress, HighPagePriority);
                    693: 
                    694:                                if (dataBuffer || mdlWaitTime >= TC_ENC_IO_QUEUE_MEM_ALLOC_TIMEOUT)
                    695:                                        break;
                    696: 
1.1.1.8   root      697:                                if (mdlWaitPerfCounter.QuadPart == 0)
                    698:                                        GetElapsedTimeInit (&mdlWaitPerfCounter);
                    699: 
                    700:                                TCSleep (TC_ENC_IO_QUEUE_MEM_ALLOC_RETRY_DELAY);
                    701:                                mdlWaitTime += GetElapsedTime (&mdlWaitPerfCounter) / 1000;
1.1.1.5   root      702:                        }
                    703: 
1.1       root      704:                        if (dataBuffer == NULL)
                    705:                        {
                    706:                                CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
                    707:                                continue;
                    708:                        }
                    709: 
                    710:                        // Divide data block to fragments to enable efficient overlapping of encryption and IO operations
                    711: 
                    712:                        dataRemaining = item->OriginalLength;
                    713:                        fragmentOffset = item->OriginalOffset;
                    714: 
                    715:                        while (dataRemaining > 0)
                    716:                        {
                    717:                                BOOL isLastFragment = dataRemaining <= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    718:                                
                    719:                                ULONG dataFragmentLength = isLastFragment ? dataRemaining : TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    720:                                activeFragmentBuffer = (activeFragmentBuffer == queue->FragmentBufferA ? queue->FragmentBufferB : queue->FragmentBufferA);
                    721: 
                    722:                                // Create IO request
1.1.1.8   root      723:                                request = GetPoolBuffer (queue, sizeof (EncryptedIoRequest));
1.1       root      724:                                if (!request)
                    725:                                {
1.1.1.3   root      726:                                        while (InterlockedExchangeAdd (&item->OutstandingRequestCount, 0) > 0)
                    727:                                                KeWaitForSingleObject (&queue->RequestCompletedEvent, Executive, KernelMode, FALSE, NULL);
                    728: 
1.1       root      729:                                        CompleteOriginalIrp (item, STATUS_INSUFFICIENT_RESOURCES, 0);
                    730:                                        break;
                    731:                                }
                    732: 
1.1.1.8   root      733:                                InterlockedIncrement (&queue->IoThreadPendingRequestCount);
                    734: 
1.1       root      735:                                request->Item = item;
                    736:                                request->CompleteOriginalIrp = isLastFragment;
                    737:                                request->Offset = fragmentOffset;
                    738:                                request->Data = activeFragmentBuffer;
                    739:                                request->OrigDataBufferFragment = dataBuffer;
                    740:                                request->Length = dataFragmentLength;
                    741: 
                    742:                                if (queue->IsFilterDevice)
                    743:                                {
1.1.1.8   root      744:                                        if (queue->EncryptedAreaStart == -1 || queue->EncryptedAreaEnd == -1)
                    745:                                        {
                    746:                                                request->EncryptedLength = 0;
                    747:                                        }
                    748:                                        else
                    749:                                        {
                    750:                                                // Get intersection of data fragment with encrypted area
                    751:                                                GetIntersection (fragmentOffset.QuadPart, dataFragmentLength, queue->EncryptedAreaStart, queue->EncryptedAreaEnd, &intersectStart, &intersectLength);
1.1       root      752: 
1.1.1.8   root      753:                                                request->EncryptedOffset = intersectStart - fragmentOffset.QuadPart;
                    754:                                                request->EncryptedLength = intersectLength;
                    755:                                        }
1.1       root      756:                                }
                    757:                                else
                    758:                                {
                    759:                                        request->EncryptedOffset = 0;
                    760:                                        request->EncryptedLength = dataFragmentLength;
                    761:                                }
                    762: 
                    763:                                AcquireFragmentBuffer (queue, activeFragmentBuffer);
                    764: 
                    765:                                if (item->Write)
                    766:                                {
                    767:                                        // Encrypt data
                    768:                                        memcpy (activeFragmentBuffer, dataBuffer, dataFragmentLength);
                    769: 
                    770:                                        if (request->EncryptedLength > 0)
                    771:                                        {
                    772:                                                UINT64_STRUCT dataUnit;
                    773:                                                ASSERT (request->EncryptedOffset + request->EncryptedLength <= request->Offset.QuadPart + request->Length);
                    774: 
                    775:                                                dataUnit.Value = (request->Offset.QuadPart + request->EncryptedOffset) / ENCRYPTION_DATA_UNIT_SIZE;
                    776: 
1.1.1.3   root      777:                                                if (queue->CryptoInfo->bPartitionInInactiveSysEncScope)
                    778:                                                        dataUnit.Value += queue->CryptoInfo->FirstDataUnitNo.Value;
1.1.1.5   root      779:                                                else if (queue->RemapEncryptedArea)
                    780:                                                        dataUnit.Value += queue->RemappedAreaDataUnitOffset;
                    781:                                                                
1.1.1.3   root      782:                                                EncryptDataUnits (activeFragmentBuffer + request->EncryptedOffset, &dataUnit, request->EncryptedLength / ENCRYPTION_DATA_UNIT_SIZE, queue->CryptoInfo);
1.1       root      783:                                        }
                    784:                                }
                    785: 
                    786:                                // Queue IO request
1.1.1.3   root      787:                                InterlockedIncrement (&item->OutstandingRequestCount);
                    788: 
1.1       root      789:                                ExInterlockedInsertTailList (&queue->IoThreadQueue, &request->ListEntry, &queue->IoThreadQueueLock);
1.1.1.3   root      790:                                KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      791: 
                    792:                                if (isLastFragment)
                    793:                                        break;
                    794: 
                    795:                                dataRemaining -= TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    796:                                dataBuffer += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    797:                                fragmentOffset.QuadPart += TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE;
                    798:                        }
                    799:                }
                    800:        }
                    801: 
                    802:        PsTerminateSystemThread (STATUS_SUCCESS);
                    803: }
                    804: 
                    805: 
                    806: NTSTATUS EncryptedIoQueueAddIrp (EncryptedIoQueue *queue, PIRP irp)
                    807: {
                    808:        NTSTATUS status;
                    809: 
                    810:        InterlockedIncrement (&queue->OutstandingIoCount);
                    811:        if (queue->StopPending)
                    812:        {
                    813:                Dump ("STATUS_DEVICE_NOT_READY  out=%d\n", queue->OutstandingIoCount);
                    814:                status = STATUS_DEVICE_NOT_READY;
                    815:                goto err;
                    816:        }
                    817: 
                    818:        if (queue->IsFilterDevice)
                    819:        {
                    820:                status = IoAcquireRemoveLock (&queue->RemoveLock, irp);
                    821:                if (!NT_SUCCESS (status))
                    822:                        goto err;
                    823:        }
                    824: 
1.1.1.8   root      825: #ifdef TC_TRACE_IO_QUEUE
                    826:        {
                    827:                PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
                    828:                Dump ("* %I64d [%I64d] %c len=%d out=%d\n", irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.ByteOffset : irpSp->Parameters.Read.ByteOffset, GetElapsedTime (&queue->LastPerformanceCounter), irpSp->MajorFunction == IRP_MJ_WRITE ? 'W' : 'R', irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.Length : irpSp->Parameters.Read.Length, queue->OutstandingIoCount);
                    829:        }
                    830: #endif
                    831: 
1.1       root      832:        IoMarkIrpPending (irp);
                    833: 
1.1.1.5   root      834:        ExInterlockedInsertTailList (&queue->MainThreadQueue, &irp->Tail.Overlay.ListEntry, &queue->MainThreadQueueLock);
1.1.1.3   root      835:        KeSetEvent (&queue->MainThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      836:        
                    837:        return STATUS_PENDING;
                    838: 
                    839: err:
                    840:        DecrementOutstandingIoCount (queue);
                    841:        return status;
                    842: }
                    843: 
                    844: 
                    845: NTSTATUS EncryptedIoQueueHoldWhenIdle (EncryptedIoQueue *queue, int64 timeout)
                    846: {
                    847:        NTSTATUS status;
                    848:        ASSERT (!queue->Suspended);
                    849: 
                    850:        queue->SuspendPending = TRUE;
                    851:        
                    852:        while (TRUE)
                    853:        {
                    854:                while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
                    855:                {
                    856:                        LARGE_INTEGER waitTimeout;
                    857: 
                    858:                        waitTimeout.QuadPart = timeout * -10000;
                    859:                        status = KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, timeout != 0 ? &waitTimeout : NULL);
                    860: 
                    861:                        if (status == STATUS_TIMEOUT)
                    862:                                status = STATUS_UNSUCCESSFUL;
                    863: 
                    864:                        if (!NT_SUCCESS (status))
1.1.1.8   root      865:                        {
                    866:                                queue->SuspendPending = FALSE;
1.1       root      867:                                return status;
1.1.1.8   root      868:                        }
1.1.1.6   root      869: 
1.1.1.7   root      870:                        TCSleep (1);
1.1.1.6   root      871:                        if (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
1.1.1.8   root      872:                        {
                    873:                                queue->SuspendPending = FALSE;
1.1.1.6   root      874:                                return STATUS_UNSUCCESSFUL;
1.1.1.8   root      875:                        }
1.1       root      876:                }
                    877: 
                    878:                KeClearEvent (&queue->QueueResumedEvent);
                    879:                queue->Suspended = TRUE;
                    880: 
                    881:                if (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) == 0)
                    882:                        break;
                    883: 
                    884:                queue->Suspended = FALSE;
1.1.1.3   root      885:                KeSetEvent (&queue->QueueResumedEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      886:        }
                    887: 
1.1.1.8   root      888:        queue->ReadAheadBufferValid = FALSE;
1.1       root      889: 
1.1.1.8   root      890:        queue->SuspendPending = FALSE;
1.1       root      891:        return STATUS_SUCCESS;
                    892: }
                    893: 
                    894: 
                    895: BOOL EncryptedIoQueueIsSuspended (EncryptedIoQueue *queue)
                    896: {
                    897:        return queue->Suspended;
                    898: }
                    899: 
                    900: 
                    901: BOOL EncryptedIoQueueIsRunning (EncryptedIoQueue *queue)
                    902: {
                    903:        return !queue->StopPending;
                    904: }
                    905: 
                    906: 
                    907: NTSTATUS EncryptedIoQueueResumeFromHold (EncryptedIoQueue *queue)
                    908: {
                    909:        ASSERT (queue->Suspended);
                    910:        
                    911:        queue->Suspended = FALSE;
1.1.1.3   root      912:        KeSetEvent (&queue->QueueResumedEvent, IO_DISK_INCREMENT, FALSE);
1.1       root      913: 
                    914:        return STATUS_SUCCESS;
                    915: }
                    916: 
                    917: 
1.1.1.6   root      918: NTSTATUS EncryptedIoQueueStart (EncryptedIoQueue *queue)
1.1       root      919: {
                    920:        NTSTATUS status;
1.1.1.8   root      921:        EncryptedIoQueueBuffer *buffer;
                    922:        int i;
                    923: 
                    924:        queue->StartPending = TRUE;
1.1       root      925:        queue->ThreadExitRequested = FALSE;
                    926: 
1.1.1.8   root      927:        queue->OutstandingIoCount = 0;
                    928:        queue->IoThreadPendingRequestCount = 0;
                    929: 
                    930:        queue->FirstPoolBuffer = NULL;
                    931:        KeInitializeMutex (&queue->BufferPoolMutex, 0);
                    932: 
1.1       root      933:        KeInitializeEvent (&queue->NoOutstandingIoEvent, SynchronizationEvent, FALSE);
1.1.1.3   root      934:        KeInitializeEvent (&queue->RequestCompletedEvent, SynchronizationEvent, FALSE);
1.1.1.9 ! root      935:        KeInitializeEvent (&queue->PoolBufferFreeEvent, SynchronizationEvent, FALSE);
1.1       root      936:        KeInitializeEvent (&queue->QueueResumedEvent, SynchronizationEvent, FALSE);
                    937: 
                    938:        queue->FragmentBufferA = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
                    939:        if (!queue->FragmentBufferA)
                    940:                goto noMemory;
                    941: 
                    942:        queue->FragmentBufferB = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
                    943:        if (!queue->FragmentBufferB)
                    944:                goto noMemory;
                    945: 
                    946:        KeInitializeEvent (&queue->FragmentBufferAFreeEvent, SynchronizationEvent, TRUE);
                    947:        KeInitializeEvent (&queue->FragmentBufferBFreeEvent, SynchronizationEvent, TRUE);
                    948: 
1.1.1.8   root      949:        queue->ReadAheadBufferValid = FALSE;
                    950:        queue->ReadAheadBuffer = TCalloc (TC_ENC_IO_QUEUE_MAX_FRAGMENT_SIZE);
                    951:        if (!queue->ReadAheadBuffer)
                    952:                goto noMemory;
                    953: 
                    954:        // Preallocate buffers
                    955:        for (i = 0; i < TC_ENC_IO_QUEUE_PREALLOCATED_IO_REQUEST_COUNT; ++i)
                    956:        {
                    957:                if (i < TC_ENC_IO_QUEUE_PREALLOCATED_ITEM_COUNT && !GetPoolBuffer (queue, sizeof (EncryptedIoQueueItem)))
                    958:                        goto noMemory;
                    959: 
                    960:                if (!GetPoolBuffer (queue, sizeof (EncryptedIoRequest)))
                    961:                        goto noMemory;
                    962:        }
                    963: 
                    964:        for (buffer = queue->FirstPoolBuffer; buffer != NULL; buffer = buffer->NextBuffer)
                    965:        {
                    966:                buffer->InUse = FALSE;
                    967:        }
                    968: 
1.1       root      969:        // Main thread
                    970:        InitializeListHead (&queue->MainThreadQueue);
                    971:        KeInitializeSpinLock (&queue->MainThreadQueueLock);
                    972:        KeInitializeEvent (&queue->MainThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
                    973: 
                    974:        status = TCStartThread (MainThreadProc, queue, &queue->MainThread);
                    975:        if (!NT_SUCCESS (status))
                    976:                goto err;
                    977: 
                    978:        // IO thread
                    979:        InitializeListHead (&queue->IoThreadQueue);
                    980:        KeInitializeSpinLock (&queue->IoThreadQueueLock);
                    981:        KeInitializeEvent (&queue->IoThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
                    982: 
1.1.1.6   root      983:        status = TCStartThread (IoThreadProc, queue, &queue->IoThread);
1.1       root      984:        if (!NT_SUCCESS (status))
                    985:        {
                    986:                queue->ThreadExitRequested = TRUE;
                    987:                TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
                    988:                goto err;
                    989:        }
                    990: 
                    991:        // Completion thread
                    992:        InitializeListHead (&queue->CompletionThreadQueue);
                    993:        KeInitializeSpinLock (&queue->CompletionThreadQueueLock);
                    994:        KeInitializeEvent (&queue->CompletionThreadQueueNotEmptyEvent, SynchronizationEvent, FALSE);
                    995: 
                    996:        status = TCStartThread (CompletionThreadProc, queue, &queue->CompletionThread);
                    997:        if (!NT_SUCCESS (status))
                    998:        {
                    999:                queue->ThreadExitRequested = TRUE;
                   1000:                TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
                   1001:                TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent);
                   1002:                goto err;
                   1003:        }
                   1004: 
1.1.1.8   root     1005: #ifdef TC_TRACE_IO_QUEUE
                   1006:        GetElapsedTimeInit (&queue->LastPerformanceCounter);
                   1007: #endif
                   1008: 
1.1       root     1009:        queue->StopPending = FALSE;
1.1.1.8   root     1010:        queue->StartPending = FALSE;
                   1011: 
1.1       root     1012:        Dump ("Queue started\n");
                   1013:        return STATUS_SUCCESS;
                   1014: 
                   1015: noMemory:
                   1016:        status = STATUS_INSUFFICIENT_RESOURCES;
                   1017: 
                   1018: err:
                   1019:        if (queue->FragmentBufferA)
                   1020:                TCfree (queue->FragmentBufferA);
                   1021:        if (queue->FragmentBufferB)
                   1022:                TCfree (queue->FragmentBufferB);
                   1023: 
1.1.1.8   root     1024:        FreePoolBuffers (queue);
                   1025: 
                   1026:        queue->StartPending = FALSE;
1.1       root     1027:        return status;
                   1028: }
                   1029: 
                   1030: 
                   1031: NTSTATUS EncryptedIoQueueStop (EncryptedIoQueue *queue)
                   1032: {
                   1033:        ASSERT (!queue->StopPending);
                   1034:        queue->StopPending = TRUE;
                   1035:        
                   1036:        while (InterlockedExchangeAdd (&queue->OutstandingIoCount, 0) > 0)
                   1037:        {
                   1038:                KeWaitForSingleObject (&queue->NoOutstandingIoEvent, Executive, KernelMode, FALSE, NULL);
                   1039:        }
                   1040: 
                   1041:        Dump ("Queue stopping  out=%d\n", queue->OutstandingIoCount);
                   1042: 
                   1043:        queue->ThreadExitRequested = TRUE;
                   1044: 
                   1045:        TCStopThread (queue->MainThread, &queue->MainThreadQueueNotEmptyEvent);
                   1046:        TCStopThread (queue->IoThread, &queue->IoThreadQueueNotEmptyEvent);
                   1047:        TCStopThread (queue->CompletionThread, &queue->CompletionThreadQueueNotEmptyEvent);
                   1048: 
                   1049:        TCfree (queue->FragmentBufferA);
                   1050:        TCfree (queue->FragmentBufferB);
1.1.1.8   root     1051:        TCfree (queue->ReadAheadBuffer);
                   1052: 
                   1053:        FreePoolBuffers (queue);
1.1       root     1054: 
                   1055:        Dump ("Queue stopped  out=%d\n", queue->OutstandingIoCount);
                   1056:        return STATUS_SUCCESS;
                   1057: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.