windows-nt/Source/XPSP1/NT/base/ntos/po/volume.c
2020-09-26 16:20:57 +08:00

307 lines
6.9 KiB
C

/*++
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 ();
}