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

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

unix.superglobalmegacorp.com

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