ReactOS  0.4.15-dev-4870-g846c9aa
povolume.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: BSD - See COPYING.ARM in the top level directory
4  * FILE: ntoskrnl/po/povolume.c
5  * PURPOSE: Power Manager DOPE and Volume Management
6  * PROGRAMMERS: ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS *******************************************************************/
16 
17 typedef struct _POP_FLUSH_VOLUME
18 {
23 
25 
29 
30 /* PRIVATE FUNCTIONS *********************************************************/
31 
33 NTAPI
35 {
36  PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
38  KIRQL OldIrql;
39  PAGED_CODE();
40 
41  /* If the device already has the dope, return it */
42  DeviceExtension = IoGetDevObjExtension(DeviceObject);
43  if (DeviceExtension->Dope) goto Return;
44 
45  /* Allocate some dope for the device */
48  TAG_PO_DOPE);
49  if (!Dope) goto Return;
50 
51  /* Initialize the initial contents of the dope */
53  Dope->DeviceObject = DeviceObject;
56 
57  /* Make sure only one caller can assign dope to a device */
59 
60  /* Make sure the device still has no dope */
61  if (!DeviceExtension->Dope)
62  {
63  /* Give the local dope to this device, and remember we won the race */
64  DeviceExtension->Dope = (PVOID)Dope;
65  Dope = NULL;
66  }
67 
68  /* Allow other dope transactions now */
70 
71  /* Check if someone other than us already assigned the dope, so free ours */
72  if (Dope) ExFreePoolWithTag(Dope, TAG_PO_DOPE);
73 
74  /* Return the dope to the caller */
75 Return:
76  return (PDEVICE_OBJECT_POWER_EXTENSION)DeviceExtension->Dope;
77 }
78 
79 VOID
80 NTAPI
82 {
84  PAGED_CODE();
85 
86  /* Get dope from the device (if the device has no dope, it will receive some) */
87  Dope = PopGetDope(DeviceObject);
88  if (Dope)
89  {
90  /* Make sure we can flush safely */
92 
93  /* Add this volume into the list of power-manager volumes */
94  if (!Dope->Volume.Flink) InsertTailList(&PopVolumeDevices, &Dope->Volume);
95 
96  /* Allow flushes to go through */
98  }
99 }
100 
101 VOID
102 NTAPI
104 {
106  PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
107  KIRQL OldIrql;
108  PAGED_CODE();
109 
110  /* If the device already has the dope, return it */
111  DeviceExtension = IoGetDevObjExtension(DeviceObject);
112  if (!DeviceExtension->Dope)
113  {
114  /* no dope */
115  return;
116  }
117 
118  /* Make sure we can flush safely */
120 
121  /* Get dope from device */
122  Dope = (PDEVICE_OBJECT_POWER_EXTENSION)DeviceExtension->Dope;
123 
124  if (Dope->Volume.Flink)
125  {
126  /* Remove from volume from list */
127  RemoveEntryList(&Dope->Volume);
128  }
129 
130  /* Allow flushes to go through */
132 
133  /* Now remove dope from device object */
135 
136  /* remove from dev obj */
137  DeviceExtension->Dope = NULL;
138 
139  /* Release lock */
141 
142  /* Free dope */
144 }
145 
146 VOID
147 NTAPI
149 {
152  PLIST_ENTRY NextEntry;
154  UCHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + 512];
156  ULONG Length;
160 
161  /* Acquire the flush lock since we're messing with the list */
163 
164  /* Loop the flush list */
165  while (!IsListEmpty(&FlushContext->List))
166  {
167  /* Grab the next (ie: current) entry and remove it */
168  NextEntry = FlushContext->List.Flink;
169  RemoveEntryList(NextEntry);
170 
171  /* Add it back on the volume list */
172  InsertTailList(&PopVolumeDevices, NextEntry);
173 
174  /* Done touching the volume list */
176 
177  /* Get the dope from the volume link */
179 
180  /* Get the name */
182  NameInfo,
183  sizeof(Buffer),
184  &Length);
185  if ((NT_SUCCESS(Status)) && (NameInfo->Name.Buffer))
186  {
187  /* Open the volume */
188  DPRINT("Opening: %wZ\n", &NameInfo->Name);
190  &NameInfo->Name,
192  0,
193  0);
194  Status = ZwCreateFile(&VolumeHandle,
197  &IoStatusBlock,
198  NULL,
201  FILE_OPEN,
202  0,
203  NULL,
204  0);
205  if (NT_SUCCESS(Status))
206  {
207  /* Flush it and close it */
208  DPRINT("Sending flush to: %p\n", VolumeHandle);
211  }
212  }
213 
214  /* Acquire the flush lock again since we'll touch the list */
216  }
217 
218  /* One more flush completed... if it was the last, signal the caller */
219  if (!--FlushContext->Count) KeSetEvent(&FlushContext->Wait, IO_NO_INCREMENT, FALSE);
220 
221  /* Serialize with flushers */
223 }
224 
225 VOID
226 NTAPI
228 {
229  POP_FLUSH_VOLUME FlushContext = {{0}};
230  ULONG FlushPolicy;
231  UNICODE_STRING RegistryName = RTL_CONSTANT_STRING(L"\\Registry");
233  HANDLE RegistryHandle;
234  PLIST_ENTRY NextEntry;
236  ULONG VolumeCount = 0;
238  HANDLE ThreadHandle;
239  ULONG ThreadCount;
240 
241  /* Setup the flush context */
242  InitializeListHead(&FlushContext.List);
244 
245  /* What to flush */
246  FlushPolicy = ShuttingDown ? 1 | 2 : PopFlushPolicy;
247  if ((FlushPolicy & 1))
248  {
249  /* Registry flush requested, so open it */
250  DPRINT("Opening registry\n");
252  &RegistryName,
254  NULL,
255  NULL);
256  Status = ZwOpenKey(&RegistryHandle, KEY_READ, &ObjectAttributes);
257  if (NT_SUCCESS(Status))
258  {
259  /* Flush the registry */
260  DPRINT("Flushing registry\n");
261  ZwFlushKey(RegistryHandle);
262  ZwClose(RegistryHandle);
263  }
264  }
265 
266  /* Serialize with other flushes */
268 
269  /* Scan the volume list */
270  NextEntry = PopVolumeDevices.Flink;
271  while (NextEntry != &PopVolumeDevices)
272  {
273  /* Get the dope from the link */
275 
276  /* Grab the next entry now, since we'll be modifying the list */
277  NextEntry = NextEntry->Flink;
278 
279  /* Make sure the object is mounted, writable, exists, and is not a floppy */
280  if (!(Dope->DeviceObject->Vpb->Flags & VPB_MOUNTED) ||
281  (Dope->DeviceObject->Characteristics & FILE_FLOPPY_DISKETTE) ||
282  (Dope->DeviceObject->Characteristics & FILE_READ_ONLY_DEVICE) ||
283  ((Dope->DeviceObject->Vpb->RealDevice) &&
284  (Dope->DeviceObject->Vpb->RealDevice->Characteristics & FILE_FLOPPY_DISKETTE)))
285  {
286  /* Not flushable */
287  continue;
288  }
289 
290  /* Remove it from the dope and add it to the flush context list */
291  RemoveEntryList(&Dope->Volume);
292  InsertTailList(&FlushContext.List, &Dope->Volume);
293 
294  /* Next */
295  VolumeCount++;
296  }
297 
298  /* Check if we should skip non-removable devices */
299  if (!(FlushPolicy & 2))
300  {
301  /* ReactOS only implements this routine for shutdown, which requires it */
303  }
304 
305  /* Check if there were no volumes at all */
306  if (!VolumeCount)
307  {
308  /* Nothing to do */
310  return;
311  }
312 
313  /* Allocate up to 8 flusher threads */
314  ThreadCount = min(VolumeCount, 8);
316  NULL,
318  NULL,
319  NULL);
320 
321  /* We will ourselves become a flusher thread */
322  FlushContext.Count = 1;
323  ThreadCount--;
324 
325  /* Look for any extra ones we might need */
326  while (ThreadCount > 0)
327  {
328  /* Create a new one */
329  ThreadCount--;
330  DPRINT("Creating flush thread\n");
331  Status = PsCreateSystemThread(&ThreadHandle,
334  0L,
335  NULL,
337  &FlushContext);
338  if (NT_SUCCESS(Status))
339  {
340  /* One more created... */
341  FlushContext.Count++;
342  ZwClose(ThreadHandle);
343  }
344  }
345 
346  /* Allow flushes to go through */
348 
349  /* Enter the flush work */
350  DPRINT("Local flush\n");
351  PopFlushVolumeWorker(&FlushContext);
352 
353  /* Wait for all flushes to be over */
354  DPRINT("Waiting for flushes\n");
356  DPRINT("Flushes have completed\n");
357 }
358 
359 VOID
360 NTAPI
362 {
363  PEXTENDED_DEVOBJ_EXTENSION DeviceExtension = (PVOID)DeviceObjectExtension;
364  PAGED_CODE();
365 
366  /* Initialize the power flags */
367  DeviceExtension->PowerFlags = PowerSystemUnspecified & 0xF;
368  DeviceExtension->PowerFlags |= ((PowerDeviceUnspecified << 4) & 0xF0);
369 
370  /* The device object is not on drugs yet */
371  DeviceExtension->Dope = NULL;
372 }
373 
374 /* PUBLIC FUNCTIONS **********************************************************/
375 
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
#define IN
Definition: typedefs.h:39
#define THREAD_ALL_ACCESS
Definition: nt_native.h:1339
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
NTSYSAPI NTSTATUS NTAPI ZwFlushBuffersFile(_In_ HANDLE FileHandle, _Out_ PIO_STATUS_BLOCK IoStatusBlock)
#define KEY_READ
Definition: nt_native.h:1023
struct _POP_FLUSH_VOLUME POP_FLUSH_VOLUME
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
LONG NTSTATUS
Definition: precomp.h:26
VOID NTAPI KeAcquireSpinLock(PKSPIN_LOCK SpinLock, PKIRQL OldIrql)
Definition: spinlock.c:50
NTSTATUS NTAPI ObQueryNameString(IN PVOID Object, OUT POBJECT_NAME_INFORMATION ObjectNameInfo, IN ULONG Length, OUT PULONG ReturnLength)
Definition: obname.c:1207
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define InsertTailList(ListHead, Entry)
if(dx==0 &&dy==0)
Definition: linetemp.h:174
KGUARDED_MUTEX PopVolumeLock
Definition: povolume.c:26
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
VOID NTAPI PoInitializeDeviceObject(IN OUT PDEVOBJ_EXTENSION DeviceObjectExtension)
Definition: povolume.c:361
#define FILE_SHARE_READ
Definition: compat.h:136
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
UCHAR KIRQL
Definition: env_spec_w32.h:591
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
#define L(x)
Definition: ntvdm.h:50
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
LIST_ENTRY PopVolumeDevices
Definition: povolume.c:27
#define FALSE
Definition: types.h:117
long LONG
Definition: pedump.c:60
#define FILE_READ_DATA
Definition: nt_native.h:628
#define GENERIC_WRITE
Definition: nt_native.h:90
unsigned char BOOLEAN
struct _OBJECT_NAME_INFORMATION OBJECT_NAME_INFORMATION
VOID NTAPI PopFlushVolumes(IN BOOLEAN ShuttingDown)
Definition: povolume.c:227
Definition: bufpool.h:45
struct _POP_FLUSH_VOLUME * PPOP_FLUSH_VOLUME
void * PVOID
Definition: retypes.h:9
#define FILE_WRITE_DATA
Definition: nt_native.h:631
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
Status
Definition: gdiplustypes.h:24
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
LIST_ENTRY List
Definition: povolume.c:19
struct _DEVICE_OBJECT_POWER_EXTENSION * Dope
Definition: iotypes.h:933
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
_Must_inspect_result_ _Out_ PHANDLE VolumeHandle
Definition: fltkernel.h:2283
#define TAG_PO_DOPE
Definition: tag.h:126
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
unsigned char UCHAR
Definition: xmlstorage.h:181
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:792
#define GENERIC_READ
Definition: compat.h:135
Definition: typedefs.h:119
struct _DEVICE_OBJECT_POWER_EXTENSION * PDEVICE_OBJECT_POWER_EXTENSION
ULONG PopFlushPolicy
Definition: povolume.c:24
#define SYNCHRONIZE
Definition: nt_native.h:61
DEVICE_POWER_STATE State
Definition: po.h:251
KSPIN_LOCK PopDopeGlobalLock
Definition: povolume.c:28
#define FILE_OPEN
Definition: from_kernel.h:54
VOID NTAPI PoRemoveVolumeDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: povolume.c:103
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
NTSTATUS NTAPI PsCreateSystemThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PCLIENT_ID ClientId, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext)
Definition: thread.c:602
PDEVICE_OBJECT DeviceObject
Definition: po.h:249
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define min(a, b)
Definition: monoChain.cc:55
#define NULL
Definition: types.h:112
VOID NTAPI PoVolumeDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: povolume.c:81
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
#define OUT
Definition: typedefs.h:40
PDEVICE_OBJECT_POWER_EXTENSION NTAPI PopGetDope(IN PDEVICE_OBJECT DeviceObject)
Definition: povolume.c:34
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#define UNIMPLEMENTED
Definition: debug.h:115
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define DPRINT
Definition: sndvol32.h:71
#define FILE_FLOPPY_DISKETTE
Definition: nt_native.h:809
#define IoGetDevObjExtension(DeviceObject)
Definition: io.h:129
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define VPB_MOUNTED
Definition: iotypes.h:1807
#define FILE_READ_ONLY_DEVICE
Definition: nt_native.h:808
#define PAGED_CODE()
VOID NTAPI PopFlushVolumeWorker(IN PVOID Context)
Definition: povolume.c:148
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14