Esempio n. 1
0
VOID
IopFileObjectFree(
    IN OUT PIO_FILE_OBJECT* ppFileObject
    )
{
    PIO_FILE_OBJECT pFileObject = *ppFileObject;

    if (pFileObject)
    {
        LWIO_ASSERT(LwListIsEmpty(&pFileObject->IrpList));

        IopIrpFreeZctIrpList(pFileObject);

        IopDeviceLock(pFileObject->pDevice);
        LwListRemove(&pFileObject->DeviceLinks);
        IopDeviceUnlock(pFileObject->pDevice);

        IopDeviceDereference(&pFileObject->pDevice);

        LwRtlCleanupConditionVariable(&pFileObject->Rundown.Condition);
        LwRtlCleanupMutex(&pFileObject->Mutex);

        LwRtlUnicodeStringFree(&pFileObject->FileName);

        IopIrpDereference(&pFileObject->pCloseIrp);

        IoMemoryFree(pFileObject);
        *ppFileObject = NULL;
    }
}
Esempio n. 2
0
NTSTATUS
IopIrpCreate(
    OUT PIRP* ppIrp,
    IN IRP_TYPE Type,
    IN PIO_FILE_OBJECT pFileObject
    )
{
    NTSTATUS status = 0;
    int EE = 0;
    PIRP pIrp = NULL;

    status = IopIrpCreateDetached(&pIrp);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    status = IopIrpAttach(pIrp, Type, pFileObject);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

cleanup:
    if (status)
    {
        IopIrpDereference(&pIrp);
    }

    *ppIrp = pIrp;

    IO_LOG_LEAVE_ON_STATUS_EE(status, EE);
    return status;
}
Esempio n. 3
0
NTSTATUS
IopIrpCreateDetached(
    OUT PIRP* ppIrp
    )
{
    NTSTATUS status = 0;
    int EE = 0;
    PIRP pIrp = NULL;
    PIRP_INTERNAL irpInternal = NULL;

    // Note that we allocate enough space for the internal fields.
    status = IO_ALLOCATE(&pIrp, IRP, sizeof(IRP_INTERNAL));
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    irpInternal = IopIrpGetInternal(pIrp);
    irpInternal->ReferenceCount = 1;

cleanup:
    if (status)
    {
        IopIrpDereference(&pIrp);
    }

    *ppIrp = pIrp;

    IO_LOG_LEAVE_ON_STATUS_EE(status, EE);
    return status;
}
Esempio n. 4
0
BOOLEAN
IopIrpCancel(
    IN PIRP pIrp
    )
{
    PIRP_INTERNAL irpInternal = IopIrpGetInternal(pIrp);
    BOOLEAN isCancellable = FALSE;
    BOOLEAN isAcquired = FALSE;

    if (!pIrp)
    {
        GOTO_CLEANUP();
    }

    IopIrpReference(pIrp);

    IopIrpAcquireCancelLock(pIrp);
    isAcquired = TRUE;

    if (!IsSetFlag(irpInternal->Flags, IRP_FLAG_CANCELLED | IRP_FLAG_COMPLETE))
    {
        if (irpInternal->Cancel.Callback)
        {
            ClearFlag(irpInternal->Flags, IRP_FLAG_CANCEL_PENDING);
            SetFlag(irpInternal->Flags, IRP_FLAG_CANCELLED);
            isCancellable = TRUE;
            irpInternal->Cancel.Callback(
                    pIrp,
                    irpInternal->Cancel.CallbackContext);
        }
        else
        {
            SetFlag(irpInternal->Flags, IRP_FLAG_CANCEL_PENDING);
        }
    }
    else
    {
        // If already cancelled or complete, we consider it as cancellable.
        isCancellable = TRUE;
    }

cleanup:

    if (isAcquired)
    {
        IopIrpReleaseCancelLock(pIrp);
    }

    if (pIrp)
    {
        IopIrpDereference(&pIrp);
    }

    return isCancellable;
}
Esempio n. 5
0
VOID
IopIrpFreeZctIrpList(
    IN OUT PIO_FILE_OBJECT pFileObject
    )
{
    PLW_LIST_LINKS pLinks = NULL;;
    PIRP_INTERNAL irpInternal = NULL;
    PIRP pIrp = NULL;

    while (!LwListIsEmpty(&pFileObject->ZctCompletionIrpList))
    {
        pLinks = LwListRemoveHead(&pFileObject->ZctCompletionIrpList);
        irpInternal = LW_STRUCT_FROM_FIELD(pLinks, IRP_INTERNAL, CancelLinks);
        pIrp = &irpInternal->Irp;

        LWIO_ASSERT(1 == irpInternal->ReferenceCount);
        LWIO_ASSERT(!pIrp->FileHandle);

        IopIrpDereference(&pIrp);
    }
}
Esempio n. 6
0
static
NTSTATUS
IopContinueAsyncCloseFile(
    IN PIO_FILE_OBJECT FileHandle,
    IN OPTIONAL PIO_ASYNC_COMPLETE_CALLBACK Callback,
    IN OPTIONAL PVOID CallbackContext,
    OUT PIO_STATUS_BLOCK IoStatusBlock
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    int EE = 0;
    PIRP pIrp = NULL;
    IO_ASYNC_CONTROL_BLOCK asyncControlBlock = { 0 };
    PIO_ASYNC_CONTROL_BLOCK useAsyncControlBlock = NULL;
    BOOLEAN isOpen = FALSE;

    //
    // If the create never completed successfully, we do not want
    // to send a CLOSE IRP.
    //

    // TODO -- There is probably still a small race window
    // wrt create and device rundown.  The fix may involve
    // changing when IopFileObjectRemoveDispatched() is called
    // from IopIrpCompleteInternal() so that it is called
    // after the switch on the IRP type.

    IopFileObjectLock(FileHandle);
    isOpen = IsSetFlag(FileHandle->Flags, FILE_OBJECT_FLAG_CREATE_DONE);
    IopFileObjectUnlock(FileHandle);

    if (!isOpen)
    {
        status = STATUS_SUCCESS;
        GOTO_CLEANUP_EE(EE);
    }

    //
    // The file was actually opened, so do rest of close cleanup.
    //

    status = IopFileObjectGetCloseIrp(FileHandle, &pIrp);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    status = IopIrpAttach(pIrp, IRP_TYPE_CLOSE, FileHandle);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    if (Callback)
    {
        asyncControlBlock.Callback = Callback;
        asyncControlBlock.CallbackContext = CallbackContext;
        useAsyncControlBlock = &asyncControlBlock;
    }

    status = IopIrpDispatch(
                    pIrp,
                    useAsyncControlBlock,
                    IoStatusBlock);
    if (STATUS_PENDING == status)
    {
        IoDereferenceAsyncCancelContext(&asyncControlBlock.AsyncCancelContext);
    }
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

cleanup:
    IopIrpDereference(&pIrp);

    if (!useAsyncControlBlock && IoStatusBlock && (STATUS_PENDING != status))
    {
        IO_STATUS_BLOCK ioStatusBlock = { 0 };

        ioStatusBlock.Status = status;
        *IoStatusBlock = ioStatusBlock;
    }

    IO_LOG_LEAVE_ON_STATUS_EE(status, EE);

    return status;
}
Esempio n. 7
0
VOID
IopIrpCancelFileObject(
    IN PIO_FILE_OBJECT pFileObject,
    IN BOOLEAN IsForRundown
    )
{
    BOOLEAN isLocked = FALSE;
    PLW_LIST_LINKS pLinks = NULL;
    PIRP_INTERNAL irpInternal = NULL;
    LW_LIST_LINKS cancelList = { 0 };
    PIRP pIrp = NULL;

    LwListInit(&cancelList);

    // Gather IRPs we want to cancel while holding FO lock.
    IopFileObjectLock(pFileObject);
    isLocked = TRUE;

    if (IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_CANCELLED))
    {
        GOTO_CLEANUP();
    }

    if (IsForRundown)
    {
        SetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_CANCELLED);
    }

    // gather list of IRPs
    for (pLinks = pFileObject->IrpList.Next;
         pLinks != &pFileObject->IrpList;
         pLinks = pLinks->Next)
    {
        irpInternal = LW_STRUCT_FROM_FIELD(pLinks, IRP_INTERNAL, FileObjectLinks);

        LWIO_ASSERT(irpInternal->Irp.FileHandle == pFileObject);

        // Verify that this IRP is not already being cancelled.
        if (!irpInternal->CancelLinks.Next)
        {
            IopIrpReference(&irpInternal->Irp);
            LwListInsertTail(&cancelList, &irpInternal->CancelLinks);
        }
    }
    IopFileObjectUnlock(pFileObject);
    isLocked = FALSE;

    // Iterate over list, calling IopIrpCancel as appropriate.
    while (!LwListIsEmpty(&cancelList))
    {
        pLinks = LwListRemoveHead(&cancelList);
        irpInternal = LW_STRUCT_FROM_FIELD(pLinks, IRP_INTERNAL, CancelLinks);
        pIrp = &irpInternal->Irp;

        IopIrpCancel(pIrp);
        IopIrpDereference(&pIrp);
    }

