Exemple #1
0
static
NTSTATUS
IopFileObjectGetCloseIrp(
    IN IO_FILE_HANDLE FileHandle,
    OUT PIRP* ppIrp
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    int EE = 0;
    PIRP pIrp = NULL;

    // TODO-Use InterlockedExchangePointer()

    IopFileObjectLock(FileHandle);
    pIrp = FileHandle->pCloseIrp;
    FileHandle->pCloseIrp = NULL;
    IopFileObjectUnlock(FileHandle);

    if (!LWIO_ASSERT_VALUE_MSG(pIrp, "Cannot close already closed file"))
    {
        status = STATUS_FILE_CLOSED;
        GOTO_CLEANUP_ON_STATUS_EE(status, EE);
    }

cleanup:
    IO_LOG_LEAVE_ON_STATUS_EE(status, EE);

    *ppIrp = pIrp;

    return status;
}
Exemple #2
0
NTSTATUS
IopFileObjectAddDispatched(
    IN PIO_FILE_OBJECT pFileObject,
    IN IRP_TYPE Type
    )
{
    NTSTATUS status = STATUS_SUCCESS;

    IopFileObjectLock(pFileObject);

    if ((Type != IRP_TYPE_CLOSE) &&
        (IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_CANCELLED) ||
         IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN)))
    {
        status = STATUS_CANCELLED;
    }
    else
    {
        status = STATUS_SUCCESS;

        pFileObject->DispatchedIrpCount++;
        LWIO_ASSERT(pFileObject->DispatchedIrpCount >= 1);
    }

    IopFileObjectUnlock(pFileObject);

    return status;
}
Exemple #3
0
VOID
IoFileSetZctSupportMask(
    IN IO_FILE_HANDLE FileHandle,
    IN LW_ZCT_ENTRY_MASK ZctReadMask,
    IN LW_ZCT_ENTRY_MASK ZctWriteMask
    )
{
    // It is up to the FSD to synchornize
    IopFileObjectLock(FileHandle);
    FileHandle->ZctReadMask = ZctReadMask;
    FileHandle->ZctWriteMask = ZctWriteMask;
    IopFileObjectUnlock(FileHandle);
}
Exemple #4
0
VOID
IopFileObjectRemoveDispatched(
    IN PIO_FILE_OBJECT pFileObject,
    IN IRP_TYPE Type
    )
{
    BOOLEAN needContinueAsycClose = FALSE;

    IopFileObjectLock(pFileObject);

    pFileObject->DispatchedIrpCount--;
    LWIO_ASSERT(pFileObject->DispatchedIrpCount >= 0);

    if (IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN_WAIT) &&
        (0 == pFileObject->DispatchedIrpCount))
    {
        // TODO-Perhaps remove Type parameter since the use of
        // FILE_OBJECT_FLAG_RUNDOWN_WAIT negates the need for it.
        LWIO_ASSERT(Type != IRP_TYPE_CLOSE);

        if (pFileObject->Rundown.Callback)
        {
            needContinueAsycClose = TRUE;
        }
        else
        {
            LwRtlSignalConditionVariable(&pFileObject->Rundown.Condition);
        }

        ClearFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN_WAIT);
    }

    IopFileObjectUnlock(pFileObject);

    if (needContinueAsycClose)
    {
        // This will send the close to the FSD.  Note that the callback
        // must be called from here on a synchronous completion because
        // there was no asynchronous IRP completion to take care of calling
        // the callback.
        NTSTATUS status = IopContinueAsyncCloseFile(
                pFileObject,
                pFileObject->Rundown.Callback,
                pFileObject->Rundown.CallbackContext,
                pFileObject->Rundown.pIoStatusBlock);
        if (STATUS_PENDING != status)
        {
            pFileObject->Rundown.Callback(pFileObject->Rundown.CallbackContext);
        }
    }
}
Exemple #5
0
NTSTATUS
IopIrpAttach(
    IN OUT PIRP pIrp,
    IN IRP_TYPE Type,
    IN PIO_FILE_OBJECT pFileObject
    )
{
    NTSTATUS status = 0;
    int EE = 0;
    PIRP_INTERNAL irpInternal = IopIrpGetInternal(pIrp);

    LWIO_ASSERT(!pIrp->FileHandle);
    LWIO_ASSERT(pIrp->Type == IRP_TYPE_UNINITIALIZED);
    LWIO_ASSERT(Type != IRP_TYPE_UNINITIALIZED);

    IopFileObjectLock(pFileObject);

    // TODO-Add FILE_OBJECT_FLAG_CLOSED
    if ((Type != IRP_TYPE_CLOSE) &&
        (IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_CANCELLED) ||
         IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN)))
    {
        status = STATUS_CANCELLED;
        GOTO_CLEANUP_EE(EE);
    }
    else
    {
        LwListInsertTail(&pFileObject->IrpList,
                         &irpInternal->FileObjectLinks);
    }

    // These are immutable from here until the IRP is freed.
    pIrp->Type = Type;
    pIrp->FileHandle = pFileObject;
    IopFileObjectReference(pFileObject);
    // The file object reference keeps an implicit reference to the
    // device and driver.
    pIrp->DeviceHandle = pFileObject->pDevice;
    pIrp->DriverHandle = pFileObject->pDevice->Driver;

