Ejemplo n.º 1
0
static
VOID
IopIrpFree(
    IN OUT PIRP* ppIrp
    )
{
    PIRP pIrp = *ppIrp;

    if (pIrp)
    {
        PIRP_INTERNAL irpInternal = IopIrpGetInternal(pIrp);

        LWIO_ASSERT(0 == irpInternal->ReferenceCount);
        LWIO_ASSERT(STATUS_PENDING != pIrp->IoStatusBlock.Status);

        switch (pIrp->Type)
        {
            case IRP_TYPE_CREATE:
            case IRP_TYPE_CREATE_NAMED_PIPE:
                IoSecurityDereferenceSecurityContext(&pIrp->Args.Create.SecurityContext);
                RtlUnicodeStringFree(&pIrp->Args.Create.FileName.Name);
                break;
            case IRP_TYPE_QUERY_DIRECTORY:
                if (pIrp->Args.QueryDirectory.FileSpec)
                {
                    LwRtlUnicodeStringFree(&pIrp->Args.QueryDirectory.FileSpec->Pattern);
                    IO_FREE(&pIrp->Args.QueryDirectory.FileSpec);
                }
                break;
            default:
                break;
        }

        // Note that the parent (FO) lock is already held
        // by IopIrpDereference().

        // Might not be in the list if IRP creation failed.
        if (irpInternal->FileObjectLinks.Next)
        {
            LwListRemove(&irpInternal->FileObjectLinks);
        }
        IopFileObjectDereference(&pIrp->FileHandle);

        IoMemoryFree(pIrp);
        *ppIrp = NULL;
    }
}
Ejemplo n.º 2
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;
    }
}
Ejemplo n.º 3
0
NTSTATUS
IopFileObjectAllocate(
    OUT PIO_FILE_OBJECT* ppFileObject,
    IN PIO_DEVICE_OBJECT pDevice,
    IN PIO_FILE_NAME FileName
    )
{
    NTSTATUS status = 0;
    int EE = 0;
    PIO_FILE_OBJECT pFileObject = NULL;

    status = IO_ALLOCATE(&pFileObject, IO_FILE_OBJECT, sizeof(*pFileObject));
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    pFileObject->ReferenceCount = 1;
    pFileObject->pDevice = pDevice;
    IopDeviceReference(pDevice);

    LwListInit(&pFileObject->IrpList);
    LwListInit(&pFileObject->DeviceLinks);
    LwListInit(&pFileObject->RundownLinks);
    LwListInit(&pFileObject->ZctCompletionIrpList);

    // Pre-allocate IRP for close.
    status = IopIrpCreateDetached(&pFileObject->pCloseIrp);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    if (FileName->RootFileHandle)
    {
        SetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RELATIVE);
    }

    status = LwRtlUnicodeStringDuplicate(
                    &pFileObject->FileName,
                    &FileName->Name);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    status = LwRtlInitializeMutex(&pFileObject->Mutex, TRUE);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    status = LwRtlInitializeConditionVariable(&pFileObject->Rundown.Condition);
    GOTO_CLEANUP_ON_STATUS_EE(status, EE);

    IopDeviceLock(pDevice);
    if (IsSetFlag(pDevice->Flags, IO_DEVICE_OBJECT_FLAG_RUNDOWN) ||
        IsSetFlag(pDevice->Flags, IO_DEVICE_OBJECT_FLAG_RUNDOWN_DRIVER))
    {
        // TODO: Find "correct" error code.
        status = STATUS_INVALID_HANDLE;
    }
    else
    {
        LwListInsertTail(&pDevice->FileObjectsList, &pFileObject->DeviceLinks);
    }
    IopDeviceUnlock(pDevice);

cleanup:
    if (status)
    {
        IopFileObjectDereference(&pFileObject);
    }

    *ppFileObject = pFileObject;

    IO_LOG_LEAVE_ON_STATUS_EE(status, EE);
    return status;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
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);
    }
}