cleanup:
    if (isLocked)
    {
        IopFileObjectUnlock(pFileObject);
    }
}
Esempio n. 8
0
NTSTATUS
IopIrpDispatch(
    IN PIRP pIrp,
    IN OUT OPTIONAL PIO_ASYNC_CONTROL_BLOCK AsyncControlBlock,
    OUT PIO_STATUS_BLOCK pIoStatusBlock
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    int EE = 0;
    BOOLEAN isAsyncCall = FALSE;
    LW_RTL_EVENT event = LW_RTL_EVENT_ZERO_INITIALIZER;
    PIRP pExtraIrpReference = NULL;
    PIRP_INTERNAL irpInternal = IopIrpGetInternal(pIrp);
    BOOLEAN needCancel = FALSE;
    IRP_TYPE irpType = pIrp->Type;

    LWIO_ASSERT(pIoStatusBlock);

    isAsyncCall = AsyncControlBlock ? TRUE : FALSE;
    if (isAsyncCall)
    {
        LWIO_ASSERT(!AsyncControlBlock->AsyncCancelContext);
        LWIO_ASSERT(AsyncControlBlock->Callback);

        irpInternal->Completion.Async.Callback = AsyncControlBlock->Callback;
        irpInternal->Completion.Async.CallbackContext = AsyncControlBlock->CallbackContext;
        irpInternal->Completion.Async.pIoStatusBlock = pIoStatusBlock;

        // Assert that caller has set required out params via IopIrpSetOutput*().
        LWIO_ASSERT(!IopIrpIsCreate(pIrp) || irpInternal->Completion.Async.OpOut.Create.pFileHandle);
        LWIO_ASSERT(!IopIrpIsPrepareZctReadWrite(pIrp) || irpInternal->Completion.Async.OpOut.PrepareZctReadWrite.pCompletionContext);

        // Reference IRP since we may need to return an an async cancel context.
        IopIrpReference(pIrp);
        pExtraIrpReference = pIrp;
    }
    else
    {
        // Since sync, assert IopIrpSetOutput*() has not actually set anything.
        LWIO_ASSERT(!irpInternal->Completion.IsAsyncCall);

        status = LwRtlInitializeEvent(&event);
        GOTO_CLEANUP_ON_STATUS_EE(status, EE);

        irpInternal->Completion.Sync.Event = &event;
    }

    irpInternal->Completion.IsAsyncCall = isAsyncCall;

    // We have to dispatch once we add the IRP as "dipatched"
    // and we have to call IopIrpCompleteInternal() so that
    // it gets subtracted.

    status = IopFileObjectAddDispatched(pIrp->FileHandle, pIrp->Type);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    SetFlag(irpInternal->Flags, IRP_FLAG_DISPATCHED);

    status = IopDeviceCallDriver(pIrp->DeviceHandle, pIrp);
    // Handle synchronous completion
    if (STATUS_PENDING != status)
    {
        IopIrpCompleteInternal(pIrp, FALSE);
    }
    // Handle asynchronous dispatch
    else
    {
        IopIrpAcquireCancelLock(pIrp);

        LWIO_ASSERT(IsSetFlag(irpInternal->Flags, IRP_FLAG_PENDING));
        LWIO_ASSERT(irpInternal->Cancel.Callback);

        needCancel = IsSetFlag(irpInternal->Flags, IRP_FLAG_CANCEL_PENDING);

        IopIrpReleaseCancelLock(pIrp);

        if (needCancel)
        {
            IopIrpCancel(pIrp);
        }

        // Handle waiting for asynchronous completion for synchronous caller
        if (!isAsyncCall)
        {
            LwRtlWaitEvent(&event, NULL);

            LWIO_ASSERT(pIrp->IoStatusBlock.Status != STATUS_PENDING);
            status = pIrp->IoStatusBlock.Status;
        }
    }

    //
    // At this point, we are either complete or this is
    // an async call that returned STATUS_PENDING.
    //

    LWIO_ASSERT((STATUS_PENDING == status) || (pIrp->IoStatusBlock.Status == status));

cleanup:
    LwRtlCleanupEvent(&event);

    if (STATUS_PENDING == status)
    {
        LWIO_ASSERT(isAsyncCall);

        AsyncControlBlock->AsyncCancelContext = IopIrpGetAsyncCancelContextFromIrp(pIrp);
    }
    else
    {
        if (isAsyncCall)
        {
            //
            // Remove async cancel context reference added earlier since we
            // are returning synchronously w/o an async cancel context.
            //

            IopIrpDereference(&pExtraIrpReference);
        }

        pIrp->IoStatusBlock.Status = status;
        *pIoStatusBlock = pIrp->IoStatusBlock;
    }

    LWIO_ASSERT(IS_BOTH_OR_NEITHER(pExtraIrpReference, (STATUS_PENDING == status)));
    LWIO_ASSERT((STATUS_PENDING != status) || isAsyncCall);
    LWIO_ASSERT(IsValidStatusForIrpType(status, irpType));
    return status;
}
Esempio n. 9
0
static
VOID
IopIrpCompleteInternal(
    IN OUT PIRP pIrp,
    IN BOOLEAN IsAsyncCompletion
    )
{
    PIRP_INTERNAL irpInternal = IopIrpGetInternal(pIrp);

    IopIrpAcquireCancelLock(pIrp);

    LWIO_ASSERT_MSG(IS_BOTH_OR_NEITHER(IsAsyncCompletion, IsSetFlag(irpInternal->Flags, IRP_FLAG_PENDING)), "IRP pending state is inconsistent.");
    LWIO_ASSERT_MSG(IsSetFlag(irpInternal->Flags, IRP_FLAG_DISPATCHED), "IRP cannot be completed unless it was properly dispatched.");
    LWIO_ASSERT_MSG(!IsSetFlag(irpInternal->Flags, IRP_FLAG_COMPLETE), "IRP cannot be completed more than once.");

    //
    // Note that the IRP may be CANCEL_PENDING or CANCELLED, but that
    // is ok.  In fact, completion may have been called in response
    // to cancellation.
    //

    SetFlag(irpInternal->Flags, IRP_FLAG_COMPLETE);

    IopIrpReleaseCancelLock(pIrp);

    IopFileObjectRemoveDispatched(pIrp->FileHandle, pIrp->Type);

    LWIO_ASSERT(IsValidStatusForIrpType(pIrp->IoStatusBlock.Status, pIrp->Type));

    switch (pIrp->Type)
    {
    case IRP_TYPE_CREATE:
    case IRP_TYPE_CREATE_NAMED_PIPE:
        if ((STATUS_SUCCESS == pIrp->IoStatusBlock.Status) ||
            (STATUS_OPLOCK_BREAK_IN_PROGRESS == pIrp->IoStatusBlock.Status))
        {
            // Handle special success processing having to do with file handle.
            // ISSUE-May not need lock since it should be only reference
            IopFileObjectLock(pIrp->FileHandle);
            SetFlag(pIrp->FileHandle->Flags, FILE_OBJECT_FLAG_CREATE_DONE);
            IopFileObjectUnlock(pIrp->FileHandle);

            IopFileObjectReference(pIrp->FileHandle);
            if (IsAsyncCompletion && irpInternal->Completion.IsAsyncCall)
            {
                *irpInternal->Completion.Async.OpOut.Create.pFileHandle = pIrp->FileHandle;
            }
        }
        break;

    case IRP_TYPE_CLOSE:
        if (STATUS_SUCCESS == pIrp->IoStatusBlock.Status)
        {
            PIO_FILE_OBJECT pFileObject = NULL;

            SetFlag(pIrp->FileHandle->Flags, FILE_OBJECT_FLAG_CLOSE_DONE);

            // Note that we must delete the reference from the create
            // w/o removing the file object value from the IRP (which
            // will be removed when the IRP is freed).

            pFileObject = pIrp->FileHandle;
            IopFileObjectDereference(&pFileObject);
        }
        else
        {
            LWIO_LOG_ERROR("Unable to close file object, status = 0x%08x",
                           pIrp->IoStatusBlock.Status);
        }
        break;

    case IRP_TYPE_READ:
    case IRP_TYPE_WRITE:
        if (IRP_ZCT_OPERATION_PREPARE == pIrp->Args.ReadWrite.ZctOperation)
        {
            if (STATUS_SUCCESS == pIrp->IoStatusBlock.Status)
            {
                LWIO_ASSERT(pIrp->Args.ReadWrite.ZctCompletionContext);

                if (IsAsyncCompletion && irpInternal->Completion.IsAsyncCall)
                {
                    PIRP pCompletionIrp = irpInternal->Completion.Async.OpOut.PrepareZctReadWrite.pCompletionIrp;
                    PVOID pCompletionContext = IopIrpSaveZctIrp(
                                                    pIrp->FileHandle,
                                                    pCompletionIrp,
                                                    pIrp->Args.ReadWrite.ZctCompletionContext);
                    *irpInternal->Completion.Async.OpOut.PrepareZctReadWrite.pCompletionContext = pCompletionContext;
                }
            }
            if (irpInternal->Completion.IsAsyncCall)
            {
                IopIrpDereference(&irpInternal->Completion.Async.OpOut.PrepareZctReadWrite.pCompletionIrp);
            }
        }
        break;
    }

    if (IsAsyncCompletion)
    {
        if (irpInternal->Completion.IsAsyncCall)
        {
            *irpInternal->Completion.Async.pIoStatusBlock = pIrp->IoStatusBlock;
            irpInternal->Completion.Async.Callback(
                    irpInternal->Completion.Async.CallbackContext);
        }
        else
        {
            LwRtlSetEvent(irpInternal->Completion.Sync.Event);
        }

        //
        // Release reference from IoIrpMarkPending().
        //

        IopIrpDereference(&pIrp);
    }
}