VOID PvfsZctCloseCcb( IN PPVFS_CCB pCcb ) { BOOLEAN bMutexLocked = FALSE; PLW_LIST_LINKS pZctCtxLink = NULL; PLW_LIST_LINKS pNextLink = NULL; PPVFS_ZCT_CONTEXT pZctContext = NULL; LWIO_LOCK_MUTEX(bMutexLocked, &pCcb->FileMutex); pZctCtxLink = PvfsListTraverse(pCcb->pZctContextList, NULL); while (pZctCtxLink) { pZctContext = LW_STRUCT_FROM_FIELD( pZctCtxLink, PVFS_ZCT_CONTEXT, CcbLinks); pNextLink = PvfsListTraverse(pCcb->pZctContextList, pZctCtxLink); PvfsListRemoveItem(pCcb->pZctContextList, pZctCtxLink); pZctCtxLink = pNextLink; PvfsFreeZctContext(&pZctContext); } LWIO_UNLOCK_MUTEX(bMutexLocked, &pCcb->FileMutex); }
static VOID PvfsNotifyFullReportBuffer( PPVFS_FCB pFcb, PPVFS_FCB pReportParentFcb, PPVFS_NOTIFY_REPORT_RECORD pReport ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PLW_LIST_LINKS pFilterLink = NULL; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); for (pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, NULL); pFilterLink; pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, pFilterLink)) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); /* Match the filter and depth */ if ((pFilter->NotifyFilter & pReport->Filter) && ((pFcb == pReportParentFcb) || pFilter->bWatchTree)) { ntError = PvfsNotifyReportBuffer( &pFilter->Buffer, pReport->Action, pReport->pszFilename); break; } } LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); return; }
static VOID PvfsNotifyCleanIrpList( PVOID pContext ) { PPVFS_IRP_CONTEXT pIrpCtx = (PPVFS_IRP_CONTEXT)pContext; PPVFS_FCB pFcb = NULL; BOOLEAN bFcbLocked = FALSE; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; PLW_LIST_LINKS pFilterLink = NULL; PLW_LIST_LINKS pNextLink = NULL; BOOLEAN bFound = FALSE; LWIO_ASSERT(pIrpCtx->pScb->pOwnerFcb); // We have the IrpCtx->Scb's reference so no need to take another pFcb = pIrpCtx->pScb->pOwnerFcb; LWIO_LOCK_MUTEX(bFcbLocked, &pFcb->BaseControlBlock.Mutex); pFilterLink = PvfsListTraverse(pFcb->pNotifyListIrp, NULL); while (pFilterLink) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); pNextLink = PvfsListTraverse(pFcb->pNotifyListIrp, pFilterLink); if (pFilter->pIrpContext != pIrpCtx) { pFilterLink = pNextLink; continue; } bFound = TRUE; PvfsListRemoveItem(pFcb->pNotifyListIrp, pFilterLink); pFilterLink = NULL; LWIO_UNLOCK_MUTEX(bFcbLocked, &pFcb->BaseControlBlock.Mutex); pFilter->pIrpContext->pIrp->IoStatusBlock.Status = STATUS_CANCELLED; PvfsCompleteIrpContext(pFilter->pIrpContext); PvfsFreeNotifyRecord(&pFilter); /* Can only be one IrpContext match so we are done */ } LWIO_UNLOCK_MUTEX(bFcbLocked, &pFcb->BaseControlBlock.Mutex); if (!bFound) { pIrpCtx->pIrp->IoStatusBlock.Status = STATUS_CANCELLED; PvfsCompleteIrpContext(pIrpCtx); } if (pIrpCtx) { PvfsReleaseIrpContext(&pIrpCtx); } return; }
static VOID PvfsNotifyFullReportIrp( PPVFS_FCB pFcb, PPVFS_FCB pReportParentFcb, PPVFS_NOTIFY_REPORT_RECORD pReport ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PLW_LIST_LINKS pFilterLink = NULL; PLW_LIST_LINKS pNextLink = NULL; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; BOOLEAN bActive = FALSE; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); pFilterLink = PvfsListTraverse(pFcb->pNotifyListIrp, NULL); while(pFilterLink) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); pNextLink = PvfsListTraverse(pFcb->pNotifyListIrp, pFilterLink); /* Continue if we don't match the filter and depth */ if (!((pFilter->NotifyFilter & pReport->Filter) && ((pFcb == pReportParentFcb) || pFilter->bWatchTree))) { pFilter = NULL; pFilterLink = pNextLink; continue; } PvfsListRemoveItem(pFcb->pNotifyListIrp, pFilterLink); LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); pFilterLink = NULL; PvfsQueueCancelIrpIfRequested(pFilter->pIrpContext); bActive = PvfsIrpContextMarkIfNotSetFlag( pFilter->pIrpContext, PVFS_IRP_CTX_FLAG_CANCELLED, PVFS_IRP_CTX_FLAG_ACTIVE); if (!bActive) { PvfsFreeNotifyRecord(&pFilter); pFilterLink = pNextLink; continue; } ntError = PvfsNotifyReportIrp( pFilter->pIrpContext, pReport->Action, pReport->pszFilename); BAIL_ON_NT_STATUS(ntError); /* If we have been asked to buffer changes, move the Fitler Record to the buffer list */ if (pFilter->Buffer.Length > 0) { LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); ntError = PvfsListAddTail(pFcb->pNotifyListBuffer, pFilterLink); LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); BAIL_ON_NT_STATUS(ntError); pFilter = NULL; } /* We only process on matching IRP */ break; } cleanup: LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); if (pFilter) { PvfsFreeNotifyRecord(&pFilter); } return; error: goto cleanup; }
static NTSTATUS PvfsNotifyReportBufferedChanges( PPVFS_CCB pCcb, PPVFS_FCB pFcb, PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; FILE_NOTIFY_CHANGE Filter = pIrpContext->pIrp->Args.ReadDirectoryChange.NotifyFilter; PVOID pBuffer = pIrpContext->pIrp->Args.ReadDirectoryChange.Buffer; ULONG Length = pIrpContext->pIrp->Args.ReadDirectoryChange.Length; PLW_LIST_LINKS pFilterLink = NULL; PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL; BOOLEAN bLocked = FALSE; LWIO_LOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); /* See if we have any changes to report immediately */ for (pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, NULL); pFilterLink; pFilterLink = PvfsListTraverse(pFcb->pNotifyListBuffer, pFilterLink)) { pFilter = LW_STRUCT_FROM_FIELD( pFilterLink, PVFS_NOTIFY_FILTER_RECORD, NotifyList); /* To return the buffered changes, we have to match the handle and the filter */ if ((pFilter->NotifyFilter != Filter) || (pFilter->pCcb != pCcb)) { continue; } /* We have a match to check to see if we have anything */ if ((pFilter->Buffer.Length == 0) || (pFilter->Buffer.Offset == 0)) { ntError = STATUS_NOT_FOUND; BAIL_ON_NT_STATUS(ntError); } /* We have changes....Do we have enough space? Have we already overflowed the buffer? */ ntError = pFilter->Buffer.Status; BAIL_ON_NT_STATUS(ntError); if (pFilter->Buffer.Offset > Length) { PvfsNotifyClearBufferedChanges(&pFilter->Buffer); ntError = STATUS_NOTIFY_ENUM_DIR; BAIL_ON_NT_STATUS(ntError); } memcpy(pBuffer, pFilter->Buffer.pData, pFilter->Buffer.Offset); pIrpContext->pIrp->IoStatusBlock.BytesTransferred = pFilter->Buffer.Offset; PvfsNotifyClearBufferedChanges(&pFilter->Buffer); } if (pFilterLink == NULL) { ntError = STATUS_NOT_FOUND; BAIL_ON_NT_STATUS(ntError); } cleanup: LWIO_UNLOCK_MUTEX(bLocked, &pFcb->BaseControlBlock.Mutex); return ntError; error: goto cleanup; }
NTSTATUS PvfsRemoveStreamObjects( IN PPVFS_FCB pFcb ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN scbBucketLocked = FALSE; BOOLEAN scbLocked = FALSE; PLW_LIST_LINKS scbCursorLink = NULL; PPVFS_SCB scbCursor = NULL; PPVFS_FILE_NAME streamName = NULL; PSTR fullStreamName = NULL; PPVFS_CB_TABLE_ENTRY scbCursorBucket = NULL; for (scbCursorLink = PvfsListTraverse(pFcb->pScbList, NULL); scbCursorLink; scbCursorLink = PvfsListTraverse(pFcb->pScbList, scbCursorLink)) { scbCursor = LW_STRUCT_FROM_FIELD( scbCursorLink, PVFS_SCB, FcbList); LWIO_ASSERT(scbCursor->OpenHandleCount == 0); status = PvfsAllocateFileNameFromScb(&streamName, scbCursor); BAIL_ON_NT_STATUS(status); status = PvfsAllocateCStringFromFileName(&fullStreamName, streamName); BAIL_ON_NT_STATUS(status); LWIO_LOCK_MUTEX(scbLocked, &scbCursor->BaseControlBlock.Mutex); scbCursorBucket = scbCursor->BaseControlBlock.pBucket; LWIO_LOCK_RWMUTEX_EXCLUSIVE(scbBucketLocked, &scbCursorBucket->rwLock); status = PvfsCbTableRemove_inlock( (PPVFS_CONTROL_BLOCK)scbCursor, fullStreamName); LWIO_ASSERT(STATUS_SUCCESS == status); LWIO_UNLOCK_RWMUTEX(scbBucketLocked, &scbCursorBucket->rwLock); LWIO_UNLOCK_MUTEX(scbLocked, &scbCursor->BaseControlBlock.Mutex); if (streamName) { PvfsFreeFileName(streamName); streamName = NULL; } if (fullStreamName) { LwRtlCStringFree(&fullStreamName); } } error: LWIO_UNLOCK_RWMUTEX(scbBucketLocked, &scbCursorBucket->rwLock); LWIO_UNLOCK_MUTEX(scbLocked, &scbCursor->BaseControlBlock.Mutex); if (streamName) { PvfsFreeFileName(streamName); } if (fullStreamName) { LwRtlCStringFree(&fullStreamName); } return status; }
static NTSTATUS PvfsRenameFile( PPVFS_CCB pCcb, PPVFS_FILE_NAME pNewFileName ) { NTSTATUS ntError = STATUS_SUCCESS; PPVFS_CB_TABLE scbTable = &gPvfsDriverState.ScbTable; PPVFS_CB_TABLE_ENTRY pTargetBucket = NULL; PPVFS_CB_TABLE_ENTRY pCurrentBucket = NULL; BOOLEAN renameLock = FALSE; BOOLEAN targetBucketLock = FALSE; BOOLEAN currentBucketLock = FALSE; PPVFS_FCB pFcb = NULL; PLW_LIST_LINKS scbCursorLink = NULL; PPVFS_SCB scbCursor = NULL; BOOLEAN scbMutexLock = FALSE; BOOLEAN fcbListLocked = FALSE; PPVFS_FILE_NAME origTargetFileName = NULL; PPVFS_FILE_NAME scbCursorFileName = NULL; PSTR origFullStreamName = NULL; PSTR newFullStreamName = NULL; // The CCB holds out reference down the chain so no need to take a new one pFcb = pCcb->pScb->pOwnerFcb; ntError = PvfsAllocateFileNameFromScb(&origTargetFileName, pCcb->pScb); BAIL_ON_NT_STATUS(ntError); LWIO_LOCK_RWMUTEX_EXCLUSIVE(renameLock, &scbTable->rwLock); LWIO_LOCK_RWMUTEX_SHARED(fcbListLocked, &pFcb->rwScbLock); ntError = PvfsRenameFCB(pFcb, pCcb, pNewFileName); BAIL_ON_NT_STATUS(ntError); for (scbCursorLink = PvfsListTraverse(pFcb->pScbList, NULL); scbCursorLink; scbCursorLink = PvfsListTraverse(pFcb->pScbList, scbCursorLink)) { scbCursor = LW_STRUCT_FROM_FIELD( scbCursorLink, PVFS_SCB, FcbList); ntError = PvfsAllocateFileNameFromScb(&scbCursorFileName, scbCursor); BAIL_ON_NT_STATUS(ntError); ntError = PvfsAllocateCStringFromFileName( &newFullStreamName, scbCursorFileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsRenameBaseFileName( scbCursorFileName, PvfsGetCStringBaseFileName(origTargetFileName)); BAIL_ON_NT_STATUS(ntError); ntError = PvfsAllocateCStringFromFileName( &origFullStreamName, scbCursorFileName); BAIL_ON_NT_STATUS(ntError); pCurrentBucket = scbCursor->BaseControlBlock.pBucket; ntError = PvfsCbTableGetBucket(&pTargetBucket, scbTable, newFullStreamName); BAIL_ON_NT_STATUS(ntError); LWIO_LOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex); LWIO_LOCK_RWMUTEX_EXCLUSIVE(currentBucketLock, &pCurrentBucket->rwLock); if (pCurrentBucket != pTargetBucket) { // Will be moved to a new bucket in the table LWIO_LOCK_RWMUTEX_EXCLUSIVE(targetBucketLock, &pTargetBucket->rwLock); } ntError = PvfsCbTableRemove_inlock( (PPVFS_CONTROL_BLOCK)scbCursor, origFullStreamName); LWIO_ASSERT(STATUS_SUCCESS == ntError); ntError = PvfsCbTableAdd_inlock( pTargetBucket, newFullStreamName, (PPVFS_CONTROL_BLOCK)scbCursor); if (STATUS_SUCCESS != ntError) { LWIO_LOG_ERROR( "Failed to rename stream \"%s\" (%s)\n", newFullStreamName, LwNtStatusToName(ntError)); } LWIO_UNLOCK_RWMUTEX(targetBucketLock, &pTargetBucket->rwLock); LWIO_UNLOCK_RWMUTEX(currentBucketLock, &pCurrentBucket->rwLock); LWIO_UNLOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex); if (origFullStreamName) { LwRtlCStringFree(&origFullStreamName); } if (newFullStreamName) { LwRtlCStringFree(&newFullStreamName); } } error: LWIO_UNLOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex); LWIO_UNLOCK_RWMUTEX(targetBucketLock, &pTargetBucket->rwLock); LWIO_UNLOCK_RWMUTEX(currentBucketLock, &pCurrentBucket->rwLock); LWIO_UNLOCK_RWMUTEX(fcbListLocked, &pFcb->rwScbLock); LWIO_UNLOCK_RWMUTEX(renameLock, &scbTable->rwLock); if (origTargetFileName) { PvfsFreeFileName(origTargetFileName); } if (origFullStreamName) { LwRtlCStringFree(&origFullStreamName); } if (newFullStreamName) { LwRtlCStringFree(&newFullStreamName); } return ntError; }