VOID ExRaiseDatatypeMisalignment ( VOID ) /*++ Routine Description: This function raises a datatype misalignment exception. Arguments: None. Return Value: None. --*/ { ExRaiseStatus(STATUS_DATATYPE_MISALIGNMENT); return; }
PVOID FuseMapUserBuffer ( IN OUT PIRP Irp ) { // // If there is no Mdl, then we must be in the Fsd, and we can simply // return the UserBuffer field from the Irp. // if (Irp->MdlAddress == NULL) { return Irp->UserBuffer; } else { PVOID Address = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority ); if (Address == NULL) { ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); } return Address; } }
VOID ExRaiseAccessViolation ( VOID ) /*++ Routine Description: This function raises an access violation exception. Arguments: None. Return Value: None. --*/ { ExRaiseStatus(STATUS_ACCESS_VIOLATION); return; }
VOID CdRaiseStatusEx ( _In_ PIRP_CONTEXT IrpContext, _In_ NTSTATUS Status, _In_ BOOLEAN NormalizeStatus, _In_opt_ ULONG FileId, _In_opt_ ULONG Line ) { BOOLEAN BreakIn = FALSE; AssertVerifyDevice( IrpContext, Status); if (CdTraceRaises) { DbgPrint( "%p CdRaiseStatusEx 0x%x @ fid %d, line %d\n", PsGetCurrentThread(), Status, FileId, Line); } if (CdTestRaisedStatus && !CdBreakOnAnyRaise) { ULONG Index; for (Index = 0; Index < (sizeof( CdInterestingExceptionCodes) / sizeof( CdInterestingExceptionCodes[0])); Index++) { if ((STATUS_SUCCESS != CdInterestingExceptionCodes[Index]) && (CdInterestingExceptionCodes[Index] == Status)) { BreakIn = TRUE; break; } } } if (BreakIn || CdBreakOnAnyRaise) { DbgPrint( "CDFS: Breaking on raised status %08x (BI=%d,BA=%d)\n", Status, BreakIn, CdBreakOnAnyRaise); DbgPrint( "CDFS: (FILEID %d LINE %d)\n", FileId, Line); DbgPrint( "CDFS: Contact CDFS.SYS component owner for triage.\n"); DbgPrint( "CDFS: 'eb %p 0;eb %p 0' to disable this alert.\n", &CdTestRaisedStatus, &CdBreakOnAnyRaise); NT_ASSERT(FALSE); } if (NormalizeStatus) { IrpContext->ExceptionStatus = FsRtlNormalizeNtstatus( Status, STATUS_UNEXPECTED_IO_ERROR); } else { IrpContext->ExceptionStatus = Status; } IrpContext->RaisedAtLineFile = (FileId << 16) | Line; ExRaiseStatus( IrpContext->ExceptionStatus); }
static VOID ThrowAtPassiveLevel() { CFIX_ASSERT_EQUALS_ULONG( 1, 1 ); CFIX_LOG( L"" ); CFIX_LOG( L"" ); // // N.B. ExRaiseStatus requires PASSIVE_LEVEL. // ExRaiseStatus( 'Excp' ); }
/*++ * @name FsRtlAllocatePoolWithQuota * @implemented * * FILLME * * @param PoolType * FILLME * * @param NumberOfBytes * FILLME * * @return None * * @remarks The pool tag used is "FSrt". * *--*/ PVOID NTAPI FsRtlAllocatePoolWithQuota(IN POOL_TYPE PoolType, IN ULONG NumberOfBytes) { PVOID Address; Address = ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, IFS_POOL_TAG); if (NULL == Address) { ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); } return Address; }
/* * @implemented */ VOID NTAPI PsChargePoolQuota(IN PEPROCESS Process, IN POOL_TYPE PoolType, IN SIZE_T Amount) { NTSTATUS Status; ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); /* Don't do anything for the system process */ if (Process == PsInitialSystemProcess) return; /* Charge the usage */ Status = PsChargeProcessPoolQuota(Process, PoolType, Amount); if (!NT_SUCCESS(Status)) ExRaiseStatus(Status); }
VOID NtfsInitializeNtfsData ( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: This routine initializes the global ntfs data record Arguments: DriverObject - Supplies the driver object for NTFS Return Value: None. --*/ { USHORT FileLockMaxDepth; USHORT IoContextMaxDepth; USHORT IrpContextMaxDepth; USHORT KeventMaxDepth; USHORT ScbNonpagedMaxDepth; USHORT ScbSnapshotMaxDepth; USHORT CcbDataMaxDepth; USHORT CcbMaxDepth; USHORT DeallocatedRecordsMaxDepth; USHORT FcbDataMaxDepth; USHORT FcbIndexMaxDepth; USHORT IndexContextMaxDepth; USHORT LcbMaxDepth; USHORT NukemMaxDepth; USHORT ScbDataMaxDepth; PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL; BOOLEAN CapturedSubjectContext = FALSE; PACL SystemDacl = NULL; ULONG SystemDaclLength; PSID AdminSid = NULL; PSID SystemSid = NULL; NTSTATUS Status = STATUS_SUCCESS; PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsInitializeNtfsData\n") ); // // Zero the record and set its node type code and size // RtlZeroMemory( &NtfsData, sizeof(NTFS_DATA)); NtfsData.NodeTypeCode = NTFS_NTC_DATA_HEADER; NtfsData.NodeByteSize = sizeof(NTFS_DATA); // // Initialize the queue of mounted Vcbs // InitializeListHead(&NtfsData.VcbQueue); // // This list head keeps track of closes yet to be done. // InitializeListHead( &NtfsData.AsyncCloseList ); InitializeListHead( &NtfsData.DelayedCloseList ); ExInitializeWorkItem( &NtfsData.NtfsCloseItem, (PWORKER_THREAD_ROUTINE)NtfsFspClose, NULL ); // // Set the driver object, device object, and initialize the global // resource protecting the file system // NtfsData.DriverObject = DriverObject; ExInitializeResource( &NtfsData.Resource ); // // Now allocate and initialize the s-list structures used as our pool // of IRP context records. The size of the zone is based on the // system memory size. We also initialize the spin lock used to protect // the zone. // KeInitializeSpinLock( &NtfsData.StrucSupSpinLock ); { switch ( MmQuerySystemSize() ) { case MmSmallSystem: NtfsData.FreeEresourceTotal = 14; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 4; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 8; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 4; CcbMaxDepth = 4; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 8; FcbIndexMaxDepth = 4; IndexContextMaxDepth = 8; LcbMaxDepth = 4; NukemMaxDepth = 8; ScbDataMaxDepth = 4; SetFlag( NtfsData.Flags, NTFS_FLAGS_SMALL_SYSTEM ); NtfsMaxDelayedCloseCount = MAX_DELAYED_CLOSE_COUNT; break; case MmMediumSystem: NtfsData.FreeEresourceTotal = 30; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 8; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 30; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 12; CcbMaxDepth = 6; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 30; FcbIndexMaxDepth = 12; IndexContextMaxDepth = 8; LcbMaxDepth = 12; NukemMaxDepth = 8; ScbDataMaxDepth = 12; SetFlag( NtfsData.Flags, NTFS_FLAGS_MEDIUM_SYSTEM ); NtfsMaxDelayedCloseCount = 4 * MAX_DELAYED_CLOSE_COUNT; break; case MmLargeSystem: SetFlag( NtfsData.Flags, NTFS_FLAGS_LARGE_SYSTEM ); NtfsMaxDelayedCloseCount = 16 * MAX_DELAYED_CLOSE_COUNT; if (MmIsThisAnNtAsSystem()) { NtfsData.FreeEresourceTotal = 256; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 256; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 128; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 40; CcbMaxDepth = 20; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 128; FcbIndexMaxDepth = 40; IndexContextMaxDepth = 8; LcbMaxDepth = 40; NukemMaxDepth = 8; ScbDataMaxDepth = 40; } else { NtfsData.FreeEresourceTotal = 128; // // Nonpaged Lookaside list maximum depths // FileLockMaxDepth = 8; IoContextMaxDepth = 8; IrpContextMaxDepth = 64; KeventMaxDepth = 8; ScbNonpagedMaxDepth = 64; ScbSnapshotMaxDepth = 8; // // Paged Lookaside list maximum depths // CcbDataMaxDepth = 20; CcbMaxDepth = 10; DeallocatedRecordsMaxDepth = 8; FcbDataMaxDepth = 64; FcbIndexMaxDepth = 20; IndexContextMaxDepth = 8; LcbMaxDepth = 20; NukemMaxDepth = 8; ScbDataMaxDepth = 20; } break; } NtfsMinDelayedCloseCount = NtfsMaxDelayedCloseCount * 4 / 5; } // // Initialize our various lookaside lists. To make it a bit more readable we'll // define two quick macros to do the initialization // #if DBG && i386 && defined (NTFSPOOLCHECK) #define NPagedInit(L,S,T,D) { ExInitializeNPagedLookasideList( (L), NtfsDebugAllocatePoolWithTag, NtfsDebugFreePool, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #define PagedInit(L,S,T,D) { ExInitializePagedLookasideList( (L), NtfsDebugAllocatePoolWithTag, NtfsDebugFreePool, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #else // DBG && i386 #define NPagedInit(L,S,T,D) { ExInitializeNPagedLookasideList( (L), NULL, NULL, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #define PagedInit(L,S,T,D) { ExInitializePagedLookasideList( (L), NULL, NULL, POOL_RAISE_IF_ALLOCATION_FAILURE, S, T, D); } #endif // DBG && i386 NPagedInit( &NtfsFileLockLookasideList, sizeof(FILE_LOCK), 'kftN', FileLockMaxDepth ); NPagedInit( &NtfsIoContextLookasideList, sizeof(NTFS_IO_CONTEXT), 'IftN', IoContextMaxDepth ); NPagedInit( &NtfsIrpContextLookasideList, sizeof(IRP_CONTEXT), 'iftN', IrpContextMaxDepth ); NPagedInit( &NtfsKeventLookasideList, sizeof(KEVENT), 'KftN', KeventMaxDepth ); NPagedInit( &NtfsScbNonpagedLookasideList, sizeof(SCB_NONPAGED), 'nftN', ScbNonpagedMaxDepth ); NPagedInit( &NtfsScbSnapshotLookasideList, sizeof(SCB_SNAPSHOT), 'TftN', ScbSnapshotMaxDepth ); PagedInit( &NtfsCcbLookasideList, sizeof(CCB), 'CftN', CcbMaxDepth ); PagedInit( &NtfsCcbDataLookasideList, sizeof(CCB_DATA), 'cftN', CcbDataMaxDepth ); PagedInit( &NtfsDeallocatedRecordsLookasideList, sizeof(DEALLOCATED_RECORDS), 'DftN', DeallocatedRecordsMaxDepth ); PagedInit( &NtfsFcbDataLookasideList, sizeof(FCB_DATA), 'fftN', FcbDataMaxDepth ); PagedInit( &NtfsFcbIndexLookasideList, sizeof(FCB_INDEX), 'FftN', FcbIndexMaxDepth ); PagedInit( &NtfsIndexContextLookasideList, sizeof(INDEX_CONTEXT), 'EftN', IndexContextMaxDepth ); PagedInit( &NtfsLcbLookasideList, sizeof(LCB), 'lftN', LcbMaxDepth ); PagedInit( &NtfsNukemLookasideList, sizeof(NUKEM), 'NftN', NukemMaxDepth ); PagedInit( &NtfsScbDataLookasideList, SIZEOF_SCB_DATA, 'sftN', ScbDataMaxDepth ); // // Initialize the cache manager callback routines, First are the routines // for normal file manipulations, followed by the routines for // volume manipulations. // { PCACHE_MANAGER_CALLBACKS Callbacks = &NtfsData.CacheManagerCallbacks; Callbacks->AcquireForLazyWrite = &NtfsAcquireScbForLazyWrite; Callbacks->ReleaseFromLazyWrite = &NtfsReleaseScbFromLazyWrite; Callbacks->AcquireForReadAhead = &NtfsAcquireScbForReadAhead; Callbacks->ReleaseFromReadAhead = &NtfsReleaseScbFromReadAhead; } { PCACHE_MANAGER_CALLBACKS Callbacks = &NtfsData.CacheManagerVolumeCallbacks; Callbacks->AcquireForLazyWrite = &NtfsAcquireVolumeFileForLazyWrite; Callbacks->ReleaseFromLazyWrite = &NtfsReleaseVolumeFileFromLazyWrite; Callbacks->AcquireForReadAhead = NULL; Callbacks->ReleaseFromReadAhead = NULL; } // // Initialize the queue of read ahead threads // InitializeListHead(&NtfsData.ReadAheadThreads); // // Set up global pointer to our process. // NtfsData.OurProcess = PsGetCurrentProcess(); // // Use a try-finally to cleanup on errors. // try { SECURITY_DESCRIPTOR NewDescriptor; SID_IDENTIFIER_AUTHORITY Authority = SECURITY_NT_AUTHORITY; SubjectContext = NtfsAllocatePool( PagedPool, sizeof( SECURITY_SUBJECT_CONTEXT )); SeCaptureSubjectContext( SubjectContext ); CapturedSubjectContext = TRUE; // // Build the default security descriptor which gives full access to // system and administrator. // AdminSid = (PSID) NtfsAllocatePool( PagedPool, RtlLengthRequiredSid( 2 )); RtlInitializeSid( AdminSid, &Authority, 2 ); *(RtlSubAuthoritySid( AdminSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID; *(RtlSubAuthoritySid( AdminSid, 1 )) = DOMAIN_ALIAS_RID_ADMINS; SystemSid = (PSID) NtfsAllocatePool( PagedPool, RtlLengthRequiredSid( 1 )); RtlInitializeSid( SystemSid, &Authority, 1 ); *(RtlSubAuthoritySid( SystemSid, 0 )) = SECURITY_LOCAL_SYSTEM_RID; SystemDaclLength = sizeof( ACL ) + (2 * sizeof( ACCESS_ALLOWED_ACE )) + SeLengthSid( AdminSid ) + SeLengthSid( SystemSid ) + 8; // The 8 is just for good measure SystemDacl = NtfsAllocatePool( PagedPool, SystemDaclLength ); Status = RtlCreateAcl( SystemDacl, SystemDaclLength, ACL_REVISION2 ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlAddAccessAllowedAce( SystemDacl, ACL_REVISION2, GENERIC_ALL, SystemSid ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlAddAccessAllowedAce( SystemDacl, ACL_REVISION2, GENERIC_ALL, AdminSid ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlCreateSecurityDescriptor( &NewDescriptor, SECURITY_DESCRIPTOR_REVISION1 ); if (!NT_SUCCESS( Status )) { leave; } Status = RtlSetDaclSecurityDescriptor( &NewDescriptor, TRUE, SystemDacl, FALSE ); if (!NT_SUCCESS( Status )) { leave; } Status = SeAssignSecurity( NULL, &NewDescriptor, &NtfsData.DefaultDescriptor, FALSE, SubjectContext, IoGetFileObjectGenericMapping(), PagedPool ); if (!NT_SUCCESS( Status )) { leave; } NtfsData.DefaultDescriptorLength = RtlLengthSecurityDescriptor( NtfsData.DefaultDescriptor ); ASSERT( SeValidSecurityDescriptor( NtfsData.DefaultDescriptorLength, NtfsData.DefaultDescriptor )); } finally { if (CapturedSubjectContext) { SeReleaseSubjectContext( SubjectContext ); } if (SubjectContext != NULL) { NtfsFreePool( SubjectContext ); } if (SystemDacl != NULL) { NtfsFreePool( SystemDacl ); } if (AdminSid != NULL) { NtfsFreePool( AdminSid ); } if (SystemSid != NULL) { NtfsFreePool( SystemSid ); } } // // Raise if we hit an error building the security descriptor. // if (!NT_SUCCESS( Status )) { ExRaiseStatus( Status ); } // // And return to our caller // DebugTrace( -1, Dbg, ("NtfsInitializeNtfsData -> VOID\n") ); return; }
/* * @implemented */ VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation) { PPFN_NUMBER MdlPages; PVOID Base, Address, LastAddress, StartAddress; ULONG LockPages, TotalPages; NTSTATUS Status = STATUS_SUCCESS; PEPROCESS CurrentProcess; NTSTATUS ProbeStatus; PMMPTE PointerPte, LastPte; PMMPDE PointerPde; #if (_MI_PAGING_LEVELS >= 3) PMMPDE PointerPpe; #endif #if (_MI_PAGING_LEVELS == 4) PMMPDE PointerPxe; #endif PFN_NUMBER PageFrameIndex; BOOLEAN UsePfnLock; KIRQL OldIrql; PMMPFN Pfn1; DPRINT("Probing MDL: %p\n", Mdl); // // Sanity checks // ASSERT(Mdl->ByteCount != 0); ASSERT(((ULONG)Mdl->ByteOffset & ~(PAGE_SIZE - 1)) == 0); ASSERT(((ULONG_PTR)Mdl->StartVa & (PAGE_SIZE - 1)) == 0); ASSERT((Mdl->MdlFlags & (MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA | MDL_SOURCE_IS_NONPAGED_POOL | MDL_PARTIAL | MDL_IO_SPACE)) == 0); // // Get page and base information // MdlPages = (PPFN_NUMBER)(Mdl + 1); Base = Mdl->StartVa; // // Get the addresses and how many pages we span (and need to lock) // Address = (PVOID)((ULONG_PTR)Base + Mdl->ByteOffset); LastAddress = (PVOID)((ULONG_PTR)Address + Mdl->ByteCount); LockPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Address, Mdl->ByteCount); ASSERT(LockPages != 0); /* Block invalid access */ if ((AccessMode != KernelMode) && ((LastAddress > (PVOID)MM_USER_PROBE_ADDRESS) || (Address >= LastAddress))) { /* Caller should be in SEH, raise the error */ *MdlPages = LIST_HEAD; ExRaiseStatus(STATUS_ACCESS_VIOLATION); } // // Get the process // if (Address <= MM_HIGHEST_USER_ADDRESS) { // // Get the process // CurrentProcess = PsGetCurrentProcess(); } else { // // No process // CurrentProcess = NULL; } // // Save the number of pages we'll have to lock, and the start address // TotalPages = LockPages; StartAddress = Address; /* Large pages not supported */ ASSERT(!MI_IS_PHYSICAL_ADDRESS(Address)); // // Now probe them // ProbeStatus = STATUS_SUCCESS; _SEH2_TRY { // // Enter probe loop // do { // // Assume failure // *MdlPages = LIST_HEAD; // // Read // *(volatile CHAR*)Address; // // Check if this is write access (only probe for user-mode) // if ((Operation != IoReadAccess) && (Address <= MM_HIGHEST_USER_ADDRESS)) { // // Probe for write too // ProbeForWriteChar(Address); } // // Next address... // Address = PAGE_ALIGN((ULONG_PTR)Address + PAGE_SIZE); // // Next page... // LockPages--; MdlPages++; } while (Address < LastAddress); // // Reset back to the original page // ASSERT(LockPages == 0); MdlPages = (PPFN_NUMBER)(Mdl + 1); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { // // Oops :( // ProbeStatus = _SEH2_GetExceptionCode(); } _SEH2_END; // // So how did that go? // if (ProbeStatus != STATUS_SUCCESS) { // // Fail // DPRINT1("MDL PROBE FAILED!\n"); Mdl->Process = NULL; ExRaiseStatus(ProbeStatus); } // // Get the PTE and PDE // PointerPte = MiAddressToPte(StartAddress); PointerPde = MiAddressToPde(StartAddress); #if (_MI_PAGING_LEVELS >= 3) PointerPpe = MiAddressToPpe(StartAddress); #endif #if (_MI_PAGING_LEVELS == 4) PointerPxe = MiAddressToPxe(StartAddress); #endif // // Sanity check // ASSERT(MdlPages == (PPFN_NUMBER)(Mdl + 1)); // // Check what kind of operation this is // if (Operation != IoReadAccess) { // // Set the write flag // Mdl->MdlFlags |= MDL_WRITE_OPERATION; } else { // // Remove the write flag // Mdl->MdlFlags &= ~(MDL_WRITE_OPERATION); } // // Mark the MDL as locked *now* // Mdl->MdlFlags |= MDL_PAGES_LOCKED; // // Check if this came from kernel mode // if (Base > MM_HIGHEST_USER_ADDRESS) { // // We should not have a process // ASSERT(CurrentProcess == NULL); Mdl->Process = NULL; // // In kernel mode, we don't need to check for write access // Operation = IoReadAccess; // // Use the PFN lock // UsePfnLock = TRUE; OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); } else { // // Sanity checks // ASSERT(TotalPages != 0); ASSERT(CurrentProcess == PsGetCurrentProcess()); // // Track locked pages // InterlockedExchangeAddSizeT(&CurrentProcess->NumberOfLockedPages, TotalPages); // // Save the process // Mdl->Process = CurrentProcess; /* Lock the process working set */ MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); UsePfnLock = FALSE; OldIrql = MM_NOIRQL; } // // Get the last PTE // LastPte = MiAddressToPte((PVOID)((ULONG_PTR)LastAddress - 1)); // // Loop the pages // do { // // Assume failure and check for non-mapped pages // *MdlPages = LIST_HEAD; while ( #if (_MI_PAGING_LEVELS == 4) (PointerPxe->u.Hard.Valid == 0) || #endif #if (_MI_PAGING_LEVELS >= 3) (PointerPpe->u.Hard.Valid == 0) || #endif (PointerPde->u.Hard.Valid == 0) || (PointerPte->u.Hard.Valid == 0)) { // // What kind of lock were we using? // if (UsePfnLock) { // // Release PFN lock // KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); } else { /* Release process working set */ MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); } // // Access the page // Address = MiPteToAddress(PointerPte); //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked Status = MmAccessFault(FALSE, Address, KernelMode, (PVOID)0xBADBADA3); if (!NT_SUCCESS(Status)) { // // Fail // DPRINT1("Access fault failed\n"); goto Cleanup; } // // What lock should we use? // if (UsePfnLock) { // // Grab the PFN lock // OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); } else { /* Lock the process working set */ MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); } } // // Check if this was a write or modify // if (Operation != IoReadAccess) { // // Check if the PTE is not writable // if (MI_IS_PAGE_WRITEABLE(PointerPte) == FALSE) { // // Check if it's copy on write // if (MI_IS_PAGE_COPY_ON_WRITE(PointerPte)) { // // Get the base address and allow a change for user-mode // Address = MiPteToAddress(PointerPte); if (Address <= MM_HIGHEST_USER_ADDRESS) { // // What kind of lock were we using? // if (UsePfnLock) { // // Release PFN lock // KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); } else { /* Release process working set */ MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); } // // Access the page // //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked Status = MmAccessFault(TRUE, Address, KernelMode, (PVOID)0xBADBADA3); if (!NT_SUCCESS(Status)) { // // Fail // DPRINT1("Access fault failed\n"); goto Cleanup; } // // Re-acquire the lock // if (UsePfnLock) { // // Grab the PFN lock // OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); } else { /* Lock the process working set */ MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); } // // Start over // continue; } } // // Fail, since we won't allow this // Status = STATUS_ACCESS_VIOLATION; goto CleanupWithLock; } } // // Grab the PFN // PageFrameIndex = PFN_FROM_PTE(PointerPte); Pfn1 = MiGetPfnEntry(PageFrameIndex); if (Pfn1) { /* Either this is for kernel-mode, or the working set is held */ ASSERT((CurrentProcess == NULL) || (UsePfnLock == FALSE)); /* No Physical VADs supported yet */ if (CurrentProcess) ASSERT(CurrentProcess->PhysicalVadRoot == NULL); /* This address should already exist and be fully valid */ MiReferenceProbedPageAndBumpLockCount(Pfn1); } else { // // For I/O addresses, just remember this // Mdl->MdlFlags |= MDL_IO_SPACE; } // // Write the page and move on // *MdlPages++ = PageFrameIndex; PointerPte++; /* Check if we're on a PDE boundary */ if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++; #if (_MI_PAGING_LEVELS >= 3) if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++; #endif #if (_MI_PAGING_LEVELS == 4) if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++; #endif } while (PointerPte <= LastPte); // // What kind of lock were we using? // if (UsePfnLock) { // // Release PFN lock // KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); } else { /* Release process working set */ MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); } // // Sanity check // ASSERT((Mdl->MdlFlags & MDL_DESCRIBES_AWE) == 0); return; CleanupWithLock: // // This is the failure path // ASSERT(!NT_SUCCESS(Status)); // // What kind of lock were we using? // if (UsePfnLock) { // // Release PFN lock // KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); } else { /* Release process working set */ MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); } Cleanup: // // Pages must be locked so MmUnlock can work // ASSERT(Mdl->MdlFlags & MDL_PAGES_LOCKED); MmUnlockPages(Mdl); // // Raise the error // ExRaiseStatus(Status); }
NTSTATUS KeWaitForSingleObject ( IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL ) /*++ Routine Description: This function waits until the specified object attains a state of Signaled. An optional timeout can also be specified. If a timeout is not specified, then the wait will not be satisfied until the object attains a state of Signaled. If a timeout is specified, and the object has not attained a state of Signaled when the timeout expires, then the wait is automatically satisfied. If an explicit timeout value of zero is specified, then no wait will occur if the wait cannot be satisfied immediately. The wait can also be specified as alertable. Arguments: Object - Supplies a pointer to a dispatcher object. WaitReason - Supplies the reason for the wait. WaitMode - Supplies the processor mode in which the wait is to occur. Alertable - Supplies a boolean value that specifies whether the wait is alertable. Timeout - Supplies a pointer to an optional absolute of relative time over which the wait is to occur. Return Value: The wait completion status. A value of STATUS_TIMEOUT is returned if a timeout occurred. A value of STATUS_SUCCESS is returned if the specified object satisfied the wait. A value of STATUS_ALERTED is returned if the wait was aborted to deliver an alert to the current thread. A value of STATUS_USER_APC is returned if the wait was aborted to deliver a user APC to the current thread. --*/ { LARGE_INTEGER DueTime; LARGE_INTEGER NewTime; PRKTHREAD NextThread; PKMUTANT Objectx; PLARGE_INTEGER OriginalTime; PRKQUEUE Queue; PRKTHREAD Thread; PRKTIMER Timer; PKWAIT_BLOCK WaitBlock; NTSTATUS WaitStatus; PKWAIT_BLOCK WaitTimer; // // Collect call data. // #if defined(_COLLECT_WAIT_SINGLE_CALLDATA_) RECORD_CALL_DATA(&KiWaitSingleCallData); #endif // // If the dispatcher database lock is not already held, then set the wait // IRQL and lock the dispatcher database. Else set boolean wait variable // to FALSE. // Thread = KeGetCurrentThread(); if (Thread->WaitNext) { Thread->WaitNext = FALSE; } else { KiLockDispatcherDatabase(&Thread->WaitIrql); } // // Start of wait loop. // // Note this loop is repeated if a kernel APC is delivered in the middle // of the wait or a kernel APC is pending on the first attempt through // the loop. // OriginalTime = Timeout; WaitBlock = &Thread->WaitBlock[0]; do { // // Test to determine if a kernel APC is pending. // // If a kernel APC is pending and the previous IRQL was less than // APC_LEVEL, then a kernel APC was queued by another processor just // after IRQL was raised to DISPATCH_LEVEL, but before the dispatcher // database was locked. // // N.B. that this can only happen in a multiprocessor system. // if (Thread->ApcState.KernelApcPending && (Thread->WaitIrql < APC_LEVEL)) { // // Unlock the dispatcher database and lower IRQL to its previous // value. An APC interrupt will immediately occur which will result // in the delivery of the kernel APC if possible. // KiUnlockDispatcherDatabase(Thread->WaitIrql); } else { // // Test if the wait can be immediately satisfied. // Objectx = (PKMUTANT)Object; Thread->WaitStatus = (NTSTATUS)0; ASSERT(Objectx->Header.Type != QueueObject); // // If the object is a mutant object and the mutant object has been // recursively acquired MINLONG times, then raise an exception. // Otherwise if the signal state of the mutant object is greater // than zero, or the current thread is the owner of the mutant // object, then satisfy the wait. // if (Objectx->Header.Type == MutantObject) { if ((Objectx->Header.SignalState > 0) || (Thread == Objectx->OwnerThread)) { if (Objectx->Header.SignalState != MINLONG) { KiWaitSatisfyMutant(Objectx, Thread); WaitStatus = (NTSTATUS)(Thread->WaitStatus); goto NoWait; } else { KiUnlockDispatcherDatabase(Thread->WaitIrql); ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED); } } // // If the signal state is greater than zero, then satisfy the wait. // } else if (Objectx->Header.SignalState > 0) { KiWaitSatisfyOther(Objectx); WaitStatus = (NTSTATUS)(0); goto NoWait; } // // Construct a wait block for the object. // Thread->WaitBlockList = WaitBlock; WaitBlock->Object = Object; WaitBlock->WaitKey = (CSHORT)(STATUS_SUCCESS); WaitBlock->WaitType = WaitAny; // // Test for alert pending. // TestForAlertPending(Alertable); // // The wait cannot be satisifed immediately. Check to determine if // a timeout value is specified. // if (ARGUMENT_PRESENT(Timeout)) { // // If the timeout value is zero, then return immediately without // waiting. // if (!(Timeout->LowPart | Timeout->HighPart)) { WaitStatus = (NTSTATUS)(STATUS_TIMEOUT); goto NoWait; } // // Initialize a wait block for the thread specific timer, insert // wait block in timer wait list, insert the timer in the timer // tree. // // N.B. The timer wait block is initialized when the respective // thread is initialized. Thus the constant fields are not // reinitialized. These include the wait object, wait key, // wait type, and the wait list entry link pointers. // Timer = &Thread->Timer; WaitTimer = &Thread->WaitBlock[TIMER_WAIT_BLOCK]; WaitBlock->NextWaitBlock = WaitTimer; Timer->Header.WaitListHead.Flink = &WaitTimer->WaitListEntry; Timer->Header.WaitListHead.Blink = &WaitTimer->WaitListEntry; WaitTimer->NextWaitBlock = WaitBlock; if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) { WaitStatus = (NTSTATUS)STATUS_TIMEOUT; goto NoWait; } DueTime.QuadPart = Timer->DueTime.QuadPart; } else { WaitBlock->NextWaitBlock = WaitBlock; } // // Insert wait block in object wait list. // InsertTailList(&Objectx->Header.WaitListHead, &WaitBlock->WaitListEntry); // // If the current thread is processing a queue entry, then attempt // to activate another thread that is blocked on the queue object. // Queue = Thread->Queue; if (Queue != NULL) { KiActivateWaiterQueue(Queue); } // // Set the thread wait parameters, set the thread dispatcher state // to Waiting, and insert the thread in the wait list. // Thread->Alertable = Alertable; Thread->WaitMode = WaitMode; Thread->WaitReason = (UCHAR)WaitReason; Thread->WaitTime= KiQueryLowTickCount(); Thread->State = Waiting; KiInsertWaitList(WaitMode, Thread); // // Switch context to selected thread. // // Control is returned at the original IRQL. // ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL); WaitStatus = (NTSTATUS)KiSwapThread(); // // If the thread was not awakened to deliver a kernel mode APC, // then return wait status. // if (WaitStatus != STATUS_KERNEL_APC) { return WaitStatus; } if (ARGUMENT_PRESENT(Timeout)) { // // Reduce the amount of time remaining before timeout occurs. // Timeout = KiComputeWaitInterval(OriginalTime, &DueTime, &NewTime); } } // // Raise IRQL to DISPATCH_LEVEL and lock the dispatcher database. // KiLockDispatcherDatabase(&Thread->WaitIrql); } while (TRUE); // // The thread is alerted or a user APC should be delivered. Unlock the // dispatcher database, lower IRQL to its previous value, and return // the wait status. // KiUnlockDispatcherDatabase(Thread->WaitIrql); return WaitStatus; // // The wait has been satisfied without actually waiting. // // If the thread priority that is less than time critical, then reduce // the thread quantum. If a quantum end occurs, then reduce the thread // priority. // NoWait: KiAdjustQuantumThread(Thread); // // Unlock the dispatcher database, lower IRQL to its previous value, and // return the wait status. // KiUnlockDispatcherDatabase(Thread->WaitIrql); return WaitStatus; }
PXIXFS_LCB xixfs_FCBTLBFindPrefix ( IN PXIXFS_IRPCONTEXT IrpContext, IN OUT PXIXFS_FCB *CurrentFcb, IN OUT PUNICODE_STRING RemainingName, IN BOOLEAN bIgnoreCase ) { UNICODE_STRING LocalRemainingName; UNICODE_STRING FinalName; PXIXFS_LCB NameLink; PXIXFS_LCB CurrentLcb = NULL; BOOLEAN Waitable = FALSE; PAGED_CODE(); DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_CREATE|DEBUG_TARGET_CLOSE| DEBUG_TARGET_FCB), ("Enter xixfs_FCBTLBFindPrefix \n" )); // // Check inputs. // ASSERT_IRPCONTEXT( IrpContext ); ASSERT_FCB( *CurrentFcb ); ASSERT_EXCLUSIVE_FCB( *CurrentFcb ); Waitable = XIXCORE_TEST_FLAGS(IrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_WAIT); try{ // // Make a local copy of the input strings. // LocalRemainingName = *RemainingName; // // Loop until we find the longest matching prefix. // while (TRUE) { // // If there are no characters left or we are not at an IndexFcb then // return immediately. // if ((LocalRemainingName.Length == 0) || (XifsSafeNodeType( *CurrentFcb ) != XIFS_NODE_FCB)) { try_return(TRUE); // return CurrentLcb; } if((*CurrentFcb)->XixcoreFcb.FCBType != FCB_TYPE_DIR){ try_return(TRUE); //return CurrentLcb; } // // Split off the next component from the name. // FsRtlDissectName( LocalRemainingName, &FinalName, &LocalRemainingName); // // Check if this name is in the splay tree for this Fcb. // if(bIgnoreCase){ NameLink = xixfs_NLFindNameLinkIgnoreCase( IrpContext, &(*CurrentFcb)->IgnoreCaseRoot, &FinalName ); }else{ NameLink = xixfs_NLFindNameLink( IrpContext, &(*CurrentFcb)->Root, &FinalName ); } // // If we didn't find a match then exit. // if (NameLink == NULL) { break; } // // // //if ( XIXCORE_TEST_FLAGS(NameLink->LCBFlags, // (XIFSD_LCB_STATE_LINK_IS_GONE)) ) //{ // break; //} CurrentLcb = NameLink; // // Update the caller's remaining name string to reflect the fact that we found // a match. // *RemainingName = LocalRemainingName; // // Move down to the next component in the tree. Acquire without waiting. // If this fails then lock the Fcb to reference this Fcb and then drop // the parent and acquire the child. // ASSERT( NameLink->ParentFcb == *CurrentFcb ); if (!XifsdAcquireFcbExclusive( Waitable, NameLink->ChildFcb, FALSE )) { // // If we can't wait then raise CANT_WAIT. // if ( Waitable) { XifsdRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } XifsdLockVcb( IrpContext, IrpContext->VCB ); NameLink->ChildFcb->FCBReference += 1; NameLink->Reference += 1; XifsdUnlockVcb( IrpContext, IrpContext->VCB ); XifsdReleaseFcb( IrpContext, *CurrentFcb ); XifsdAcquireFcbExclusive( Waitable, NameLink->ChildFcb, FALSE ); XifsdLockVcb( IrpContext, IrpContext->VCB ); NameLink->ChildFcb->FCBReference -= 1; NameLink->Reference -= 1; XifsdUnlockVcb( IrpContext, IrpContext->VCB ); } else { XifsdReleaseFcb( IrpContext, *CurrentFcb ); } *CurrentFcb = NameLink->ChildFcb; } }finally{ if(AbnormalTermination()){ ExRaiseStatus(STATUS_CANT_WAIT); } } DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_CREATE|DEBUG_TARGET_CLOSE| DEBUG_TARGET_FCB), ("Exit xixfs_FCBTLBFindPrefix \n" )); return CurrentLcb; }
PXIFS_IRPCONTEXT XixFsdAllocateIrpContext( PIRP Irp, PDEVICE_OBJECT PtrTargetDeviceObject ) { BOOLEAN IsFromLookasideList = FALSE; PXIFS_IRPCONTEXT IrpContext = NULL; PIO_STACK_LOCATION PtrIoStackLocation = NULL; BOOLEAN IsFsDo = FALSE; PAGED_CODE(); DebugTrace((DEBUG_LEVEL_TRACE|DEBUG_LEVEL_INFO), (DEBUG_TARGET_CREATE|DEBUG_TARGET_IRPCONTEXT), ("Enter XixFsdAllocateIrpContext Irp(%p) TargetDevObj(%p)\n", Irp, PtrTargetDeviceObject)); ASSERT(Irp); PtrIoStackLocation = IoGetCurrentIrpStackLocation(Irp); if(PtrIoStackLocation->DeviceObject == XiGlobalData.XifsControlDeviceObject){ IsFsDo = TRUE; } if(IsFsDo){ if(PtrIoStackLocation->FileObject != NULL && PtrIoStackLocation->MajorFunction != IRP_MJ_CREATE && PtrIoStackLocation->MajorFunction != IRP_MJ_CLEANUP && PtrIoStackLocation->MajorFunction != IRP_MJ_CLOSE && PtrIoStackLocation->MajorFunction != IRP_MJ_FILE_SYSTEM_CONTROL ) { ExRaiseStatus(STATUS_INVALID_DEVICE_REQUEST); } ASSERT(PtrIoStackLocation->FileObject != NULL || (PtrIoStackLocation->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && PtrIoStackLocation->MinorFunction == IRP_MN_USER_FS_REQUEST && PtrIoStackLocation->Parameters.FileSystemControl.FsControlCode == FSCTL_INVALIDATE_VOLUMES) || (PtrIoStackLocation->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && PtrIoStackLocation->Parameters.FileSystemControl.FsControlCode == NDAS_XIXFS_UNLOAD) || (PtrIoStackLocation->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && PtrIoStackLocation->MinorFunction == IRP_MN_MOUNT_VOLUME ) || PtrIoStackLocation->MajorFunction == IRP_MJ_SHUTDOWN ); } // allocate memory IrpContext = (PXIFS_IRPCONTEXT)ExAllocateFromNPagedLookasideList(&(XifsIrpContextLookasideList)); if(!IrpContext) { IrpContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(XIFS_IRPCONTEXT),TAG_IPCONTEXT); if(!IrpContext) { DebugTrace(DEBUG_LEVEL_ERROR, (DEBUG_TARGET_CREATE|DEBUG_TARGET_IRPCONTEXT), ("ERROR XixFsdAllocateIrpContext Can't allocate\n")); return NULL; } IsFromLookasideList = FALSE; } else { IsFromLookasideList = TRUE; } RtlZeroMemory(IrpContext,sizeof(XIFS_IRPCONTEXT)); IrpContext->NodeTypeCode = XIFS_NODE_IRPCONTEXT; IrpContext->NodeByteSize = sizeof(XIFS_IRPCONTEXT); IrpContext->TargetDeviceObject = PtrTargetDeviceObject; IrpContext->Irp = Irp; if (IoGetTopLevelIrp() != Irp) { // We are not top-level. Note this fact in the context structure XifsdSetFlag(IrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_NOT_TOP_LEVEL); DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CREATE|DEBUG_TARGET_IRPCONTEXT|DEBUG_TARGET_ALL), ("XixFsdAllocateIrpContext IrpContextFlags(0x%x)\n", IrpContext->IrpContextFlags)); } IrpContext->MajorFunction = PtrIoStackLocation->MajorFunction; IrpContext->MinorFunction = PtrIoStackLocation->MinorFunction; if(XifsdCheckFlagBoolean(IrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_NOT_TOP_LEVEL)){ }else if (PtrIoStackLocation->FileObject == NULL){ XifsdSetFlag(IrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_WAIT); DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CREATE|DEBUG_TARGET_IRPCONTEXT), ("XixFsdAllocateIrpContext Set Watable form FileObject== NULL IrpContextFlags(0x%x)\n", IrpContext->IrpContextFlags)); } else { if (IoIsOperationSynchronous(Irp)) { XifsdSetFlag(IrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_WAIT); DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CREATE|DEBUG_TARGET_IRPCONTEXT), ("XixFsdAllocateIrpContext Set Watable form IoIsOperationSynchronous IrpContextFlags(0x%x)\n", IrpContext->IrpContextFlags)); } } if(!IsFsDo){ IrpContext->VCB = &((PXI_VOLUME_DEVICE_OBJECT)PtrIoStackLocation->DeviceObject)->VCB; } if (IsFromLookasideList == FALSE) { XifsdSetFlag(IrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_NOT_FROM_POOL); DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CREATE|DEBUG_TARGET_IRPCONTEXT), ("XixFsdAllocateIrpContext IrpContextFlags(0x%x)\n", IrpContext->IrpContextFlags)); } if ( IoGetTopLevelIrp() != Irp) { XifsdSetFlag(IrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_RECURSIVE_CALL); } DebugTrace(DEBUG_LEVEL_INFO, (DEBUG_TARGET_FCB|DEBUG_TARGET_CREATE|DEBUG_TARGET_IRPCONTEXT), ("[IrpCxt(%p) INFO] Irp(%x):MJ(%x):MN(%x):Flags(%x)\n", IrpContext, Irp, IrpContext->MajorFunction, IrpContext->MinorFunction, IrpContext->IrpContextFlags)); DebugTrace((DEBUG_LEVEL_TRACE|DEBUG_LEVEL_INFO), (DEBUG_TARGET_CREATE|DEBUG_TARGET_IRPCONTEXT), ("Exit XixFsdAllocateIrpContext IrpContext(%p) Irp(%p) TargetDevObj(%p)\n", IrpContext, Irp, PtrTargetDeviceObject)); return IrpContext; }
VOID PopApplyPolicy( BOOLEAN UpdateRegistry, BOOLEAN IsAcPolicy, PSYSTEM_POWER_POLICY NewPolicy, ULONG PolicyLength ) { HANDLE RegKeyHandle; PCWSTR RegValueNameRawString; UNICODE_STRING RegValueNameString; SYSTEM_POWER_POLICY Policy; SYSTEM_POWER_POLICY VerifiedPolicy; PSYSTEM_POWER_POLICY TargetPolicy; ULONG DischargePolicyMatchCount = 0; NTSTATUS Status; ULONG i; // // Determine if the target policy type is AC or DC, and set the local reference variables // accordingly. // if (IsAcPolicy == TRUE) // AcPolicy { RegValueNameRawString = L"AcPolicy"; TargetPolicy = &PopAcPolicy; } else // DcPolicy { RegValueNameRawString = L"DcPolicy"; TargetPolicy = &PopDcPolicy; } // // Ensure that the length of the NewPolicy struct supplied is valid // if (PolicyLength < sizeof(SYSTEM_POWER_POLICY)) { ExRaiseStatus(STATUS_BUFFER_TOO_SMALL); } else if (PolicyLength > sizeof(SYSTEM_POWER_POLICY)) { ExRaiseStatus(STATUS_BUFFER_OVERFLOW); } // // Copy the new policy to the function local buffer // RtlCopyMemory(&Policy, NewPolicy, sizeof(SYSTEM_POWER_POLICY)); // // Verify and adjust the newly specified system power policy to comply with the current system // and power manager configuration. // PopVerifyPowerPolicy(IsAcPolicy, &Policy, &VerifiedPolicy); // // If the verified policy does not correspond to the existing target policy, the following code // block is executed. // if (RtlCompareMemory(&VerifiedPolicy, TargetPolicy, sizeof(SYSTEM_POWER_POLICY)) != 0) { // // Compare the discharge policy of the verified policy to that of the target policy. Ignore // the discharge policy entries that are not enabled, as long as they are disabled on both // policies. // for (i = 0; i < NUM_DISCHARGE_POLICIES; i++) { if ((VerifiedPolicy.DischargePolicy[i].Enable == TargetPolicy->DischargePolicy[i].Enable) && ((VerifiedPolicy.DischargePolicy[i].Enable == FALSE) || (RtlCompareMemory( &VerifiedPolicy.DischargePolicy[i], &TargetPolicy->DischargePolicy[i], sizeof(SYSTEM_POWER_LEVEL)) == 0))) { DischargePolicyMatchCount++; } } // // Copy the verified policy to the target policy // RtlCopyMemory(TargetPolicy, &VerifiedPolicy, sizeof(SYSTEM_POWER_POLICY)); // // If the target policy is the active system policy, call the support functions required to // make the policy changes effective. // if (TargetPolicy == PopPolicy) { /*PopSetNotificationWork(20); if (DischargePolicyMatchCount == NUM_DISCHARGE_POLICIES) PopResetCBTriggers(0x82); PopApplyThermalThrottle(); PopInitSIdle();*/ } // // If UpdateRegistry flag is set, save the NewPolicy to the corresponding registry value. // if (UpdateRegistry == TRUE) { Status = PopOpenPowerKey(&RegKeyHandle); if (NT_SUCCESS(Status)) { RtlInitUnicodeString(&RegValueNameString, RegValueNameRawString); ZwSetValueKey( RegKeyHandle, &RegValueNameString, 0, REG_BINARY, &Policy, sizeof(SYSTEM_POWER_POLICY) ); ZwClose(RegKeyHandle); } } } }
NTSTATUS BuildQueryDirectoryIrp( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass, IN BOOLEAN ReturnSingleEntry, IN PUNICODE_STRING FileName OPTIONAL, IN BOOLEAN RestartScan, IN UCHAR MinorFunction, OUT BOOLEAN *SynchronousIo, OUT PDEVICE_OBJECT *DeviceObject, OUT PIRP *Irp, OUT PFILE_OBJECT *FileObject, OUT KPROCESSOR_MODE *RequestorMode ) /*++ Routine Description: This service operates on a directory file or OLE container specified by the FileHandle parameter. The service returns information about files in the directory or embeddings and streams in the container specified by the file handle. The ReturnSingleEntry parameter specifies that only a single entry should be returned rather than filling the buffer. The actual number of files whose information is returned, is the smallest of the following: o One entry, if the ReturnSingleEntry parameter is TRUE. o The number of entries whose information fits into the specified buffer. o The number of entries that exist. o One entry if the optional FileName parameter is specified. If the optional FileName parameter is specified, then the only information that is returned is for that single entries, if it exists. Note that the file name may not specify any wildcard characters according to the naming conventions of the target file system. The ReturnSingleEntry parameter is simply ignored. The information that is obtained about the entries in the directory or OLE container is based on the FileInformationClass parameter. Legal values are hard coded based on the MinorFunction. Arguments: FileHandle - Supplies a handle to the directory file or OLE container for which information should be returned. Event - Supplies an optional event to be set to the Signaled state when the query is complete. ApcRoutine - Supplies an optional APC routine to be executed when the query is complete. ApcContext - Supplies a context parameter to be passed to the ApcRoutine, if an ApcRoutine was specified. IoStatusBlock - Address of the caller's I/O status block. FileInformation - Supplies a buffer to receive the requested information returned about the contents of the directory. Length - Supplies the length, in bytes, of the FileInformation buffer. FileInformationClass - Specfies the type of information that is to be returned about the files in the specified directory or OLE container. ReturnSingleEntry - Supplies a BOOLEAN value that, if TRUE, indicates that only a single entry should be returned. FileName - Optionally supplies a file name within the specified directory or OLE container. RestartScan - Supplies a BOOLEAN value that, if TRUE, indicates that the scan should be restarted from the beginning. This parameter must be set to TRUE by the caller the first time the service is invoked. MinorFunction - IRP_MN_QUERY_DIRECTORY or IRP_MN_QUERY_OLE_DIRECTORY SynchronousIo - pointer to returned BOOLEAN; TRUE if synchronous I/O DeviceObject - pointer to returned pointer to device object Irp - pointer to returned pointer to device object FileObject - pointer to returned pointer to file object RequestorMode - pointer to returned requestor mode Return Value: The status returned is STATUS_SUCCESS if a valid irp was created for the query operation. --*/ { PIRP irp; NTSTATUS status; PFILE_OBJECT fileObject; PDEVICE_OBJECT deviceObject; PKEVENT eventObject = (PKEVENT) NULL; KPROCESSOR_MODE requestorMode; PCHAR auxiliaryBuffer = (PCHAR) NULL; PIO_STACK_LOCATION irpSp; PMDL mdl; PETHREAD CurrentThread; PAGED_CODE(); // // Get the previous mode; i.e., the mode of the caller. // CurrentThread = PsGetCurrentThread (); requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb); *RequestorMode = requestorMode; try { if (requestorMode != KernelMode) { ULONG operationlength = 0; // assume invalid // // The caller's access mode is not kernel so probe and validate // each of the arguments as necessary. If any failures occur, // the condition handler will be invoked to handle them. It // will simply cleanup and return an access violation status // code back to the system service dispatcher. // // // The IoStatusBlock parameter must be writeable by the caller. // ProbeForWriteIoStatus(IoStatusBlock); // // Ensure that the FileInformationClass parameter is legal for // querying information about files in the directory or object. // if (FileInformationClass == FileDirectoryInformation) { operationlength = sizeof(FILE_DIRECTORY_INFORMATION); } else if (MinorFunction == IRP_MN_QUERY_DIRECTORY) { switch (FileInformationClass) { case FileFullDirectoryInformation: operationlength = sizeof(FILE_FULL_DIR_INFORMATION); break; case FileIdFullDirectoryInformation: operationlength = sizeof(FILE_ID_FULL_DIR_INFORMATION); break; case FileBothDirectoryInformation: operationlength = sizeof(FILE_BOTH_DIR_INFORMATION); break; case FileIdBothDirectoryInformation: operationlength = sizeof(FILE_ID_BOTH_DIR_INFORMATION); break; case FileNamesInformation: operationlength = sizeof(FILE_NAMES_INFORMATION); break; case FileObjectIdInformation: operationlength = sizeof(FILE_OBJECTID_INFORMATION); break; case FileQuotaInformation: operationlength = sizeof(FILE_QUOTA_INFORMATION); break; case FileReparsePointInformation: operationlength = sizeof(FILE_REPARSE_POINT_INFORMATION); break; } } // // If the FileInformationClass parameter is illegal, fail now. // if (operationlength == 0) { return STATUS_INVALID_INFO_CLASS; } // // Ensure that the caller's supplied buffer is at least large enough // to contain the fixed part of the structure required for this // query. // if (Length < operationlength) { return STATUS_INFO_LENGTH_MISMATCH; } // // The FileInformation buffer must be writeable by the caller. // #if defined(_X86_) ProbeForWrite( FileInformation, Length, sizeof( ULONG ) ); #elif defined(_WIN64) // // If we are a wow64 process, follow the X86 rules // if (PsGetCurrentProcessByThread(CurrentThread)->Wow64Process) { ProbeForWrite( FileInformation, Length, sizeof( ULONG ) ); } else { ProbeForWrite( FileInformation, Length, IopQuerySetAlignmentRequirement[FileInformationClass] ); } #else ProbeForWrite( FileInformation, Length, IopQuerySetAlignmentRequirement[FileInformationClass] ); #endif } // // If the optional FileName parameter was specified, then it must be // readable by the caller. Capture the file name string in a pool // block. Note that if an error occurs during the copy, the cleanup // code in the exception handler will deallocate the pool before // returning an access violation status. // if (ARGUMENT_PRESENT( FileName )) { UNICODE_STRING fileName; PUNICODE_STRING nameBuffer; // // Capture the string descriptor itself to ensure that the // string is readable by the caller without the caller being // able to change the memory while its being checked. // if (requestorMode != KernelMode) { ProbeAndReadUnicodeStringEx( &fileName, FileName ); } else { fileName = *FileName; } // // If the length is not an even number of bytes // return an error. // if (fileName.Length & (sizeof(WCHAR) - 1)) { return STATUS_INVALID_PARAMETER; } if (fileName.Length) { // // The length of the string is non-zero, so probe the // buffer described by the descriptor if the caller was // not kernel mode. Likewise, if the caller's mode was // not kernel, then check the length of the name string // to ensure that it is not too long. // if (requestorMode != KernelMode) { ProbeForRead( fileName.Buffer, fileName.Length, sizeof( UCHAR ) ); // // account for unicode // if (fileName.Length > MAXIMUM_FILENAME_LENGTH<<1) { ExRaiseStatus( STATUS_INVALID_PARAMETER ); } } // // Allocate an auxiliary buffer large enough to contain // a file name descriptor and to hold the entire file // name itself. Copy the body of the string into the // buffer. // auxiliaryBuffer = ExAllocatePoolWithQuota( NonPagedPool, fileName.Length + sizeof( UNICODE_STRING ) ); RtlCopyMemory( auxiliaryBuffer + sizeof( UNICODE_STRING ), fileName.Buffer, fileName.Length ); // // Finally, build the Unicode string descriptor in the // auxiliary buffer. // nameBuffer = (PUNICODE_STRING) auxiliaryBuffer; nameBuffer->Length = fileName.Length; nameBuffer->MaximumLength = fileName.Length; nameBuffer->Buffer = (PWSTR) (auxiliaryBuffer + sizeof( UNICODE_STRING ) ); } } } except(EXCEPTION_EXECUTE_HANDLER) { // // An exception was incurred while probing the caller's buffers, // attempting to allocate a pool buffer, or while trying to copy // the caller's data. Determine what happened, clean everything // up, and return an appropriate error status code. // if (auxiliaryBuffer) { ExFreePool( auxiliaryBuffer ); } return GetExceptionCode(); } // // There were no blatant errors so far, so reference the file object so // the target device object can be found. Note that if the handle does // not refer to a file object, or if the caller does not have the required // access to the file, then it will fail. // status = ObReferenceObjectByHandle( FileHandle, FILE_LIST_DIRECTORY, IoFileObjectType, requestorMode, (PVOID *) &fileObject, (POBJECT_HANDLE_INFORMATION) NULL ); if (!NT_SUCCESS( status )) { if (auxiliaryBuffer) { ExFreePool( auxiliaryBuffer ); } return status; } *FileObject = fileObject; // // If this file has an I/O completion port associated w/it, then ensure // that the caller did not supply an APC routine, as the two are mutually // exclusive methods for I/O completion notification. // if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) { ObDereferenceObject( fileObject ); if (auxiliaryBuffer) { ExFreePool( auxiliaryBuffer ); } return STATUS_INVALID_PARAMETER; } // // Get the address of the event object and set the event to the Not- // Signaled state, if an event was specified. Note here, too, that if // the handle does not refer to an event, or if the event cannot be // written, then the reference will fail. // if (ARGUMENT_PRESENT( Event )) { status = ObReferenceObjectByHandle( Event, EVENT_MODIFY_STATE, ExEventObjectType, requestorMode, (PVOID *) &eventObject, (POBJECT_HANDLE_INFORMATION) NULL ); if (!NT_SUCCESS( status )) { if (auxiliaryBuffer) { ExFreePool( auxiliaryBuffer ); } ObDereferenceObject( fileObject ); return status; } else { KeClearEvent( eventObject ); } } // // Make a special check here to determine whether this is a synchronous // I/O operation. If it is, then wait here until the file is owned by // the current thread. // if (fileObject->Flags & FO_SYNCHRONOUS_IO) { BOOLEAN interrupted; if (!IopAcquireFastLock( fileObject )) { status = IopAcquireFileObjectLock( fileObject, requestorMode, (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), &interrupted ); if (interrupted) { if (auxiliaryBuffer != NULL) { ExFreePool( auxiliaryBuffer ); } if (eventObject != NULL) { ObDereferenceObject( eventObject ); } ObDereferenceObject( fileObject ); return status; } } *SynchronousIo = TRUE; } else { *SynchronousIo = FALSE; #if defined(_WIN64) if (requestorMode != KernelMode) { try { // // If this is a 32-bit asynchronous IO, then mark the Iosb being sent as so. // Note: IopMarkApcRoutineIfAsyncronousIo32 must be called after probing // the IoStatusBlock structure for write. // IopMarkApcRoutineIfAsyncronousIo32(IoStatusBlock,ApcRoutine,FALSE); } except (EXCEPTION_EXECUTE_HANDLER) { // // An IRP could not be allocated. Cleanup and return an appropriate // error status code. // IopAllocateIrpCleanup( fileObject, eventObject ); if (auxiliaryBuffer) { ExFreePool( auxiliaryBuffer ); } return GetExceptionCode (); } } #endif } // // Set the file object to the Not-Signaled state. // KeClearEvent( &fileObject->Event ); // // Get the address of the target device object. // deviceObject = IoGetRelatedDeviceObject( fileObject ); *DeviceObject = deviceObject; // // Allocate and initialize the I/O Request Packet (IRP) for this operation. // The allocation is performed with an exception handler in case the // caller does not have enough quota to allocate the packet. irp = IoAllocateIrp( deviceObject->StackSize, !(*SynchronousIo) ); if (!irp) { // // An IRP could not be allocated. Cleanup and return an appropriate // error status code. // IopAllocateIrpCleanup( fileObject, eventObject ); if (auxiliaryBuffer) { ExFreePool( auxiliaryBuffer ); } return STATUS_INSUFFICIENT_RESOURCES; } *Irp = irp; irp->Tail.Overlay.OriginalFileObject = fileObject; irp->Tail.Overlay.Thread = CurrentThread; irp->RequestorMode = requestorMode; // // Fill in the service independent parameters in the IRP. // irp->UserEvent = eventObject; irp->UserIosb = IoStatusBlock; irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine; irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext; // // Get a pointer to the stack location for the first driver. This will be // used to pass the original function codes and parameters. // irpSp = IoGetNextIrpStackLocation( irp ); irpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL; irpSp->MinorFunction = MinorFunction; irpSp->FileObject = fileObject; // Also, copy the caller's parameters to the service-specific portion of // the IRP. // irp->Tail.Overlay.AuxiliaryBuffer = auxiliaryBuffer; irp->AssociatedIrp.SystemBuffer = (PVOID) NULL; irp->MdlAddress = (PMDL) NULL; // // Now determine whether this driver expects to have data buffered to it // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO // flag in the device object. If the flag is set, then a system buffer is // allocated and the driver's data will be copied into it. Otherwise, a // Memory Descriptor List (MDL) is allocated and the caller's buffer is // locked down using it. // if (deviceObject->Flags & DO_BUFFERED_IO) { // // The device does not support direct I/O. Allocate a system buffer // and specify that it should be deallocated on completion. Also // indicate that this is an input operation so the data will be copied // into the caller's buffer. This is done using an exception handler // that will perform cleanup if the operation fails. // try { // // Allocate the intermediary system buffer from nonpaged pool and // charge quota for it. // irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( NonPagedPool, Length ); } except(EXCEPTION_EXECUTE_HANDLER) { // // An exception was incurred while either probing the caller's // buffer or allocate the system buffer. Determine what actually // happened, clean everything up, and return an appropriate error // status code. // IopExceptionCleanup( fileObject, irp, eventObject, (PKEVENT) NULL ); if (auxiliaryBuffer != NULL) { ExFreePool( auxiliaryBuffer ); } return GetExceptionCode(); } // // Remember the address of the caller's buffer so the copy can take // place during I/O completion. Also, set the flags so that the // completion code knows to do the copy and to deallocate the buffer. // irp->UserBuffer = FileInformation; irp->Flags = (ULONG) (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION); } else if (deviceObject->Flags & DO_DIRECT_IO) {
BOOLEAN NtfsAcquireScbForReadAhead ( IN PVOID OpaqueScb, IN BOOLEAN Wait ) /*++ Routine Description: The address of this routine is specified when creating a CacheMap for a file. It is subsequently called by the Lazy Writer prior to its performing read ahead to the file. Arguments: Scb - The Scb which was specified as a context parameter for this routine. Wait - TRUE if the caller is willing to block. Return Value: FALSE - if Wait was specified as FALSE and blocking would have been required. The Fcb is not acquired. TRUE - if the Scb has been acquired --*/ { PREAD_AHEAD_THREAD ReadAheadThread; PVOID CurrentThread; KIRQL OldIrql; PSCB Scb = (PSCB)OpaqueScb; PFCB Fcb = Scb->Fcb; BOOLEAN AcquiredFile = FALSE; ASSERT_SCB(Scb); // // Acquire the Scb only for those files that the read wil // acquire it for, i.e., not the first set of system files. // Otherwise we can deadlock, for example with someone needing // a new Mft record. // if ((Scb->Header.PagingIoResource == NULL) || ExAcquireResourceShared( Scb->Header.PagingIoResource, Wait )) { AcquiredFile = TRUE; // // Add our thread to the read ahead list. // KeAcquireSpinLock( &NtfsData.StrucSupSpinLock, &OldIrql ); CurrentThread = (PVOID)PsGetCurrentThread(); ReadAheadThread = (PREAD_AHEAD_THREAD)NtfsData.ReadAheadThreads.Flink; while ((ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) && (ReadAheadThread->Thread != NULL)) { // // We better not already see ourselves. // ASSERT( ReadAheadThread->Thread != CurrentThread ); ReadAheadThread = (PREAD_AHEAD_THREAD)ReadAheadThread->Links.Flink; } // // If we hit the end of the list, then allocate a new one. Note we // should have at most one entry per critical worker thread in the // system. // if (ReadAheadThread == (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) { ReadAheadThread = ExAllocatePoolWithTag( NonPagedPool, sizeof(READ_AHEAD_THREAD), 'RftN' ); // // If we failed to allocate an entry, clean up and raise. // if (ReadAheadThread == NULL) { KeReleaseSpinLock( &NtfsData.StrucSupSpinLock, OldIrql ); if (NtfsSegmentNumber( &Fcb->FileReference ) > VOLUME_DASD_NUMBER) { if (Scb->Header.PagingIoResource != NULL) { ExReleaseResource( Scb->Header.PagingIoResource ); } } ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); } InsertTailList( &NtfsData.ReadAheadThreads, &ReadAheadThread->Links ); } ReadAheadThread->Thread = CurrentThread; KeReleaseSpinLock( &NtfsData.StrucSupSpinLock, OldIrql ); } return AcquiredFile; }
BOOLEAN LfsReadNextLogRecord ( IN LFS_LOG_HANDLE LogHandle, IN OUT LFS_LOG_CONTEXT Context, OUT PLFS_RECORD_TYPE RecordType, OUT TRANSACTION_ID *TransactionId, OUT PLSN UndoNextLsn, OUT PLSN PreviousLsn, OUT PLSN Lsn, OUT PULONG BufferLength, OUT PVOID *Buffer ) /*++ Routine Description: This routine is called to continue a query operation. The Lfs uses private information stored in the context structure to determine the next log record to return to the caller. Arguments: LogHandle - Pointer to private Lfs structure used to identify this client. Context - Supplies the address to store a pointer to the Lfs created context structure. Lsn - Lsn for this log record. RecordType - Supplies the address to store the record type of this log record. TransactionId - Supplies the address to store the transaction Id of this log record. UndoNextLsn - Supplies the address to store the Undo Next Lsn for this log record. PreviousLsn - Supplies the address to store the Previous Lsn for this log record. BufferLength - This is the length of the log data. Buffer - This is a pointer to the start of the log data. Return Value: None --*/ { volatile NTSTATUS Status = STATUS_SUCCESS; PLCH Lch; PLFCB Lfcb; PLfsLCB Lcb; BOOLEAN FoundNextLsn; BOOLEAN UnwindRememberLcbFields; PBCB UnwindRecordHeaderBcb; PLFS_RECORD_HEADER UnwindRecordHeader; PVOID UnwindCurrentLogRecord; BOOLEAN UnwindAuxilaryBuffer; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsReadNextLogRecord: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle ); LfsDebugTrace( 0, Dbg, "Context -> %08lx\n", Context ); FoundNextLsn = FALSE; UnwindRememberLcbFields = FALSE; Lch = (PLCH) LogHandle; Lcb = (PLfsLCB) Context; // // Check that the structure is a valid log handle structure. // LfsValidateLch( Lch ); // // Use a try-except to catch errors. // try { // // Use a try-finally to facilitate cleanup. // try { // // Acquire the log file control block for this log file. // LfsAcquireLch( Lch ); Lfcb = Lch->Lfcb; // // If the Log file has been closed then refuse access. // if (Lfcb == NULL) { ExRaiseStatus( STATUS_ACCESS_DENIED ); } // // Check that the client Id is valid. // LfsValidateClientId( Lfcb, Lch ); // // Check that the context structure is valid. // LfsValidateLcb( Lcb, Lch ); // // Remember any context fields to be overwritten. // UnwindRememberLcbFields = TRUE; UnwindRecordHeaderBcb = Lcb->RecordHeaderBcb; Lcb->RecordHeaderBcb = NULL; UnwindRecordHeader = Lcb->RecordHeader; UnwindCurrentLogRecord = Lcb->CurrentLogRecord; UnwindAuxilaryBuffer = Lcb->AuxilaryBuffer; Lcb->AuxilaryBuffer = FALSE; // // Find the next Lsn number based on the current Lsn number in // the context block. // if (LfsFindClientNextLsn( Lfcb, Lcb, Lsn )) { // // We can give up the Lfcb as we know the Lsn is within the file. // LfsReleaseLfcb( Lfcb ); // // Cleanup the context block so we can do the next search. // Lcb->CurrentLogRecord = NULL; Lcb->AuxilaryBuffer = FALSE; // // Perform the work of getting the log record. // LfsFindLogRecord( Lfcb, Lcb, *Lsn, RecordType, TransactionId, UndoNextLsn, PreviousLsn, BufferLength, Buffer ); FoundNextLsn = TRUE; } } finally { DebugUnwind( LfsReadNextLogRecord ); // // If we exited due to an error, we have to restore the context // block. // if (UnwindRememberLcbFields) { if (AbnormalTermination()) { // // If the record header in the context block is not // the same as we started with. Then we unpin that // data. // if (Lcb->RecordHeaderBcb != NULL) { CcUnpinData( Lcb->RecordHeaderBcb ); } if (Lcb->CurrentLogRecord != NULL && Lcb->AuxilaryBuffer == TRUE) { ExFreePool( Lcb->CurrentLogRecord ); } Lcb->RecordHeaderBcb = UnwindRecordHeaderBcb; Lcb->RecordHeader = UnwindRecordHeader; Lcb->CurrentLogRecord = UnwindCurrentLogRecord; Lcb->AuxilaryBuffer = UnwindAuxilaryBuffer; // // Otherwise, if we have successfully found the next Lsn, // we free up any resources being held from the previous search. // } else if (FoundNextLsn ) { if (UnwindRecordHeaderBcb != NULL) { CcUnpinData( UnwindRecordHeaderBcb ); } if (UnwindCurrentLogRecord != NULL && UnwindAuxilaryBuffer == TRUE) { ExFreePool( UnwindCurrentLogRecord ); } // // Restore the Bcb and auxilary buffer field for the final // cleanup. // } else { if (UnwindRecordHeaderBcb != NULL) { if (Lcb->RecordHeaderBcb != NULL) { CcUnpinData( UnwindRecordHeaderBcb ); } else { Lcb->RecordHeaderBcb = UnwindRecordHeaderBcb; } } if (UnwindAuxilaryBuffer) { if (Lcb->CurrentLogRecord == UnwindCurrentLogRecord) { Lcb->AuxilaryBuffer = TRUE; } else { ExFreePool( UnwindCurrentLogRecord ); } } } } // // Release the log file control block if held. // LfsReleaseLch( Lch ); LfsDebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart ); LfsDebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart ); LfsDebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength ); LfsDebugTrace( 0, Dbg, "Buffer -> %08lx\n", *Buffer ); LfsDebugTrace( -1, Dbg, "LfsReadNextLogRecord: Exit\n", 0 ); } } except (LfsExceptionFilter( GetExceptionInformation() )) { Status = GetExceptionCode(); } if (Status != STATUS_SUCCESS) { ExRaiseStatus( Status ); } return FoundNextLsn; }
LSN LfsQueryLastLsn ( IN LFS_LOG_HANDLE LogHandle ) /*++ Routine Description: This routine will return the most recent Lsn for this log record. Arguments: LogHandle - Pointer to private Lfs structure used to identify this client. Return Value: LSN - This is the last Lsn assigned in this log file. --*/ { PLCH Lch; PLFCB Lfcb; LSN LastLsn; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsQueryLastLsn: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle ); Lch = (PLCH) LogHandle; // // Check that the structure is a valid log handle structure. // LfsValidateLch( Lch ); // // Use a try-finally to facilitate cleanup. // try { // // Acquire the log file control block for this log file. // LfsAcquireLch( Lch ); Lfcb = Lch->Lfcb; // // If the Log file has been closed then refuse access. // if (Lfcb == NULL) { ExRaiseStatus( STATUS_ACCESS_DENIED ); } // // Check that the client Id is valid. // LfsValidateClientId( Lfcb, Lch ); // // Copy the last Lsn out of the Lfcb. If the last Lsn is // does not correspond to a log record, we will return the // zero Lsn. // if (FlagOn( Lfcb->Flags, LFCB_NO_LAST_LSN )) { LastLsn = LfsZeroLsn; } else { LastLsn = Lfcb->RestartArea->CurrentLsn; } } finally { DebugUnwind( LfsQueryLastLsn ); // // Release the Lfcb if acquired. // LfsReleaseLch( Lch ); LfsDebugTrace( 0, Dbg, "Last Lsn (Low) -> %08lx\n", LastLsn.LowPart ); LfsDebugTrace( 0, Dbg, "Last Lsn (High) -> %08lx\n", LastLsn.HighPart ); LfsDebugTrace( -1, Dbg, "LfsQueryLastLsn: Exit\n", 0 ); } return LastLsn; }
LONG KeReleaseMutant ( IN PRKMUTANT Mutant, IN KPRIORITY Increment, IN BOOLEAN Abandoned, IN BOOLEAN Wait ) /*++ Routine Description: This function releases a mutant object by incrementing the mutant count. If the resultant value is one, then an attempt is made to satisfy as many Waits as possible. The previous signal state of the mutant is returned as the function value. If the Abandoned parameter is TRUE, then the mutant object is released by settings the signal state to one. Arguments: Mutant - Supplies a pointer to a dispatcher object of type mutant. Increment - Supplies the priority increment that is to be applied if setting the event causes a Wait to be satisfied. Abandoned - Supplies a boolean value that signifies whether the mutant object is being abandoned. Wait - Supplies a boolean value that signifies whether the call to KeReleaseMutant will be immediately followed by a call to one of the kernel Wait functions. Return Value: The previous signal state of the mutant object. --*/ { KIRQL OldIrql; LONG OldState; PRKTHREAD Thread; ASSERT_MUTANT(Mutant); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); // // Raise IRQL to dispatcher level and lock dispatcher database. // KiLockDispatcherDatabase(&OldIrql); // // Capture the current signal state of the mutant object. // OldState = Mutant->Header.SignalState; // // If the Abandoned parameter is TRUE, then force the release of the // mutant object by setting its ownership count to one and setting its // abandoned state to TRUE. Otherwise increment mutant ownership count. // If the result count is one, then remove the mutant object from the // thread's owned mutant list, set the owner thread to NULL, and attempt // to satisfy a Wait for the mutant object if the mutant object wait // list is not empty. // Thread = KeGetCurrentThread(); if (Abandoned != FALSE) { Mutant->Header.SignalState = 1; Mutant->Abandoned = TRUE; } else { // // If the Mutant object is not owned by the current thread, then // unlock the dispatcher data base and raise an exception. Otherwise // increment the ownership count. // if (Mutant->OwnerThread != Thread) { KiUnlockDispatcherDatabase(OldIrql); ExRaiseStatus(Mutant->Abandoned ? STATUS_ABANDONED : STATUS_MUTANT_NOT_OWNED); } Mutant->Header.SignalState += 1; } if (Mutant->Header.SignalState == 1) { if (OldState <= 0) { RemoveEntryList(&Mutant->MutantListEntry); Thread->KernelApcDisable += Mutant->ApcDisable; if ((Thread->KernelApcDisable == 0) && (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE)) { Thread->ApcState.KernelApcPending = TRUE; KiRequestSoftwareInterrupt(APC_LEVEL); } } Mutant->OwnerThread = (PKTHREAD)NULL; if (IsListEmpty(&Mutant->Header.WaitListHead) == FALSE) { KiWaitTest(Mutant, Increment); } } // // If the value of the Wait argument is TRUE, then return to // caller with IRQL raised and the dispatcher database locked. // Else release the dispatcher database lock and lower IRQL to // its previous value. // if (Wait != FALSE) { Thread->WaitNext = Wait; Thread->WaitIrql = OldIrql; } else { KiUnlockDispatcherDatabase(OldIrql); } // // Return previous signal state of mutant object. // return OldState; }
VOID LfsFlushToLsnPriv ( IN PLFCB Lfcb, IN LSN Lsn ) /*++ Routine Description: This routine is the worker routine which performs the work of flushing a particular Lsn to disk. This routine is always called with the Lfcb acquired. This routines makes no guarantee about whether the Lfcb is acquired on exit. Arguments: Lfcb - This is the file control block for the log file. Lsn - This is the Lsn to flush to disk. Return Value: None. --*/ { PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsFlushToLsnPriv: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); LfsDebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn.LowPart ); LfsDebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn.HighPart ); // // We check if the Lsn is in the valid range. Raising an // exception if not. // if ( Lsn.QuadPart > Lfcb->RestartArea->CurrentLsn.QuadPart ) { LfsDebugTrace( 0, Dbg, "Lsn is not in the file\n", 0 ); ExRaiseStatus( STATUS_INVALID_PARAMETER ); } // // If the Lsn has already been flushed we are done. // Otherwise we need to look through the workqueues and the // active queue. // if ( Lsn.QuadPart > Lfcb->LastFlushedLsn.QuadPart ) { PLIST_ENTRY ThisEntry; PLBCB ThisLbcb; // // Check the workqueue first. We are looking for the last // buffer block of a log page block which contains this // Lsn. // ThisEntry = Lfcb->LbcbWorkque.Flink; // // We keep looping. // while (TRUE) { ThisLbcb = CONTAINING_RECORD( ThisEntry, LBCB, WorkqueLinks ); // // We pass over any restart areas. We also skip any // Lbcb's which do not contain the end of a log record. // if (!LfsLbcbIsRestart( ThisLbcb ) && FlagOn( ThisLbcb->Flags, LOG_PAGE_LOG_RECORD_END )) { // // If the last complete Lsn in this Lbcb is greater or equal // to the desired Lsn, we exit the loop. // if ( ThisLbcb->LastEndLsn.QuadPart >= Lsn.QuadPart ) { break; } } // // Otherwise move to the next Lbcb. // ThisEntry = ThisEntry->Flink; ASSERT( ThisEntry != &Lfcb->LbcbWorkque ); } // // If we are not supporting a packed log file and this Lbcb is from // the active queue, we need to check that losing the tail of the // will not swallow up any of our reserved space. // if (!FlagOn( Lfcb->Flags, LFCB_PACK_LOG ) && FlagOn( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE )) { LONGLONG CurrentAvail; LONGLONG UnusedBytes; // // Find the unused bytes. // UnusedBytes = 0; LfsCurrentAvailSpace( Lfcb, &CurrentAvail, (PULONG)&UnusedBytes ); CurrentAvail = CurrentAvail - Lfcb->TotalUndoCommitment; if ( UnusedBytes > CurrentAvail ) { LfsDebugTrace( -1, Dbg, "Have to preserve these bytes for possible aborts\n", 0 ); ExRaiseStatus( STATUS_LOG_FILE_FULL ); } // // We want to make sure we don't write any more data into this // page. Remove this from the active queue. // RemoveEntryList( &ThisLbcb->ActiveLinks ); ClearFlag( ThisLbcb->LbcbFlags, LBCB_ON_ACTIVE_QUEUE ); } // // We now have the Lbcb we want to flush to disk. // LfsFlushLbcb( Lfcb, ThisLbcb ); } LfsDebugTrace( -1, Dbg, "LfsFlushToLsnPriv: Exit\n", 0 ); return; }
VOID LfsReadRestartArea ( IN LFS_LOG_HANDLE LogHandle, IN OUT PULONG BufferLength, IN PVOID Buffer, OUT PLSN Lsn ) /*++ Routine Description: This routine is called by the client when he wishes to read his restart area in the log file. Arguments: LogHandle - Pointer to private Lfs structure used to identify this client. BufferLength - On entry it is the length of the user buffer. On exit it is the size of the data stored in the buffer. Buffer - Pointer to the buffer where the client restart data is to be copied. Lsn - This is the Lsn for client restart area. Return Value: None --*/ { volatile NTSTATUS Status = STATUS_SUCCESS; BOOLEAN UsaError; PLCH Lch; PLFS_CLIENT_RECORD ClientRecord; PLFS_RECORD_HEADER RecordHeader; PBCB RecordHeaderBcb; PLFCB Lfcb; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsReadRestartArea: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle ); LfsDebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength ); LfsDebugTrace( 0, Dbg, "Buffer -> %08lx\n", Buffer ); RecordHeaderBcb = NULL; Lch = (PLCH) LogHandle; // // Check that the structure is a valid log handle structure. // LfsValidateLch( Lch ); // // Use a try-except to catch errors. // try { // // Use a try-finally to facilitate cleanup. // try { // // Acquire the log file control block for this log file. // LfsAcquireLch( Lch ); Lfcb = Lch->Lfcb; // // If the Log file has been closed then refuse access. // if (Lfcb == NULL) { ExRaiseStatus( STATUS_ACCESS_DENIED ); } // // Check that the client Id is valid. // LfsValidateClientId( Lfcb, Lch ); ClientRecord = LfsAdd2Ptr( Lfcb->ClientArray, Lch->ClientArrayByteOffset, PLFS_CLIENT_RECORD ); // // If the client doesn't have a restart area, go ahead and exit // now. // if ( ClientRecord->ClientRestartLsn.QuadPart == 0 ) { //**** xxEqlZero( ClientRecord->ClientRestartLsn ) // // We show there is no restart area by returning a length // of zero. We also set the Lsn value to zero so that // we can catch it if the user tries to use the Lsn. // LfsDebugTrace( 0, Dbg, "No client restart area exists\n", 0 ); *BufferLength = 0; *Lsn = LfsZeroLsn; try_return( NOTHING ); } // // Release the Lfcb as we won't be modifying any fields in it. // LfsReleaseLfcb( Lfcb ); // // Pin the log record for this Lsn. // LfsPinOrMapLogRecordHeader( Lfcb, ClientRecord->ClientRestartLsn, FALSE, FALSE, &UsaError, &RecordHeader, &RecordHeaderBcb ); // // If the Lsn values don't match, then the disk is corrupt. // if ( ClientRecord->ClientRestartLsn.QuadPart != RecordHeader->ThisLsn.QuadPart ) { //**** xxNeq( ClientRecord->ClientRestartLsn, RecordHeader->ThisLsn ) ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); } // // Check that the user's buffer is big enough to hold the restart // data. We raise an error status for this error. // if (RecordHeader->ClientDataLength > *BufferLength) { LfsDebugTrace( 0, Dbg, "Client buffer is too small\n", 0 ); *BufferLength = 0; *Lsn = LfsZeroLsn; ExRaiseStatus( STATUS_BUFFER_OVERFLOW ); } // // Use the cache manager to copy the data into the user's buffer. // LfsCopyReadLogRecord( Lfcb, RecordHeader, Buffer ); // // Pass the length and the Lsn of the restart area back to the // caller. // *BufferLength = RecordHeader->ClientDataLength; *Lsn = RecordHeader->ThisLsn; try_exit: NOTHING; } finally { DebugUnwind( LfsReadRestartArea ); // // Release the log file control block if held. // LfsReleaseLch( Lch ); // // Unpin the log record header for the client restart if pinned. // if (RecordHeaderBcb != NULL) { CcUnpinData( RecordHeaderBcb ); } LfsDebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart ); LfsDebugTrace( 0, Dbg, "Lsn (High) -> %08lx\n", Lsn->HighPart ); LfsDebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength ); LfsDebugTrace( -1, Dbg, "LfsReadRestartArea: Exit\n", 0 ); } } except (LfsExceptionFilter( GetExceptionInformation() )) { Status = GetExceptionCode(); } if (Status != STATUS_SUCCESS) { ExRaiseStatus( Status ); } return; }
VOID LfsSetBaseLsn ( IN LFS_LOG_HANDLE LogHandle, IN LSN BaseLsn ) /*++ Routine Description: This routine is called by the client to notify the log service of the oldest Lsn he expects to need during restart. The Lfs is allowed to reuse any part of the circular log file which logically precedes this Lsn. A client may only specify a Lsn which follows the previous Lsn specified by this client. Arguments: LogHandle - Pointer to private Lfs structure used to identify this client. BaseLsn - This is the oldest Lsn the client may require during a restart. Return Value: None --*/ { volatile NTSTATUS Status = STATUS_SUCCESS; PLCH Lch; PLFCB Lfcb; PLFS_CLIENT_RECORD ClientRecord; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsSetBaseLsn: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle ); LfsDebugTrace( 0, Dbg, "Base Lsn (Low) -> %08lx\n", BaseLsn.LowPart ); LfsDebugTrace( 0, Dbg, "Base Lsn (High) -> %08lx\n", BaseLsn.HighPart ); Lch = (PLCH) LogHandle; // // Check that the structure is a valid log handle structure. // LfsValidateLch( Lch ); // // Use a try-except to catch errors. // try { // // Use a try-finally to facilitate cleanup. // try { // // Acquire the log file control block for this log file. // LfsAcquireLch( Lch ); Lfcb = Lch->Lfcb; // // If the Log file has been closed then refuse access. // if (Lfcb == NULL) { ExRaiseStatus( STATUS_ACCESS_DENIED ); } // // Check that the client Id is valid. // LfsValidateClientId( Lfcb, Lch ); ClientRecord = LfsAdd2Ptr( Lfcb->ClientArray, Lch->ClientArrayByteOffset, PLFS_CLIENT_RECORD ); // // We simply call the worker routine to advance the base lsn. // If we moved forward in the file, we will put our restart area in the // queue. // LfsSetBaseLsnPriv( Lfcb, ClientRecord, BaseLsn ); LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, FALSE ); } finally { DebugUnwind( LfsSetBaseLsn ); // // Release the log file control block if held. // LfsReleaseLch( Lch ); LfsDebugTrace( -1, Dbg, "LfsSetBaseLsn: Exit\n", 0 ); } } except (LfsExceptionFilter( GetExceptionInformation() )) { Status = GetExceptionCode(); } if (Status != STATUS_SUCCESS) { ExRaiseStatus( Status ); } return; }
VOID LfsWriteRestartArea ( IN LFS_LOG_HANDLE LogHandle, IN ULONG BufferLength, IN PVOID Buffer, OUT PLSN Lsn ) /*++ Routine Description: This routine is called by the client to write a restart area to the disk. This routine will not return to the caller until the client restart area and all prior Lsn's have been flushed and the Lfs restart area on the disk has been updated. On return, all log records up to and including 'Lsn' have been flushed to the disk. Arguments: LogHandle - Pointer to private Lfs structure used to identify this client. BufferLength - On entry it is the length of the user buffer. Buffer - Pointer to the buffer where the client restart data resides. Lsn - This is the Lsn for this write operation. On input, this will be the new Base Lsn for this client. **** This was used to prevent adding an interface change to the Beta release. Return Value: None --*/ { volatile NTSTATUS Status = STATUS_SUCCESS; PLCH Lch; PLFCB Lfcb; PLFS_CLIENT_RECORD ClientRecord; LFS_WRITE_ENTRY WriteEntry; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsWriteRestartArea: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle ); LfsDebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", BufferLength ); LfsDebugTrace( 0, Dbg, "Buffer -> %08lx\n", Buffer ); Lch = (PLCH) LogHandle; // // Check that the structure is a valid log handle structure. // LfsValidateLch( Lch ); // // Use a try-except to catch errors. // try { // // Use a try-finally to facilitate cleanup. // try { // // Acquire the log file control block for this log file. // LfsAcquireLch( Lch ); Lfcb = Lch->Lfcb; // // If the Log file has been closed then refuse access. // if (Lfcb == NULL) { ExRaiseStatus( STATUS_ACCESS_DENIED ); } // // Check that the client Id is valid. // LfsValidateClientId( Lfcb, Lch ); ClientRecord = LfsAdd2Ptr( Lfcb->ClientArray, Lch->ClientArrayByteOffset, PLFS_CLIENT_RECORD ); // // Go ahead and update the Base Lsn in the client area if the value // given is not zero. // if ( Lsn->QuadPart != 0 ) { //**** xxNeqZero( *Lsn ) LfsSetBaseLsnPriv( Lfcb, ClientRecord, *Lsn ); } // // Write this restart area as a log record into a log page. // WriteEntry.Buffer = Buffer; WriteEntry.ByteLength = BufferLength; LfsWriteLogRecordIntoLogPage( Lfcb, Lch, 1, &WriteEntry, LfsClientRestart, NULL, LfsZeroLsn, LfsZeroLsn, 0, TRUE, Lsn ); // // Update the restart area for the client. // ClientRecord->ClientRestartLsn = *Lsn; // // Write the restart area to the disk. // LfsWriteLfsRestart( Lfcb, Lfcb->RestartAreaSize, TRUE ); } finally { DebugUnwind( LfsWriteRestartArea ); // // Release the log file control block if still held. // LfsReleaseLch( Lch ); LfsDebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn->LowPart ); LfsDebugTrace( 0, Dbg, "Log (High) -> %08lx\n", Lsn->HighPart ); LfsDebugTrace( -1, Dbg, "LfsWriteRestartArea: Exit\n", 0 ); } } except (LfsExceptionFilter( GetExceptionInformation() )) { Status = GetExceptionCode(); } if (Status != STATUS_SUCCESS) { ExRaiseStatus( Status ); } return; }
VOID LfsReadLogRecord ( IN LFS_LOG_HANDLE LogHandle, IN LSN FirstLsn, IN LFS_CONTEXT_MODE ContextMode, OUT PLFS_LOG_CONTEXT Context, OUT PLFS_RECORD_TYPE RecordType, OUT TRANSACTION_ID *TransactionId, OUT PLSN UndoNextLsn, OUT PLSN PreviousLsn, OUT PULONG BufferLength, OUT PVOID *Buffer ) /*++ Routine Description: This routine initiates the query operation. It returns the log record in question and a context structure used by the Lfs to return related log records. The caller specifies what mode of query to use. He may walk backwards through the file by Undo records or all records for this client linked through the previous Lsn fields. He may also look forwards through the file for all records for the issuing client. Arguments: LogHandle - Pointer to private Lfs structure used to identify this client. FirstLsn - Starting record for this query operation. ContextMode - Method of query. Context - Supplies the address to store a pointer to the Lfs created context structure. RecordType - Supplies the address to store the record type of this log record. TransactionId - Supplies the address to store the transaction Id of this log record. UndoNextLsn - Supplies the address to store the Undo Next Lsn for this log record. PreviousLsn - Supplies the address to store the Previous Lsn for this log record. BufferLength - This is the length of the log data. Buffer - This is a pointer to the start of the log data. Return Value: None --*/ { volatile NTSTATUS Status = STATUS_SUCCESS; PLFS_CLIENT_RECORD ClientRecord; PLCH Lch; PLFCB Lfcb; PLfsLCB Lcb = NULL; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsReadLogRecord: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Log Handle -> %08lx\n", LogHandle ); LfsDebugTrace( 0, Dbg, "First Lsn (Low) -> %08lx\n", FirstLsn.LowPart ); LfsDebugTrace( 0, Dbg, "First Lsn (High) -> %08lx\n", FirstLsn.HighPart ); LfsDebugTrace( 0, Dbg, "Context Mode -> %08lx\n", ContextMode ); Lch = (PLCH) LogHandle; // // Check that the context mode is valid. // switch (ContextMode) { case LfsContextUndoNext : case LfsContextPrevious : case LfsContextForward : break; default: LfsDebugTrace( 0, Dbg, "Invalid context mode -> %08x\n", ContextMode ); ExRaiseStatus( STATUS_INVALID_PARAMETER ); } // // Check that the structure is a valid log handle structure. // LfsValidateLch( Lch ); // // Use a try-except to catch errors. // try { // // Use a try-finally to facilitate cleanup. // try { // // Acquire the log file control block for this log file. // LfsAcquireLch( Lch ); Lfcb = Lch->Lfcb; // // If the Log file has been closed then refuse access. // if (Lfcb == NULL) { ExRaiseStatus( STATUS_ACCESS_DENIED ); } // // Check that the client Id is valid. // LfsValidateClientId( Lfcb, Lch ); // // Check that the given Lsn is in the legal range for this client. // ClientRecord = LfsAdd2Ptr( Lfcb->ClientArray, Lch->ClientArrayByteOffset, PLFS_CLIENT_RECORD ); if (!LfsVerifyClientLsnInRange( Lfcb, ClientRecord, FirstLsn )) { ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); } // // We can give up the Lfcb as we know the Lsn is within the file. // LfsReleaseLch( Lch ); // // Allocate and initialize a context structure. // LfsAllocateLcb( &Lcb ); LfsInitializeLcb( Lcb, Lch->ClientId, ContextMode ); // // Find the log record indicated by the given Lsn. // LfsFindLogRecord( Lfcb, Lcb, FirstLsn, RecordType, TransactionId, UndoNextLsn, PreviousLsn, BufferLength, Buffer ); // // Update the client's arguments. // *Context = Lcb; Lcb = NULL; } finally { DebugUnwind( LfsReadLogRecord ); // // Release the log file control block if held. // LfsReleaseLch( Lch ); // // Deallocate the context block if an error occurred. // if (Lcb != NULL) { LfsDeallocateLcb( Lcb ); } LfsDebugTrace( 0, Dbg, "Context -> %08lx\n", *Context ); LfsDebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength ); LfsDebugTrace( 0, Dbg, "Buffer -> %08lx\n", *Buffer ); LfsDebugTrace( -1, Dbg, "LfsReadLogRecord: Exit\n", 0 ); } } except (LfsExceptionFilter( GetExceptionInformation() )) { Status = GetExceptionCode(); } if (Status != STATUS_SUCCESS) { ExRaiseStatus( Status ); } return; }
BOOLEAN PopVerifyPowerActionPolicy( PPOWER_ACTION_POLICY Policy ) // NOTE: Returns TRUE if an error occurs. { ULONG SleepStateCount = 0; BOOLEAN AllowHibernate = FALSE; POWER_ACTION CurrentAction; BOOLEAN RetError = FALSE; PAGED_CODE(); // // If POWER_ACTION_CRITICAL is set in the power action policy flags, disable all conflicting // flags and force POWER_ACTION_OVERRIDE_APPS. // if (Policy->Flags & POWER_ACTION_CRITICAL) { Policy->Flags = Policy->Flags & ~(POWER_ACTION_QUERY_ALLOWED | POWER_ACTION_UI_ALLOWED) | POWER_ACTION_OVERRIDE_APPS; } // // Count available sleep states // if (PopCapabilities.SystemS1 == TRUE) SleepStateCount++; if (PopCapabilities.SystemS2 == TRUE) SleepStateCount++; if (PopCapabilities.SystemS3 == TRUE) SleepStateCount++; // // Allow hibernate action if S4 state is supported and hibernation file is present // if ((PopCapabilities.SystemS4 == TRUE) && (PopCapabilities.HiberFilePresent == TRUE)) { AllowHibernate = TRUE; } // // Validate the power action based on the system states // do { // // Set current action to the policy action // CurrentAction = Policy->Action; // // If PowerActionNone, there is nothing to verify. // if (CurrentAction == PowerActionNone) { continue; } // // If PowerActionReserved, assume PowerActionSleep. // else if (CurrentAction == PowerActionReserved) { Policy->Action = PowerActionSleep; continue; } // // If PowerActionSleep, verify that at least one sleep state is supported by the system. // This is done by checking the SleepStateCount variable. If no sleep state is available, // PowerActionNone is assigned and an error is returned. // else if (CurrentAction == PowerActionSleep) { if (SleepStateCount == 0) { Policy->Action = PowerActionNone; RetError = TRUE; } continue; } // // If PowerActionHibernate, verify that the AllowHibernate variable is set to TRUE. This // variable is TRUE only if the system supports the state S4 and hibernation file is // supported and present. If not, PowerActionSleep is set instead. // else if (CurrentAction == PowerActionHibernate) { if (AllowHibernate != TRUE) { Policy->Action = PowerActionSleep; } continue; } // // If PowerActionShutdown or PowerActionShutdownReset, there is nothing to verify. // else if (CurrentAction == PowerActionShutdown) { continue; } else if (CurrentAction == PowerActionShutdownReset) { continue; } // // If PowerActionShutdownOff, verify that the state S5 is supported. If not, // PowerActionShutdown is set instead. // else if (CurrentAction == PowerActionShutdownOff) { if (PopCapabilities.SystemS5 == FALSE) { Policy->Action = PowerActionShutdown; } continue; } // // If an unsupported power action is detected, BSOD // else { ExRaiseStatus(STATUS_INVALID_PARAMETER); } } while (CurrentAction != Policy->Action); return RetError; }
VOID LfsFindLogRecord ( IN PLFCB Lfcb, IN OUT PLfsLCB Lcb, IN LSN Lsn, OUT PLFS_RECORD_TYPE RecordType, OUT TRANSACTION_ID *TransactionId, OUT PLSN UndoNextLsn, OUT PLSN PreviousLsn, OUT PULONG BufferLength, OUT PVOID *Buffer ) /*++ Routine Description: This routine is called recover a log record for a client. Arguments: Lfcb - Log file control block for this file. Lcb - Pointer to the context block to update. Lsn - This is the Lsn for the log record. RecordType - Supplies the address to store the record type of this log record. TransactionId - Supplies the address to store the transaction Id of this log record. UndoNextLsn - Supplies the address to store the Undo Next Lsn for this log record. PreviousLsn - Supplies the address to store the Previous Lsn for this log record. BufferLength - Pointer to address to store the length in bytes of the log record. Buffer - Pointer to store the address where the log record data begins. Return Value: None --*/ { PCHAR NewBuffer; BOOLEAN UsaError; LONGLONG LogRecordLength; ULONG PageOffset; PAGED_CODE(); LfsDebugTrace( +1, Dbg, "LfsFindLogRecord: Entered\n", 0 ); LfsDebugTrace( 0, Dbg, "Lfcb -> %08lx\n", Lfcb ); LfsDebugTrace( 0, Dbg, "Context Block -> %08lx\n", Lcb ); LfsDebugTrace( 0, Dbg, "Lsn (Low) -> %08lx\n", Lsn.LowPart ); NewBuffer = NULL; // // Use a try-finally to facilitate cleanup. // try { // // Map the record header for this Lsn if we haven't already. // if (Lcb->RecordHeader == NULL) { LfsPinOrMapLogRecordHeader( Lfcb, Lsn, FALSE, FALSE, &UsaError, &Lcb->RecordHeader, &Lcb->RecordHeaderBcb ); } // // We now have the log record desired. If the Lsn in the // log record doesn't match the desired Lsn then the disk is // corrupt. // if ( Lsn.QuadPart != Lcb->RecordHeader->ThisLsn.QuadPart ) { //**** xxNeq( Lsn, Lcb->RecordHeader->ThisLsn ) ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); } // // Check that the length field isn't greater than the total available space // in the log file. // LogRecordLength = Lcb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength; //**** xxFromUlong( Lcb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength ); if ( LogRecordLength >= Lfcb->TotalAvailable ) { //**** xxGeq( LogRecordLength, Lfcb->TotalAvailable ) ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); } // // If the entire log record is on this log page, put a pointer to // the log record in the context block. // if (!FlagOn( Lcb->RecordHeader->Flags, LOG_RECORD_MULTI_PAGE )) { // // If client size indicates that we have to go beyond the end of the current // page, we raise an error. // PageOffset = LfsLsnToPageOffset( Lfcb, Lsn ); if ((PageOffset + Lcb->RecordHeader->ClientDataLength + Lfcb->RecordHeaderLength) > (ULONG)Lfcb->LogPageSize) { ExRaiseStatus( STATUS_DISK_CORRUPT_ERROR ); } Lcb->CurrentLogRecord = LfsAdd2Ptr( Lcb->RecordHeader, LFS_RECORD_HEADER_SIZE, PVOID ); Lcb->AuxilaryBuffer = FALSE; // // Else we copy the data and remember that we allocated a buffer. // } else { NewBuffer = FsRtlAllocatePool( PagedPool, Lcb->RecordHeader->ClientDataLength ); LfsCopyReadLogRecord( Lfcb, Lcb->RecordHeader, NewBuffer ); Lcb->CurrentLogRecord = NewBuffer; Lcb->AuxilaryBuffer = TRUE; NewBuffer = NULL; } // // We need to update the caller's parameters and the context block. // *RecordType = Lcb->RecordHeader->RecordType; *TransactionId = Lcb->RecordHeader->TransactionId; *UndoNextLsn = Lcb->RecordHeader->ClientUndoNextLsn; *PreviousLsn = Lcb->RecordHeader->ClientPreviousLsn; *Buffer = Lcb->CurrentLogRecord; *BufferLength = Lcb->RecordHeader->ClientDataLength; } finally { DebugUnwind( LfsFindLogRecord ); // // If an error occurred we unpin the record header and the log // We also free the buffer if allocated by us. // if (NewBuffer != NULL) { ExFreePool( NewBuffer ); } LfsDebugTrace( 0, Dbg, "Buffer Length -> %08lx\n", *BufferLength ); LfsDebugTrace( 0, Dbg, "Buffer -> %08lx\n", *Buffer ); LfsDebugTrace( -1, Dbg, "LfsFindLogRecord: Exit\n", 0 ); } return; }
VOID PopVerifyPowerPolicy( BOOLEAN IsAcPolicy, PSYSTEM_POWER_POLICY InputPolicy, PSYSTEM_POWER_POLICY OutputPolicy ) { ULONG i; PAGED_CODE(); // // Copy the input policy content to the output policy buffer // RtlCopyMemory(OutputPolicy, InputPolicy, sizeof(SYSTEM_POWER_POLICY)); // // Validate the system power policy structure revision // if (OutputPolicy->Revision != 1) { ExRaiseStatus(STATUS_INVALID_PARAMETER); } // // Compare the new system policy values to the existing administrator policy value and override // its values if necessary. // if (OutputPolicy->MinSleep < PopAdminPolicy.MinSleep) { OutputPolicy->MinSleep = PopAdminPolicy.MinSleep; } if (OutputPolicy->MaxSleep > PopAdminPolicy.MaxSleep) { OutputPolicy->MaxSleep = PopAdminPolicy.MaxSleep; } if (OutputPolicy->VideoTimeout < PopAdminPolicy.MinVideoTimeout) { OutputPolicy->VideoTimeout = PopAdminPolicy.MinVideoTimeout; } if (OutputPolicy->VideoTimeout > PopAdminPolicy.MaxVideoTimeout) { OutputPolicy->VideoTimeout = PopAdminPolicy.MaxVideoTimeout; } if (OutputPolicy->SpindownTimeout < PopAdminPolicy.MinSpindownTimeout) { OutputPolicy->SpindownTimeout = PopAdminPolicy.MinSpindownTimeout; } if (OutputPolicy->SpindownTimeout > PopAdminPolicy.MaxSpindownTimeout) { OutputPolicy->SpindownTimeout = PopAdminPolicy.MaxSpindownTimeout; } // // Verify the power action policies // PopVerifyPowerActionPolicy(&OutputPolicy->PowerButton); PopVerifyPowerActionPolicy(&OutputPolicy->SleepButton); PopVerifyPowerActionPolicy(&OutputPolicy->LidClose); PopVerifyPowerActionPolicy(&OutputPolicy->Idle); // // Verify the system power states // PopVerifySystemPowerState(&OutputPolicy->LidOpenWake); PopVerifySystemPowerState(&OutputPolicy->MinSleep); PopVerifySystemPowerState(&OutputPolicy->MaxSleep); PopVerifySystemPowerState(&OutputPolicy->ReducedLatencySleep); // // Verify the discharge policies // for (i = 0; i < NUM_DISCHARGE_POLICIES; i++) { if (OutputPolicy->DischargePolicy[i].Enable == TRUE) { PopVerifyPowerActionPolicy(&OutputPolicy->DischargePolicy[i].PowerPolicy); PopVerifySystemPowerState(&OutputPolicy->DischargePolicy[i].MinSystemState); // FIXME: Use proper flag definition. if (OutputPolicy->DischargePolicy[i].BatteryLevel > 0x64) { OutputPolicy->DischargePolicy[i].BatteryLevel = 0x64; } } } // // Verify the processor throttle policy. If processor throttling is not supported, set the // default (maximum) throttling values. // PopVerifyPowerActionPolicy(&OutputPolicy->OverThrottled); if (PopCapabilities.ProcessorThrottle == FALSE) { OutputPolicy->OptimizeForPower = FALSE; OutputPolicy->FanThrottleTolerance = 100; OutputPolicy->ForcedThrottle = 100; } // // Perform a sanity check on policy parameters and adjust their values if logically invalid. // if (PopCapabilities.ThermalControl == FALSE) { OutputPolicy->FanThrottleTolerance = 100; } // NOTE: PopSimulate 0x4 = force throttle to maximum on AC // (PROPOSED: POWER_SIMULATE_FORCE_MAX_THROTTLE_ON_AC) // FIXME: Use proper flag definition. if ((IsAcPolicy == TRUE) && (PopSimulate & 4)) { OutputPolicy->ForcedThrottle = 100; } if (OutputPolicy->BroadcastCapacityResolution == 0) { OutputPolicy->BroadcastCapacityResolution = 100; } if (OutputPolicy->Idle.Action == PowerActionNone) { OutputPolicy->IdleTimeout = 0; } if ((OutputPolicy->IdleTimeout > 0) && (OutputPolicy->IdleTimeout < 60)) { OutputPolicy->IdleTimeout = 60; } if ((OutputPolicy->IdleSensitivity > 90) || ((OutputPolicy->IdleTimeout > 0) && (OutputPolicy->IdleSensitivity == 0))) { OutputPolicy->IdleSensitivity = 90; } if (OutputPolicy->MaxSleep < OutputPolicy->MinSleep) { OutputPolicy->MaxSleep = OutputPolicy->MinSleep; } if (OutputPolicy->ReducedLatencySleep > OutputPolicy->MinSleep) { OutputPolicy->ReducedLatencySleep = OutputPolicy->MinSleep; } // // Verify the throttle parameters // PopVerifyThrottle(&OutputPolicy->FanThrottleTolerance, 20); PopVerifyThrottle(&OutputPolicy->MinThrottle, 20); PopVerifyThrottle(&OutputPolicy->ForcedThrottle, OutputPolicy->MinThrottle); // // Set OptimizeForPower value to TRUE if fan throttle tolerance or forced throttle value is // non-zero. // if ((OutputPolicy->FanThrottleTolerance != 100) || (OutputPolicy->ForcedThrottle != 100)) { OutputPolicy->OptimizeForPower = TRUE; } }
LONG KeReleaseSemaphore ( IN PRKSEMAPHORE Semaphore, IN KPRIORITY Increment, IN LONG Adjustment, IN BOOLEAN Wait ) /*++ Routine Description: This function releases a semaphore by adding the specified adjustment value to the current semaphore count and attempts to satisfy as many Waits as possible. The previous signal state of the semaphore object is returned as the function value. Arguments: Semaphore - Supplies a pointer to a dispatcher object of type semaphore. Increment - Supplies the priority increment that is to be applied if releasing the semaphore causes a Wait to be satisfied. Adjustment - Supplies value that is to be added to the current semaphore count. Wait - Supplies a boolean value that signifies whether the call to KeReleaseSemaphore will be immediately followed by a call to one of the kernel Wait functions. Return Value: The previous signal state of the semaphore object. --*/ { LONG NewState; KIRQL OldIrql; LONG OldState; PRKTHREAD Thread; ASSERT_SEMAPHORE( Semaphore ); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); // // Raise IRQL to dispatcher level and lock dispatcher database. // KiLockDispatcherDatabase(&OldIrql); // // Capture the current signal state of the semaphore object and // compute the new count value. // OldState = Semaphore->Header.SignalState; NewState = OldState + Adjustment; // // If the new state value is greater than the limit or a carry occurs, // then unlock the dispatcher database, and raise an exception. // if ((NewState > Semaphore->Limit) || (NewState < OldState)) { KiUnlockDispatcherDatabase(OldIrql); ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED); } // // Set the new signal state of the semaphore object and set the wait // next value. If the previous signal state was Not-Signaled (i.e. // the count was zero), and the wait queue is not empty, then attempt // to satisfy as many Waits as possible. // Semaphore->Header.SignalState = NewState; if ((OldState == 0) && (IsListEmpty(&Semaphore->Header.WaitListHead) == FALSE)) { KiWaitTest(Semaphore, Increment); } // // If the value of the Wait argument is TRUE, then return to the // caller with IRQL raised and the dispatcher database locked. Else // release the dispatcher database lock and lower IRQL to its // previous value. // if (Wait != FALSE) { Thread = KeGetCurrentThread(); Thread->WaitNext = Wait; Thread->WaitIrql = OldIrql; } else { KiUnlockDispatcherDatabase(OldIrql); } // // Return previous signal state of sempahore object. // return OldState; }
VOID PopVerifySystemPowerState( PSYSTEM_POWER_STATE State ) { SYSTEM_POWER_STATE VerifiedState; PAGED_CODE(); // // Copy the state parameter to the function local variable // VerifiedState = *State; // // If an invalid power state is specified, raise an exception // if ((VerifiedState == PowerSystemUnspecified) || (VerifiedState >= PowerSystemShutdown)) { ExRaiseStatus(STATUS_INVALID_PARAMETER); } // // Perform state verification if the power state is not PowerSystemWorking. If the current // system state is not supported, check if any lower power states are supported. // if (VerifiedState != PowerSystemWorking) { if ((VerifiedState == PowerSystemHibernate) && ((PopCapabilities.SystemS4 == FALSE) || (PopCapabilities.HiberFilePresent == FALSE))) { VerifiedState = PowerSystemSleeping3; } if ((VerifiedState == PowerSystemSleeping3) && (PopCapabilities.SystemS3 == FALSE)) { VerifiedState = PowerSystemSleeping2; } if ((VerifiedState == PowerSystemSleeping2) && (PopCapabilities.SystemS2 == FALSE)) { VerifiedState = PowerSystemSleeping1; } if ((VerifiedState == PowerSystemSleeping1) && (PopCapabilities.SystemS1 == FALSE)) { VerifiedState = PowerSystemSleeping2; if (PopCapabilities.SystemS2 == FALSE) { VerifiedState = PowerSystemSleeping3; } if ((VerifiedState == PowerSystemSleeping3) && (PopCapabilities.SystemS3 == FALSE)) { VerifiedState = PowerSystemWorking; } } } // // Set the verified state value to the state parameter // *State = VerifiedState; }
VOID MmProbeForWrite ( IN PVOID Address, IN ULONG Length ) /*++ Routine Description: This function probes an address for write accessibility on the Intel 386. Arguments: Address - Supplies a pointer to the structure to probe. Length - Supplies the length of the structure. Return Value: None. If the Address cannot be written an exception is raised. --*/ { PMMPTE PointerPte; PMMPTE LastPte; MMPTE PteContents; CCHAR Temp; // // Loop on the copy on write case until the page is only // writable. // if (Address >= (PVOID)MM_HIGHEST_USER_ADDRESS) { ExRaiseStatus(STATUS_ACCESS_VIOLATION); } PointerPte = MiGetPteAddress (Address); LastPte = MiGetPteAddress ((PVOID)((ULONG)Address + Length - 1)); while (PointerPte <= LastPte) { for (;;) { // // Touch the address as a byte to check for readability and // get the PTE built. // do { Temp = *(volatile CCHAR *)Address; PteContents = *(volatile MMPTE *)PointerPte; } while (PteContents.u.Hard.Valid == 0); if (PteContents.u.Hard.Write == 1) { // // The PTE is writable and not copy on write. // break; } if (PteContents.u.Hard.CopyOnWrite == 1) { // // The PTE is copy on write. Call the pager and let // it deal with this. Once the page fault is complete, // this loop will again be repeated and the PTE will // again be checked for write access and copy-on-write // access. The PTE could still be copy-on-write even // after the pager is called if the page table page // was removed from the working set at this time (unlikely, // but still possible). // if (!NT_SUCCESS (MmAccessFault (TRUE, Address, UserMode))) { // // Raise an access violation status. // ExRaiseStatus(STATUS_ACCESS_VIOLATION); } } else { // // Raise an access violation status. // ExRaiseStatus(STATUS_ACCESS_VIOLATION); } } PointerPte += 1; Address = (PVOID)((ULONG)Address + PAGE_SIZE); } }
VOID PopApplyAdminPolicy( BOOLEAN UpdateRegistry, PADMINISTRATOR_POWER_POLICY NewPolicy, ULONG PolicyLength ) { HANDLE RegKeyHandle; UNICODE_STRING RegValueNameString; ADMINISTRATOR_POWER_POLICY Policy; NTSTATUS Status; // // Ensure that the length of the NewPolicy struct supplied is valid // if (PolicyLength < sizeof(ADMINISTRATOR_POWER_POLICY)) { ExRaiseStatus(STATUS_BUFFER_TOO_SMALL); } else if (PolicyLength > sizeof(ADMINISTRATOR_POWER_POLICY)) { ExRaiseStatus(STATUS_BUFFER_OVERFLOW); } // // Copy the new policy to the function local buffer // RtlCopyMemory(&Policy, NewPolicy, sizeof(ADMINISTRATOR_POWER_POLICY)); // // Validate the new administrator policy // // FIXME: If this same check is routinely used throughout the power manager code, make this // check routine a macro defined in pop.h. // if ((Policy.MinSleep < PowerSystemSleeping1) || (Policy.MinSleep > PowerSystemHibernate) || (Policy.MaxSleep > PowerSystemHibernate) || (Policy.MinSleep > Policy.MaxSleep) || (Policy.MinVideoTimeout > Policy.MaxVideoTimeout) || (Policy.MinSpindownTimeout > Policy.MaxSpindownTimeout)) { ExRaiseStatus(STATUS_INVALID_PARAMETER); } // // If the new administrator policy is different from the pre-existing PopAdminPolicy, copy // the NewPolicy to the PopAdminPolicy. // if (RtlCompareMemory(&Policy, &PopAdminPolicy, sizeof(ADMINISTRATOR_POWER_POLICY)) != 0) { RtlCopyMemory(&PopAdminPolicy, &Policy, sizeof(ADMINISTRATOR_POWER_POLICY)); // // If UpdateRegistry flag is set, save the NewPolicy to the registry PolicyOverrides value. // if (UpdateRegistry == TRUE) { Status = PopOpenPowerKey(&RegKeyHandle); if (NT_SUCCESS(Status)) { RtlInitUnicodeString(&RegValueNameString, L"PolicyOverrides"); ZwSetValueKey( RegKeyHandle, &RegValueNameString, 0, REG_BINARY, &Policy, sizeof(ADMINISTRATOR_POWER_POLICY) ); ZwClose(RegKeyHandle); } } } }