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

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

unix.superglobalmegacorp.com

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