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