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

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

unix.superglobalmegacorp.com

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