cleanup:
    IopFileObjectUnlock(pFileObject);

    IO_LOG_LEAVE_ON_STATUS_EE(status, EE);
    return status;
}
Exemple #6
0
PIRP
IopIrpLoadZctIrp(
    IN OUT PIO_FILE_OBJECT pFileObject,
    IN PVOID pCompletionContext
    )
{
    PIRP pIrp = (PIRP) pCompletionContext;
    PIRP_INTERNAL irpInternal = IopIrpGetInternal(pIrp);

    LWIO_ASSERT(pIrp->Args.ReadWrite.ZctCompletionContext);
    LWIO_ASSERT(irpInternal->CancelLinks.Next && irpInternal->CancelLinks.Prev);

    IopFileObjectLock(pFileObject);
    LwListRemove(&irpInternal->CancelLinks);
    IopFileObjectUnlock(pFileObject);

    RtlZeroMemory(&irpInternal->CancelLinks, sizeof(irpInternal->CancelLinks));

    return pIrp;
}
Exemple #7
0
VOID
IopFileGetZctSupportMask(
    IN IO_FILE_HANDLE FileHandle,
    OUT OPTIONAL PLW_ZCT_ENTRY_MASK ZctReadMask,
    OUT OPTIONAL PLW_ZCT_ENTRY_MASK ZctWriteMask
    )
{
    if (ZctReadMask || ZctWriteMask)
    {
        IopFileObjectLock(FileHandle);
        if (ZctReadMask)
        {
            *ZctReadMask = FileHandle->ZctReadMask;
        }
        if (ZctWriteMask)
        {
            *ZctWriteMask = FileHandle->ZctWriteMask;
        }
        IopFileObjectUnlock(FileHandle);
    }
}
Exemple #8
0
PVOID
IopIrpSaveZctIrp(
    IN OUT PIO_FILE_OBJECT pFileObject,
    IN PIRP pIrp,
    IN PVOID pCompletionContext
    )
{
    PIRP_INTERNAL irpInternal = IopIrpGetInternal(pIrp);

    LWIO_ASSERT(pCompletionContext);

    IopIrpReference(pIrp);

    pIrp->Args.ReadWrite.ZctCompletionContext = pCompletionContext;

    IopFileObjectLock(pFileObject);
    LwListInsertTail(&pFileObject->ZctCompletionIrpList, &irpInternal->CancelLinks);
    IopFileObjectUnlock(pFileObject);

    return pIrp;
}
Exemple #9
0
VOID
IopIrpFreeZctIrpList(
    IN OUT PIO_FILE_OBJECT pFileObject
    )
{
    PLW_LIST_LINKS pLinks = NULL;;
    PIRP_INTERNAL irpInternal = NULL;
    PIRP pIrp = NULL;

    IopFileObjectLock(pFileObject);
    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);
    }
    IopFileObjectUnlock(pFileObject);
}
Exemple #10
0
VOID
IopIrpDereference(
    IN OUT PIRP* ppIrp
    )
{
    PIRP pIrp = *ppIrp;
    if (pIrp)
    {
        PIRP_INTERNAL irpInternal = IopIrpGetInternal(pIrp);
        LONG count = 0;
        PIO_FILE_OBJECT pFileObject = pIrp->FileHandle;

        if (pFileObject)
        {
            // Take a reference in case we free the IRP.
            IopFileObjectReference(pFileObject);
            // Lock since we may free and manipulate the FO IRP list.
            IopFileObjectLock(pFileObject);
        }

        count = InterlockedDecrement(&irpInternal->ReferenceCount);
        LWIO_ASSERT(count >= 0);
        if (0 == count)
        {
            IopIrpFree(ppIrp);
        }

        // Remove our reference.
        if (pFileObject)
        {
            IopFileObjectUnlock(pFileObject);
            IopFileObjectDereference(&pFileObject);
        }
        *ppIrp = NULL;
    }
}
Exemple #11
0
NTSTATUS
IopFileObjectRundownEx(
    IN OUT PIO_FILE_OBJECT pFileObject,
    IN OPTIONAL PIO_ASYNC_COMPLETE_CALLBACK Callback,
    IN OPTIONAL PVOID CallbackContext,
    OUT PIO_STATUS_BLOCK IoStatusBlock
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    int EE = 0;
    BOOLEAN isLocked = FALSE;
    IO_STATUS_BLOCK ioStatusBlock = { 0 };

    IopFileObjectLock(pFileObject);
    isLocked = TRUE;

    if (IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_CLOSE_DONE))
    {
        LWIO_ASSERT(IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN));
        // Note that there can be IRP references for completed IRPs sitting
        // around where the caller has not yet gotten rid of the IRP by
        // calling IoDereferenceAsyncCancelContext().  So we cannot assert
        // that (1 == pFileObject->ReferenceCount).  Therefore, we do the
        // next best thing and check DispatchedIrpCount.  Technically, if
        // someone got far enough into a new call that they created an IRP,
        // they will also have a new IRP file objeject reference.  However,
        // the new IRP will fail to dispatch.  While that is a logic bug
        // in the caller, we cannot trap those sorts of bugs via asserts
        // in the I/O manager.
        LWIO_ASSERT(0 == pFileObject->DispatchedIrpCount);

        IopFileObjectUnlock(pFileObject);
        isLocked = FALSE;

        IopFileObjectDereference(&pFileObject);

        status = STATUS_SUCCESS;
        GOTO_CLEANUP_EE(EE);
    }

    if (IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN))
    {
        LWIO_LOG_ERROR("Attempt to rundown multiple times");
        status = STATUS_FILE_CLOSED;
        GOTO_CLEANUP_EE(EE);
    }

    SetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN);

    IopFileObjectUnlock(pFileObject);
    isLocked = FALSE;

    // Cancel everything now that rundown flag is set.
    IopIrpCancelFileObject(pFileObject, TRUE);

    // Now check whether we need to wait for rundown.
    IopFileObjectLock(pFileObject);
    isLocked = TRUE;

    if (0 != pFileObject->DispatchedIrpCount)
    {
        // Need to wait

        SetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RUNDOWN_WAIT);

        if (!Callback)
        {
            // Wait inline for synchronous case

            LwRtlWaitConditionVariable(
                    &pFileObject->Rundown.Condition,
                    &pFileObject->Mutex,
                    NULL);
            LWIO_ASSERT(0 == pFileObject->DispatchedIrpCount);
        }
        else
        {
            // Set up rundown callback for async case

            pFileObject->Rundown.Callback = Callback;
            pFileObject->Rundown.CallbackContext = CallbackContext;
            pFileObject->Rundown.pIoStatusBlock = IoStatusBlock;

            status = STATUS_PENDING;
            GOTO_CLEANUP_EE(EE);
        }
    }

    IopFileObjectUnlock(pFileObject);
    isLocked = FALSE;

    // We can now continue closing.

    status = IopContinueAsyncCloseFile(
                    pFileObject,
                    Callback,
                    CallbackContext,
                    IoStatusBlock);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);
    
cleanup:
    if (isLocked)
    {
        IopFileObjectUnlock(pFileObject);
    }

    if (status && (STATUS_PENDING != status))
    {
        ioStatusBlock.Status = status;
    }

    if ((STATUS_PENDING != status) && IoStatusBlock)
    {
        *IoStatusBlock = ioStatusBlock;
    }

    // TODO-Perhaps do not ASSERT here because LwRtlInitializeEvent()
    // could have failed if disaptching close IRP synchronously.
    LWIO_ASSERT((STATUS_SUCCESS == status) ||
                (STATUS_PENDING == status) ||
                (STATUS_FILE_CLOSED == status));

    // TODO-Perhaps also remove object from device's file object
    // list such that it cannot be rundown multiple times.  This
    // would avoid the STATUS_FILE_CLOSED above.

    IO_LOG_LEAVE_ON_STATUS_EE(status, EE);
    return status;
}
Exemple #12
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;
}
Exemple #13
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);
    }
}
Exemple #14
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);
    }
}