NTSTATUS PvfsListAddTail( PPVFS_LIST pList, PLW_LIST_LINKS pItem ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; BAIL_ON_INVALID_PTR(pList, ntError); BAIL_ON_INVALID_PTR(pItem, ntError); /* Using >= here to be safe. Technically, == should be fine */ if (PvfsListIsFull(pList)) { ntError = STATUS_INSUFFICIENT_RESOURCES; BAIL_ON_NT_STATUS(ntError); } LwListInsertTail(&pList->DataList, pItem); pList->CurrentSize++; ntError = STATUS_SUCCESS; cleanup: return ntError; error: goto cleanup; }
VOID RdrNotifyContextList( PLW_LIST_LINKS pList, BOOLEAN bLocked, pthread_mutex_t* pMutex, NTSTATUS status, PVOID pParam ) { LW_LIST_LINKS List; PLW_LIST_LINKS pLink = NULL; BOOLEAN bWasLocked = bLocked; LWIO_LOCK_MUTEX(bLocked, pMutex); LwListInit(&List); while ((pLink = LwListRemoveHead(pList))) { LwListInsertTail(&List, pLink); } LWIO_UNLOCK_MUTEX(bLocked, pMutex); RdrContinueContextList(&List, status, pParam); LWIO_LOCK_MUTEX(bLocked, pMutex); while ((pLink = LwListRemoveHead(&List))) { LwListInsertTail(pList, pLink); } if (!bWasLocked) { LWIO_UNLOCK_MUTEX(bLocked, pMutex); } }
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; }
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; }
static BOOLEAN RdrSessionSetupComplete2( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SESSION2 pSession = pParam; PRDR_TREE2 pTree = NULL; BOOLEAN bTreeLocked = FALSE; BOOLEAN bFreeContext = FALSE; BAIL_ON_NT_STATUS(status); status = RdrTree2FindOrCreate( &pSession, pContext->State.TreeConnect.pwszSharename, &pTree); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pTree2 = pTree; LWIO_LOCK_MUTEX(bTreeLocked, &pTree->mutex); switch (pTree->state) { case RDR_TREE_STATE_NOT_READY: pTree->state = RDR_TREE_STATE_INITIALIZING; pContext->Continue = RdrFinishTreeConnect2; status = RdrTransceiveTreeConnect2(pContext, pTree, pTree->pwszPath); BAIL_ON_NT_STATUS(status); break; case RDR_TREE_STATE_INITIALIZING: pContext->Continue = RdrTreeConnect2Complete; LwListInsertTail(&pTree->StateWaiters, &pContext->Link); bFreeContext = TRUE; status = STATUS_PENDING; break; case RDR_TREE_STATE_READY: RdrTreeConnect2Complete(pContext, status, pTree); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_TREE_STATE_ERROR: status = pTree->error; BAIL_ON_NT_STATUS(status); break; } cleanup: LWIO_UNLOCK_MUTEX(bTreeLocked, &pTree->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } return FALSE; error: if (status != STATUS_PENDING && pTree) { LWIO_UNLOCK_MUTEX(bTreeLocked, &pTree->mutex); RdrTree2Invalidate(pTree, status); RdrTree2Release(pTree); } if (status != STATUS_PENDING && pSession) { RdrSession2Release(pSession); } goto cleanup; }
BOOLEAN RdrNegotiateComplete2( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SOCKET pSocket = pParam; PRDR_SESSION2 pSession = NULL; BOOLEAN bSessionLocked = FALSE; BOOLEAN bFreeContext = FALSE; PIO_CREDS pCreds = pContext->State.TreeConnect.pCreds; BAIL_ON_NT_STATUS(status); if (pContext->State.TreeConnect.bStopOnDfs && pSocket->capabilities & RDR_SMB2_CAP_DFS) { status = STATUS_DFS_EXIT_PATH_FOUND; BAIL_ON_NT_STATUS(status); } status = RdrSession2FindOrCreate( &pSocket, pContext->State.TreeConnect.pCreds, pContext->State.TreeConnect.Uid, &pSession); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pSession2 = pSession; LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); switch (pSession->state) { case RDR_SESSION_STATE_NOT_READY: pSession->state = RDR_SESSION_STATE_INITIALIZING; switch (pCreds->type) { case IO_CREDS_TYPE_KRB5_TGT: status = SMBCredTokenToKrb5CredCache( pCreds, &pContext->State.TreeConnect.pszCachePath); BAIL_ON_NT_STATUS(status); break; case IO_CREDS_TYPE_PLAIN: break; default: status = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(status); } LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrProcessSessionSetupResponse2(pContext, STATUS_SUCCESS, NULL); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_INITIALIZING: pContext->Continue = RdrSessionSetupComplete2; LwListInsertTail(&pSession->StateWaiters, &pContext->Link); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_READY: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete2(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_ERROR: status = pSession->error; BAIL_ON_NT_STATUS(status); break; } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } return FALSE; error: if (status != STATUS_PENDING && pSession) { LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSession2Invalidate(pSession, status); } RdrSession2Release(pSession); } if (status != STATUS_PENDING && pSocket) { if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSocketInvalidate(pSocket, status); } RdrSocketRelease(pSocket); } goto cleanup; }
static BOOLEAN RdrNegotiateComplete( PRDR_OP_CONTEXT pContext, NTSTATUS status, PVOID pParam ) { PRDR_SOCKET pSocket = pParam; PRDR_SESSION pSession = NULL; BOOLEAN bSessionLocked = FALSE; BOOLEAN bFreeContext = FALSE; PIO_CREDS pCreds = pContext->State.TreeConnect.pCreds; BAIL_ON_NT_STATUS(status); /* Several op contexts could be queued with this function * as the continue routine before we transition to SMB2 mode, * so we need to hand off to the correct function in this case. * Subsequent attempts should go straight to connect2.c */ if (pSocket->version == SMB_PROTOCOL_VERSION_2) { /* Short circuit to SMB2 session setup logic in connect2.c */ return RdrNegotiateComplete2(pContext, status, pParam); } if (pContext->State.TreeConnect.bStopOnDfs && pSocket->capabilities & CAP_DFS) { /* Abort tree connect because we need to do DFS referral processing first */ status = STATUS_DFS_EXIT_PATH_FOUND; BAIL_ON_NT_STATUS(status); } status = RdrSessionFindOrCreate( &pSocket, pContext->State.TreeConnect.pCreds, pContext->State.TreeConnect.Uid, &pSession); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pSession = pSession; LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); switch (pSession->state) { case RDR_SESSION_STATE_NOT_READY: pSession->state = RDR_SESSION_STATE_INITIALIZING; switch (pCreds->type) { case IO_CREDS_TYPE_KRB5_TGT: status = SMBCredTokenToKrb5CredCache( pCreds, &pContext->State.TreeConnect.pszCachePath); BAIL_ON_NT_STATUS(status); break; case IO_CREDS_TYPE_PLAIN: break; default: status = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(status); } LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrProcessSessionSetupResponse(pContext, STATUS_SUCCESS, NULL); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_INITIALIZING: pContext->Continue = RdrSessionSetupComplete; LwListInsertTail(&pSession->StateWaiters, &pContext->Link); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_READY: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SESSION_STATE_ERROR: status = pSession->error; BAIL_ON_NT_STATUS(status); break; } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_PENDING) { RdrContinueContext(pContext->State.TreeConnect.pContinue, status, NULL); bFreeContext = TRUE; } if (bFreeContext) { RdrFreeTreeConnectContext(pContext); } return FALSE; error: if (status != STATUS_PENDING && pSession) { LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSessionInvalidate(pSession, status); } RdrSessionRelease(pSession); } if (status != STATUS_PENDING && pSocket) { if (status != STATUS_DFS_EXIT_PATH_FOUND) { RdrSocketInvalidate(pSocket, status); } RdrSocketRelease(pSocket); } goto cleanup; }
NTSTATUS RdrTreeConnect( PCWSTR pwszHostname, PCWSTR pwszSharename, PIO_CREDS pCreds, uid_t Uid, BOOLEAN bStopOnDfs, PRDR_OP_CONTEXT pContinue ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContext = NULL; BOOLEAN bSocketLocked = FALSE; PRDR_SOCKET pSocket = NULL; status = RdrCreateContext(pContinue->pIrp, &pContext); BAIL_ON_NT_STATUS(status); LWIO_LOG_DEBUG("Tree connect context %p will continue %p\n", pContext, pContinue); pContext->State.TreeConnect.Uid = Uid; pContext->State.TreeConnect.bStopOnDfs = bStopOnDfs; pContext->State.TreeConnect.pContinue = pContinue; status = LwRtlWC16StringDuplicate( &pContext->State.TreeConnect.pwszSharename, pwszSharename); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pCreds = pCreds; status = RdrSocketFindOrCreate( pwszHostname, &pSocket); BAIL_ON_NT_STATUS(status); pContext->State.TreeConnect.pSocket = pSocket; LWIO_LOCK_MUTEX(bSocketLocked, &pSocket->mutex); switch (pSocket->state) { case RDR_SOCKET_STATE_NOT_READY: pSocket->state = RDR_SOCKET_STATE_CONNECTING; LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); /* Add extra reference to socket for work item */ RdrSocketRetain(pSocket); status = LwRtlQueueWorkItem( gRdrRuntime.pThreadPool, RdrSocketConnectWorkItem, pSocket, 0); if (status) { /* Nevermind */ RdrSocketRelease(pSocket); } BAIL_ON_NT_STATUS(status); pContext->Continue = RdrProcessNegotiateResponse; status = RdrTransceiveNegotiate(pContext, pSocket); BAIL_ON_NT_STATUS(status); break; case RDR_SOCKET_STATE_CONNECTING: case RDR_SOCKET_STATE_NEGOTIATING: pContext->Continue = RdrNegotiateComplete; LwListInsertTail(&pSocket->StateWaiters, &pContext->Link); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SOCKET_STATE_READY: LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrNegotiateComplete(pContext, STATUS_SUCCESS, pSocket); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); break; case RDR_SOCKET_STATE_ERROR: status = pSocket->error; BAIL_ON_NT_STATUS(status); break; } cleanup: LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); if (status != STATUS_PENDING) { RdrFreeTreeConnectContext(pContext); } return status; error: if (status != STATUS_PENDING && pSocket) { LWIO_UNLOCK_MUTEX(bSocketLocked, &pSocket->mutex); RdrSocketInvalidate(pSocket, status); RdrSocketRelease(pSocket); } goto cleanup; }
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 IopDeviceRundown( IN PIO_DEVICE_OBJECT pDeviceObject ) { NTSTATUS status = 0; int EE = 0; BOOLEAN isLocked = FALSE; PLW_LIST_LINKS pLinks = NULL; LW_LIST_LINKS rundownList = { 0 }; LwListInit(&rundownList); IopDeviceLock(pDeviceObject); isLocked = TRUE; if (IsSetFlag(pDeviceObject->Flags, IO_DEVICE_OBJECT_FLAG_RUNDOWN)) { // TODO: Perhaps wait if currently running down. status = STATUS_SUCCESS; GOTO_CLEANUP_EE(EE); } SetFlag(pDeviceObject->Flags, IO_DEVICE_OBJECT_FLAG_RUNDOWN); // Gather rundown list for (pLinks = pDeviceObject->FileObjectsList.Next; pLinks != &pDeviceObject->FileObjectsList; pLinks = pLinks->Next) { PIO_FILE_OBJECT pFileObject = LW_STRUCT_FROM_FIELD(pLinks, IO_FILE_OBJECT, DeviceLinks); IopFileObjectReference(pFileObject); LwListInsertTail(&rundownList, &pFileObject->RundownLinks); } IopDeviceUnlock(pDeviceObject); isLocked = FALSE; // Now, actually run down every file w/o holding the device lock. while (!LwListIsEmpty(&rundownList)) { PIO_FILE_OBJECT pFileObject = NULL; pLinks = LwListRemoveHead(&rundownList); pFileObject = LW_STRUCT_FROM_FIELD(pLinks, IO_FILE_OBJECT, RundownLinks); IopFileObjectRundown(pFileObject); } IopRootRemoveDevice(pDeviceObject->Driver->Root, &pDeviceObject->RootLinks); cleanup: if (isLocked) { IopDeviceUnlock(pDeviceObject); } 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); } }