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; } }
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; }
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; }
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; }
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); } }
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; }
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); } }
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; }
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); } }