NTSTATUS bus_plugin_dev(ioctl_usbvbus_plugin * plugin, PFDO_DEVICE_DATA fdodata, PFILE_OBJECT fo) { PDEVICE_OBJECT pdo; PPDO_DEVICE_DATA pdodata, old_pdodata; NTSTATUS status; ULONG len; PLIST_ENTRY entry; unsigned long i; PAGED_CODE (); Bus_KdPrint (fdodata, BUS_DBG_PNP_INFO, ("Exposing PDO\n" "======addr: %d\n" "======vendor:product: %04x:%04x\n", plugin->addr, plugin->vendor, plugin->product)); if(plugin->addr <= 0) return STATUS_INVALID_PARAMETER; ExAcquireFastMutex (&fdodata->Mutex); for (entry = fdodata->ListOfPDOs.Flink; entry != &fdodata->ListOfPDOs; entry = entry->Flink) { pdodata = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if (plugin->addr == pdodata->SerialNo && pdodata->DevicePnPState != SurpriseRemovePending) { ExReleaseFastMutex (&fdodata->Mutex); return STATUS_INVALID_PARAMETER; } } ExReleaseFastMutex (&fdodata->Mutex); // Create the PDO // Bus_KdPrint(fdodata, BUS_DBG_PNP_NOISE, ("fdodata->NextLowerDriver = 0x%p\n", fdodata->NextLowerDriver)); // // PDO must have a name. You should let the system auto generate a // name by specifying FILE_AUTOGENERATED_DEVICE_NAME in the // DeviceCharacteristics parameter. Let us create a secure deviceobject, // in case the child gets installed as a raw device (RawDeviceOK), to prevent // an unpriviledged user accessing our device. This function is avaliable // in a static WDMSEC.LIB and can be used in Win2k, XP, and Server 2003 // Just make sure that the GUID specified here is not a setup class GUID. // If you specify a setup class guid, you must make sure that class is // installed before enumerating the PDO. // status = IoCreateDeviceSecure(fdodata->Self->DriverObject, sizeof (PDO_DEVICE_DATA), NULL, FILE_DEVICE_BUS_EXTENDER, FILE_AUTOGENERATED_DEVICE_NAME |FILE_DEVICE_SECURE_OPEN, FALSE, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX, // allow normal users to access the devices (LPCGUID)&GUID_SD_BUSENUM_PDO, &pdo); if (!NT_SUCCESS (status)) { return status; } pdodata = (PPDO_DEVICE_DATA) pdo->DeviceExtension; #define HARDWARE_IDS_TPL L"USB\\Vid_%04x&Pid_%04x&Rev_%04xZUSB\\Vid_%04x&Pid_%04xZ" len = sizeof(HARDWARE_IDS_TPL); pdodata->HardwareIDs = ExAllocatePoolWithTag (NonPagedPool, len, BUSENUM_POOL_TAG); if (NULL == pdodata->HardwareIDs) { IoDeleteDevice(pdo); return STATUS_INSUFFICIENT_RESOURCES; } RtlStringCchPrintfW(pdodata->HardwareIDs, len/sizeof(wchar_t), HARDWARE_IDS_TPL, plugin->vendor, plugin->product, plugin->version, plugin->vendor, plugin->product); for(i=0;i<len/sizeof(wchar_t);i++){ if('Z'==pdodata->HardwareIDs[i]) pdodata->HardwareIDs[i]=0; } #define COMPATIBLE_IDS_TPL L"USB\\Class_%02x&SubClass_%02x&Prot_%02xZUSB\\Class_%02x&SubClass_%02xZUSB\\Class_%02xZ" #define COMPATIBLE_COMPOSITE_IDS_TPL L"USB\\Class_%02x&SubClass_%02x&Prot_%02xZUSB\\Class_%02x&SubClass_%02xZUSB\\Class_%02xZUSB\\COMPOSITEZ" if(plugin->inum>1) len = sizeof(COMPATIBLE_COMPOSITE_IDS_TPL); else len = sizeof(COMPATIBLE_IDS_TPL); pdodata->compatible_ids = ExAllocatePoolWithTag (NonPagedPool, len, BUSENUM_POOL_TAG); if (NULL == pdodata->compatible_ids) { ExFreePool(pdodata->HardwareIDs); IoDeleteDevice(pdo); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(pdodata->compatible_ids, len); pdodata->compatible_ids_len = len; RtlStringCchPrintfW(pdodata->compatible_ids, len/sizeof(wchar_t), (plugin->inum>1)?COMPATIBLE_COMPOSITE_IDS_TPL:COMPATIBLE_IDS_TPL, plugin->int0_class, plugin->int0_subclass, plugin->int0_protocol, plugin->int0_class, plugin->int0_subclass, plugin->int0_class); for(i=0;i<len/sizeof(wchar_t);i++){ if('Z'==pdodata->compatible_ids[i]) pdodata->compatible_ids[i]=0; } old_pdodata = (PPDO_DEVICE_DATA) InterlockedCompareExchangePointer(&(fo->FsContext), pdodata, 0); if(old_pdodata){ KdPrint(("you can't plugin again")); ExFreePool(pdodata->HardwareIDs); ExFreePool(pdodata->compatible_ids); IoDeleteDevice(pdo); return STATUS_INVALID_PARAMETER; } pdodata->SerialNo = plugin->addr; pdodata->fo = fo; pdodata->devid = plugin->devid; pdodata->speed = plugin->speed; bus_init_pdo (pdo, fdodata); // // Device Relation changes if a new pdo is created. So let // the PNP system now about that. This forces it to send bunch of pnp // queries and cause the function driver to be loaded. // IoInvalidateDeviceRelations (fdodata->UnderlyingPDO, BusRelations); return status; }
// for pdo NTSTATUS DoPdoPnP(PDEVICE_OBJECT pDevice,PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; PPdoExt pPdoExt = static_cast<PPdoExt>(pDevice->DeviceExtension); PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(pIrp); switch(pIoStack->MinorFunction) { case IRP_MN_START_DEVICE: // set power state pPdoExt->m_devPowerState = PowerDeviceD0; POWER_STATE state; state.DeviceState = PowerDeviceD0; PoSetPowerState(pDevice,DevicePowerState,state); // set pnp state directly case IRP_MN_STOP_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: case IRP_MN_QUERY_REMOVE_DEVICE: SetNewPnpState(pPdoExt,pIoStack->MinorFunction); break; // check prev state case IRP_MN_CANCEL_REMOVE_DEVICE: if(pPdoExt->m_ulCurrentPnpState == IRP_MN_QUERY_REMOVE_DEVICE) { RestorePnpState(pPdoExt); } break; // the same case IRP_MN_CANCEL_STOP_DEVICE: if(pPdoExt->m_ulCurrentPnpState == IRP_MN_QUERY_STOP_DEVICE) { RestorePnpState(pPdoExt); } break; // remove case IRP_MN_REMOVE_DEVICE: { // delete only if we have reported the device physical removal if(pPdoExt->m_bReportMissing) { SetNewPnpState(pPdoExt,IRP_MN_REMOVE_DEVICE); PDEVICE_OBJECT pFdo = pPdoExt->m_pParentFdo; if(pFdo) { PFdoExt pFdoExt = static_cast<PFdoExt>(pFdo->DeviceExtension); // update fdo's pointer ExAcquireFastMutex(&pFdoExt->m_mutexEnumPdo); pFdoExt->m_pEnumPdo = NULL; ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); } // delete device IoDeleteDevice(pDevice); } // if it's present if(pPdoExt->m_bPresent) { // set it as stopped SetNewPnpState(pPdoExt,IRP_MN_STOP_DEVICE); } } break; // query caps case IRP_MN_QUERY_CAPABILITIES: { PDEVICE_CAPABILITIES pCaps = pIoStack->Parameters.DeviceCapabilities.Capabilities; // version check if(pCaps->Version != 1 || pCaps->Size < sizeof(DEVICE_CAPABILITIES)) { status = STATUS_UNSUCCESSFUL; break; } IO_STATUS_BLOCK ioStatus; KEVENT pnpEvent; PDEVICE_OBJECT pTargetObject; PIO_STACK_LOCATION pIrpStack; PIRP pPnpIrp; DEVICE_CAPABILITIES parentCaps; RtlZeroMemory(&parentCaps,sizeof(DEVICE_CAPABILITIES)); parentCaps.Size = sizeof(DEVICE_CAPABILITIES); parentCaps.Version = 1; parentCaps.Address = -1; parentCaps.UINumber = -1; KeInitializeEvent(&pnpEvent,NotificationEvent,FALSE); pTargetObject = IoGetAttachedDeviceReference( static_cast<PFdoExt>(pPdoExt->m_pParentFdo->DeviceExtension)->m_pLowerDevice); // get parent fdo's caps pPnpIrp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,pTargetObject,NULL,0,NULL,&pnpEvent,&ioStatus); if(pPnpIrp == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; } else { pPnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; pIrpStack = IoGetNextIrpStackLocation(pPnpIrp); RtlZeroMemory(pIrpStack,sizeof(IO_STACK_LOCATION)); pIrpStack->MajorFunction = IRP_MJ_PNP; pIrpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES; pIrpStack->Parameters.DeviceCapabilities.Capabilities = pCaps; status = IoCallDriver(pTargetObject,pPnpIrp); if (status == STATUS_PENDING) { KeWaitForSingleObject(&pnpEvent,Executive,KernelMode,FALSE,NULL); status = ioStatus.Status; } } // dec the ref of the fdo's stack upper device ObDereferenceObject(pTargetObject); // copy the device state RtlCopyMemory(pCaps->DeviceState,parentCaps.DeviceState,(PowerSystemShutdown + 1) * sizeof(DEVICE_POWER_STATE)); // set our own supported device state pCaps->DeviceState[PowerSystemWorking] = PowerDeviceD0; if(pCaps->DeviceState[PowerSystemSleeping1] != PowerDeviceD0) pCaps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3; if(pCaps->DeviceState[PowerSystemSleeping2] != PowerDeviceD0) pCaps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3; if(pCaps->DeviceState[PowerSystemSleeping3] != PowerDeviceD0) pCaps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3; // donot support d1 and d2 pCaps->DeviceD1 = pCaps->DeviceD2 = FALSE; // no wake pCaps->DeviceWake = PowerDeviceUnspecified; pCaps->SystemWake = PowerSystemUnspecified; pCaps->WakeFromD0 = FALSE; pCaps->WakeFromD1 = FALSE; pCaps->WakeFromD2 = FALSE; pCaps->WakeFromD3 = FALSE; // no latency pCaps->D1Latency = 0; pCaps->D2Latency = 0; pCaps->D3Latency = 0; // can eject pCaps->EjectSupported = TRUE; // don't disable pCaps->HardwareDisabled = FALSE; // can be removed pCaps->Removable = TRUE; // don't display surprise remove warning dlg pCaps->SurpriseRemovalOK = TRUE; // no unique id pCaps->UniqueID = FALSE; // nead user action for install pCaps->SilentInstall = FALSE; // bus address pCaps->Address = 0; // ui display number pCaps->UINumber = 0; } break; // query pdo id case IRP_MN_QUERY_ID: { switch(pIoStack->Parameters.QueryId.IdType) { case BusQueryInstanceID: { PVOID buffer = ExAllocatePoolWithTag(PagedPool,10,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlStringCchPrintfW(static_cast<PWCHAR>(buffer),10,L"%04d",0); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tBusQueryInstanceID\n"); } break; case BusQueryDeviceID: { PVOID buffer = ExAllocatePoolWithTag(PagedPool,PDO_DEVICE_ID_LENGTH,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory(buffer,PDO_DEVICE_ID,PDO_DEVICE_ID_LENGTH); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tBusQueryDeviceID\n"); } break; case BusQueryHardwareIDs: { PVOID buffer = ExAllocatePoolWithTag(PagedPool,PDO_HARDWARE_IDS_LENGTH,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory(buffer,PDO_HARDWARE_IDS,PDO_HARDWARE_IDS_LENGTH); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tBusQueryHardwareIDs\n"); } break; case BusQueryCompatibleIDs: { PVOID buffer = ExAllocatePoolWithTag(PagedPool,PDO_COMPATIBLE_IDS_LENGTH,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlCopyMemory(buffer,PDO_COMPATIBLE_IDS,PDO_COMPATIBLE_IDS_LENGTH); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tBusQueryCompatibleIDs\n"); } break; } } break; // query text case IRP_MN_QUERY_DEVICE_TEXT: { switch (pIoStack->Parameters.QueryDeviceText.DeviceTextType) { case DeviceTextDescription: if(!pIrp->IoStatus.Information) { PVOID buffer = ExAllocatePoolWithTag (PagedPool,PDO_TEXT_LENGTH,'suBT'); if(!buffer) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlStringCchPrintfW(static_cast<PWCHAR>(buffer),PDO_TEXT_LENGTH,L"%ws",PDO_TEXT); pIrp->IoStatus.Information = PtrToUlong(buffer); devDebugPrint("\tDeviceTextDescription\n"); } break; default: status = pIrp->IoStatus.Status; break; } } break; // boot resource case IRP_MN_QUERY_RESOURCES: { PCM_RESOURCE_LIST pResList = static_cast<PCM_RESOURCE_LIST>(ExAllocatePoolWithTag(PagedPool, sizeof(CM_RESOURCE_LIST),'suBT')); if(pResList) { // shareed busnumber resource RtlZeroMemory(pResList,sizeof(CM_RESOURCE_LIST)); pResList->Count = 1; pResList->List[0].BusNumber = 0; pResList->List[0].InterfaceType = Internal; pResList->List[0].PartialResourceList.Count = 1; pResList->List[0].PartialResourceList.Revision = 1; pResList->List[0].PartialResourceList.Version = 1; pResList->List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareShared; pResList->List[0].PartialResourceList.PartialDescriptors[0].Type = CmResourceTypeBusNumber; pResList->List[0].PartialResourceList.PartialDescriptors[0].u.BusNumber.Length = 1; pIrp->IoStatus.Information = PtrToUlong(pResList); } else { status = STATUS_INSUFFICIENT_RESOURCES; } } break; // resource requirements case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: { PIO_RESOURCE_REQUIREMENTS_LIST pList = static_cast<PIO_RESOURCE_REQUIREMENTS_LIST>( ExAllocatePoolWithTag(PagedPool,sizeof(IO_RESOURCE_REQUIREMENTS_LIST),'suBT')); if(pList) { RtlZeroMemory(pList,sizeof(IO_RESOURCE_REQUIREMENTS_LIST)); pList->ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); pList->AlternativeLists = 1; pList->InterfaceType = InterfaceTypeUndefined; pList->BusNumber = 0; pList->List[0].Version = 1; pList->List[0].Revision = 1; pList->List[0].Count = 1; pList->List[0].Descriptors[0].Option = IO_RESOURCE_PREFERRED; pList->List[0].Descriptors[0].ShareDisposition = CmResourceShareShared; pList->List[0].Descriptors[0].Type = CmResourceTypeBusNumber; pList->List[0].Descriptors[0].u.BusNumber.MaxBusNumber = 0x10; pList->List[0].Descriptors[0].u.BusNumber.Length = 1; pIrp->IoStatus.Information = PtrToUlong(pList); } else { status = STATUS_INSUFFICIENT_RESOURCES; } } break; // bus info case IRP_MN_QUERY_BUS_INFORMATION: { PPNP_BUS_INFORMATION busInfo; busInfo = static_cast<PPNP_BUS_INFORMATION>(ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION),'suBT')); if (busInfo == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } busInfo->BusTypeGuid = GUID_TIAMO_BUS; busInfo->LegacyBusType = Internal; busInfo->BusNumber = 0; pIrp->IoStatus.Information = PtrToUlong(busInfo); } break; // usage case IRP_MN_DEVICE_USAGE_NOTIFICATION: status = STATUS_UNSUCCESSFUL; break; case IRP_MN_EJECT: { // device physical removed pPdoExt->m_bPresent = FALSE; } break; //case IRP_MN_QUERY_INTERFACE: // break; // target relations case IRP_MN_QUERY_DEVICE_RELATIONS: { if(pIoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) { /*switch(pIoStack->Parameters.QueryDeviceRelations.Type) { case EjectionRelations: devDebugPrint("\tquery EjectionRelations\n"); break; case PowerRelations: devDebugPrint("\tquery PowerRelations\n"); break; case RemovalRelations: devDebugPrint("\tquery RemovalRelations\n"); break; case BusDeviceRelation: devDebugPrint("\tquery BusDeviceRelation\n"); break; case SingleBusRelations: devDebugPrint("\tquery SingleBusRelations\n"); break; }*/ break; } PDEVICE_RELATIONS pRel = static_cast<PDEVICE_RELATIONS>(ExAllocatePoolWithTag(PagedPool,sizeof(DEVICE_RELATIONS),'suBT')); if(!pRel) { status = STATUS_INSUFFICIENT_RESOURCES; break; } pRel->Count = 1; pRel->Objects[0] = pDevice; ObReferenceObject(pDevice); status = STATUS_SUCCESS; pIrp->IoStatus.Information = PtrToUlong(pRel); } break; default: status = pIrp->IoStatus.Status; break; } // pdo should complete the irp pIrp->IoStatus.Status = status; IoCompleteRequest (pIrp, IO_NO_INCREMENT); return status; }
NTSTATUS SecondaryRecoverySession ( IN PSECONDARY Secondary ) { NTSTATUS status; LONG slotIndex; LARGE_INTEGER timeOut; OBJECT_ATTRIBUTES objectAttributes; ULONG reconnectionTry; PLIST_ENTRY ccblistEntry; BOOLEAN isLocalAddress; SetFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); ASSERT( FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ); ASSERT( Secondary->ThreadHandle ); ASSERT( IsListEmpty(&Secondary->RequestQueue) ); for (slotIndex=0; slotIndex < Secondary->Thread.SessionContext.SessionSlotCount; slotIndex++) { ASSERT( Secondary->Thread.SessionSlot[slotIndex] == NULL ); } if (Secondary->ThreadHandle) { ASSERT( Secondary->ThreadObject ); timeOut.QuadPart = -NDASNTFS_TIME_OUT; status = KeWaitForSingleObject( Secondary->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if(status != STATUS_SUCCESS) { ASSERT( NDASNTFS_BUG ); return status; } DebugTrace( 0, Dbg2, ("Secondary_Stop: thread stoped\n") ); ObDereferenceObject( Secondary->ThreadObject ); Secondary->ThreadHandle = 0; Secondary->ThreadObject = 0; RtlZeroMemory( &Secondary->Thread.Flags, sizeof(SECONDARY) - FIELD_OFFSET(SECONDARY, Thread.Flags) ); } for (status = STATUS_UNSUCCESSFUL, reconnectionTry = 0; reconnectionTry < MAX_RECONNECTION_TRY; reconnectionTry++) { if (FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_TARGET_DEVICE_STOPPED)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_FLAG_SHUTDOWN)) { ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (FlagOn(Secondary->VolDo->NdasNtfsFlags, NDAS_NTFS_DEVICE_FLAG_SHUTDOWN)) { //DebugTrace( 0, Dbg2, ("SecondaryToPrimary NDAS_NTFS_DEVICE_FLAG_SHUTDOWN\n") ); //DbgPrint( "SecondaryToPrimary NDAS_NTFS_DEVICE_FLAG_SHUTDOWN\n" ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } if (Secondary->VolDo->NetdiskEnableMode == NETDISK_SECONDARY2PRIMARY) { status = STATUS_SUCCESS; } else { status = ((PVOLUME_DEVICE_OBJECT) NdasNtfsFileSystemDeviceObject)-> NdfsCallback.SecondaryToPrimary( Secondary->VolDo->Vcb.Vpb->RealDevice, TRUE ); if (status == STATUS_NO_SUCH_DEVICE) { NDASNTFS_ASSERT( FlagOn(Secondary->VolDo->Vcb.VcbState, VCB_STATE_TARGET_DEVICE_STOPPED) ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); return STATUS_UNSUCCESSFUL; } } //NtfsDebugTraceLevel = 0; DebugTrace( 0, Dbg2, ("SecondaryToPrimary status = %x\n", status) ); if (status == STATUS_SUCCESS) { PVCB vcb = &Secondary->VolDo->Vcb; TOP_LEVEL_CONTEXT topLevelContext; PTOP_LEVEL_CONTEXT threadTopLevelContext; PIRP_CONTEXT tempIrpContext = NULL; SetFlag( Secondary->Flags, SECONDARY_FLAG_CLEANUP_VOLUME ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->Resource) ); DebugTrace( 0, Dbg2, ("Vcb->State = %X\n", vcb->VcbState) ); DebugTrace( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); tempIrpContext = NULL; threadTopLevelContext = NtfsInitializeTopLevelIrp( &topLevelContext, TRUE, FALSE ); ASSERT( threadTopLevelContext == &topLevelContext ); NtfsInitializeIrpContext( NULL, TRUE, &tempIrpContext ); NtfsUpdateIrpContextWithTopLevel( tempIrpContext, threadTopLevelContext ); SetFlag( tempIrpContext->NdasNtfsFlags, NDAS_NTFS_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); ASSERT( FlagOn(tempIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL) ); tempIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; tempIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->Vcb = vcb; try { status = CleanUpVcb( tempIrpContext, vcb ); } finally { NtfsCompleteRequest( tempIrpContext, NULL, 0 ); ASSERT( IoGetTopLevelIrp() != (PIRP) &topLevelContext ); tempIrpContext = NULL; } ASSERT( status == STATUS_SUCCESS ); ASSERT( FlagOn(vcb->VcbState, VCB_STATE_MOUNT_COMPLETED) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->Resource) ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_CLEANUP_VOLUME ); DebugTrace( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->CloseCount = %d\n", vcb->CloseCount) ); Secondary->VolDo->NetdiskEnableMode = NETDISK_SECONDARY2PRIMARY; tempIrpContext = NULL; threadTopLevelContext = NtfsInitializeTopLevelIrp( &topLevelContext, TRUE, FALSE ); ASSERT( threadTopLevelContext == &topLevelContext ); NtfsInitializeIrpContext( NULL, TRUE, &tempIrpContext ); NtfsUpdateIrpContextWithTopLevel( tempIrpContext, threadTopLevelContext ); ASSERT( FlagOn(tempIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL) ); //tempIrpContext->TopLevelIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; //tempIrpContext->TopLevelIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; tempIrpContext->MinorFunction = IRP_MN_MOUNT_VOLUME; tempIrpContext->Vcb = vcb; try { status = NdasNtfsMountVolume( tempIrpContext, vcb ); } finally { NtfsCompleteRequest( tempIrpContext, NULL, 0 ); ASSERT( IoGetTopLevelIrp() != (PIRP) &topLevelContext ); tempIrpContext = NULL; } NDASNTFS_ASSERT( status == STATUS_SUCCESS ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&NtfsData.Resource) ); ASSERT( !ExIsResourceAcquiredExclusiveLite(&vcb->Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(&vcb->Resource) ); DebugTrace( 0, Dbg2, ("Vcb->TargetDeviceObject->ReferenceCount = %X\n", vcb->TargetDeviceObject->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->Vpb->ReferenceCount = %X\n", vcb->Vpb->ReferenceCount) ); DebugTrace( 0, Dbg2, ("Vcb->CloseCount = %d\n", vcb->CloseCount) ); if (vcb->MftScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->MftScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->MftScb->Header.Resource) ); } if (vcb->Mft2Scb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->Mft2Scb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->Mft2Scb->Header.Resource) ); } if (vcb->LogFileScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->LogFileScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->LogFileScb->Header.Resource) ); } if (vcb->VolumeDasdScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->VolumeDasdScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->VolumeDasdScb->Header.Resource) ); } if (vcb->AttributeDefTableScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->AttributeDefTableScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->AttributeDefTableScb->Header.Resource) ); } if (vcb->UpcaseTableScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->UpcaseTableScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->UpcaseTableScb->Header.Resource) ); } if (vcb->RootIndexScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->RootIndexScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->RootIndexScb->Header.Resource) ); } if (vcb->BitmapScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->BitmapScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->BitmapScb->Header.Resource) ); } if (vcb->BadClusterFileScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->BadClusterFileScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->BadClusterFileScb->Header.Resource) ); } if (vcb->MftBitmapScb) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->MftBitmapScb->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->MftBitmapScb->Header.Resource) ); } if (vcb->SecurityDescriptorStream) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->SecurityDescriptorStream->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->SecurityDescriptorStream->Header.Resource) ); } if (vcb->UsnJournal) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->UsnJournal->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->UsnJournal->Header.Resource) ); } if (vcb->ExtendDirectory) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->ExtendDirectory->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->ExtendDirectory->Header.Resource) ); } if (vcb->SecurityDescriptorHashIndex) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->SecurityDescriptorHashIndex->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->SecurityDescriptorHashIndex->Header.Resource) ); } if (vcb->SecurityIdIndex) { ASSERT( !ExIsResourceAcquiredExclusiveLite(vcb->SecurityIdIndex->Header.Resource) ); ASSERT( !ExIsResourceAcquiredSharedLite(vcb->SecurityIdIndex->Header.Resource) ); } } status = ((PVOLUME_DEVICE_OBJECT) NdasNtfsFileSystemDeviceObject)-> NdfsCallback.QueryPrimaryAddress( &Secondary->VolDo->NetdiskPartitionInformation, &Secondary->PrimaryAddress, &isLocalAddress ); DebugTrace( 0, Dbg2, ("RecoverSession: LfsTable_QueryPrimaryAddress status = %X\n", status) ); if (status == STATUS_SUCCESS && !(Secondary->VolDo->NetdiskEnableMode == NETDISK_SECONDARY && isLocalAddress)) { DebugTrace( 0, Dbg, ("SessionRecovery: Found PrimaryAddress :%02x:%02x:%02x:%02x:%02x:%02x/%d\n", Secondary->PrimaryAddress.Node[0], Secondary->PrimaryAddress.Node[1], Secondary->PrimaryAddress.Node[2], Secondary->PrimaryAddress.Node[3], Secondary->PrimaryAddress.Node[4], Secondary->PrimaryAddress.Node[5], NTOHS(Secondary->PrimaryAddress.Port)) ); } else { continue; } KeInitializeEvent( &Secondary->ReadyEvent, NotificationEvent, FALSE ); KeInitializeEvent( &Secondary->RequestEvent, NotificationEvent, FALSE ); InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); status = PsCreateSystemThread( &Secondary->ThreadHandle, THREAD_ALL_ACCESS, &objectAttributes, NULL, NULL, SecondaryThreadProc, Secondary ); if (!NT_SUCCESS(status)) { ASSERT( NDASNTFS_UNEXPECTED ); break; } status = ObReferenceObjectByHandle( Secondary->ThreadHandle, FILE_READ_DATA, NULL, KernelMode, &Secondary->ThreadObject, NULL ); if (!NT_SUCCESS(status)) { ASSERT( NDASNTFS_INSUFFICIENT_RESOURCES ); break; } timeOut.QuadPart = -NDASNTFS_TIME_OUT; status = KeWaitForSingleObject( &Secondary->ReadyEvent, Executive, KernelMode, FALSE, &timeOut ); if(status != STATUS_SUCCESS) { ASSERT( NDASNTFS_BUG ); break; } KeClearEvent( &Secondary->ReadyEvent ); InterlockedIncrement( &Secondary->SessionId ); ExAcquireFastMutex( &Secondary->FastMutex ); if (!FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_START) || FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_STOPED)) { ExReleaseFastMutex( &Secondary->FastMutex ); if(Secondary->Thread.SessionStatus == STATUS_DISK_CORRUPT_ERROR) { status = STATUS_SUCCESS; break; } timeOut.QuadPart = -NDASNTFS_TIME_OUT; status = KeWaitForSingleObject( Secondary->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if(status != STATUS_SUCCESS) { ASSERT( NDASNTFS_BUG ); return status; } DebugTrace( 0, Dbg, ("Secondary_Stop: thread stoped\n") ); ObDereferenceObject( Secondary->ThreadObject ); Secondary->ThreadHandle = 0; Secondary->ThreadObject = 0; RtlZeroMemory( &Secondary->Thread.Flags, sizeof(SECONDARY) - FIELD_OFFSET(SECONDARY, Thread.Flags) ); continue; } ExReleaseFastMutex( &Secondary->FastMutex ); status = STATUS_SUCCESS; DebugTrace( 0, Dbg2, ("SessionRecovery Success Secondary = %p\n", Secondary) ); break; }
VOID SecondaryTryClose ( IN PSECONDARY Secondary ) { PIRP_CONTEXT irpContext; BOOLEAN secondaryResourceAcquired = FALSE; BOOLEAN acquiredVcb = FALSE; BOOLEAN wait; irpContext = FatAllocateIrpContext(); if (irpContext == NULL) { return; } DebugTrace2( 0, Dbg, ("Secondary_TryCloseFiles start\n") ); try { RtlZeroMemory( irpContext, sizeof(IRP_CONTEXT) ); SetFlag( irpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); SetFlag( irpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); irpContext->Vcb = &Secondary->VolDo->Vcb; secondaryResourceAcquired = SecondaryAcquireResourceSharedLite( irpContext, &Secondary->VolDo->Resource, FALSE ); if (secondaryResourceAcquired == FALSE) { leave; } wait = BooleanFlagOn( irpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); acquiredVcb = FatAcquireExclusiveVcb( irpContext, irpContext->Vcb ); if (acquiredVcb == FALSE) { leave; } FsRtlEnterFileSystem(); FatFspClose( &Secondary->VolDo->Vcb ); FsRtlExitFileSystem(); DebugTrace2( 0, Dbg, ("Secondary_TryCloseFiles FatFspClose, Secondary->VolDo->Vcb.SecondaryOpenCount = %d\n", Secondary->VolDo->Vcb.SecondaryOpenFileCount) ); SetFlag( irpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_TRY_CLOSE_FILES ); Secondary_TryCloseFilExts( Secondary ); } finally { ClearFlag( irpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_TRY_CLOSE_FILES ); if (acquiredVcb) { FatReleaseVcb( irpContext, irpContext->Vcb ); } DebugTrace2( 0, Dbg, ("Secondary_TryCloseFiles exit\n") ); ExAcquireFastMutex( &Secondary->FastMutex ); Secondary->TryCloseActive = FALSE; ExReleaseFastMutex( &Secondary->FastMutex ); if (secondaryResourceAcquired) SecondaryReleaseResourceLite( NULL, &Secondary->VolDo->Resource ); Secondary_Dereference(Secondary); FatFreeIrpContext(irpContext); } return; }
NTSTATUS FatCommonPnp ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for doing PnP operations called by both the fsd and fsp threads Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PVOLUME_DEVICE_OBJECT OurDeviceObject; PVCB Vcb; // // Force everything to wait. // SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); // // Get the current Irp stack location. // IrpSp = IoGetCurrentIrpStackLocation( Irp ); // // Find our Vcb. This is tricky since we have no file object in the Irp. // OurDeviceObject = (PVOLUME_DEVICE_OBJECT) IrpSp->DeviceObject; // // Take the global lock to synchronise against volume teardown. // FatAcquireExclusiveGlobal( IrpContext ); // // Make sure this device object really is big enough to be a volume device // object. If it isn't, we need to get out before we try to reference some // field that takes us past the end of an ordinary device object. // if (OurDeviceObject->DeviceObject.Size != sizeof(VOLUME_DEVICE_OBJECT) || NodeType( &OurDeviceObject->Vcb ) != FAT_NTC_VCB) { // // We were called with something we don't understand. // FatReleaseGlobal( IrpContext ); Status = STATUS_INVALID_PARAMETER; FatCompleteRequest( IrpContext, Irp, Status ); return Status; } #if __NDAS_FAT__ if (OurDeviceObject->NetdiskEnableMode == NETDISK_SECONDARY) SetFlag( IrpContext->NdFatFlags, ND_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); #endif Vcb = &OurDeviceObject->Vcb; // // Case on the minor code. // #if __NDAS_FAT_SECONDARY__ if ( ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Secondary && ( ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode == NETDISK_SECONDARY || ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode == NETDISK_SECONDARY2PRIMARY ) ) { PSECONDARY Secondary = ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Secondary; Status = STATUS_SUCCESS; Secondary_Reference( Secondary ); switch ( IrpSp->MinorFunction ) { case IRP_MN_QUERY_REMOVE_DEVICE: { DebugTrace2( 0, Dbg, ("FatCommonPnp: IRP_MN_QUERY_REMOVE_DEVICE NetdiskEnableMode = %d\n", ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode) ); ExAcquireFastMutex( &Secondary->FastMutex ); if (!Secondary->TryCloseActive) { Secondary->TryCloseActive = TRUE; ExReleaseFastMutex( &Secondary->FastMutex ); Secondary_Reference( Secondary ); //FatDebugTraceLevel |= DEBUG_TRACE_CLOSE; SecondaryTryClose( IrpContext, Secondary ); //FatDebugTraceLevel &= ~DEBUG_TRACE_CLOSE; } else { ExReleaseFastMutex( &Secondary->FastMutex ); } if (Vcb->SecondaryOpenFileCount) { LARGE_INTEGER interval; // Wait all files closed interval.QuadPart = (1 * HZ); //delay 1 seconds KeDelayExecutionThread(KernelMode, FALSE, &interval); } #if 0 if (Vcb->SecondaryOpenFileCount) { LONG ccbCount; PLIST_ENTRY ccbListEntry; PVOID restartKey; PFCB fcb; ExAcquireFastMutex( &Secondary->RecoveryCcbQMutex ); for (ccbCount = 0, ccbListEntry = Secondary->RecoveryCcbQueue.Flink; ccbListEntry != &Secondary->RecoveryCcbQueue; ccbListEntry = ccbListEntry->Flink, ccbCount++); ExReleaseFastMutex( &Secondary->RecoveryCcbQMutex ); ASSERT( !IsListEmpty(&Secondary->RecoveryCcbQueue) ); ASSERT( ccbCount == Vcb->SecondaryOpenFileCount ); DebugTrace2( 0, Dbg, ("IRP_MN_QUERY_REMOVE_DEVICE: Vcb->SecondaryCloseCount = %d, Vcb->CloseCount = %d, ccbCount = %d\n", Vcb->SecondaryOpenFileCount, Vcb->OpenCount, ccbCount) ); restartKey = NULL; fcb = NdFatGetNextFcbTableEntry( &Secondary->VolDo->Vcb, &restartKey ); ASSERT( fcb != NULL || !IsListEmpty(&Secondary->DeletedFcbQueue) ); Status = STATUS_UNSUCCESSFUL; } #endif break; } case IRP_MN_REMOVE_DEVICE: { PVOID restartKey; PFCB fcb; DebugTrace2( 0, Dbg, ("FatCommonPnp: IRP_MN_REMOVE_DEVICE NetdiskEnableMode = %d\n", ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode) ); #if 0 restartKey = NULL; fcb = NdFatGetNextFcbTableEntry( &Secondary->VolDo->Vcb, &restartKey ); ASSERT( fcb == NULL && IsListEmpty(&Secondary->DeletedFcbQueue) ); #endif if (Vcb->SecondaryOpenFileCount) { ASSERT( NDFAT_BUG ); Status = STATUS_UNSUCCESSFUL; } break; } default: { DebugTrace2( 0, Dbg, ("FatCommonPnp: IrpSp-MinorFunction = %d NetdiskEnableMode = %d\n", IrpSp->MinorFunction, ((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->NetdiskEnableMode) ); if (IrpSp->MinorFunction != IRP_MN_QUERY_DEVICE_RELATIONS) { if (IrpSp->FileObject && IS_SECONDARY_FILEOBJECT(IrpSp->FileObject)) { ASSERT( FALSE ); } } Status = STATUS_SUCCESS; break; } } Secondary_Dereference( Secondary ); if (!NT_SUCCESS(Status)) { FatCompleteRequest( NULL, Irp, Status ); return Status; } } #endif switch ( IrpSp->MinorFunction ) { case IRP_MN_QUERY_REMOVE_DEVICE: Status = FatPnpQueryRemove( IrpContext, Irp, Vcb ); break; case IRP_MN_SURPRISE_REMOVAL: Status = FatPnpSurpriseRemove( IrpContext, Irp, Vcb ); break; case IRP_MN_REMOVE_DEVICE: Status = FatPnpRemove( IrpContext, Irp, Vcb ); break; case IRP_MN_CANCEL_REMOVE_DEVICE: Status = FatPnpCancelRemove( IrpContext, Irp, Vcb ); break; default: FatReleaseGlobal( IrpContext ); // // Just pass the IRP on. As we do not need to be in the // way on return, ellide ourselves out of the stack. // IoSkipCurrentIrpStackLocation( Irp ); Status = IoCallDriver(Vcb->TargetDeviceObject, Irp); // // Cleanup our Irp Context. The driver has completed the Irp. // FatCompleteRequest( IrpContext, NULL, STATUS_SUCCESS ); break; } return Status; }
VOID Bus_InitializePdo ( PDEVICE_OBJECT Pdo, PFDO_DEVICE_DATA FdoData ) { PPDO_DEVICE_DATA pdoData; int acpistate; DEVICE_POWER_STATE ntState; PAGED_CODE (); pdoData = (PPDO_DEVICE_DATA) Pdo->DeviceExtension; DPRINT("pdo 0x%p, extension 0x%p\n", Pdo, pdoData); if (pdoData->AcpiHandle) acpi_bus_get_power(pdoData->AcpiHandle, &acpistate); else acpistate = ACPI_STATE_D0; switch(acpistate) { case ACPI_STATE_D0: ntState = PowerDeviceD0; break; case ACPI_STATE_D1: ntState = PowerDeviceD1; break; case ACPI_STATE_D2: ntState = PowerDeviceD2; break; case ACPI_STATE_D3: ntState = PowerDeviceD3; break; default: DPRINT1("Unknown power state (%d) returned by acpi\n",acpistate); ntState = PowerDeviceUnspecified; break; } // // Initialize the rest // pdoData->Common.IsFDO = FALSE; pdoData->Common.Self = Pdo; pdoData->ParentFdo = FdoData->Common.Self; INITIALIZE_PNP_STATE(pdoData->Common); pdoData->Common.DevicePowerState = ntState; pdoData->Common.SystemPowerState = FdoData->Common.SystemPowerState; Pdo->Flags |= DO_POWER_PAGABLE; ExAcquireFastMutex (&FdoData->Mutex); InsertTailList(&FdoData->ListOfPDOs, &pdoData->Link); FdoData->NumPDOs++; ExReleaseFastMutex (&FdoData->Mutex); // This should be the last step in initialization. Pdo->Flags &= ~DO_DEVICE_INITIALIZING; }
PSECONDARY Secondary_Create ( IN PIRP_CONTEXT IrpContext, IN PVOLUME_DEVICE_OBJECT VolDo ) { NTSTATUS status; PSECONDARY secondary; OBJECT_ATTRIBUTES objectAttributes; LARGE_INTEGER timeOut; ULONG tryQuery; BOOLEAN isLocalAddress; UNREFERENCED_PARAMETER( IrpContext ); secondary = ExAllocatePoolWithTag( NonPagedPool, sizeof(SECONDARY), NDASFAT_ALLOC_TAG ); if (secondary == NULL) { ASSERT( NDASFAT_INSUFFICIENT_RESOURCES ); return NULL; } RtlZeroMemory( secondary, sizeof(SECONDARY) ); #define MAX_TRY_QUERY 2 for (tryQuery = 0; tryQuery < MAX_TRY_QUERY; tryQuery++) { secondary->NumberOfPrimaryAddress = 0; status = ((PVOLUME_DEVICE_OBJECT) FatData.DiskFileSystemDeviceObject)-> NdfsCallback.QueryPrimaryAddress( &VolDo->NetdiskPartitionInformation, secondary->PrimaryAddressList, &secondary->NumberOfPrimaryAddress, &isLocalAddress ); DebugTrace2( 0, Dbg2, ("Secondary_Create: QueryPrimaryAddress %08x\n", status) ); if (NT_SUCCESS(status)) { LONG i; NDAS_ASSERT( secondary->NumberOfPrimaryAddress ); for (i = 0; i < secondary->NumberOfPrimaryAddress; i++) { DebugTrace2( 0, Dbg2, ("Secondary_Create: QueryPrimaryAddress: Found PrimaryAddress[%d] :%02x:%02x:%02x:%02x:%02x:%02x/%d\n", i, secondary->PrimaryAddressList[i].Node[0], secondary->PrimaryAddressList[i].Node[1], secondary->PrimaryAddressList[i].Node[2], secondary->PrimaryAddressList[i].Node[3], secondary->PrimaryAddressList[i].Node[4], secondary->PrimaryAddressList[i].Node[5], NTOHS(secondary->PrimaryAddressList[i].Port)) ); } break; } } if (status != STATUS_SUCCESS || isLocalAddress) { ExFreePoolWithTag( secondary, NDASFAT_ALLOC_TAG ); return NULL; } secondary->Flags = SECONDARY_FLAG_INITIALIZING; #if 0 ExInitializeResourceLite( &secondary->RecoveryResource ); ExInitializeResourceLite( &secondary->Resource ); ExInitializeResourceLite( &secondary->SessionResource ); ExInitializeResourceLite( &secondary->CreateResource ); #endif ExInitializeFastMutex( &secondary->FastMutex ); secondary->ReferenceCount = 1; VolDo_Reference( VolDo ); secondary->VolDo = VolDo; secondary->ThreadHandle = NULL; InitializeListHead( &secondary->RecoveryCcbQueue ); ExInitializeFastMutex( &secondary->RecoveryCcbQMutex ); InitializeListHead( &secondary->DeletedFcbQueue ); KeQuerySystemTime( &secondary->TryCloseTime ); secondary->TryCloseWorkItem = IoAllocateWorkItem( (PDEVICE_OBJECT)VolDo ); KeInitializeEvent( &secondary->ReadyEvent, NotificationEvent, FALSE ); InitializeListHead( &secondary->RequestQueue ); KeInitializeSpinLock( &secondary->RequestQSpinLock ); KeInitializeEvent( &secondary->RequestEvent, NotificationEvent, FALSE ); InitializeListHead( &secondary->FcbQueue ); ExInitializeFastMutex( &secondary->FcbQMutex ); KeInitializeEvent( &secondary->RecoveryReadyEvent, NotificationEvent, FALSE ); InitializeObjectAttributes( &objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); secondary->SessionId = 0; status = PsCreateSystemThread( &secondary->ThreadHandle, THREAD_ALL_ACCESS, &objectAttributes, NULL, NULL, SecondaryThreadProc, secondary ); if (!NT_SUCCESS(status)) { ASSERT( NDASFAT_UNEXPECTED ); Secondary_Close( secondary ); return NULL; } status = ObReferenceObjectByHandle( secondary->ThreadHandle, FILE_READ_DATA, NULL, KernelMode, &secondary->ThreadObject, NULL ); if (!NT_SUCCESS(status)) { ASSERT( NDASFAT_INSUFFICIENT_RESOURCES ); Secondary_Close( secondary ); return NULL; } secondary->SessionId ++; timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( &secondary->ReadyEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { NDAS_ASSERT( FALSE ); Secondary_Close( secondary ); return NULL; } KeClearEvent( &secondary->ReadyEvent ); ExAcquireFastMutex( &secondary->FastMutex ); if (!FlagOn(secondary->Thread.Flags, SECONDARY_THREAD_FLAG_START) || FlagOn(secondary->Thread.Flags, SECONDARY_THREAD_FLAG_STOPED)) { if (secondary->Thread.SessionStatus != STATUS_DISK_CORRUPT_ERROR && secondary->Thread.SessionStatus != STATUS_UNRECOGNIZED_VOLUME) { ExReleaseFastMutex( &secondary->FastMutex ); Secondary_Close( secondary ); return NULL; } } ASSERT( secondary->Thread.SessionContext.SessionSlotCount != 0 ); ClearFlag( secondary->Flags, SECONDARY_FLAG_INITIALIZING ); SetFlag( secondary->Flags, SECONDARY_FLAG_START ); ExReleaseFastMutex( &secondary->FastMutex ); DebugTrace2( 0, Dbg2, ("Secondary_Create: The client thread are ready secondary = %p\n", secondary) ); return secondary; }
VOID Readonly_Close ( IN PREADONLY Readonly ) { NTSTATUS status; LARGE_INTEGER timeOut; PLIST_ENTRY readonlyRequestEntry; PREADONLY_REQUEST readonlyRequest; SPY_LOG_PRINT( LFS_DEBUG_READONLY_INFO, ("Readonly close Readonly = %p\n", Readonly) ); ExAcquireFastMutex( &Readonly->FastMutex ); ASSERT( !FlagOn(Readonly->Flags, READONLY_FLAG_RECONNECTING) ); if (FlagOn(Readonly->Flags, READONLY_FLAG_CLOSED)) { //ASSERT( FALSE ); ExReleaseFastMutex( &Readonly->FastMutex ); return; } SetFlag( Readonly->Flags, READONLY_FLAG_CLOSED ); ExReleaseFastMutex( &Readonly->FastMutex ); FsRtlNotifyUninitializeSync( &Readonly->NotifySync ); if (Readonly->ThreadHandle == NULL) { //ASSERT( FALSE ); Readonly_Dereference( Readonly ); return; } ASSERT( Readonly->ThreadObject != NULL ); SPY_LOG_PRINT( LFS_DEBUG_READONLY_TRACE, ("Readonly close READONLY_REQ_DISCONNECT Readonly = %p\n", Readonly) ); readonlyRequest = AllocReadonlyRequest( Readonly, 0, FALSE ); readonlyRequest->RequestType = READONLY_REQ_DISCONNECT; QueueingReadonlyRequest( Readonly, readonlyRequest ); readonlyRequest = AllocReadonlyRequest( Readonly, 0, FALSE ); readonlyRequest->RequestType = READONLY_REQ_DOWN; QueueingReadonlyRequest( Readonly, readonlyRequest ); SPY_LOG_PRINT( LFS_DEBUG_READONLY_TRACE, ("Readonly close READONLY_REQ_DISCONNECT end Readonly = %p\n", Readonly) ); timeOut.QuadPart = -LFS_TIME_OUT; status = KeWaitForSingleObject( Readonly->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if (status == STATUS_SUCCESS) { SPY_LOG_PRINT( LFS_DEBUG_READONLY_TRACE, ("Readonly_Close: thread stoped Readonly = %p\n", Readonly) ); ObDereferenceObject( Readonly->ThreadObject ); Readonly->ThreadHandle = NULL; Readonly->ThreadObject = NULL; } else { ASSERT( LFS_BUG ); return; } if (!IsListEmpty(&Readonly->FcbQueue)) NDAS_ASSERT( FALSE ); if (!IsListEmpty(&Readonly->CcbQueue)) NDAS_ASSERT( FALSE ); if (!IsListEmpty(&Readonly->RequestQueue)) NDAS_ASSERT( FALSE ); while (readonlyRequestEntry = ExInterlockedRemoveHeadList(&Readonly->RequestQueue, &Readonly->RequestQSpinLock)) { PREADONLY_REQUEST readonlyRequest2; InitializeListHead( readonlyRequestEntry ); readonlyRequest2 = CONTAINING_RECORD( readonlyRequestEntry, READONLY_REQUEST, ListEntry ); readonlyRequest2->ExecuteStatus = STATUS_IO_DEVICE_ERROR; if (readonlyRequest2->Synchronous == TRUE) KeSetEvent( &readonlyRequest2->CompleteEvent, IO_DISK_INCREMENT, FALSE ); else DereferenceReadonlyRequest( readonlyRequest2 ); } Readonly_Dereference( Readonly ); return; }
VOID ReadonlyThreadProc ( IN PREADONLY Readonly ) { BOOLEAN readonlyThreadTerminate = FALSE; PLIST_ENTRY readonlyRequestEntry; SPY_LOG_PRINT( LFS_DEBUG_READONLY_TRACE, ("ReadonlyThreadProc: Start Readonly = %p\n", Readonly) ); Readonly_Reference( Readonly ); Readonly->Thread.Flags = READONLY_THREAD_FLAG_INITIALIZING; ExAcquireFastMutex( &Readonly->FastMutex ); SetFlag( Readonly->Thread.Flags, READONLY_THREAD_FLAG_START ); ClearFlag( Readonly->Thread.Flags, READONLY_THREAD_FLAG_INITIALIZING ); ExReleaseFastMutex( &Readonly->FastMutex ); KeSetEvent( &Readonly->ReadyEvent, IO_DISK_INCREMENT, FALSE ); readonlyThreadTerminate = FALSE; while (readonlyThreadTerminate == FALSE) { PKEVENT events[2]; LONG eventCount; NTSTATUS eventStatus; LARGE_INTEGER timeOut; ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); eventCount = 0; events[eventCount++] = &Readonly->RequestEvent; timeOut.QuadPart = -LFS_READONLY_THREAD_FLAG_TIME_OUT; eventStatus = KeWaitForMultipleObjects( eventCount, events, WaitAny, Executive, KernelMode, TRUE, &timeOut, NULL ); if (eventStatus == STATUS_TIMEOUT) { ReadonlyTryCloseCcb( Readonly ); ReadonlyDismountVolumeStart( Readonly ); continue; } ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); ASSERT( eventCount < THREAD_WAIT_OBJECTS ); if (!NT_SUCCESS( eventStatus ) || eventStatus >= eventCount) { ASSERT( LFS_UNEXPECTED ); SetFlag( Readonly->Thread.Flags, READONLY_THREAD_FLAG_ERROR ); readonlyThreadTerminate = TRUE; continue; } KeClearEvent( events[eventStatus] ); if (eventStatus == 0) { while (!FlagOn(Readonly->Thread.Flags, READONLY_THREAD_FLAG_STOPED) && (readonlyRequestEntry = ExInterlockedRemoveHeadList(&Readonly->RequestQueue, &Readonly->RequestQSpinLock))) { PREADONLY_REQUEST readonlyRequest; InitializeListHead( readonlyRequestEntry ); readonlyRequest = CONTAINING_RECORD( readonlyRequestEntry, READONLY_REQUEST, ListEntry ); if (!(readonlyRequest->RequestType == READONLY_REQ_DISCONNECT || readonlyRequest->RequestType == READONLY_REQ_DOWN || readonlyRequest->RequestType == READONLY_REQ_SEND_MESSAGE)) { ASSERT( FALSE ); ExAcquireFastMutex( &Readonly->FastMutex ); SetFlag( Readonly->Thread.Flags, READONLY_THREAD_FLAG_STOPED | READONLY_THREAD_FLAG_ERROR ); ExReleaseFastMutex( &Readonly->FastMutex ); ExInterlockedInsertHeadList( &Readonly->RequestQueue, &readonlyRequest->ListEntry, &Readonly->RequestQSpinLock ); readonlyThreadTerminate = TRUE; break; } if (readonlyRequest->RequestType == READONLY_REQ_DISCONNECT) { if (readonlyRequest->Synchronous == TRUE) KeSetEvent(&readonlyRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE); else DereferenceReadonlyRequest( readonlyRequest ); continue; } if (readonlyRequest->RequestType == READONLY_REQ_DOWN) { SPY_LOG_PRINT( LFS_DEBUG_READONLY_TRACE, ("ReadonlyThread READONLY_REQ_DOWN Readonly = %p\n", Readonly) ); ExAcquireFastMutex( &Readonly->FastMutex ); SetFlag( Readonly->Thread.Flags, READONLY_THREAD_FLAG_STOPED ); ExReleaseFastMutex( &Readonly->FastMutex ); ASSERT( IsListEmpty(&Readonly->RequestQueue) ); if (readonlyRequest->Synchronous == TRUE) KeSetEvent( &readonlyRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE ); else DereferenceReadonlyRequest( readonlyRequest ); readonlyThreadTerminate = TRUE; break; } ASSERT( readonlyRequest->RequestType == READONLY_REQ_SEND_MESSAGE ); ASSERT( readonlyRequest->Synchronous == TRUE ); } // while } else { NDAS_ASSERT( FALSE ); } } ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); ExAcquireFastMutex( &Readonly->FastMutex ); SetFlag( Readonly->Thread.Flags, READONLY_THREAD_FLAG_STOPED ); while (readonlyRequestEntry = ExInterlockedRemoveHeadList(&Readonly->RequestQueue, &Readonly->RequestQSpinLock)) { PREADONLY_REQUEST readonlyRequest; InitializeListHead( readonlyRequestEntry ); readonlyRequest = CONTAINING_RECORD( readonlyRequestEntry, READONLY_REQUEST, ListEntry ); readonlyRequest->ExecuteStatus = STATUS_IO_DEVICE_ERROR; if (readonlyRequest->Synchronous == TRUE) KeSetEvent( &readonlyRequest->CompleteEvent, IO_DISK_INCREMENT, FALSE ); else DereferenceReadonlyRequest( readonlyRequest ); } ExReleaseFastMutex( &Readonly->FastMutex ); SPY_LOG_PRINT( LFS_DEBUG_READONLY_TRACE, ("ReadonlyThreadProc: PsTerminateSystemThread Readonly = %p, IsListEmpty(&Readonly->RequestQueue) = %d\n", Readonly, IsListEmpty(&Readonly->RequestQueue)) ); ExAcquireFastMutex( &Readonly->FastMutex ); SetFlag( Readonly->Thread.Flags, READONLY_THREAD_FLAG_TERMINATED ); ExReleaseFastMutex( &Readonly->FastMutex ); Readonly_Dereference( Readonly ); ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); PsTerminateSystemThread( STATUS_SUCCESS ); }
// // Checks to see if a supplied region is exempted from being allocated into // BOOLEAN IsRegionExempted( IN PVOID RegionBase, IN ULONG RegionSize, OUT PULONG EndDisplacement OPTIONAL) { PLIST_ENTRY Current; BOOLEAN Exempted = FALSE; // // Acquire the region exemption list mutex // ExAcquireFastMutex( &RegionExemptionListMutex); // // Enumerate through all of the region exemptions // for (Current = RegionExemptionList.Flink; (Current != &RegionExemptionList) && (!Exempted); Current = Current->Flink) { PREGION_EXEMPTION Exemption = (PREGION_EXEMPTION)Current; Exempted = ( (IsAddressInsideRange( RegionBase, Exemption->Base, Exemption->Size)) || (IsAddressInsideRange( Exemption->Base, RegionBase, RegionSize))) ? TRUE : FALSE; // // If this region is exempted and the caller requested a displacement // calculation, pass one back to them such that they can optimize their // search by knowing how much to add to their region base to get outside // of the exempted region. // if ((Exempted) && (EndDisplacement)) { // // The number of bytes that will have to be incremented by to get the // supplied region out of the area of the exempted region is calculated // by subtracting the end of the exempted region from the start of the // supplied region. // *EndDisplacement = (ULONG)((Exemption->Base + Exemption->Size) - (ULONG_PTR)RegionBase); // // Assert that the end of the exempted region is always greater than // the region base, which should always be true. // ASSERT((Exemption->Base + Exemption->Size) > (ULONG_PTR)RegionBase); } } // // Release the region exemption list mutex // ExReleaseFastMutex( &RegionExemptionListMutex); return Exempted; }
BOOLEAN ReadonlyPassThrough ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PFILESPY_DEVICE_EXTENSION DevExt, OUT PNTSTATUS NtStatus ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN result = FALSE; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT fileObject = irpSp->FileObject; BOOLEAN fastMutexAcquired = FALSE; UNREFERENCED_PARAMETER( DeviceObject ); ASSERT( DevExt->LfsDeviceExt.ReferenceCount ); LfsDeviceExt_Reference( &DevExt->LfsDeviceExt ); PrintIrp( LFS_DEBUG_READONLY_NOISE, __FUNCTION__, &DevExt->LfsDeviceExt, Irp ); ASSERT( KeGetCurrentIrql() <= APC_LEVEL ); ExAcquireFastMutex( &DevExt->LfsDeviceExt.FastMutex ); fastMutexAcquired = TRUE; try { if (!FlagOn(DevExt->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_MOUNTED)) { result = FALSE; leave; } ASSERT( DevExt->LfsDeviceExt.AttachedToDeviceObject == DevExt->NLExtHeader.AttachedToDeviceObject ); if (DevExt->LfsDeviceExt.AttachedToDeviceObject == NULL) { NDAS_ASSERT( FALSE ); result = FALSE; leave; } if (!(FlagOn(DevExt->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_MOUNTED) && !FlagOn(DevExt->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_DISMOUNTED))) { ASSERT( DevExt->LfsDeviceExt.Readonly == NULL || ReadonlyLookUpCcb(DevExt->LfsDeviceExt.Readonly, fileObject) == NULL ); result = FALSE; leave; } switch (irpSp->MajorFunction) { case IRP_MJ_PNP: break; default: ExReleaseFastMutex( &DevExt->LfsDeviceExt.FastMutex ); fastMutexAcquired = FALSE; if (DevExt->LfsDeviceExt.Readonly) { status = ReadonlyRedirectIrp( DevExt, Irp, &result ); } else { result = FALSE; } leave; } if (irpSp->MajorFunction == IRP_MJ_PNP) { PrintIrp( LFS_DEBUG_READONLY_NOISE, __FUNCTION__, &DevExt->LfsDeviceExt, Irp ); if (irpSp->MinorFunction == IRP_MN_SURPRISE_REMOVAL) { if (DevExt->LfsDeviceExt.NetdiskPartition == NULL) { NDAS_ASSERT( FALSE ); } else { SetFlag( DevExt->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_SURPRISE_REMOVED ); ExReleaseFastMutex( &DevExt->LfsDeviceExt.FastMutex ); fastMutexAcquired = FALSE; NetdiskManager_SurpriseRemoval( GlobalLfs.NetdiskManager, DevExt->LfsDeviceExt.NetdiskPartition, DevExt->LfsDeviceExt.NetdiskEnabledMode ); } DevExt->LfsDeviceExt.NetdiskPartition = NULL; result = FALSE; leave; } // Need to test much whether this is okay.. if (irpSp->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE || irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) { result = FALSE; leave; } else if (irpSp->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE) { KEVENT waitEvent; ExReleaseFastMutex( &DevExt->LfsDeviceExt.FastMutex ); fastMutexAcquired = FALSE; if (DevExt->LfsDeviceExt.Readonly) { ReadonlyTryCloseCcb( DevExt->LfsDeviceExt.Readonly ); if (!IsListEmpty(&DevExt->LfsDeviceExt.Readonly->FcbQueue)) { LARGE_INTEGER interval; // Wait all files closed interval.QuadPart = (1 * DELAY_ONE_SECOND); //delay 1 seconds KeDelayExecutionThread( KernelMode, FALSE, &interval ); } if (!IsListEmpty(&DevExt->LfsDeviceExt.Readonly->FcbQueue)) { status = Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; Irp->IoStatus.Information = 0; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); result = TRUE; leave; } } SetFlag( DevExt->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_DISMOUNTING ); IoCopyCurrentIrpStackLocationToNext( Irp ); KeInitializeEvent( &waitEvent, NotificationEvent, FALSE ); IoSetCompletionRoutine( Irp, ReadonlyPassThroughCompletion, &waitEvent, TRUE, TRUE, TRUE ); status = IoCallDriver( DevExt->LfsDeviceExt.AttachedToDeviceObject, Irp ); if (status == STATUS_PENDING) { status = KeWaitForSingleObject( &waitEvent, Executive, KernelMode, FALSE, NULL ); ASSERT( status == STATUS_SUCCESS ); } ASSERT( KeReadStateEvent(&waitEvent) || !NT_SUCCESS(Irp->IoStatus.Status) ); SPY_LOG_PRINT( LFS_DEBUG_READONLY_INFO, ("%s: lfsDeviceExt = %p, IRP_MN_QUERY_REMOVE_DEVICE Irp->IoStatus.Status = %x\n", __FUNCTION__, &DevExt->LfsDeviceExt, Irp->IoStatus.Status) ); ClearFlag( DevExt->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_DISMOUNTING ); if (NT_SUCCESS(Irp->IoStatus.Status)) { ASSERT( !FlagOn(DevExt->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_DISMOUNTED) ); LfsDismountVolume( &DevExt->LfsDeviceExt ); } status = Irp->IoStatus.Status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); result = TRUE; leave; } result = FALSE; leave; } } finally { if (fastMutexAcquired) ExReleaseFastMutex( &DevExt->LfsDeviceExt.FastMutex ); LfsDeviceExt_Dereference( &DevExt->LfsDeviceExt ); *NtStatus = status; } return result; }
NTSTATUS Bus_FDO_PnP ( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PIO_STACK_LOCATION IrpStack, __in PFDO_DEVICE_DATA DeviceData ) /*++ Routine Description: Handle requests from the Plug & Play system for the BUS itself --*/ { NTSTATUS status; ULONG length, prevcount, numPdosPresent; PLIST_ENTRY entry, listHead, nextEntry; PPDO_DEVICE_DATA pdoData; PDEVICE_RELATIONS relations, oldRelations; PAGED_CODE (); Bus_IncIoCount (DeviceData); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // Send the Irp down and wait for it to come back. // Do not touch the hardware until then. // status = Bus_SendIrpSynchronously (DeviceData->NextLowerDriver, Irp); if (NT_SUCCESS(status)) { // // Initialize your device with the resources provided // by the PnP manager to your device. // status = Bus_StartFdo (DeviceData, Irp); } // // We must now complete the IRP, since we stopped it in the // completion routine with MORE_PROCESSING_REQUIRED. // Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (DeviceData); return status; case IRP_MN_QUERY_STOP_DEVICE: // // The PnP manager is trying to stop the device // for resource rebalancing. Fail this now if you // cannot stop the device in response to STOP_DEVICE. // SET_NEW_PNP_STATE(DeviceData, StopPending); Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP. break; case IRP_MN_CANCEL_STOP_DEVICE: // // The PnP Manager sends this IRP, at some point after an // IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a // device that the device will not be stopped for // resource reconfiguration. // // // First check to see whether you have received cancel-stop // without first receiving a query-stop. This could happen if // someone above us fails a query-stop and passes down the subsequent // cancel-stop. // if (StopPending == DeviceData->DevicePnPState) { // // We did receive a query-stop, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); ASSERT(DeviceData->DevicePnPState == Started); } Irp->IoStatus.Status = STATUS_SUCCESS; // We must not fail the IRP. break; case IRP_MN_STOP_DEVICE: // // Stop device means that the resources given during Start device // are now revoked. Note: You must not fail this Irp. // But before you relieve resources make sure there are no I/O in // progress. Wait for the existing ones to be finished. // To do that, first we will decrement this very operation. // When the counter goes to 1, Stop event is set. // Bus_DecIoCount(DeviceData); KeWaitForSingleObject( &DeviceData->StopEvent, Executive, // Waiting reason of a driver KernelMode, // Waiting in kernel mode FALSE, // No allert NULL); // No timeout // // Increment the counter back because this IRP has to // be sent down to the lower stack. // Bus_IncIoCount (DeviceData); // // Free resources given by start device. // SET_NEW_PNP_STATE(DeviceData, Stopped); // // We don't need a completion routine so fire and forget. // // Set the current stack location to the next stack location and // call the next device object. // Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_QUERY_REMOVE_DEVICE: // // If we were to fail this call then we would need to complete the // IRP here. Since we are not, set the status to SUCCESS and // call the next driver. // SET_NEW_PNP_STATE(DeviceData, RemovePending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_REMOVE_DEVICE: // // If we were to fail this call then we would need to complete the // IRP here. Since we are not, set the status to SUCCESS and // call the next driver. // // // First check to see whether you have received cancel-remove // without first receiving a query-remove. This could happen if // someone above us fails a query-remove and passes down the // subsequent cancel-remove. // if (RemovePending == DeviceData->DevicePnPState) { // // We did receive a query-remove, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData); } Irp->IoStatus.Status = STATUS_SUCCESS;// You must not fail the IRP. break; case IRP_MN_SURPRISE_REMOVAL: // // The device has been unexpectedly removed from the machine // and is no longer available for I/O. Bus_RemoveFdo clears // all the resources, frees the interface and de-registers // with WMI, but it doesn't delete the FDO. That's done // later in Remove device query. // SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending); Bus_RemoveFdo(DeviceData); ExAcquireFastMutex (&DeviceData->Mutex); listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry,nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); RemoveEntryList (&pdoData->Link); InitializeListHead (&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; } ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP. break; case IRP_MN_REMOVE_DEVICE: // // The Plug & Play system has dictated the removal of this device. // We have no choice but to detach and delete the device object. // // // Check the state flag to see whether you are surprise removed // if (DeviceData->DevicePnPState != SurpriseRemovePending) { Bus_RemoveFdo(DeviceData); } SET_NEW_PNP_STATE(DeviceData, Deleted); // // Wait for all outstanding requests to complete. // We need two decrements here, one for the increment in // the beginning of this function, the other for the 1-biased value of // OutstandingIO. // Bus_DecIoCount (DeviceData); // // The requestCount is at least one here (is 1-biased) // Bus_DecIoCount (DeviceData); KeWaitForSingleObject ( &DeviceData->RemoveEvent, Executive, KernelMode, FALSE, NULL); // // Typically the system removes all the children before // removing the parent FDO. If for any reason child Pdos are // still present we will destroy them explicitly, with one exception - // we will not delete the PDOs that are in SurpriseRemovePending state. // ExAcquireFastMutex (&DeviceData->Mutex); listHead = &DeviceData->ListOfPDOs; for(entry = listHead->Flink,nextEntry = entry->Flink; entry != listHead; entry = nextEntry,nextEntry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); RemoveEntryList (&pdoData->Link); if (SurpriseRemovePending == pdoData->DevicePnPState) { // // We will reinitialize the list head so that we // wouldn't barf when we try to delink this PDO from // the parent's PDOs list, when the system finally // removes the PDO. Let's also not forget to set the // ReportedMissing flag to cause the deletion of the PDO. // Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO, ("\tFound a surprise removed device: 0x%p\n", pdoData->Self)); InitializeListHead (&pdoData->Link); pdoData->ParentFdo = NULL; pdoData->ReportedMissing = TRUE; continue; } DeviceData->NumPDOs--; Bus_DestroyPdo (pdoData->Self, pdoData); } ExReleaseFastMutex (&DeviceData->Mutex); // // We need to send the remove down the stack before we detach, // but we don't need to wait for the completion of this operation // (and to register a completion routine). // Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); // // Detach from the underlying devices. // IoDetachDevice (DeviceData->NextLowerDriver); Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO, ("\tDeleting FDO: 0x%p\n", DeviceObject)); IoDeleteDevice (DeviceObject); return status; case IRP_MN_QUERY_DEVICE_RELATIONS: Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\tQueryDeviceRelation Type: %s\n", DbgDeviceRelationString(\ IrpStack->Parameters.QueryDeviceRelations.Type))); if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) { // // We don't support any other Device Relations // break; } // // Tell the plug and play system about all the PDOs. // // There might also be device relations below and above this FDO, // so, be sure to propagate the relations from the upper drivers. // // No Completion routine is needed so long as the status is preset // to success. (PDOs complete plug and play irps with the current // IoStatus.Status and IoStatus.Information as the default.) // ExAcquireFastMutex (&DeviceData->Mutex); oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information; if (oldRelations) { prevcount = oldRelations->Count; if (!DeviceData->NumPDOs) { // // There is a device relations struct already present and we have // nothing to add to it, so just call IoSkip and IoCall // ExReleaseFastMutex (&DeviceData->Mutex); break; } } else { prevcount = 0; } // // Calculate the number of PDOs actually present on the bus // numPdosPresent = 0; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) numPdosPresent++; } // // Need to allocate a new relations structure and add our // PDOs to it. // length = sizeof(DEVICE_RELATIONS) + ((numPdosPresent + prevcount) * sizeof (PDEVICE_OBJECT)) -1; relations = (PDEVICE_RELATIONS) ExAllocatePoolWithTag (PagedPool, length, BUSENUM_POOL_TAG); if (NULL == relations) { // // Fail the IRP // ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest (Irp, IO_NO_INCREMENT); Bus_DecIoCount (DeviceData); return status; } // // Copy in the device objects so far // if (prevcount) { RtlCopyMemory (relations->Objects, oldRelations->Objects, prevcount * sizeof (PDEVICE_OBJECT)); } relations->Count = prevcount + numPdosPresent; // // For each PDO present on this bus add a pointer to the device relations // buffer, being sure to take out a reference to that object. // The Plug & Play system will dereference the object when it is done // with it and free the device relations buffer. // for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if (pdoData->Present) { relations->Objects[prevcount] = pdoData->Self; ObReferenceObject (pdoData->Self); prevcount++; } else { pdoData->ReportedMissing = TRUE; } } Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE, ("\t#PDOS present = %d\n\t#PDOs reported = %d\n", DeviceData->NumPDOs, relations->Count)); // // Replace the relations structure in the IRP with the new // one. // if (oldRelations) { ExFreePool (oldRelations); } Irp->IoStatus.Information = (ULONG_PTR) relations; ExReleaseFastMutex (&DeviceData->Mutex); // // Set up and pass the IRP further down the stack // Irp->IoStatus.Status = STATUS_SUCCESS; break; default: // // In the default case we merely call the next driver. // We must not modify Irp->IoStatus.Status or complete the IRP. // break; } IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); Bus_DecIoCount (DeviceData); return status; }
NTSTATUS Bus_EjectDevice ( PBUSENUM_EJECT_HARDWARE Eject, PFDO_DEVICE_DATA FdoData ) /*++ Routine Description: The user application has told us to eject the device from the bus. In a real situation the driver gets notified by an interrupt when the user presses the Eject button on the device. Arguments: Eject - pointer to Eject hardware structure. FdoData - contains the list to iterate over Returns: STATUS_SUCCESS upon successful removal from the list STATUS_INVALID_PARAMETER if the removal was unsuccessful --*/ { PLIST_ENTRY entry; PPDO_DEVICE_DATA pdoData; BOOLEAN found = FALSE, ejectAll; PAGED_CODE (); ejectAll = (0 == Eject->SerialNo); ExAcquireFastMutex (&FdoData->Mutex); if (ejectAll) { Bus_KdPrint (FdoData, BUS_DBG_IOCTL_NOISE, ("Ejecting all the pdos!\n")); } else { Bus_KdPrint (FdoData, BUS_DBG_IOCTL_NOISE, ("Ejecting %d\n", Eject->SerialNo)); } if (FdoData->NumPDOs == 0) { // // Somebody in user space isn't playing nice!!! // Bus_KdPrint (FdoData, BUS_DBG_IOCTL_ERROR, ("No devices to eject!\n")); ExReleaseFastMutex (&FdoData->Mutex); return STATUS_NO_SUCH_DEVICE; } // // Scan the list to find matching PDOs // for (entry = FdoData->ListOfPDOs.Flink; entry != &FdoData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); Bus_KdPrint (FdoData, BUS_DBG_IOCTL_NOISE, ("found device %d\n", pdoData->SerialNo)); if (ejectAll || Eject->SerialNo == pdoData->SerialNo) { Bus_KdPrint (FdoData, BUS_DBG_IOCTL_INFO, ("Ejected %d\n", pdoData->SerialNo)); found = TRUE; IoRequestDeviceEject(pdoData->Self); if (!ejectAll) { break; } } } ExReleaseFastMutex (&FdoData->Mutex); if (found) { return STATUS_SUCCESS; } Bus_KdPrint (FdoData, BUS_DBG_IOCTL_ERROR, ("Device %d is not present\n", Eject->SerialNo)); return STATUS_INVALID_PARAMETER; }
NTSTATUS bus_unplug_dev ( int addr, PFDO_DEVICE_DATA fdodata ) { PLIST_ENTRY entry; PPDO_DEVICE_DATA pdodata; int found=0, all; PAGED_CODE (); if(addr<0||addr>127) return STATUS_INVALID_PARAMETER; all = (0 == addr); ExAcquireFastMutex (&fdodata->Mutex); if (all) { Bus_KdPrint (fdodata, BUS_DBG_IOCTL_NOISE, ("Plugging out all the devices!\n")); } else { Bus_KdPrint (fdodata, BUS_DBG_IOCTL_NOISE, ("Plugging out %d\n", addr)); } if (fdodata->NumPDOs == 0) { // // We got a 2nd plugout...somebody in user space isn't playing nice!!! // Bus_KdPrint (fdodata, BUS_DBG_IOCTL_ERROR, ("BAD BAD BAD...2 removes!!! Send only one!\n")); ExReleaseFastMutex (&fdodata->Mutex); return STATUS_NO_SUCH_DEVICE; } for (entry = fdodata->ListOfPDOs.Flink; entry != &fdodata->ListOfPDOs; entry = entry->Flink) { pdodata = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); Bus_KdPrint (fdodata, BUS_DBG_IOCTL_NOISE, ("found device %d\n", pdodata->SerialNo)); if (all || addr == pdodata->SerialNo) { Bus_KdPrint (fdodata, BUS_DBG_IOCTL_INFO, ("Plugging out %d\n", pdodata->SerialNo)); pdodata->Present = FALSE; complete_pending_read_irp(pdodata); found = 1; if (!all) { break; } } } ExReleaseFastMutex (&fdodata->Mutex); if (found) { IoInvalidateDeviceRelations (fdodata->UnderlyingPDO, BusRelations); ExAcquireFastMutex (&fdodata->Mutex); for (entry = fdodata->ListOfPDOs.Flink; entry != &fdodata->ListOfPDOs; entry = entry->Flink) { pdodata = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); if( pdodata->Present ==FALSE){ complete_pending_irp(pdodata); SET_NEW_PNP_STATE(pdodata,PNP_DEVICE_REMOVED); IoInvalidateDeviceState(pdodata->Self); } } ExReleaseFastMutex (&fdodata->Mutex); Bus_KdPrint (fdodata, BUS_DBG_IOCTL_ERROR, ("Device %d plug out finished\n", addr)); return STATUS_SUCCESS; } return STATUS_INVALID_PARAMETER; }
VOID ExFreeToPagedLookasideList( IN PPAGED_LOOKASIDE_LIST Lookaside, IN PVOID Entry ) /*++ Routine Description: This function inserts (pushes) the specified entry into the specified paged lookaside list. Arguments: Lookaside - Supplies a pointer to a paged lookaside list structure. Entry - Supples a pointer to the entry that is inserted in the lookaside list. Return Value: None. --*/ { Lookaside->L.TotalFrees += 1; #if !defined(_PPC_) if (Isx86FeaturePresent(KF_CMPXCHG8B)) { if (ExQueryDepthSList(&Lookaside->L.ListHead) >= Lookaside->L.Depth) { Lookaside->L.FreeMisses += 1; (Lookaside->L.Free)(Entry); } else { ExInterlockedPushEntrySList(&Lookaside->L.ListHead, (PSINGLE_LIST_ENTRY)Entry, NULL); } return; } #endif ExAcquireFastMutex(&Lookaside->Lock); if (ExQueryDepthSList(&Lookaside->L.ListHead) >= Lookaside->L.Depth) { ExReleaseFastMutex(&Lookaside->Lock); Lookaside->L.FreeMisses += 1; (Lookaside->L.Free)(Entry); } else { PushEntryList(&Lookaside->L.ListHead.Next, (PSINGLE_LIST_ENTRY)Entry); Lookaside->L.ListHead.Depth += 1; ExReleaseFastMutex(&Lookaside->Lock); } return; }
PREADONLY Readonly_Create ( IN PLFS_DEVICE_EXTENSION LfsDeviceExt ) { NTSTATUS status; PREADONLY readonly; OBJECT_ATTRIBUTES objectAttributes; LARGE_INTEGER timeOut; readonly = ExAllocatePoolWithTag( NonPagedPool, sizeof(READONLY), LFS_ALLOC_TAG ); if (readonly == NULL) { NDAS_ASSERT( NDAS_ASSERT_INSUFFICIENT_RESOURCES ); return NULL; } RtlZeroMemory( readonly, sizeof(READONLY) ); readonly->Flags = READONLY_FLAG_INITIALIZING; #if 0 ExInitializeResourceLite( &readonly->RecoveryResource ); ExInitializeResourceLite( &readonly->Resource ); ExInitializeResourceLite( &readonly->SessionResource ); ExInitializeResourceLite( &readonly->CreateResource ); #endif ExInitializeFastMutex( &readonly->FastMutex ); readonly->ReferenceCount = 1; LfsDeviceExt_Reference( LfsDeviceExt ); readonly->LfsDeviceExt = LfsDeviceExt; readonly->ThreadHandle = NULL; InitializeListHead( &readonly->FcbQueue ); KeInitializeSpinLock( &readonly->FcbQSpinLock ); InitializeListHead( &readonly->CcbQueue ); ExInitializeFastMutex( &readonly->CcbQMutex ); #if 0 InitializeListHead( &readonly->RecoveryCcbQueue ); ExInitializeFastMutex( &readonly->RecoveryCcbQMutex ); InitializeListHead( &readonly->DeletedFcbQueue ); #endif KeQuerySystemTime( &readonly->TryCloseTime ); #if 0 readonly->TryCloseWorkItem = IoAllocateWorkItem( (PDEVICE_OBJECT)VolDo ); #endif KeInitializeEvent( &readonly->ReadyEvent, NotificationEvent, FALSE ); InitializeListHead( &readonly->RequestQueue ); KeInitializeSpinLock( &readonly->RequestQSpinLock ); KeInitializeEvent( &readonly->RequestEvent, NotificationEvent, FALSE ); #if 0 //////////////////////////////////////// InitializeListHead( &readonly->FcbQueue ); ExInitializeFastMutex( &readonly->FcbQMutex ); ///////////////////////////////////////// #endif KeInitializeEvent( &readonly->DiskmountReadyEvent, NotificationEvent, FALSE ); InitializeListHead( &readonly->DirNotifyList ); FsRtlNotifyInitializeSync( &readonly->NotifySync ); InitializeObjectAttributes( &objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL ); readonly->SessionId = 0; status = PsCreateSystemThread( &readonly->ThreadHandle, THREAD_ALL_ACCESS, &objectAttributes, NULL, NULL, ReadonlyThreadProc, readonly ); if (!NT_SUCCESS(status)) { ASSERT( LFS_UNEXPECTED ); Readonly_Close( readonly ); return NULL; } status = ObReferenceObjectByHandle( readonly->ThreadHandle, FILE_READ_DATA, NULL, KernelMode, &readonly->ThreadObject, NULL ); if (!NT_SUCCESS(status)) { NDAS_ASSERT( NDAS_ASSERT_INSUFFICIENT_RESOURCES ); Readonly_Close( readonly ); return NULL; } readonly->SessionId ++; timeOut.QuadPart = -LFS_TIME_OUT; status = KeWaitForSingleObject( &readonly->ReadyEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { NDAS_ASSERT( FALSE ); Readonly_Close( readonly ); return NULL; } KeClearEvent( &readonly->ReadyEvent ); ExAcquireFastMutex( &readonly->FastMutex ); if (!FlagOn(readonly->Thread.Flags, READONLY_THREAD_FLAG_START) || FlagOn(readonly->Thread.Flags, READONLY_THREAD_FLAG_STOPED)) { if (readonly->Thread.SessionStatus != STATUS_DISK_CORRUPT_ERROR && readonly->Thread.SessionStatus != STATUS_UNRECOGNIZED_VOLUME) { ExReleaseFastMutex( &readonly->FastMutex ); Readonly_Close( readonly ); return NULL; } } ExReleaseFastMutex( &readonly->FastMutex ); ClearFlag( readonly->Flags, READONLY_FLAG_INITIALIZING ); SetFlag( readonly->Flags, READONLY_FLAG_START ); SPY_LOG_PRINT( LFS_DEBUG_READONLY_TRACE, ("Readonly_Create: The client thread are ready readonly = %p\n", readonly) ); return readonly; }
NTSTATUS NdFatSecondaryCommonRead ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp, IN ULONG BytesToRead ) { NTSTATUS status; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT fileObject = irpSp->FileObject; struct Read read; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB fcb; PCCB ccb; BOOLEAN fcbAcquired = FALSE; PUCHAR outputBuffer; ULONG totalReadLength; _U64 primaryFileHandle = 0; ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); typeOfOpen = FatDecodeFileObject( fileObject, &vcb, &fcb, &ccb ); ASSERT( typeOfOpen == UserFileOpen ); if (FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { /*if (FlagOn( fcb->FcbState, FCB_STATE_FILE_DELETED )) { ASSERT( FALSE ); FatRaiseStatus( IrpContext, STATUS_FILE_DELETED, NULL, NULL ); } else */{ ASSERT( FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ); return STATUS_FILE_CORRUPT_ERROR; } } if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { ASSERT( FALSE ); DebugTrace2( 0, Dbg, ("Can't wait in create\n") ); status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace2( -1, Dbg2, ("NdFatSecondaryCommonRead: FatFsdPostRequest -> %08lx\n", status) ); return status; } if (irpSp->Parameters.Read.ByteOffset.QuadPart == FILE_WRITE_TO_END_OF_FILE && irpSp->Parameters.Read.ByteOffset.HighPart == -1) { read.ByteOffset = fcb->Header.FileSize; } else { read.ByteOffset = irpSp->Parameters.Read.ByteOffset; } read.Key = 0; read.Length = irpSp->Parameters.Read.Length; read.Length = BytesToRead; ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); //FatAcquireSharedFcb( IrpContext, fcb ); //fcbAcquired = TRUE; try { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->Secondary->SessionResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { PrintIrp( Dbg2, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } outputBuffer = FatMapUserBuffer( IrpContext, Irp ); totalReadLength = 0; do { ULONG outputBufferLength; if (fcb->UncleanCount == 0) { DebugTrace( 0, Dbg2, "NdFatSecondaryCommonRead: fileName = %wZ\n", &fileObject->FileName ); status = STATUS_FILE_CLOSED; break; } if (!FlagOn(ccb->NdFatFlags, ND_FAT_CLEANUP_COMPLETE)) { primaryFileHandle = ccb->PrimaryFileHandle; } else { PLIST_ENTRY ccbListEntry; ExAcquireFastMutex( &fcb->CcbQMutex ); for (primaryFileHandle = 0, ccbListEntry = fcb->CcbQueue.Flink; ccbListEntry != &fcb->CcbQueue; ccbListEntry = ccbListEntry->Flink) { if (!FlagOn(CONTAINING_RECORD(ccbListEntry, CCB, FcbListEntry)->NdFatFlags, ND_FAT_CLEANUP_COMPLETE)) { primaryFileHandle = CONTAINING_RECORD(ccbListEntry, CCB, FcbListEntry)->PrimaryFileHandle; break; } } ExReleaseFastMutex( &fcb->CcbQMutex ); } ASSERT( primaryFileHandle ); outputBufferLength = ((read.Length-totalReadLength) <= volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize) ? (read.Length-totalReadLength) : volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize; secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_READ, volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize ); if (secondaryRequest == NULL) { FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_READ, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); //ndfsWinxpRequestHeader->IrpTag = (_U32)Irp; ndfsWinxpRequestHeader->IrpMajorFunction = IRP_MJ_READ; ndfsWinxpRequestHeader->IrpMinorFunction = 0; ndfsWinxpRequestHeader->FileHandle = ccb->PrimaryFileHandle; ndfsWinxpRequestHeader->IrpFlags = 0; ndfsWinxpRequestHeader->IrpSpFlags = 0; ndfsWinxpRequestHeader->Read.Length = outputBufferLength; ndfsWinxpRequestHeader->Read.Key = read.Key; ndfsWinxpRequestHeader->Read.ByteOffset = read.ByteOffset.QuadPart + totalReadLength; secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { secondaryRequest = NULL; status = STATUS_IO_DEVICE_ERROR; leave; } KeClearEvent( &secondaryRequest->CompleteEvent ); if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; if (ndfsWinxpReplytHeader->Status == STATUS_END_OF_FILE) { ASSERT( ndfsWinxpReplytHeader->Information == 0 ); if (!(read.ByteOffset.QuadPart & (((ULONG)vcb->Bpb.BytesPerSector) - 1))) { RtlZeroMemory( outputBuffer + totalReadLength, read.Length - totalReadLength ); totalReadLength = read.Length; } else { ASSERT( FALSE ); } DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; break; } if (ndfsWinxpReplytHeader->Status != STATUS_SUCCESS) { ASSERT( totalReadLength == 0 ); ASSERT( ndfsWinxpReplytHeader->Status == STATUS_FILE_CLOSED ); DebugTrace2( 0, Dbg, ("ndfsWinxpReplytHeader->Status = %x\n", ndfsWinxpReplytHeader->Status) ); if (totalReadLength) status = STATUS_SUCCESS; else status = ndfsWinxpReplytHeader->Status; ASSERT( ndfsWinxpReplytHeader->Information == 0 ); DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; break; } ASSERT( ndfsWinxpReplytHeader->Information <= outputBufferLength ); ASSERT( outputBufferLength == 0 || outputBuffer ); //if (fcb->Header.FileSize.LowPart < 100) // DbgPrint( "data = %s\n", (_U8 *)(ndfsWinxpReplytHeader+1) ); if (ndfsWinxpReplytHeader->Information && outputBuffer) { try { RtlCopyMemory( outputBuffer + totalReadLength, (_U8 *)(ndfsWinxpReplytHeader+1), ndfsWinxpReplytHeader->Information ); } finally { if (AbnormalTermination()) { DebugTrace2( 0, Dbg2, ("RedirectIrpMajorRead: Exception - output buffer is not valid\n") ); totalReadLength = read.Length; // Pretend that we read all the data.Buffer owner is already dead anyway.. status = STATUS_SUCCESS; } else { if (ndfsWinxpReplytHeader->Status == STATUS_SUCCESS) totalReadLength += ndfsWinxpReplytHeader->Information; if (totalReadLength) status = STATUS_SUCCESS; else status = ndfsWinxpReplytHeader->Status; } } } //if (fcb->Header.FileSize.LowPart < 100) // DbgPrint( "data = %s\n", outputBuffer ); DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; } while( totalReadLength < read.Length ); if (status == STATUS_FILE_CLOSED) { _U64 fcbHandle; ULONG dataSize; _U8 *ndfsWinxpRequestData; ASSERT( ccb ); ASSERT( totalReadLength == 0 ); ASSERT( secondaryRequest == NULL ); if (ccb->CreateContext.RelatedFileHandle != 0) { ASSERT( FALSE ); try_return( status = STATUS_FILE_CLOSED ); } DebugTrace2( 0, Dbg, ("SecondaryRecoverySessionStart: ccb->Lcb->ExactCaseLink.LinkName = %wZ \n", &ccb->Fcb->FullFileName) ); dataSize = ccb->CreateContext.EaLength + ccb->CreateContext.FileNameLength; secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_CREATE, (dataSize >= DEFAULT_NDAS_MAX_DATA_SIZE) ? dataSize : DEFAULT_NDAS_MAX_DATA_SIZE ); if (secondaryRequest == NULL) { ASSERT( FALSE ); try_return( status = STATUS_FILE_CLOSED ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_CREATE, (ccb->BufferLength + ccb->Fcb->FullFileName.Length) ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); ndfsWinxpRequestHeader->IrpMajorFunction = IRP_MJ_CREATE; ndfsWinxpRequestHeader->IrpMinorFunction = 0; ndfsWinxpRequestHeader->FileHandle = 0; ndfsWinxpRequestHeader->IrpFlags = 0; ndfsWinxpRequestHeader->IrpSpFlags = 0; //irpSp->Flags; ndfsWinxpRequestHeader->Create.AllocationSize = 0; ndfsWinxpRequestHeader->Create.EaLength = 0; ndfsWinxpRequestHeader->Create.FileAttributes = 0; ndfsWinxpRequestHeader->Create.Options = 0; //irpSp->Parameters.Create.Options & ~FILE_DELETE_ON_CLOSE; ndfsWinxpRequestHeader->Create.Options &= 0x00FFFFFF; ndfsWinxpRequestHeader->Create.Options |= (FILE_OPEN << 24); ndfsWinxpRequestHeader->Create.FileNameLength = (USHORT)(ccb->Fcb->FullFileName.Length + (ccb->BufferLength - ccb->CreateContext.EaLength)); ndfsWinxpRequestHeader->Create.FileNameLength = ccb->CreateContext.FileNameLength; ndfsWinxpRequestHeader->Create.EaLength = 0; //ccb->CreateContext.EaLength; ndfsWinxpRequestData = (_U8 *)(ndfsWinxpRequestHeader+1); RtlCopyMemory( ndfsWinxpRequestData + ndfsWinxpRequestHeader->Create.EaLength, ccb->Fcb->FullFileName.Buffer, ccb->Fcb->FullFileName.Length ); RtlCopyMemory( ndfsWinxpRequestData + ndfsWinxpRequestHeader->Create.EaLength + ccb->Fcb->FullFileName.Length, ccb->Buffer + ccb->CreateContext.EaLength, ccb->BufferLength - ccb->CreateContext.EaLength ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); KeClearEvent(&secondaryRequest->CompleteEvent); if (status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); secondaryRequest = NULL; ASSERT( FALSE ); try_return( status ); } if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { status = secondaryRequest->ExecuteStatus; DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; ASSERT( FALSE ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; DebugTrace2( 0, Dbg, ("SecondaryRecoverySessionStart: ndfsWinxpReplytHeader->Status = %x\n", ndfsWinxpReplytHeader->Status) ); if (ndfsWinxpReplytHeader->Status != STATUS_SUCCESS) { ASSERT( FALSE ); status = secondaryRequest->ExecuteStatus; DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; try_return( status = STATUS_FILE_CLOSED ); } primaryFileHandle = ndfsWinxpReplytHeader->Open.FileHandle; ASSERT( fcb->Handle == ndfsWinxpReplytHeader->Open.FcbHandle ); DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; do { ULONG outputBufferLength; outputBufferLength = ((read.Length-totalReadLength) <= volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize) ? (read.Length-totalReadLength) : volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize; secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_READ, volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize ); if (secondaryRequest == NULL) { FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_READ, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); //ndfsWinxpRequestHeader->IrpTag = (_U32)Irp; ndfsWinxpRequestHeader->IrpMajorFunction = IRP_MJ_READ; ndfsWinxpRequestHeader->IrpMinorFunction = 0; ndfsWinxpRequestHeader->FileHandle = primaryFileHandle; ndfsWinxpRequestHeader->IrpFlags = 0; ndfsWinxpRequestHeader->IrpSpFlags = 0; ndfsWinxpRequestHeader->Read.Length = outputBufferLength; ndfsWinxpRequestHeader->Read.Key = read.Key; ndfsWinxpRequestHeader->Read.ByteOffset = read.ByteOffset.QuadPart + totalReadLength; secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { secondaryRequest = NULL; status = STATUS_IO_DEVICE_ERROR; leave; } KeClearEvent( &secondaryRequest->CompleteEvent ); if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; if (ndfsWinxpReplytHeader->Status == STATUS_END_OF_FILE) { ASSERT( ndfsWinxpReplytHeader->Information == 0 ); if (!(read.ByteOffset.QuadPart & (((ULONG)vcb->Bpb.BytesPerSector) - 1))) { RtlZeroMemory( outputBuffer + totalReadLength, read.Length - totalReadLength ); totalReadLength = read.Length; } else { ASSERT( FALSE ); } DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; break; } if (ndfsWinxpReplytHeader->Status != STATUS_SUCCESS) { ASSERT( FALSE ); DebugTrace2( 0, Dbg2, ("ndfsWinxpReplytHeader->Status = %x\n", ndfsWinxpReplytHeader->Status) ); if (totalReadLength) status = STATUS_SUCCESS; else status = ndfsWinxpReplytHeader->Status; ASSERT( ndfsWinxpReplytHeader->Information == 0 ); DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; break; } ASSERT( ndfsWinxpReplytHeader->Information <= outputBufferLength ); ASSERT( outputBufferLength == 0 || outputBuffer ); if (ndfsWinxpReplytHeader->Information && outputBuffer) { try { RtlCopyMemory( outputBuffer + totalReadLength, (_U8 *)(ndfsWinxpReplytHeader+1), ndfsWinxpReplytHeader->Information ); } finally { if (AbnormalTermination()) { DebugTrace2( 0, Dbg2, ("RedirectIrpMajorRead: Exception - output buffer is not valid\n") ); totalReadLength = read.Length; // Pretend that we read all the data.Buffer owner is already dead anyway.. status = STATUS_SUCCESS; } else { if (ndfsWinxpReplytHeader->Status == STATUS_SUCCESS) totalReadLength += ndfsWinxpReplytHeader->Information; if (totalReadLength) status = STATUS_SUCCESS; else status = ndfsWinxpReplytHeader->Status; } } } DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; } while( totalReadLength < read.Length ); ASSERT( totalReadLength == read.Length ); ClosePrimaryFile( volDo->Secondary, primaryFileHandle ); } try_exit: NOTHING; } finally {
PPHYSICAL_MEMORY_RANGE MmGetPhysicalMemoryRanges ( VOID ) /*++ Routine Description: This routine returns the virtual address of a nonpaged pool block which contains the physical memory ranges in the system. The returned block contains physical address and page count pairs. The last entry contains zero for both. The caller must understand that this block can change at any point before or after this snapshot. It is the caller's responsibility to free this block. Arguments: None. Return Value: NULL on failure. Environment: Kernel mode. PASSIVE level. No locks held. --*/ { ULONG i; KIRQL OldIrql; PPHYSICAL_MEMORY_RANGE p; PPHYSICAL_MEMORY_RANGE PhysicalMemoryBlock; ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); ExAcquireFastMutex (&MmDynamicMemoryMutex); i = sizeof(PHYSICAL_MEMORY_RANGE) * (MmPhysicalMemoryBlock->NumberOfRuns + 1); PhysicalMemoryBlock = ExAllocatePoolWithTag (NonPagedPool, i, 'hPmM'); if (PhysicalMemoryBlock == NULL) { ExReleaseFastMutex (&MmDynamicMemoryMutex); return NULL; } p = PhysicalMemoryBlock; LOCK_PFN (OldIrql); ASSERT (i == (sizeof(PHYSICAL_MEMORY_RANGE) * (MmPhysicalMemoryBlock->NumberOfRuns + 1))); for (i = 0; i < MmPhysicalMemoryBlock->NumberOfRuns; i += 1) { p->BaseAddress.QuadPart = (LONGLONG)MmPhysicalMemoryBlock->Run[i].BasePage * PAGE_SIZE; p->NumberOfBytes.QuadPart = (LONGLONG)MmPhysicalMemoryBlock->Run[i].PageCount * PAGE_SIZE; p += 1; } p->BaseAddress.QuadPart = 0; p->NumberOfBytes.QuadPart = 0; UNLOCK_PFN (OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); return PhysicalMemoryBlock; }
NTSTATUS Bus_FDO_PnP ( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpStack, PFDO_DEVICE_DATA DeviceData ) { NTSTATUS status; ULONG length, prevcount, numPdosPresent; PLIST_ENTRY entry; PPDO_DEVICE_DATA pdoData; PDEVICE_RELATIONS relations, oldRelations; PAGED_CODE (); switch (IrpStack->MinorFunction) { case IRP_MN_START_DEVICE: status = Bus_StartFdo (DeviceData, Irp); // // We must now complete the IRP, since we stopped it in the // completion routine with MORE_PROCESSING_REQUIRED. // Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; case IRP_MN_QUERY_STOP_DEVICE: // // The PnP manager is trying to stop the device // for resource rebalancing. // SET_NEW_PNP_STATE(DeviceData->Common, StopPending); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_CANCEL_STOP_DEVICE: // // The PnP Manager sends this IRP, at some point after an // IRP_MN_QUERY_STOP_DEVICE, to inform the drivers for a // device that the device will not be stopped for // resource reconfiguration. // // // First check to see whether you have received cancel-stop // without first receiving a query-stop. This could happen if // someone above us fails a query-stop and passes down the subsequent // cancel-stop. // if (StopPending == DeviceData->Common.DevicePnPState) { // // We did receive a query-stop, so restore. // RESTORE_PREVIOUS_PNP_STATE(DeviceData->Common); ASSERT(DeviceData->Common.DevicePnPState == Started); } Irp->IoStatus.Status = STATUS_SUCCESS; // We must not fail the IRP. break; case IRP_MN_QUERY_DEVICE_RELATIONS: DPRINT("\tQueryDeviceRelation Type: %s\n", DbgDeviceRelationString(\ IrpStack->Parameters.QueryDeviceRelations.Type)); if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) { // // We don't support any other Device Relations // break; } ExAcquireFastMutex (&DeviceData->Mutex); oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information; if (oldRelations) { prevcount = oldRelations->Count; if (!DeviceData->NumPDOs) { // // There is a device relations struct already present and we have // nothing to add to it, so just call IoSkip and IoCall // ExReleaseFastMutex (&DeviceData->Mutex); break; } } else { prevcount = 0; } // // Calculate the number of PDOs actually present on the bus // numPdosPresent = 0; for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); numPdosPresent++; } // // Need to allocate a new relations structure and add our // PDOs to it. // length = sizeof(DEVICE_RELATIONS) + (((numPdosPresent + prevcount) - 1) * sizeof (PDEVICE_OBJECT)); relations = ExAllocatePoolWithTag(PagedPool, length, 'IpcA'); if (NULL == relations) { // // Fail the IRP // ExReleaseFastMutex (&DeviceData->Mutex); Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest (Irp, IO_NO_INCREMENT); return status; } // // Copy in the device objects so far // if (prevcount) { RtlCopyMemory (relations->Objects, oldRelations->Objects, prevcount * sizeof (PDEVICE_OBJECT)); } relations->Count = prevcount + numPdosPresent; // // For each PDO present on this bus add a pointer to the device relations // buffer, being sure to take out a reference to that object. // The Plug & Play system will dereference the object when it is done // with it and free the device relations buffer. // for (entry = DeviceData->ListOfPDOs.Flink; entry != &DeviceData->ListOfPDOs; entry = entry->Flink) { pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link); relations->Objects[prevcount] = pdoData->Common.Self; ObReferenceObject (pdoData->Common.Self); prevcount++; } DPRINT("\t#PDOs present = %d\n\t#PDOs reported = %d\n", DeviceData->NumPDOs, relations->Count); // // Replace the relations structure in the IRP with the new // one. // if (oldRelations) { ExFreePoolWithTag(oldRelations, 0); } Irp->IoStatus.Information = (ULONG_PTR) relations; ExReleaseFastMutex (&DeviceData->Mutex); // // Set up and pass the IRP further down the stack // Irp->IoStatus.Status = STATUS_SUCCESS; break; default: // // In the default case we merely call the next driver. // We must not modify Irp->IoStatus.Status or complete the IRP. // break; } IoSkipCurrentIrpStackLocation (Irp); status = IoCallDriver (DeviceData->NextLowerDriver, Irp); return STATUS_SUCCESS; }
NTSTATUS MmAddPhysicalMemory ( IN PPHYSICAL_ADDRESS StartAddress, IN OUT PLARGE_INTEGER NumberOfBytes ) /*++ Routine Description: This routine adds the specified physical address range to the system. This includes initializing PFN database entries and adding it to the freelists. Arguments: StartAddress - Supplies the starting physical address. NumberOfBytes - Supplies a pointer to the number of bytes being added. If any bytes were added (ie: STATUS_SUCCESS is being returned), the actual amount is returned here. Return Value: NTSTATUS. Environment: Kernel mode. PASSIVE level. No locks held. --*/ { ULONG i; PMMPFN Pfn1; KIRQL OldIrql; LOGICAL Inserted; LOGICAL Updated; MMPTE TempPte; PMMPTE PointerPte; PMMPTE LastPte; PFN_NUMBER NumberOfPages; PFN_NUMBER start; PFN_NUMBER count; PFN_NUMBER StartPage; PFN_NUMBER EndPage; PFN_NUMBER PageFrameIndex; PFN_NUMBER Page; PFN_NUMBER LastPage; PFN_COUNT PagesNeeded; PPHYSICAL_MEMORY_DESCRIPTOR OldPhysicalMemoryBlock; PPHYSICAL_MEMORY_DESCRIPTOR NewPhysicalMemoryBlock; PPHYSICAL_MEMORY_RUN NewRun; LOGICAL PfnDatabaseIsPhysical; ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); ASSERT (BYTE_OFFSET(NumberOfBytes->LowPart) == 0); ASSERT (BYTE_OFFSET(StartAddress->LowPart) == 0); if (MI_IS_PHYSICAL_ADDRESS(MmPfnDatabase)) { // // The system must be configured for dynamic memory addition. This is // critical as only then is the database guaranteed to be non-sparse. // if (MmDynamicPfn == FALSE) { return STATUS_NOT_SUPPORTED; } PfnDatabaseIsPhysical = TRUE; } else { PfnDatabaseIsPhysical = FALSE; } StartPage = (PFN_NUMBER)(StartAddress->QuadPart >> PAGE_SHIFT); NumberOfPages = (PFN_NUMBER)(NumberOfBytes->QuadPart >> PAGE_SHIFT); EndPage = StartPage + NumberOfPages; if (EndPage - 1 > MmHighestPossiblePhysicalPage) { // // Truncate the request into something that can be mapped by the PFN // database. // EndPage = MmHighestPossiblePhysicalPage + 1; NumberOfPages = EndPage - StartPage; } // // The range cannot wrap. // if (StartPage >= EndPage) { return STATUS_INVALID_PARAMETER_1; } ExAcquireFastMutex (&MmDynamicMemoryMutex); i = (sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + (sizeof(PHYSICAL_MEMORY_RUN) * (MmPhysicalMemoryBlock->NumberOfRuns + 1))); NewPhysicalMemoryBlock = ExAllocatePoolWithTag (NonPagedPool, i, ' mM'); if (NewPhysicalMemoryBlock == NULL) { ExReleaseFastMutex (&MmDynamicMemoryMutex); return STATUS_INSUFFICIENT_RESOURCES; } // // The range cannot overlap any ranges that are already present. // start = 0; LOCK_PFN (OldIrql); do { count = MmPhysicalMemoryBlock->Run[start].PageCount; Page = MmPhysicalMemoryBlock->Run[start].BasePage; if (count != 0) { LastPage = Page + count; if ((StartPage < Page) && (EndPage > Page)) { UNLOCK_PFN (OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); ExFreePool (NewPhysicalMemoryBlock); return STATUS_CONFLICTING_ADDRESSES; } if ((StartPage >= Page) && (StartPage < LastPage)) { UNLOCK_PFN (OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); ExFreePool (NewPhysicalMemoryBlock); return STATUS_CONFLICTING_ADDRESSES; } } start += 1; } while (start != MmPhysicalMemoryBlock->NumberOfRuns); // // Fill any gaps in the (sparse) PFN database needed for these pages, // unless the PFN database was physically allocated and completely // committed up front. // PagesNeeded = 0; if (PfnDatabaseIsPhysical == FALSE) { PointerPte = MiGetPteAddress (MI_PFN_ELEMENT(StartPage)); LastPte = MiGetPteAddress ((PCHAR)(MI_PFN_ELEMENT(EndPage)) - 1); while (PointerPte <= LastPte) { if (PointerPte->u.Hard.Valid == 0) { PagesNeeded += 1; } PointerPte += 1; } if (MmAvailablePages < PagesNeeded) { UNLOCK_PFN (OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); ExFreePool (NewPhysicalMemoryBlock); return STATUS_INSUFFICIENT_RESOURCES; } TempPte = ValidKernelPte; PointerPte = MiGetPteAddress (MI_PFN_ELEMENT(StartPage)); while (PointerPte <= LastPte) { if (PointerPte->u.Hard.Valid == 0) { PageFrameIndex = MiRemoveZeroPage(MI_GET_PAGE_COLOR_FROM_PTE (PointerPte)); MiInitializePfn (PageFrameIndex, PointerPte, 0); TempPte.u.Hard.PageFrameNumber = PageFrameIndex; *PointerPte = TempPte; } PointerPte += 1; } MmResidentAvailablePages -= PagesNeeded; } // // If the new range is adjacent to an existing range, just merge it into // the old block. Otherwise use the new block as a new entry will have to // be used. // NewPhysicalMemoryBlock->NumberOfRuns = MmPhysicalMemoryBlock->NumberOfRuns + 1; NewPhysicalMemoryBlock->NumberOfPages = MmPhysicalMemoryBlock->NumberOfPages + NumberOfPages; NewRun = &NewPhysicalMemoryBlock->Run[0]; start = 0; Inserted = FALSE; Updated = FALSE; do { Page = MmPhysicalMemoryBlock->Run[start].BasePage; count = MmPhysicalMemoryBlock->Run[start].PageCount; if (Inserted == FALSE) { // // Note overlaps into adjacent ranges were already checked above. // if (StartPage == Page + count) { MmPhysicalMemoryBlock->Run[start].PageCount += NumberOfPages; OldPhysicalMemoryBlock = NewPhysicalMemoryBlock; MmPhysicalMemoryBlock->NumberOfPages += NumberOfPages; // // Coalesce below and above to avoid leaving zero length gaps // as these gaps would prevent callers from removing ranges // the span them. // if (start + 1 < MmPhysicalMemoryBlock->NumberOfRuns) { start += 1; Page = MmPhysicalMemoryBlock->Run[start].BasePage; count = MmPhysicalMemoryBlock->Run[start].PageCount; if (StartPage + NumberOfPages == Page) { MmPhysicalMemoryBlock->Run[start - 1].PageCount += count; MmPhysicalMemoryBlock->NumberOfRuns -= 1; // // Copy any remaining entries. // if (start != MmPhysicalMemoryBlock->NumberOfRuns) { RtlMoveMemory (&MmPhysicalMemoryBlock->Run[start], &MmPhysicalMemoryBlock->Run[start + 1], (MmPhysicalMemoryBlock->NumberOfRuns - start) * sizeof (PHYSICAL_MEMORY_RUN)); } } } Updated = TRUE; break; } if (StartPage + NumberOfPages == Page) { MmPhysicalMemoryBlock->Run[start].BasePage = StartPage; MmPhysicalMemoryBlock->Run[start].PageCount += NumberOfPages; OldPhysicalMemoryBlock = NewPhysicalMemoryBlock; MmPhysicalMemoryBlock->NumberOfPages += NumberOfPages; Updated = TRUE; break; } if (StartPage + NumberOfPages <= Page) { if (start + 1 < MmPhysicalMemoryBlock->NumberOfRuns) { if (StartPage + NumberOfPages <= MmPhysicalMemoryBlock->Run[start + 1].BasePage) { // // Don't insert here - the new entry really belongs // (at least) one entry further down. // continue; } } NewRun->BasePage = StartPage; NewRun->PageCount = NumberOfPages; NewRun += 1; Inserted = TRUE; Updated = TRUE; } } *NewRun = MmPhysicalMemoryBlock->Run[start]; NewRun += 1; start += 1; } while (start != MmPhysicalMemoryBlock->NumberOfRuns); // // If the memory block has not been updated, then the new entry must // be added at the very end. // if (Updated == FALSE) { ASSERT (Inserted == FALSE); NewRun->BasePage = StartPage; NewRun->PageCount = NumberOfPages; Inserted = TRUE; } // // Repoint the MmPhysicalMemoryBlock at the new chunk, free the old after // releasing the PFN lock. // if (Inserted == TRUE) { OldPhysicalMemoryBlock = MmPhysicalMemoryBlock; MmPhysicalMemoryBlock = NewPhysicalMemoryBlock; } // // Note that the page directory (page parent entries on Win64) must be // filled in at system boot so that already-created processes do not fault // when referencing the new PFNs. // // // Walk through the memory descriptors and add pages to the // free list in the PFN database. // PageFrameIndex = StartPage; Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); if (EndPage - 1 > MmHighestPhysicalPage) { MmHighestPhysicalPage = EndPage - 1; } while (PageFrameIndex < EndPage) { ASSERT (Pfn1->u2.ShareCount == 0); ASSERT (Pfn1->u3.e2.ShortFlags == 0); ASSERT (Pfn1->u3.e2.ReferenceCount == 0); ASSERT64 (Pfn1->UsedPageTableEntries == 0); ASSERT (Pfn1->OriginalPte.u.Long == ZeroKernelPte.u.Long); ASSERT (Pfn1->PteFrame == 0); ASSERT ((Pfn1->PteAddress == PFN_REMOVED) || (Pfn1->PteAddress == (PMMPTE)(UINT_PTR)0)); // // Set the PTE address to the physical page for // virtual address alignment checking. // Pfn1->PteAddress = (PMMPTE)(PageFrameIndex << PTE_SHIFT); MiInsertPageInList (MmPageLocationList[FreePageList], PageFrameIndex); PageFrameIndex += 1; Pfn1 += 1; } MmResidentAvailablePages += NumberOfPages; MmNumberOfPhysicalPages += (PFN_COUNT)NumberOfPages; UNLOCK_PFN (OldIrql); // // Increase all commit limits to reflect the additional memory. // ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql); MmTotalCommitLimit += NumberOfPages; MmTotalCommitLimitMaximum += NumberOfPages; MmTotalCommittedPages += PagesNeeded; ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); ExFreePool (OldPhysicalMemoryBlock); // // Indicate number of bytes actually added to our caller. // NumberOfBytes->QuadPart = (ULONGLONG)NumberOfPages * PAGE_SIZE; return STATUS_SUCCESS; }
VOID Secondary_Close ( IN PSECONDARY Secondary ) { NTSTATUS status; LARGE_INTEGER timeOut; PLIST_ENTRY secondaryRequestEntry; PSECONDARY_REQUEST secondaryRequest; DebugTrace2( 0, Dbg2, ("Secondary close Secondary = %p\n", Secondary) ); ExAcquireFastMutex( &Secondary->FastMutex ); if (FlagOn(Secondary->Flags, SECONDARY_FLAG_CLOSED)) { //ASSERT( FALSE ); ExReleaseFastMutex( &Secondary->FastMutex ); return; } SetFlag( Secondary->Flags, SECONDARY_FLAG_CLOSED ); ExReleaseFastMutex( &Secondary->FastMutex ); if (Secondary->ThreadHandle == NULL) { Secondary_Dereference( Secondary ); return; } ASSERT( Secondary->ThreadObject != NULL ); DebugTrace2( 0, Dbg, ("Secondary close SECONDARY_REQ_DISCONNECT Secondary = %p\n", Secondary) ); secondaryRequest = AllocSecondaryRequest( Secondary, 0, FALSE ); secondaryRequest->RequestType = SECONDARY_REQ_DISCONNECT; QueueingSecondaryRequest( Secondary, secondaryRequest ); secondaryRequest = AllocSecondaryRequest( Secondary, 0, FALSE ); secondaryRequest->RequestType = SECONDARY_REQ_DOWN; QueueingSecondaryRequest( Secondary, secondaryRequest ); DebugTrace2( 0, Dbg, ("Secondary close SECONDARY_REQ_DISCONNECT end Secondary = %p\n", Secondary) ); timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( Secondary->ThreadObject, Executive, KernelMode, FALSE, &timeOut ); if (status == STATUS_SUCCESS) { DebugTrace2( 0, Dbg, ("Secondary_Close: thread stoped Secondary = %p\n", Secondary)); ObDereferenceObject( Secondary->ThreadObject ); Secondary->ThreadHandle = NULL; Secondary->ThreadObject = NULL; } else { ASSERT( NDASFAT_BUG ); return; } ASSERT( Secondary->VolDo->Vcb.SecondaryOpenFileCount == 0 ); ASSERT( IsListEmpty(&Secondary->FcbQueue) ); ASSERT( IsListEmpty(&Secondary->RecoveryCcbQueue) ); ASSERT( IsListEmpty(&Secondary->RequestQueue) ); while (secondaryRequestEntry = ExInterlockedRemoveHeadList(&Secondary->RequestQueue, &Secondary->RequestQSpinLock)) { PSECONDARY_REQUEST secondaryRequest2; InitializeListHead( secondaryRequestEntry ); secondaryRequest2 = CONTAINING_RECORD( secondaryRequestEntry, SECONDARY_REQUEST, ListEntry ); secondaryRequest2->ExecuteStatus = STATUS_IO_DEVICE_ERROR; if (secondaryRequest2->Synchronous == TRUE) KeSetEvent( &secondaryRequest2->CompleteEvent, IO_DISK_INCREMENT, FALSE ); else DereferenceSecondaryRequest( secondaryRequest2 ); } Secondary_Dereference( Secondary ); return; }
NTSTATUS MmRemovePhysicalMemory ( IN PPHYSICAL_ADDRESS StartAddress, IN OUT PLARGE_INTEGER NumberOfBytes ) /*++ Routine Description: This routine attempts to remove the specified physical address range from the system. Arguments: StartAddress - Supplies the starting physical address. NumberOfBytes - Supplies a pointer to the number of bytes being removed. Return Value: NTSTATUS. Environment: Kernel mode. PASSIVE level. No locks held. --*/ { ULONG i; ULONG Additional; PFN_NUMBER Page; PFN_NUMBER LastPage; PFN_NUMBER OriginalLastPage; PFN_NUMBER start; PFN_NUMBER PagesReleased; PMMPFN Pfn1; PMMPFN StartPfn; PMMPFN EndPfn; KIRQL OldIrql; PFN_NUMBER StartPage; PFN_NUMBER EndPage; PFN_COUNT NumberOfPages; SPFN_NUMBER MaxPages; PFN_NUMBER PageFrameIndex; PFN_NUMBER RemovedPages; LOGICAL Inserted; NTSTATUS Status; PMMPTE PointerPte; PMMPTE EndPte; PVOID VirtualAddress; PPHYSICAL_MEMORY_DESCRIPTOR OldPhysicalMemoryBlock; PPHYSICAL_MEMORY_DESCRIPTOR NewPhysicalMemoryBlock; PPHYSICAL_MEMORY_RUN NewRun; LOGICAL PfnDatabaseIsPhysical; ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL); ASSERT (BYTE_OFFSET(NumberOfBytes->LowPart) == 0); ASSERT (BYTE_OFFSET(StartAddress->LowPart) == 0); if (MI_IS_PHYSICAL_ADDRESS(MmPfnDatabase)) { // // The system must be configured for dynamic memory addition. This is // not strictly required to remove the memory, but it's better to check // for it now under the assumption that the administrator is probably // going to want to add this range of memory back in - better to give // the error now and refuse the removal than to refuse the addition // later. // if (MmDynamicPfn == FALSE) { return STATUS_NOT_SUPPORTED; } PfnDatabaseIsPhysical = TRUE; } else { PfnDatabaseIsPhysical = FALSE; } StartPage = (PFN_NUMBER)(StartAddress->QuadPart >> PAGE_SHIFT); NumberOfPages = (PFN_COUNT)(NumberOfBytes->QuadPart >> PAGE_SHIFT); EndPage = StartPage + NumberOfPages; if (EndPage - 1 > MmHighestPossiblePhysicalPage) { // // Truncate the request into something that can be mapped by the PFN // database. // EndPage = MmHighestPossiblePhysicalPage + 1; NumberOfPages = (PFN_COUNT)(EndPage - StartPage); } // // The range cannot wrap. // if (StartPage >= EndPage) { return STATUS_INVALID_PARAMETER_1; } StartPfn = MI_PFN_ELEMENT (StartPage); EndPfn = MI_PFN_ELEMENT (EndPage); ExAcquireFastMutex (&MmDynamicMemoryMutex); #if DBG MiDynmemData[0] += 1; #endif // // Decrease all commit limits to reflect the removed memory. // ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql); ASSERT (MmTotalCommitLimit <= MmTotalCommitLimitMaximum); if ((NumberOfPages + 100 > MmTotalCommitLimit - MmTotalCommittedPages) || (MmTotalCommittedPages > MmTotalCommitLimit)) { #if DBG MiDynmemData[1] += 1; #endif ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); return STATUS_INSUFFICIENT_RESOURCES; } MmTotalCommitLimit -= NumberOfPages; MmTotalCommitLimitMaximum -= NumberOfPages; ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); // // Check for outstanding promises that cannot be broken. // LOCK_PFN (OldIrql); MaxPages = MI_NONPAGABLE_MEMORY_AVAILABLE() - 100; if ((SPFN_NUMBER)NumberOfPages > MaxPages) { #if DBG MiDynmemData[2] += 1; #endif UNLOCK_PFN (OldIrql); Status = STATUS_INSUFFICIENT_RESOURCES; goto giveup2; } MmResidentAvailablePages -= NumberOfPages; MmNumberOfPhysicalPages -= NumberOfPages; // // The range must be contained in a single entry. It is permissible for // it to be part of a single entry, but it must not cross multiple entries. // Additional = (ULONG)-2; start = 0; do { Page = MmPhysicalMemoryBlock->Run[start].BasePage; LastPage = Page + MmPhysicalMemoryBlock->Run[start].PageCount; if ((StartPage >= Page) && (EndPage <= LastPage)) { if ((StartPage == Page) && (EndPage == LastPage)) { Additional = (ULONG)-1; } else if ((StartPage == Page) || (EndPage == LastPage)) { Additional = 0; } else { Additional = 1; } break; } start += 1; } while (start != MmPhysicalMemoryBlock->NumberOfRuns); if (Additional == (ULONG)-2) { #if DBG MiDynmemData[3] += 1; #endif MmResidentAvailablePages += NumberOfPages; MmNumberOfPhysicalPages += NumberOfPages; UNLOCK_PFN (OldIrql); Status = STATUS_CONFLICTING_ADDRESSES; goto giveup2; } for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { Pfn1->u3.e1.RemovalRequested = 1; } // // The free and zero lists must be pruned now before releasing the PFN // lock otherwise if another thread allocates the page from these lists, // the allocation will clear the RemovalRequested flag forever. // RemovedPages = MiRemovePhysicalPages (StartPage, EndPage); if (RemovedPages != NumberOfPages) { #if DBG retry: #endif Pfn1 = StartPfn; InterlockedIncrement (&MiDelayPageFaults); for (i = 0; i < 5; i += 1) { UNLOCK_PFN (OldIrql); // // Attempt to move pages to the standby list. Note that only the // pages with RemovalRequested set are moved. // MiTrimRemovalPagesOnly = TRUE; MiEmptyAllWorkingSets (); MiTrimRemovalPagesOnly = FALSE; MiFlushAllPages (); KeDelayExecutionThread (KernelMode, FALSE, &MmHalfSecond); LOCK_PFN (OldIrql); RemovedPages += MiRemovePhysicalPages (StartPage, EndPage); if (RemovedPages == NumberOfPages) { break; } // // RemovedPages doesn't include pages that were freed directly to // the bad page list via MiDecrementReferenceCount. So use the above // check purely as an optimization - and walk here when necessary. // for ( ; Pfn1 < EndPfn; Pfn1 += 1) { if (Pfn1->u3.e1.PageLocation != BadPageList) { break; } } if (Pfn1 == EndPfn) { RemovedPages = NumberOfPages; break; } } InterlockedDecrement (&MiDelayPageFaults); } if (RemovedPages != NumberOfPages) { #if DBG MiDynmemData[4] += 1; if (MiShowStuckPages != 0) { RemovedPages = 0; for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { if (Pfn1->u3.e1.PageLocation != BadPageList) { RemovedPages += 1; } } ASSERT (RemovedPages != 0); DbgPrint("MmRemovePhysicalMemory : could not get %d of %d pages\n", RemovedPages, NumberOfPages); if (MiShowStuckPages & 0x2) { ULONG PfnsPrinted; ULONG EnoughShown; PMMPFN FirstPfn; PFN_COUNT PfnCount; PfnCount = 0; PfnsPrinted = 0; EnoughShown = 100; if (MiShowStuckPages & 0x4) { EnoughShown = (ULONG)-1; } DbgPrint("Stuck PFN list: "); for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { if (Pfn1->u3.e1.PageLocation != BadPageList) { if (PfnCount == 0) { FirstPfn = Pfn1; } PfnCount += 1; } else { if (PfnCount != 0) { DbgPrint("%x -> %x ; ", FirstPfn - MmPfnDatabase, (FirstPfn - MmPfnDatabase) + PfnCount - 1); PfnsPrinted += 1; if (PfnsPrinted == EnoughShown) { break; } PfnCount = 0; } } } if (PfnCount != 0) { DbgPrint("%x -> %x ; ", FirstPfn - MmPfnDatabase, (FirstPfn - MmPfnDatabase) + PfnCount - 1); } DbgPrint("\n"); } if (MiShowStuckPages & 0x8) { DbgBreakPoint (); } if (MiShowStuckPages & 0x10) { goto retry; } } #endif UNLOCK_PFN (OldIrql); Status = STATUS_NO_MEMORY; goto giveup; } #if DBG for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { ASSERT (Pfn1->u3.e1.PageLocation == BadPageList); } #endif // // All the pages in the range have been removed. Update the physical // memory blocks and other associated housekeeping. // if (Additional == 0) { // // The range can be split off from an end of an existing chunk so no // pool growth or shrinkage is required. // NewPhysicalMemoryBlock = MmPhysicalMemoryBlock; OldPhysicalMemoryBlock = NULL; } else { // // The range cannot be split off from an end of an existing chunk so // pool growth or shrinkage is required. // UNLOCK_PFN (OldIrql); i = (sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + (sizeof(PHYSICAL_MEMORY_RUN) * (MmPhysicalMemoryBlock->NumberOfRuns + Additional))); NewPhysicalMemoryBlock = ExAllocatePoolWithTag (NonPagedPool, i, ' mM'); if (NewPhysicalMemoryBlock == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; #if DBG MiDynmemData[5] += 1; #endif goto giveup; } OldPhysicalMemoryBlock = MmPhysicalMemoryBlock; RtlZeroMemory (NewPhysicalMemoryBlock, i); LOCK_PFN (OldIrql); } // // Remove or split the requested range from the existing memory block. // NewPhysicalMemoryBlock->NumberOfRuns = MmPhysicalMemoryBlock->NumberOfRuns + Additional; NewPhysicalMemoryBlock->NumberOfPages = MmPhysicalMemoryBlock->NumberOfPages - NumberOfPages; NewRun = &NewPhysicalMemoryBlock->Run[0]; start = 0; Inserted = FALSE; do { Page = MmPhysicalMemoryBlock->Run[start].BasePage; LastPage = Page + MmPhysicalMemoryBlock->Run[start].PageCount; if (Inserted == FALSE) { if ((StartPage >= Page) && (EndPage <= LastPage)) { if ((StartPage == Page) && (EndPage == LastPage)) { ASSERT (Additional == -1); start += 1; continue; } else if ((StartPage == Page) || (EndPage == LastPage)) { ASSERT (Additional == 0); if (StartPage == Page) { MmPhysicalMemoryBlock->Run[start].BasePage += NumberOfPages; } MmPhysicalMemoryBlock->Run[start].PageCount -= NumberOfPages; } else { ASSERT (Additional == 1); OriginalLastPage = LastPage; MmPhysicalMemoryBlock->Run[start].PageCount = StartPage - MmPhysicalMemoryBlock->Run[start].BasePage; *NewRun = MmPhysicalMemoryBlock->Run[start]; NewRun += 1; NewRun->BasePage = EndPage; NewRun->PageCount = OriginalLastPage - EndPage; NewRun += 1; start += 1; continue; } Inserted = TRUE; } } *NewRun = MmPhysicalMemoryBlock->Run[start]; NewRun += 1; start += 1; } while (start != MmPhysicalMemoryBlock->NumberOfRuns); // // Repoint the MmPhysicalMemoryBlock at the new chunk. // Free the old block after releasing the PFN lock. // MmPhysicalMemoryBlock = NewPhysicalMemoryBlock; if (EndPage - 1 == MmHighestPhysicalPage) { MmHighestPhysicalPage = StartPage - 1; } // // Throw away all the removed pages that are currently enqueued. // for (Pfn1 = StartPfn; Pfn1 < EndPfn; Pfn1 += 1) { ASSERT (Pfn1->u3.e1.PageLocation == BadPageList); ASSERT (Pfn1->u3.e1.RemovalRequested == 1); MiUnlinkPageFromList (Pfn1); ASSERT (Pfn1->u1.Flink == 0); ASSERT (Pfn1->u2.Blink == 0); ASSERT (Pfn1->u3.e2.ReferenceCount == 0); ASSERT64 (Pfn1->UsedPageTableEntries == 0); Pfn1->PteAddress = PFN_REMOVED; Pfn1->u3.e2.ShortFlags = 0; Pfn1->OriginalPte.u.Long = ZeroKernelPte.u.Long; Pfn1->PteFrame = 0; } // // Now that the removed pages have been discarded, eliminate the PFN // entries that mapped them. Straddling entries left over from an // adjacent earlier removal are not collapsed at this point. // // PagesReleased = 0; if (PfnDatabaseIsPhysical == FALSE) { VirtualAddress = (PVOID)ROUND_TO_PAGES(MI_PFN_ELEMENT(StartPage)); PointerPte = MiGetPteAddress (VirtualAddress); EndPte = MiGetPteAddress (PAGE_ALIGN(MI_PFN_ELEMENT(EndPage))); while (PointerPte < EndPte) { PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); ASSERT (Pfn1->u2.ShareCount == 1); ASSERT (Pfn1->u3.e2.ReferenceCount == 1); Pfn1->u2.ShareCount = 0; MI_SET_PFN_DELETED (Pfn1); #if DBG Pfn1->u3.e1.PageLocation = StandbyPageList; #endif //DBG MiDecrementReferenceCount (PageFrameIndex); KeFlushSingleTb (VirtualAddress, TRUE, TRUE, (PHARDWARE_PTE)PointerPte, ZeroKernelPte.u.Flush); PagesReleased += 1; PointerPte += 1; VirtualAddress = (PVOID)((PCHAR)VirtualAddress + PAGE_SIZE); } MmResidentAvailablePages += PagesReleased; } #if DBG MiDynmemData[6] += 1; #endif UNLOCK_PFN (OldIrql); if (PagesReleased != 0) { MiReturnCommitment (PagesReleased); } ExReleaseFastMutex (&MmDynamicMemoryMutex); if (OldPhysicalMemoryBlock != NULL) { ExFreePool (OldPhysicalMemoryBlock); } NumberOfBytes->QuadPart = (ULONGLONG)NumberOfPages * PAGE_SIZE; return STATUS_SUCCESS; giveup: // // All the pages in the range were not obtained. Back everything out. // PageFrameIndex = StartPage; Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); LOCK_PFN (OldIrql); while (PageFrameIndex < EndPage) { ASSERT (Pfn1->u3.e1.RemovalRequested == 1); Pfn1->u3.e1.RemovalRequested = 0; if ((Pfn1->u3.e1.PageLocation == BadPageList) && (Pfn1->u3.e1.ParityError == 0)) { MiUnlinkPageFromList (Pfn1); MiInsertPageInList (MmPageLocationList[FreePageList], PageFrameIndex); } Pfn1 += 1; PageFrameIndex += 1; } MmResidentAvailablePages += NumberOfPages; MmNumberOfPhysicalPages += NumberOfPages; UNLOCK_PFN (OldIrql); giveup2: ExAcquireSpinLock (&MmChargeCommitmentLock, &OldIrql); MmTotalCommitLimit += NumberOfPages; MmTotalCommitLimitMaximum += NumberOfPages; ExReleaseSpinLock (&MmChargeCommitmentLock, OldIrql); ExReleaseFastMutex (&MmDynamicMemoryMutex); return Status; }
NTSTATUS NdFatSecondaryCommonWrite3 ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) { NTSTATUS status; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT fileObject = irpSp->FileObject; struct Write write; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB fcb; PCCB ccb; BOOLEAN fcbAcquired = FALSE; BOOLEAN writeToEof; PUCHAR inputBuffer; ULONG totalWriteLength; ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); ASSERT (!FlagOn(Irp->Flags, IRP_PAGING_IO)); typeOfOpen = FatDecodeFileObject( fileObject, &vcb, &fcb, &ccb ); ASSERT( typeOfOpen == UserFileOpen ); if (FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { /*if (FlagOn( fcb->FcbState, FCB_STATE_FILE_DELETED )) { ASSERT( FALSE ); FatRaiseStatus( IrpContext, STATUS_FILE_DELETED, NULL, NULL ); } else */{ ASSERT( FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ); status = STATUS_FILE_CORRUPT_ERROR; FatCompleteRequest( IrpContext, Irp, status ); return status; } } writeToEof = (irpSp->Parameters.Write.ByteOffset.QuadPart == FILE_WRITE_TO_END_OF_FILE && irpSp->Parameters.Write.ByteOffset.HighPart == -1); write.ByteOffset = irpSp->Parameters.Write.ByteOffset; write.Key = irpSp->Parameters.Write.Key; write.Length = irpSp->Parameters.Write.Length; ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); //FatAcquireSharedFcb( IrpContext, fcb ); //fcbAcquired = TRUE; try { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->Secondary->SessionResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { PrintIrp( Dbg, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); if (FlagOn(Irp->Flags, IRP_PAGING_IO)) { try_return( status = STATUS_FILE_LOCK_CONFLICT ); } else { FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } } inputBuffer = FatMapUserBuffer( IrpContext, Irp ); totalWriteLength = 0; do { ULONG inputBufferLength; _U8 *ndfsWinxpRequestData; _U64 primaryFileHandle; if (fcb->UncleanCount == 0) { DebugTrace( 0, Dbg2, "NdFatSecondaryCommonWrite2: fileName = %wZ\n", &fileObject->FileName ); totalWriteLength = write.Length; status = STATUS_FILE_CLOSED; break; } if (!FlagOn(ccb->NdFatFlags, ND_FAT_CLEANUP_COMPLETE)) { primaryFileHandle = ccb->PrimaryFileHandle; } else { PLIST_ENTRY ccbListEntry; ExAcquireFastMutex( &fcb->CcbQMutex ); for (primaryFileHandle = 0, ccbListEntry = fcb->CcbQueue.Flink; ccbListEntry != &fcb->CcbQueue; ccbListEntry = ccbListEntry->Flink) { if (!FlagOn(CONTAINING_RECORD(ccbListEntry, CCB, FcbListEntry)->NdFatFlags, ND_FAT_CLEANUP_COMPLETE)) { primaryFileHandle = CONTAINING_RECORD(ccbListEntry, CCB, FcbListEntry)->PrimaryFileHandle; break; } } ExReleaseFastMutex( &fcb->CcbQMutex ); } ASSERT( primaryFileHandle ); inputBufferLength = ((write.Length-totalWriteLength) <= volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize) ? (write.Length-totalWriteLength) : volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize; secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_WRITE, volDo->Secondary->Thread.SessionContext.PrimaryMaxDataSize ); if (secondaryRequest == NULL) { FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_WRITE, inputBufferLength ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); //ndfsWinxpRequestHeader->IrpTag = (_U32)Irp; ndfsWinxpRequestHeader->IrpMajorFunction = IRP_MJ_WRITE; ndfsWinxpRequestHeader->IrpMinorFunction = 0; ndfsWinxpRequestHeader->FileHandle = primaryFileHandle; ndfsWinxpRequestHeader->IrpFlags = 0; ndfsWinxpRequestHeader->IrpSpFlags = 0; ndfsWinxpRequestHeader->Write.Length = inputBufferLength; ndfsWinxpRequestHeader->Write.Key = write.Key; if (writeToEof) ndfsWinxpRequestHeader->Write.ByteOffset = write.ByteOffset.QuadPart; else ndfsWinxpRequestHeader->Write.ByteOffset = write.ByteOffset.QuadPart + totalWriteLength; ndfsWinxpRequestHeader->Write.ForceWrite = TRUE; DebugTrace2( 0, Dbg, ("ndfsWinxpRequestHeader->Write.ByteOffset = %I64d, ndfsWinxpRequestHeader->Write.Length = %d\n", ndfsWinxpRequestHeader->Write.ByteOffset, ndfsWinxpRequestHeader->Write.Length) ); ndfsWinxpRequestData = (_U8 *)(ndfsWinxpRequestHeader+1); if (inputBufferLength) { try { RtlCopyMemory( ndfsWinxpRequestData, inputBuffer + totalWriteLength, inputBufferLength ); } except (EXCEPTION_EXECUTE_HANDLER) { DebugTrace2( 0, Dbg2, ("RedirectIrp: Exception - Input buffer is not valid\n") ); status = GetExceptionCode(); break; } } //if (fcb->Header.FileSize.LowPart < 100) // DbgPrint( "data = %s\n", ndfsWinxpRequestData ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDFAT_TIME_OUT; status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { secondaryRequest = NULL; status = STATUS_IO_DEVICE_ERROR; leave; } KeClearEvent( &secondaryRequest->CompleteEvent ); if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); if (FlagOn(Irp->Flags, IRP_PAGING_IO)) { try_return( status = STATUS_FILE_LOCK_CONFLICT ); } else { FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; if (ndfsWinxpReplytHeader->Status != STATUS_SUCCESS) { DebugTrace2( 0, Dbg, ("ndfsWinxpReplytHeader->Status = %x\n", ndfsWinxpReplytHeader->Status) ); if (totalWriteLength) status = STATUS_SUCCESS; else status = ndfsWinxpReplytHeader->Status; ASSERT( ndfsWinxpReplytHeader->Information == 0 ); DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; break; } totalWriteLength += ndfsWinxpReplytHeader->Information; ASSERT( ndfsWinxpReplytHeader->Information <= inputBufferLength ); ASSERT( ndfsWinxpReplytHeader->Information != 0 ); DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; } while( totalWriteLength < write.Length ); try_exit: NOTHING; } finally { if (!AbnormalTermination()) { if (totalWriteLength) { Irp->IoStatus.Information = totalWriteLength; Irp->IoStatus.Status = STATUS_SUCCESS; } else { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; } } DebugTrace2( 0, Dbg, ("write.ByteOffset.QuadPart = %I64x, write.Length = %x, totalWriteRequestLength = %x lastStatus = %x\n", write.ByteOffset.QuadPart, write.Length, totalWriteLength, status) ); if (!FlagOn(ccb->NdFatFlags, ND_FAT_CLEANUP_COMPLETE) && Irp->IoStatus.Status != STATUS_SUCCESS) { DebugTrace2( 0, Dbg, ("write.ByteOffset.QuadPart = %I64x, write.Length = %x, totalWriteRequestLength = %x lastStatus = %x\n", write.ByteOffset.QuadPart, write.Length, totalWriteLength, status) ); PrintIrp( Dbg, "RedirectIrpMajorWrite", NULL, Irp ); } if (secondarySessionResourceAcquired == TRUE) SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource ); if (fcbAcquired) { FatReleaseFcb( IrpContext, fcb ); } if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); } FatCompleteRequest( IrpContext, Irp, status ); return status; }
NTSTATUS MiniSecondaryNtfsPassThrough ( IN PSECONDARY Secondary, IN OUT PFLT_CALLBACK_DATA Data ) { NTSTATUS status = FLT_PREOP_SUCCESS_NO_CALLBACK; //PIO_STACK_LOCATION iopb = IoGetCurrentIrpStackLocation( Irp ); PFLT_IO_PARAMETER_BLOCK iopb = Data->Iopb; PFILE_OBJECT fileObject = iopb->TargetFileObject; BOOLEAN fastMutexSet = FALSE; BOOLEAN retry = FALSE; ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); Secondary_Reference( Secondary ); if (fileObject && fileObject->Flags & FO_DIRECT_DEVICE_OPEN) { NDASFS_ASSERT( LFS_REQUIRED ); DbgPrint( "Direct device open\n" ); } if (iopb->MajorFunction == IRP_MJ_CREATE || // 0x00 iopb->MajorFunction == IRP_MJ_CLOSE || // 0x01 iopb->MajorFunction == IRP_MJ_READ || // 0x03 iopb->MajorFunction == IRP_MJ_WRITE || // 0x04 iopb->MajorFunction == IRP_MJ_QUERY_INFORMATION || // 0x05 iopb->MajorFunction == IRP_MJ_SET_INFORMATION || // 0x06 iopb->MajorFunction == IRP_MJ_QUERY_EA || // 0x07 iopb->MajorFunction == IRP_MJ_SET_EA || // 0x08 iopb->MajorFunction == IRP_MJ_FLUSH_BUFFERS || // 0x09 iopb->MajorFunction == IRP_MJ_QUERY_VOLUME_INFORMATION || // 0x0a iopb->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION || // 0x0b iopb->MajorFunction == IRP_MJ_DIRECTORY_CONTROL || // 0x0c iopb->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL || // 0x0c iopb->MajorFunction == IRP_MJ_LOCK_CONTROL || // 0x11 iopb->MajorFunction == IRP_MJ_CLEANUP || // 0x12 iopb->MajorFunction == IRP_MJ_QUERY_SECURITY || // 0x14 iopb->MajorFunction == IRP_MJ_SET_SECURITY || // 0x15 iopb->MajorFunction == IRP_MJ_QUERY_QUOTA || // 0x19 iopb->MajorFunction == IRP_MJ_SET_QUOTA) { // 0x1a } else if (iopb->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) { if (iopb->MinorFunction == IRP_MN_MOUNT_VOLUME || iopb->MinorFunction == IRP_MN_VERIFY_VOLUME || iopb->MinorFunction == IRP_MN_LOAD_FILE_SYSTEM) { NDASFS_ASSERT( LFS_UNEXPECTED ); ASSERT( Secondary_LookUpFileExtension(Secondary, fileObject) == NULL ); PrintData( LFS_DEBUG_SECONDARY_TRACE, "Secondary_PassThrough", Secondary->LfsDeviceExt, Irp ); Secondary_Dereference( Secondary ); return FLT_PREOP_SUCCESS_NO_CALLBACK; } } else if (iopb->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL || // 0x0f iopb->MajorFunction == IRP_MJ_SHUTDOWN || // 0x10 iopb->MajorFunction == IRP_MJ_CREATE_MAILSLOT || // 0x13 iopb->MajorFunction == IRP_MJ_POWER || // 0x16 iopb->MajorFunction == IRP_MJ_SYSTEM_CONTROL || // 0x17 iopb->MajorFunction == IRP_MJ_DEVICE_CHANGE) { // 0x18 NDASFS_ASSERT( LFS_REQUIRED ); PrintData( LFS_DEBUG_SECONDARY_TRACE, "Secondary_PassThrough", Secondary->LfsDeviceExt, Irp ); Secondary_Dereference( Secondary ); return FLT_PREOP_SUCCESS_NO_CALLBACK; } else if (iopb->MajorFunction == IRP_MJ_DEVICE_CONTROL) { PFILE_EXTENTION fileExt = NULL; fileExt = Secondary_LookUpFileExtension(Secondary, fileObject); if (fileExt == NULL || fileExt->TypeOfOpen != UserVolumeOpen) { Secondary_Dereference( Secondary ); Data->IoStatus.Status = STATUS_INVALID_PARAMETER; Data->IoStatus.Information = 0; return FLT_PREOP_COMPLETE; } status = MiniSecondary_Ioctl( Secondary, Data ); Secondary_Dereference( Secondary ); return status; } else { NDASFS_ASSERT( LFS_UNEXPECTED ); Secondary_Dereference( Secondary ); return FLT_PREOP_SUCCESS_NO_CALLBACK; } PrintData( LFS_DEBUG_SECONDARY_TRACE, "Secondary_PassThrough", Secondary->LfsDeviceExt, Irp ); if (Secondary->Thread.SessionStatus == STATUS_DISK_CORRUPT_ERROR) { NDASFS_ASSERT( Secondary_LookUpFileExtension(Secondary, fileObject) == NULL ); if (iopb->MajorFunction == IRP_MJ_CLOSE) { if (Secondary_LookUpFileExtension(Secondary, fileObject)) { SecondaryFileObjectClose( Secondary, fileObject ); } Data->IoStatus.Status = STATUS_SUCCESS; Data->IoStatus.Information = 0; } else if (iopb->MajorFunction == IRP_MJ_CLEANUP) { InterlockedDecrement( &((PLFS_FCB)iopb->TargetFileObject->FsContext)->UncleanCount ); SetFlag( fileObject->Flags, FO_CLEANUP_COMPLETE ); Data->IoStatus.Status = STATUS_SUCCESS; Data->IoStatus.Information = 0; } else { Data->IoStatus.Status = STATUS_DISK_CORRUPT_ERROR; Data->IoStatus.Information = 0; } Secondary_Dereference( Secondary ); return FLT_PREOP_COMPLETE; } if (Secondary->Thread.SessionStatus == STATUS_UNRECOGNIZED_VOLUME) { NDASFS_ASSERT( Secondary_LookUpFileExtension(Secondary, fileObject) == NULL ); if (iopb->MajorFunction == IRP_MJ_CLOSE) { if (Secondary_LookUpFileExtension(Secondary, fileObject)) { SecondaryFileObjectClose( Secondary, fileObject ); } Data->IoStatus.Status = STATUS_SUCCESS; Data->IoStatus.Information = 0; } else if (iopb->MajorFunction == IRP_MJ_CLEANUP) { InterlockedDecrement( &((PLFS_FCB)iopb->TargetFileObject->FsContext)->UncleanCount ); SetFlag( fileObject->Flags, FO_CLEANUP_COMPLETE ); Data->IoStatus.Status = STATUS_SUCCESS; Data->IoStatus.Information = 0; } else { Data->IoStatus.Status = STATUS_DISK_CORRUPT_ERROR; Data->IoStatus.Information = 0; } Secondary_Dereference( Secondary ); return FLT_PREOP_COMPLETE; } while (1) { NDASFS_ASSERT( fastMutexSet == FALSE ); NDASFS_ASSERT( retry == FALSE ); ExAcquireFastMutex( &Secondary->FastMutex ); if (FlagOn(Secondary->Flags, SECONDARY_FLAG_CLOSED)) { SPY_LOG_PRINT( LFS_DEBUG_SECONDARY_ERROR, ("Secondary is already closed Secondary = %p\n", Secondary) ); ExReleaseFastMutex( &Secondary->FastMutex ); NDASFS_ASSERT( iopb->MajorFunction == IRP_MJ_CREATE ); if (iopb->MajorFunction == IRP_MJ_CLOSE) { if (Secondary_LookUpFileExtension(Secondary, fileObject)) { SecondaryFileObjectClose( Secondary, fileObject ); } Data->IoStatus.Status = STATUS_SUCCESS; Data->IoStatus.Information = 0; } else if (iopb->MajorFunction == IRP_MJ_CLEANUP) { InterlockedDecrement( &((PLFS_FCB)iopb->TargetFileObject->FsContext)->UncleanCount ); SetFlag( fileObject->Flags, FO_CLEANUP_COMPLETE ); Data->IoStatus.Status = STATUS_SUCCESS; Data->IoStatus.Information = 0; } else { Data->IoStatus.Status = STATUS_TOO_LATE; Data->IoStatus.Information = 0; } status = FLT_PREOP_COMPLETE; break; } if (FlagOn(Secondary->Flags, SECONDARY_FLAG_ERROR)) { ExReleaseFastMutex( &Secondary->FastMutex ); if (iopb->MajorFunction == IRP_MJ_CLOSE) { if (Secondary_LookUpFileExtension(Secondary, fileObject)) { SecondaryFileObjectClose( Secondary, fileObject ); } Data->IoStatus.Status = STATUS_SUCCESS; Data->IoStatus.Information = 0; } else if (iopb->MajorFunction == IRP_MJ_CREATE) { Data->IoStatus.Status = STATUS_IO_DEVICE_ERROR; Data->IoStatus.Information = 0; } else if (iopb->MajorFunction == IRP_MJ_CLEANUP) { InterlockedDecrement( &((PLFS_FCB)iopb->TargetFileObject->FsContext)->UncleanCount ); SetFlag( fileObject->Flags, FO_CLEANUP_COMPLETE ); Data->IoStatus.Status = STATUS_SUCCESS; Data->IoStatus.Information = 0; } else { Data->IoStatus.Status = STATUS_FILE_CORRUPT_ERROR; Data->IoStatus.Information = 0; } status = FLT_PREOP_COMPLETE; break; } ExReleaseFastMutex( &Secondary->FastMutex ); if (!FlagOn(Secondary->Flags, SECONDARY_FLAG_RECONNECTING)) { NDASFS_ASSERT( Secondary->ThreadObject ); } KeEnterCriticalRegion(); status = MiniRedirectIrp( Secondary, Data, &fastMutexSet, &retry ); KeLeaveCriticalRegion(); if (retry == TRUE) { retry = FALSE; continue; } if (status == STATUS_SUCCESS) { NDASFS_ASSERT( fastMutexSet == FALSE ); if (Data->IoStatus.Status == STATUS_PENDING) { NDASFS_ASSERT( LFS_BUG ); } status = FLT_PREOP_COMPLETE; break; } if (status == STATUS_DEVICE_REQUIRES_CLEANING) { PrintData( LFS_DEBUG_LFS_INFO, "STATUS_DEVICE_REQUIRES_CLEANING", CONTAINING_RECORD(Secondary, LFS_DEVICE_EXTENSION, Secondary), Irp ); if (iopb->MajorFunction == IRP_MJ_CLEANUP) { InterlockedDecrement( &((PLFS_FCB)iopb->TargetFileObject->FsContext)->UncleanCount ); SetFlag( fileObject->Flags, FO_CLEANUP_COMPLETE ); Data->IoStatus.Status = STATUS_SUCCESS; Data->IoStatus.Information = 0; } else { Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; } status = FLT_PREOP_COMPLETE; break; } if (status == STATUS_ALERTED || status == STATUS_USER_APC) { NDASFS_ASSERT( fastMutexSet == FALSE ); continue; } NDASFS_ASSERT( status == STATUS_REMOTE_DISCONNECT || status == STATUS_IO_DEVICE_ERROR ); NDASFS_ASSERT( fastMutexSet == TRUE ); ExAcquireFastMutex( &Secondary->FastMutex ); ASSERT( FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ); if (Secondary->LfsDeviceExt->SecondaryState == CONNECTED_TO_LOCAL_STATE || FlagOn(Secondary->LfsDeviceExt->Flags, LFS_DEVICE_FLAG_SURPRISE_REMOVED) || GlobalLfs.ShutdownOccured == TRUE) { SetFlag( Secondary->Flags, SECONDARY_FLAG_ERROR ); ExReleaseFastMutex( &Secondary->FastMutex ); KeReleaseSemaphore( &Secondary->Semaphore, IO_NO_INCREMENT, 1, FALSE ); fastMutexSet = FALSE; Data->IoStatus.Status = STATUS_IO_DEVICE_ERROR; Data->IoStatus.Information = 0; status = FLT_PREOP_COMPLETE; break; } if (FlagOn(Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { //BOOLEAN recoveryResult; ASSERT( !FlagOn(Secondary->Flags, SECONDARY_FLAG_RECONNECTING) ); SetFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); ExReleaseFastMutex( &Secondary->FastMutex ); if (FlagOn(Secondary->Flags, SECONDARY_FLAG_CLOSED)) { ASSERT( iopb->MajorFunction == IRP_MJ_CREATE ); SPY_LOG_PRINT( LFS_DEBUG_SECONDARY_ERROR, ("Secondary is already closed Secondary = %p\n", Secondary) ); ClearFlag( Secondary->Flags, SECONDARY_FLAG_RECONNECTING ); KeReleaseSemaphore( &Secondary->Semaphore, IO_NO_INCREMENT, 1, FALSE ); continue; } CallRecoverySessionAsynchronously( Secondary ); fastMutexSet = FALSE; continue; } // // Recovery failed. // SetFlag( Secondary->Flags, SECONDARY_FLAG_ERROR ); ExReleaseFastMutex( &Secondary->FastMutex ); KeReleaseSemaphore( &Secondary->Semaphore, IO_NO_INCREMENT, 1, FALSE ); fastMutexSet = FALSE; NDASFS_ASSERT( IsListEmpty(&Secondary->RequestQueue) ); continue; } NDASFS_ASSERT( fastMutexSet == FALSE ); Secondary_Dereference( Secondary ); NDASFS_ASSERT( status == FLT_PREOP_COMPLETE ); return status; }
// fdo pnp NTSTATUS DoFdoPnP(PDEVICE_OBJECT pDevice,PIRP pIrp) { NTSTATUS status = STATUS_SUCCESS; PFdoExt pFdoExt = static_cast<PFdoExt>(pDevice->DeviceExtension); // nead call next driver BOOLEAN bCallNext = TRUE; PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(pIrp); // inc io count IncIoCount(pFdoExt); // save minor code UCHAR uMinorCode = pIoStack->MinorFunction; switch(uMinorCode) { case IRP_MN_START_DEVICE: { // send down first status = SendIrpToLowerDeviceSyn(pFdoExt->m_pLowerDevice,pIrp); if(NT_SUCCESS(status)) { // set device power state pFdoExt->m_devPowerState = PowerDeviceD0; POWER_STATE state; state.DeviceState = PowerDeviceD0; PoSetPowerState(pDevice,DevicePowerState,state); // set device interface state status = IoSetDeviceInterfaceState(&pFdoExt->m_symbolicName,TRUE); // set device pnp state SetNewPnpState(pFdoExt,IRP_MN_START_DEVICE); } // complete the irp pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp,IO_NO_INCREMENT); // do not call down the device stack bCallNext = FALSE; } break; // set pnp state directly case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: SetNewPnpState(pFdoExt,uMinorCode); break; // check for current pnp state,and restore it case IRP_MN_CANCEL_REMOVE_DEVICE: if(pFdoExt->m_ulCurrentPnpState == IRP_MN_QUERY_REMOVE_DEVICE) RestorePnpState(pFdoExt); break; // the same case IRP_MN_CANCEL_STOP_DEVICE: if(pFdoExt->m_ulCurrentPnpState == IRP_MN_QUERY_STOP_DEVICE) RestorePnpState(pFdoExt); break; // remove case IRP_MN_REMOVE_DEVICE: { // normal remove if(pFdoExt->m_ulCurrentPnpState != IRP_MN_SURPRISE_REMOVAL) { // just stop device interface if(pFdoExt->m_symbolicName.Buffer) { // set device interface false IoSetDeviceInterfaceState(&pFdoExt->m_symbolicName,FALSE); RtlFreeUnicodeString(&pFdoExt->m_symbolicName); } } // update pnp state SetNewPnpState(pFdoExt,IRP_MN_REMOVE_DEVICE); // dec outstandingio by 2 DecIoCount(pFdoExt); DecIoCount(pFdoExt); // wait other irps finish KeWaitForSingleObject(&pFdoExt->m_evRemove,Executive,KernelMode,FALSE,NULL); // check pdo ExAcquireFastMutex(&pFdoExt->m_mutexEnumPdo); // if the pdo is present if(pFdoExt->m_pEnumPdo) { PPdoExt pPdoExt = static_cast<PPdoExt>(pFdoExt->m_pEnumPdo->DeviceExtension); // surprise removal.update those field if(pPdoExt->m_ulCurrentPnpState == IRP_MN_SURPRISE_REMOVAL) { pPdoExt->m_pParentFdo = NULL; pPdoExt->m_bReportMissing = TRUE; pFdoExt->m_pEnumPdo = NULL; } // delete the pdo device IoDeleteDevice(pFdoExt->m_pEnumPdo); } ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); pIrp->IoStatus.Status = STATUS_SUCCESS; // call next driver,do not need to wait the finish IoSkipCurrentIrpStackLocation(pIrp); status = IoCallDriver(pFdoExt->m_pLowerDevice,pIrp); // first detach it from the device stack IoDetachDevice(pFdoExt->m_pLowerDevice); // then delete it,note that the device extension will become invalid,so dec need to check the minor code carefully IoDeleteDevice(pDevice); bCallNext = FALSE; } break; // stop case IRP_MN_STOP_DEVICE: DecIoCount(pFdoExt); KeWaitForSingleObject(&pFdoExt->m_evStop,Executive,KernelMode,FALSE,NULL); IncIoCount(pFdoExt); SetNewPnpState(pFdoExt,IRP_MN_STOP_DEVICE); break; // query bus relations case IRP_MN_QUERY_DEVICE_RELATIONS: { // only care bus relations if (BusRelations != pIoStack->Parameters.QueryDeviceRelations.Type) { /*switch(pIoStack->Parameters.QueryDeviceRelations.Type) { case EjectionRelations: devDebugPrint("\tquery EjectionRelations\n"); break; case PowerRelations: devDebugPrint("\tquery PowerRelations\n"); break; case RemovalRelations: devDebugPrint("\tquery RemovalRelations\n"); break; case TargetDeviceRelation: devDebugPrint("\tquery TargetDeviceRelation\n"); break; case SingleBusRelations: devDebugPrint("\tquery SingleBusRelations\n"); break; }*/ break; } // old relations PDEVICE_RELATIONS pOldRel = static_cast<PDEVICE_RELATIONS>(ULongToPtr(pIrp->IoStatus.Information)); ULONG ulNewCount = 0; ExAcquireFastMutex(&pFdoExt->m_mutexEnumPdo); // no pdo if(!pFdoExt->m_pEnumPdo) { devDebugPrint("\tBusRelations no device plugin \n"); ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); break; } PPdoExt pPdoExt = static_cast<PPdoExt>(pFdoExt->m_pEnumPdo->DeviceExtension); // if the pdo is not present if(!pPdoExt->m_bPresent) { // then we report it as missing pPdoExt->m_bReportMissing = TRUE; } else { // report the pdo ObReferenceObject(pFdoExt->m_pEnumPdo); ulNewCount ++; } // add the old count if(pOldRel) ulNewCount += pOldRel->Count; // allocate paged memory ULONG len = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (ulNewCount - 1); PDEVICE_RELATIONS pRel = static_cast<PDEVICE_RELATIONS>(ExAllocatePoolWithTag(PagedPool,len,'suBT')); // do not set the status,we should continue with the orignal devices that the upper devices reported if(!pRel) break; // copy old value if(pOldRel) { RtlCopyMemory(pRel,pOldRel,len - sizeof(PDEVICE_OBJECT)); if(pPdoExt->m_bPresent) pRel->Objects[pOldRel->Count] = pFdoExt->m_pEnumPdo; // free the previous buffer ExFreePool(pOldRel); } else { // the device is present if(pPdoExt->m_bPresent) pRel->Objects[0] = pFdoExt->m_pEnumPdo; } pRel->Count = ulNewCount; pIrp->IoStatus.Information = PtrToUlong(pRel); devDebugPrint("\tBusRelations pdo present %d,report %d\n",pPdoExt->m_bPresent,ulNewCount); ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); } break; // surprise removal case IRP_MN_SURPRISE_REMOVAL: { // set pnp state SetNewPnpState(pFdoExt,IRP_MN_SURPRISE_REMOVAL); // stop the fdo if(pFdoExt->m_symbolicName.Buffer) { // set device interface IoSetDeviceInterfaceState(&pFdoExt->m_symbolicName,FALSE); RtlFreeUnicodeString(&pFdoExt->m_symbolicName); } // update pdo's field ExAcquireFastMutex(&pFdoExt->m_mutexEnumPdo); PPdoExt pPdoExt = static_cast<PPdoExt>(pFdoExt->m_pEnumPdo->DeviceExtension); pPdoExt->m_pParentFdo = NULL; pPdoExt->m_bReportMissing = TRUE; ExReleaseFastMutex(&pFdoExt->m_mutexEnumPdo); } break; default: status = pIrp->IoStatus.Status; break; } // nead call lower device if(bCallNext) { pIrp->IoStatus.Status = status; IoSkipCurrentIrpStackLocation(pIrp); status = IoCallDriver(pFdoExt->m_pLowerDevice,pIrp); } // specail check for remove irp if(uMinorCode != IRP_MN_REMOVE_DEVICE) DecIoCount(pFdoExt); return status; }
NTSTATUS File_UpdateEntireFileByFileObject( __in PFLT_CALLBACK_DATA Data, __in PFLT_RELATED_OBJECTS FltObjects, __in PFILE_OBJECT FileObject, __in PSTREAM_CONTEXT pStreamCtx, __in PVOLUME_CONTEXT pVolCtx ) { NTSTATUS status = STATUS_SUCCESS ; PUCHAR Buffer = NULL ; LARGE_INTEGER ReadWriteOffset = {0} ; BOOLEAN EndOfFile = FALSE; ULONG uReadBytes = 0 ; ULONG uWriteBytes = 0 ; ULONG uAllocateBufferSize = 1024*64 ; ULONG uReadWriteLength = 0 ; ULONG uOffset = 0 ; LARGE_INTEGER FileSize = {0} ; PFILE_FLAG psFileFlag = NULL ; KIRQL OldIrql ; try{ //判断分配空间长度是否SectorSize对齐 if ((uAllocateBufferSize % pVolCtx->SectorSize) != 0) {//由于SectorSize目前为512bytes,故暂时先返回失败,以后可以对AllocateBufferSize进行调整 status = ERR_CORE_LENGTH_NOT_ALIGNED ; __leave ; } Buffer = FltAllocatePoolAlignedWithTag(FltObjects->Instance,PagedPool, uAllocateBufferSize, FILEFLAG_POOL_TAG); if (!Buffer) { status = STATUS_INSUFFICIENT_RESOURCES; __leave ; } //allocate local file flag buffer psFileFlag = (PFILE_FLAG)ExAllocatePoolWithTag(NonPagedPool, FILE_FLAG_LENGTH, FILEFLAG_POOL_TAG) ; if (NULL == psFileFlag) { status = STATUS_INSUFFICIENT_RESOURCES ; __leave ; } RtlCopyMemory(psFileFlag, g_psFileFlag, FILE_FLAG_LENGTH) ; //实际上这里应该是当前文件自身的flag //set current file size into file flag buffer File_GetFileSize(Data, FltObjects, &FileSize) ; psFileFlag->FileValidLength= FileSize.QuadPart ; //calculate padded file size if (FileSize.QuadPart % SECTOR_SIZE) {//file size is not multiply of sector size FileSize.QuadPart = FileSize.QuadPart + (SECTOR_SIZE - FileSize.QuadPart % SECTOR_SIZE) + FILE_FLAG_LENGTH ; } else {//file size is multiply of sector size FileSize.QuadPart += FILE_FLAG_LENGTH ; } RtlCopyMemory(psFileFlag->FileKeyHash, pStreamCtx->szKeyHash, HASH_SIZE) ; while (TRUE) { status = File_ReadWriteFile(IRP_MJ_READ, FltObjects->Instance, FileObject, &ReadWriteOffset, uAllocateBufferSize, Buffer, &uReadBytes, FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET) ; if (!NT_SUCCESS(status)) break; if (0 == uReadBytes) break; if (KeGetCurrentIrql() > PASSIVE_LEVEL) ExAcquireSpinLock(&pVolCtx->FsCryptSpinLock, &OldIrql); else ExAcquireFastMutex(&pVolCtx->FsCtxTableMutex) ; ///if (data_crypt(pVolCtx->aes_ctr_ctx, Buffer, uOffset, uReadBytes)) ///{ /// if (KeGetCurrentIrql() > PASSIVE_LEVEL) /// ExReleaseSpinLock(&pVolCtx->FsCryptSpinLock, OldIrql) ; /// else /// ExReleaseFastMutex(&pVolCtx->FsCtxTableMutex) ; /// break ; ///} if (KeGetCurrentIrql() > PASSIVE_LEVEL) ExReleaseSpinLock(&pVolCtx->FsCryptSpinLock, OldIrql) ; else ExReleaseFastMutex(&pVolCtx->FsCtxTableMutex) ; if (uReadBytes < uAllocateBufferSize) EndOfFile = TRUE; status = File_ReadWriteFile(IRP_MJ_WRITE, FltObjects->Instance, FileObject, &ReadWriteOffset, uReadBytes, Buffer, &uWriteBytes, FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET) ; if (!NT_SUCCESS(status)) break; if (EndOfFile) break; uOffset += uAllocateBufferSize ; ReadWriteOffset.QuadPart += uAllocateBufferSize ; RtlZeroMemory(Buffer, uAllocateBufferSize) ; } // write file flag ReadWriteOffset.QuadPart = FileSize.QuadPart - FILE_FLAG_LENGTH ; File_ReadWriteFile(IRP_MJ_WRITE, FltObjects->Instance, FileObject, &ReadWriteOffset, FILE_FLAG_LENGTH, psFileFlag, &uWriteBytes, FLTFL_IO_OPERATION_NON_CACHED|FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET) ; } finally{ if (Buffer) { FltFreePoolAlignedWithTag(FltObjects->Instance, Buffer, FILEFLAG_POOL_TAG); Buffer = NULL ; } if (psFileFlag) { ExFreePoolWithTag(psFileFlag, FILEFLAG_POOL_TAG) ; psFileFlag = NULL ; } } return status; }
VOID ExSwapinWorkerThreads ( IN BOOLEAN AllowSwap ) /*++ Routine Description: Sets the kernel stacks of the delayed worker threads to be swappable or pins them into memory. Arguments: AllowSwap - Supplies TRUE if worker kernel stacks should be swappable, FALSE if not. Return Value: None. --*/ { PETHREAD Thread; PETHREAD CurrentThread; PEPROCESS Process; KAPC Apc; KEVENT SwapSetEvent; PAGED_CODE(); CurrentThread = PsGetCurrentThread(); KeInitializeEvent (&SwapSetEvent, NotificationEvent, FALSE); Process = PsInitialSystemProcess; // // Serialize callers. // ExAcquireFastMutex (&ExpWorkerSwapinMutex); // // Stop new threads from swapping. // ExpWorkersCanSwap = AllowSwap; // // Stop existing worker threads from swapping. // for (Thread = PsGetNextProcessThread (Process, NULL); Thread != NULL; Thread = PsGetNextProcessThread (Process, Thread)) { // // Skip threads that are not worker threads or worker threads that // were permanently marked noswap at creation time. // if (Thread->ExWorkerCanWaitUser == 0) { continue; } if (Thread == CurrentThread) { // // No need to use an APC on the current thread. // KeSetKernelStackSwapEnable (AllowSwap); } else { // // Queue an APC to the thread, and wait for it to fire: // KeInitializeApc (&Apc, &Thread->Tcb, InsertApcEnvironment, ExpSetSwappingKernelApc, NULL, NULL, KernelMode, &AllowSwap); if (KeInsertQueueApc (&Apc, &SwapSetEvent, NULL, 3)) { KeWaitForSingleObject (&SwapSetEvent, Executive, KernelMode, FALSE, NULL); KeClearEvent(&SwapSetEvent); } } } ExReleaseFastMutex (&ExpWorkerSwapinMutex); }
PVOID ExAllocateFromPagedLookasideList( IN PPAGED_LOOKASIDE_LIST Lookaside ) /*++ Routine Description: This function removes (pops) the first entry from the specified paged lookaside list. Arguments: Lookaside - Supplies a pointer to a paged lookaside list structure. Return Value: If an entry is removed from the specified lookaside list, then the address of the entry is returned as the function value. Otherwise, NULL is returned. --*/ { PVOID Entry; Lookaside->L.TotalAllocates += 1; #if !defined(_PPC_) if (Isx86FeaturePresent(KF_CMPXCHG8B)) { if ((Entry = ExInterlockedPopEntrySList(&Lookaside->L.ListHead, NULL)) == NULL) { Lookaside->L.AllocateMisses += 1; Entry = (Lookaside->L.Allocate)(Lookaside->L.Type, Lookaside->L.Size, Lookaside->L.Tag); } return Entry; } #endif ExAcquireFastMutex(&Lookaside->Lock); Entry = PopEntryList(&Lookaside->L.ListHead.Next); if (Entry == NULL) { ExReleaseFastMutex(&Lookaside->Lock); Lookaside->L.AllocateMisses += 1; Entry = (Lookaside->L.Allocate)(Lookaside->L.Type, Lookaside->L.Size, Lookaside->L.Tag); } else { Lookaside->L.ListHead.Depth -= 1; ExReleaseFastMutex(&Lookaside->Lock); } return Entry; }
VOID VolDoThreadProc ( IN PVOLUME_DEVICE_OBJECT VolDo ) { BOOLEAN volDoThreadTerminate = FALSE; DebugTrace( 0, Dbg2, ("VolDoThreadProc: Start VolDo = %p\n", VolDo) ); VolDo_Reference( VolDo ); VolDo->Thread.Flags = VOLDO_THREAD_FLAG_INITIALIZING; ExAcquireFastMutex( &VolDo->FastMutex ); ClearFlag( VolDo->Thread.Flags, VOLDO_THREAD_FLAG_INITIALIZING ); SetFlag( VolDo->Thread.Flags, VOLDO_THREAD_FLAG_START ); ExReleaseFastMutex( &VolDo->FastMutex ); KeSetEvent( &VolDo->ReadyEvent, IO_DISK_INCREMENT, FALSE ); volDoThreadTerminate = FALSE; while (volDoThreadTerminate == FALSE) { PKEVENT events[2]; LONG eventCount; NTSTATUS eventStatus; LARGE_INTEGER timeOut; ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); eventCount = 0; events[eventCount++] = &VolDo->RequestEvent; timeOut.QuadPart = -NDNTFS_VOLDO_THREAD_FLAG_TIME_OUT; eventStatus = KeWaitForMultipleObjects( eventCount, events, WaitAny, Executive, KernelMode, TRUE, &timeOut, NULL ); if (eventStatus == STATUS_TIMEOUT) { LARGE_INTEGER currentTime; KeQuerySystemTime( ¤tTime ); if (FlagOn(VolDo->NdasNtfsFlags, NDAS_NTFS_DEVICE_FLAG_SHUTDOWN) || !(FlagOn(VolDo->NdasNtfsFlags, NDAS_NTFS_DEVICE_FLAG_MOUNTED) /*&& !FlagOn(LfsDeviceExt->Flags, LFS_DEVICE_STOP)*/)) { continue; } if ((VolDo->NetdiskEnableMode == NETDISK_READ_ONLY && (VolDo->TryFlushOrPurgeTime.QuadPart > currentTime.QuadPart || (currentTime.QuadPart - VolDo->TryFlushOrPurgeTime.QuadPart) >= NDNTFS_TRY_PURGE_DURATION)) || (VolDo->ReceiveWriteCommand == TRUE && (VolDo->TryFlushOrPurgeTime.QuadPart > currentTime.QuadPart || (currentTime.QuadPart - VolDo->TryFlushOrPurgeTime.QuadPart) >= NDNTFS_TRY_FLUSH_DURATION))) { if (VolDo->NetdiskEnableMode != NETDISK_READ_ONLY && (currentTime.QuadPart - VolDo->CommandReceiveTime.QuadPart) <= NDNTFS_TRY_FLUSH_DURATION /*&& (currentTime.QuadPart - VolDo->TryFlushOrPurgeTime.QuadPart) <= (100*NDNTFS_TRY_FLUSH_OR_PURGE_DURATION)*/) { continue; } do { HANDLE eventHandle = NULL; HANDLE fileHandle = NULL; ACCESS_MASK desiredAccess; ULONG attributes; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatusBlock; LARGE_INTEGER allocationSize; ULONG fileAttributes; ULONG shareAccess; ULONG createDisposition; ULONG createOptions; PVOID eaBuffer; ULONG eaLength; NTSTATUS createStatus; NTSTATUS fileSystemControlStatus; PIRP topLevelIrp; PRIMARY_REQUEST_INFO primaryRequestInfo; ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); if (VolDo->NetdiskEnableMode == NETDISK_SECONDARY) { break; } DebugTrace( 0, Dbg2, ("VolDoThreadProc: VolDo = %p, VolDo->NetdiskPartitionInformation.VolumeName = %wZ\n", VolDo, &VolDo->NetdiskPartitionInformation.VolumeName) ); desiredAccess = SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | FILE_WRITE_EA | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_EA; ASSERT( desiredAccess == 0x0012019F ); attributes = OBJ_KERNEL_HANDLE; attributes |= OBJ_CASE_INSENSITIVE; InitializeObjectAttributes( &objectAttributes, &VolDo->NetdiskPartitionInformation.VolumeName, attributes, NULL, NULL ); allocationSize.LowPart = 0; allocationSize.HighPart = 0; fileAttributes = 0; shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE; createDisposition = FILE_OPEN; createOptions = FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE; eaBuffer = NULL; eaLength = 0; RtlZeroMemory( &ioStatusBlock, sizeof(ioStatusBlock) ); createStatus = ZwCreateFile( &fileHandle, desiredAccess, &objectAttributes, &ioStatusBlock, &allocationSize, fileAttributes, shareAccess, createDisposition, createOptions, eaBuffer, eaLength ); if (createStatus != STATUS_SUCCESS) break; ASSERT( ioStatusBlock.Information == FILE_OPENED); createStatus = ZwCreateEvent( &eventHandle, GENERIC_READ, NULL, SynchronizationEvent, FALSE ); if (createStatus != STATUS_SUCCESS) { ASSERT( NDASNTFS_UNEXPECTED ); ZwClose( fileHandle ); break; } primaryRequestInfo.PrimaryTag = 0xe2027482; primaryRequestInfo.PrimarySessionId = NDASNTFS_LOCAL_PRMARY_SESSION_ID; primaryRequestInfo.PrimarySession = NULL; primaryRequestInfo.NdfsWinxpRequestHeader = NULL; topLevelIrp = IoGetTopLevelIrp(); ASSERT( topLevelIrp == NULL ); IoSetTopLevelIrp( (PIRP)&primaryRequestInfo ); RtlZeroMemory( &ioStatusBlock, sizeof(ioStatusBlock) ); fileSystemControlStatus = ZwFsControlFile( fileHandle, NULL, //&eventHandle, NULL, NULL, &ioStatusBlock, (VolDo->NetdiskEnableMode == NETDISK_READ_ONLY) ? FSCTL_NDAS_FS_PURGE : FSCTL_NDAS_FS_FLUSH, NULL, 0, NULL, 0 ); DebugTrace( 0, Dbg2, ("VolDoThreadProc: VolDo = %p, createStatus = %x, ioStatusBlock = %x\n", VolDo, fileSystemControlStatus, ioStatusBlock.Information) ); if (fileSystemControlStatus == STATUS_PENDING) { LARGE_INTEGER timeOut; timeOut.QuadPart = -3*NANO100_PER_SEC; ASSERT( FALSE ); //fileSystemControlStatus = ZwWaitForSingleObject( eventHandle, TRUE,NULL /*, &timeOut*/ ); } IoSetTopLevelIrp( topLevelIrp ); if (fileSystemControlStatus != STATUS_SUCCESS) DebugTrace( 0, Dbg2, ("VolDoThreadProc: VolDo = %p, fileSystemControlStatus = %x, ioStatusBlock = %x\n", VolDo, fileSystemControlStatus, ioStatusBlock.Information) ); ZwClose( eventHandle ); ZwClose( fileHandle ); break; } while (0); KeQuerySystemTime( &VolDo->TryFlushOrPurgeTime ); VolDo->ReceiveWriteCommand = FALSE; } continue; } ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); ASSERT( eventCount < THREAD_WAIT_OBJECTS ); if (!NT_SUCCESS( eventStatus ) || eventStatus >= eventCount) { ASSERT( NDASNTFS_UNEXPECTED ); SetFlag( VolDo->Thread.Flags, VOLDO_THREAD_FLAG_ERROR ); volDoThreadTerminate = TRUE; continue; } KeClearEvent( events[eventStatus] ); if (eventStatus == 0) { volDoThreadTerminate = TRUE; break; } else { NDAS_ASSERT( NDASNTFS_BUG ); } } ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); ExAcquireFastMutex( &VolDo->FastMutex ); SetFlag( VolDo->Thread.Flags, VOLDO_THREAD_FLAG_STOPED ); ExReleaseFastMutex( &VolDo->FastMutex ); DebugTrace( 0, Dbg2, ("VolDoThreadProc: PsTerminateSystemThread VolDo = %p\n", VolDo) ); ExAcquireFastMutex( &VolDo->FastMutex ); SetFlag( VolDo->Thread.Flags, VOLDO_THREAD_FLAG_TERMINATED ); ExReleaseFastMutex( &VolDo->FastMutex ); VolDo_Dereference( VolDo ); ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); PsTerminateSystemThread( STATUS_SUCCESS ); }
NTSTATUS NTAPI MmpPageOutPhysicalAddress(PFN_NUMBER Page) { BOOLEAN ProcRef = FALSE, PageDirty; PFN_NUMBER SectionPage = 0; PMM_RMAP_ENTRY entry; PMM_SECTION_SEGMENT Segment = NULL; LARGE_INTEGER FileOffset; PMEMORY_AREA MemoryArea; PMMSUPPORT AddressSpace = NULL; BOOLEAN Dirty = FALSE; PVOID Address = NULL; PEPROCESS Process = NULL; NTSTATUS Status = STATUS_SUCCESS; MM_REQUIRED_RESOURCES Resources = { 0 }; DPRINTC("Page out %x (ref ct %x)\n", Page, MmGetReferenceCountPage(Page)); ExAcquireFastMutex(&MiGlobalPageOperation); if ((Segment = MmGetSectionAssociation(Page, &FileOffset))) { DPRINTC("Withdrawing page (%x) %p:%x\n", Page, Segment, FileOffset.LowPart); SectionPage = MmWithdrawSectionPage(Segment, &FileOffset, &Dirty); DPRINTC("SectionPage %x\n", SectionPage); if (SectionPage == MM_WAIT_ENTRY || SectionPage == 0) { DPRINT1("In progress page out %x\n", SectionPage); ExReleaseFastMutex(&MiGlobalPageOperation); return STATUS_UNSUCCESSFUL; } else { ASSERT(SectionPage == Page); } Resources.State = Dirty ? 1 : 0; } else { DPRINT("No segment association for %x\n", Page); } Dirty = MmIsDirtyPageRmap(Page); DPRINTC("Trying to unmap all instances of %x\n", Page); ExAcquireFastMutex(&RmapListLock); entry = MmGetRmapListHeadPage(Page); // Entry and Segment might be null here in the case that the page // is new and is in the process of being swapped in if (!entry && !Segment) { Status = STATUS_UNSUCCESSFUL; DPRINT1("Page %x is in transit\n", Page); ExReleaseFastMutex(&RmapListLock); goto bail; } while (entry != NULL && NT_SUCCESS(Status)) { Process = entry->Process; Address = entry->Address; DPRINTC("Process %p Address %p Page %x\n", Process, Address, Page); if (RMAP_IS_SEGMENT(Address)) { entry = entry->Next; continue; } if (Process && Address < MmSystemRangeStart) { /* Make sure we don't try to page out part of an exiting process */ if (PspIsProcessExiting(Process)) { DPRINT("bail\n"); ExReleaseFastMutex(&RmapListLock); goto bail; } ObReferenceObject(Process); ProcRef = TRUE; AddressSpace = &Process->Vm; } else { AddressSpace = MmGetKernelAddressSpace(); } ExReleaseFastMutex(&RmapListLock); RtlZeroMemory(&Resources, sizeof(Resources)); if ((((ULONG_PTR)Address) & 0xFFF) != 0) { KeBugCheck(MEMORY_MANAGEMENT); } do { MmLockAddressSpace(AddressSpace); MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address); if (MemoryArea == NULL || MemoryArea->DeleteInProgress) { Status = STATUS_UNSUCCESSFUL; MmUnlockAddressSpace(AddressSpace); DPRINTC("bail\n"); goto bail; } DPRINTC("Type %x (%p -> %p)\n", MemoryArea->Type, MemoryArea->StartingAddress, MemoryArea->EndingAddress); Resources.DoAcquisition = NULL; Resources.Page[0] = Page; ASSERT(KeGetCurrentIrql() <= APC_LEVEL); DPRINT("%p:%p, page %x %x\n", Process, Address, Page, Resources.Page[0]); PageDirty = FALSE; Status = MmPageOutCacheSection(AddressSpace, MemoryArea, Address, &PageDirty, &Resources); Dirty |= PageDirty; DPRINT("%x\n", Status); ASSERT(KeGetCurrentIrql() <= APC_LEVEL); MmUnlockAddressSpace(AddressSpace); if (Status == STATUS_SUCCESS + 1) { // Wait page ... the other guy has it, so we'll just fail for now DPRINT1("Wait entry ... can't continue\n"); Status = STATUS_UNSUCCESSFUL; goto bail; } else if (Status == STATUS_MORE_PROCESSING_REQUIRED) { DPRINTC("DoAcquisition %p\n", Resources.DoAcquisition); Status = Resources.DoAcquisition(AddressSpace, MemoryArea, &Resources); DPRINTC("Status %x\n", Status); if (!NT_SUCCESS(Status)) { DPRINT1("bail\n"); goto bail; } else { Status = STATUS_MM_RESTART_OPERATION; } } } while (Status == STATUS_MM_RESTART_OPERATION); if (ProcRef) { ObDereferenceObject(Process); ProcRef = FALSE; } ExAcquireFastMutex(&RmapListLock); ASSERT(!MM_IS_WAIT_PTE(MmGetPfnForProcess(Process, Address))); entry = MmGetRmapListHeadPage(Page); DPRINTC("Entry %p\n", entry); } ExReleaseFastMutex(&RmapListLock); bail: DPRINTC("BAIL %x\n", Status); if (Segment) { ULONG RefCount; DPRINTC("About to finalize section page %x (%p:%x) Status %x %s\n", Page, Segment, FileOffset.LowPart, Status, Dirty ? "dirty" : "clean"); if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = MmFinalizeSectionPageOut(Segment, &FileOffset, Page, Dirty))) { DPRINTC("Failed to page out %x, replacing %x at %x in segment %x\n", SectionPage, FileOffset.LowPart, Segment); MmLockSectionSegment(Segment); MmSetPageEntrySectionSegment(Segment, &FileOffset, Dirty ? MAKE_PFN_SSE(Page) : DIRTY_SSE(MAKE_PFN_SSE(Page))); MmUnlockSectionSegment(Segment); } /* Alas, we had the last reference */ if ((RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0) MmFinalizeSegment(Segment); } if (ProcRef) { DPRINTC("Dereferencing process...\n"); ObDereferenceObject(Process); } ExReleaseFastMutex(&MiGlobalPageOperation); DPRINTC("%s %x %x\n", NT_SUCCESS(Status) ? "Evicted" : "Spared", Page, Status); return NT_SUCCESS(Status) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; }