/*++ Copyright (c) 1990 Microsoft Corporation Module Name: volume.c Abstract: This module implements power management function releated to volume devices Author: Ken Reneris (kenr) 04-April-1997 Revision History: --*/ #include "pop.h" typedef struct { LIST_ENTRY List; LONG Count; KEVENT Wait; } POP_FLUSH_VOLUME, *PPOP_FLUSH_VOLUME; VOID PoVolumeDevice ( IN PDEVICE_OBJECT DeviceObject ); VOID PopFlushVolumeWorker ( IN PPOP_FLUSH_VOLUME Flush ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE,PoVolumeDevice) #pragma alloc_text(PAGE,PopFlushVolumes) #pragma alloc_text(PAGE,PopFlushVolumeWorker) #endif VOID PoVolumeDevice ( IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: Called for any device object which gets allocated a VPB. The power policy manager keeps a list of all such device objects in order to flush all volumes before putting the system to sleep Arguments: DeviceObject - The volume device object Return Value: None --*/ { PDEVICE_OBJECT_POWER_EXTENSION Dope; Dope = PopGetDope(DeviceObject); if (Dope) { PopAcquireVolumeLock (); if (!Dope->Volume.Flink) { InsertTailList (&PopVolumeDevices, &Dope->Volume); } PopReleaseVolumeLock (); } } VOID PopFlushVolumes ( VOID ) /*++ Routine Description: Called to flush all volumes. Arguments: None Return Value: None --*/ { PDEVICE_OBJECT_POWER_EXTENSION Dope; PLIST_ENTRY Link; POP_FLUSH_VOLUME Flush; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; HANDLE Thread; ULONG i; UNICODE_STRING RegistryName; HANDLE Key; Flush.Count = 1; InitializeListHead (&Flush.List); KeInitializeEvent (&Flush.Wait, NotificationEvent, FALSE); InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); // // Move volumes onto flush work queue // PopAcquireVolumeLock (); Link = PopVolumeDevices.Flink; while (Link != &PopVolumeDevices) { Dope = CONTAINING_RECORD (Link, DEVICE_OBJECT_POWER_EXTENSION, Volume); Link = Link->Flink; if (!(Dope->DeviceObject->Vpb->Flags & VPB_MOUNTED) || (Dope->DeviceObject->Characteristics & FILE_FLOPPY_DISKETTE) || (Dope->DeviceObject->Characteristics & FILE_READ_ONLY_DEVICE) || (Dope->DeviceObject->Vpb->RealDevice && Dope->DeviceObject->Vpb->RealDevice->Characteristics & FILE_FLOPPY_DISKETTE)) { // // Skip this device, there is no point in flushing it. // } else { RemoveEntryList (&Dope->Volume); InsertTailList (&Flush.List, &Dope->Volume); } } // // Allocate worker threads to flush volumes // i = Flush.Count; if (i > 8) { i = 8; } while (i) { i -= 1; Status = PsCreateSystemThread(&Thread, THREAD_ALL_ACCESS, &ObjectAttributes, 0L, NULL, PopFlushVolumeWorker, &Flush); if (NT_SUCCESS(Status)) { Flush.Count += 1; NtClose (Thread); } } PopReleaseVolumeLock (); // // Flush the registry as well. // RtlInitUnicodeString(&RegistryName, L"\\Registry"); InitializeObjectAttributes(&ObjectAttributes, &RegistryName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(&Key, KEY_READ, &ObjectAttributes); if (NT_SUCCESS(Status)) { ZwFlushKey(Key); ZwClose(Key); } // // Verify work in complete // PopFlushVolumeWorker (&Flush); KeWaitForSingleObject (&Flush.Wait, Suspended, KernelMode, TRUE, NULL); } VOID PopFlushVolumeWorker ( IN PPOP_FLUSH_VOLUME Flush ) /*++ Routine Description: Worker routine for PopFlushVolumes to flush a single volume Arguments: None Return Value: None --*/ { PDEVICE_OBJECT_POWER_EXTENSION Dope; PLIST_ENTRY Link; NTSTATUS Status; UCHAR Buffer[512]; POBJECT_NAME_INFORMATION ObName; ULONG len; IO_STATUS_BLOCK IoStatus; OBJECT_ATTRIBUTES objA; ULONG FlushCount; KEVENT Wait; HANDLE handle; PopAcquireVolumeLock (); while (!IsListEmpty (&Flush->List)) { Link = Flush->List.Flink; RemoveEntryList (Link); InsertTailList (&PopVolumeDevices, Link); PopReleaseVolumeLock (); Dope = CONTAINING_RECORD (Link, DEVICE_OBJECT_POWER_EXTENSION, Volume); // // Get the name of this object // ObName = (POBJECT_NAME_INFORMATION) Buffer; Status = ObQueryNameString ( Dope->DeviceObject, ObName, sizeof (Buffer), &len ); if (NT_SUCCESS(Status) && ObName->Name.Buffer) { // // Open the volume // InitializeObjectAttributes ( &objA, &ObName->Name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0 ); Status = ZwCreateFile ( &handle, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, &objA, &IoStatus, NULL, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, 0, NULL, 0 ); if (NT_SUCCESS(Status)) { // // Flush the volume // ZwFlushBuffersFile (handle, &IoStatus); // // Close the reference to the volume // ZwClose (handle); } } PopAcquireVolumeLock (); } Flush->Count -= 1; if (Flush->Count == 0) { KeSetEvent (&Flush->Wait, IO_NO_INCREMENT, FALSE); } PopReleaseVolumeLock (); }