ReactOS  0.4.14-dev-337-gf981a68
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 #define TAG_PO_DOPE 'EPOD'
31 
32 /* PRIVATE FUNCTIONS *********************************************************/
33 
35 NTAPI
37 {
38  PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
40  KIRQL OldIrql;
41  PAGED_CODE();
42 
43  /* If the device already has the dope, return it */
44  DeviceExtension = IoGetDevObjExtension(DeviceObject);
45  if (DeviceExtension->Dope) goto Return;
46 
47  /* Allocate some dope for the device */
50  TAG_PO_DOPE);
51  if (!Dope) goto Return;
52 
53  /* Initialize the initial contents of the dope */
55  Dope->DeviceObject = DeviceObject;
58 
59  /* Make sure only one caller can assign dope to a device */
61 
62  /* Make sure the device still has no dope */
63  if (!DeviceExtension->Dope)
64  {
65  /* Give the local dope to this device, and remember we won the race */
66  DeviceExtension->Dope = (PVOID)Dope;
67  Dope = NULL;
68  }
69 
70  /* Allow other dope transactions now */
72 
73  /* Check if someone other than us already assigned the dope, so free ours */
74  if (Dope) ExFreePoolWithTag(Dope, TAG_PO_DOPE);
75 
76  /* Return the dope to the caller */
77 Return:
78  return (PDEVICE_OBJECT_POWER_EXTENSION)DeviceExtension->Dope;
79 }
80 
81 VOID
82 NTAPI
84 {
86  PAGED_CODE();
87 
88  /* Get dope from the device (if the device has no dope, it will receive some) */
89  Dope = PopGetDope(DeviceObject);
90  if (Dope)
91  {
92  /* Make sure we can flush safely */
94 
95  /* Add this volume into the list of power-manager volumes */
96  if (!Dope->Volume.Flink) InsertTailList(&PopVolumeDevices, &Dope->Volume);
97 
98  /* Allow flushes to go through */
100  }
101 }
102 
103 VOID
104 NTAPI
106 {
108  PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
109  KIRQL OldIrql;
110  PAGED_CODE();
111 
112  /* If the device already has the dope, return it */
113  DeviceExtension = IoGetDevObjExtension(DeviceObject);
114  if (!DeviceExtension->Dope)
115  {
116  /* no dope */
117  return;
118  }
119 
120  /* Make sure we can flush safely */
122 
123  /* Get dope from device */
124  Dope = (PDEVICE_OBJECT_POWER_EXTENSION)DeviceExtension->Dope;
125 
126  if (Dope->Volume.Flink)
127  {
128  /* Remove from volume from list */
129  RemoveEntryList(&Dope->Volume);
130  }
131 
132  /* Allow flushes to go through */
134 
135  /* Now remove dope from device object */
137 
138  /* remove from dev obj */
139  DeviceExtension->Dope = NULL;
140 
141  /* Release lock */
143 
144  /* Free dope */
146 }
147 
148 VOID
149 NTAPI
151 {
154  PLIST_ENTRY NextEntry;
156  UCHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + 512];
158  ULONG Length;
162 
163  /* Acquire the flush lock since we're messing with the list */
165 
166  /* Loop the flush list */
167  while (!IsListEmpty(&FlushContext->List))
168  {
169  /* Grab the next (ie: current) entry and remove it */
170  NextEntry = FlushContext->List.Flink;
171  RemoveEntryList(NextEntry);
172 
173  /* Add it back on the volume list */
174  InsertTailList(&PopVolumeDevices, NextEntry);
175 
176  /* Done touching the volume list */
178 
179  /* Get the dope from the volume link */
181 
182  /* Get the name */
184  NameInfo,
185  sizeof(Buffer),
186  &Length);
187  if ((NT_SUCCESS(Status)) && (NameInfo->Name.Buffer))
188  {
189  /* Open the volume */
190  DPRINT("Opening: %wZ\n", &NameInfo->Name);
192  &NameInfo->Name,
194  0,
195  0);
196  Status = ZwCreateFile(&VolumeHandle,
199  &IoStatusBlock,
200  NULL,
203  FILE_OPEN,
204  0,
205  NULL,
206  0);
207  if (NT_SUCCESS(Status))
208  {
209  /* Flush it and close it */
210  DPRINT("Sending flush to: %p\n", VolumeHandle);
213  }
214  }
215 
216  /* Acquire the flush lock again since we'll touch the list */
218  }
219 
220  /* One more flush completed... if it was the last, signal the caller */
221  if (!--FlushContext->Count) KeSetEvent(&FlushContext->Wait, IO_NO_INCREMENT, FALSE);
222 
223  /* Serialize with flushers */
225 }
226 
227 VOID
228 NTAPI
230 {
231  POP_FLUSH_VOLUME FlushContext = {{0}};
232  ULONG FlushPolicy;
233  UNICODE_STRING RegistryName = RTL_CONSTANT_STRING(L"\\Registry");
235  HANDLE RegistryHandle;
236  PLIST_ENTRY NextEntry;
238  ULONG VolumeCount = 0;
240  HANDLE ThreadHandle;
241  ULONG ThreadCount;
242 
243  /* Setup the flush context */
244  InitializeListHead(&FlushContext.List);
246 
247  /* What to flush */
248  FlushPolicy = ShuttingDown ? 1 | 2 : PopFlushPolicy;
249  if ((FlushPolicy & 1))
250  {
251  /* Registry flush requested, so open it */
252  DPRINT("Opening registry\n");
254  &RegistryName,
256  NULL,
257  NULL);
258  Status = ZwOpenKey(&RegistryHandle, KEY_READ, &ObjectAttributes);
259  if (NT_SUCCESS(Status))
260  {
261  /* Flush the registry */
262  DPRINT("Flushing registry\n");
263  ZwFlushKey(RegistryHandle);
264  ZwClose(RegistryHandle);
265  }
266  }
267 
268  /* Serialize with other flushes */
270 
271  /* Scan the volume list */
272  NextEntry = PopVolumeDevices.Flink;
273  while (NextEntry != &PopVolumeDevices)
274  {
275  /* Get the dope from the link */
277 
278  /* Grab the next entry now, since we'll be modifying the list */
279  NextEntry = NextEntry->Flink;
280 
281  /* Make sure the object is mounted, writable, exists, and is not a floppy */
282  if (!(Dope->DeviceObject->Vpb->Flags & VPB_MOUNTED) ||
283  (Dope->DeviceObject->Characteristics & FILE_FLOPPY_DISKETTE) ||
284  (Dope->DeviceObject->Characteristics & FILE_READ_ONLY_DEVICE) ||
285  ((Dope->DeviceObject->Vpb->RealDevice) &&
286  (Dope->DeviceObject->Vpb->RealDevice->Characteristics & FILE_FLOPPY_DISKETTE)))
287  {
288  /* Not flushable */
289  continue;
290  }
291 
292  /* Remove it from the dope and add it to the flush context list */
293  RemoveEntryList(&Dope->Volume);
294  InsertTailList(&FlushContext.List, &Dope->Volume);
295 
296  /* Next */
297  VolumeCount++;
298  }
299 
300  /* Check if we should skip non-removable devices */
301  if (!(FlushPolicy & 2))
302  {
303  /* ReactOS only implements this routine for shutdown, which requires it */
305  }
306 
307  /* Check if there were no volumes at all */
308  if (!VolumeCount)
309  {
310  /* Nothing to do */
312  return;
313  }
314 
315  /* Allocate up to 8 flusher threads */
316  ThreadCount = min(VolumeCount, 8);
318  NULL,
320  NULL,
321  NULL);
322 
323  /* We will ourselves become a flusher thread */
324  FlushContext.Count = 1;
325  ThreadCount--;
326 
327  /* Look for any extra ones we might need */
328  while (ThreadCount > 0)
329  {
330  /* Create a new one */
331  ThreadCount--;
332  DPRINT("Creating flush thread\n");
333  Status = PsCreateSystemThread(&ThreadHandle,
336  0L,
337  NULL,
339  &FlushContext);
340  if (NT_SUCCESS(Status))
341  {
342  /* One more created... */
343  FlushContext.Count++;
344  ZwClose(ThreadHandle);
345  }
346  }
347 
348  /* Allow flushes to go through */
350 
351  /* Enter the flush work */
352  DPRINT("Local flush\n");
353  PopFlushVolumeWorker(&FlushContext);
354 
355  /* Wait for all flushes to be over */
356  DPRINT("Waiting for flushes\n");
358  DPRINT("Flushes have completed\n");
359 }
360 
361 VOID
362 NTAPI
364 {
365  PEXTENDED_DEVOBJ_EXTENSION DeviceExtension = (PVOID)DeviceObjectExtension;
366  PAGED_CODE();
367 
368  /* Initialize the power flags */
369  DeviceExtension->PowerFlags = PowerSystemUnspecified & 0xF;
370  DeviceExtension->PowerFlags |= ((PowerDeviceUnspecified << 4) & 0xF0);
371 
372  /* The device object is not on drugs yet */
373  DeviceExtension->Dope = NULL;
374 }
375 
376 /* PUBLIC FUNCTIONS **********************************************************/
377 
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
#define IN
Definition: typedefs.h:38
#define THREAD_ALL_ACCESS
Definition: nt_native.h:1339
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
NTSTATUS NTAPI ObQueryNameString(IN PVOID Object, OUT POBJECT_NAME_INFORMATION ObjectNameInfo, IN ULONG Length, OUT PULONG ReturnLength)
Definition: obname.c:1209
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define InsertTailList(ListHead, Entry)
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
_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:363
#define PAGED_CODE()
Definition: video.h:57
#define FILE_SHARE_READ
Definition: compat.h:125
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
UCHAR KIRQL
Definition: env_spec_w32.h:591
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
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:229
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
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
#define TAG_PO_DOPE
Definition: povolume.c:30
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
if(!(yy_init))
Definition: macro.lex.yy.c:714
LIST_ENTRY List
Definition: povolume.c:19
struct _DEVICE_OBJECT_POWER_EXTENSION * Dope
Definition: iotypes.h:917
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
_Must_inspect_result_ _Out_ PHANDLE VolumeHandle
Definition: fltkernel.h:2284
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
unsigned char UCHAR
Definition: xmlstorage.h:181
static const WCHAR L[]
Definition: oid.c:1250
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#define GENERIC_READ
Definition: compat.h:124
Definition: typedefs.h:117
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
Status
Definition: gdiplustypes.h:24
KSPIN_LOCK PopDopeGlobalLock
Definition: povolume.c:28
#define FILE_OPEN
Definition: from_kernel.h:54
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
VOID NTAPI PoRemoveVolumeDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: povolume.c:105
#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
VOID NTAPI PoVolumeDevice(IN PDEVICE_OBJECT DeviceObject)
Definition: povolume.c:83
#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:39
PDEVICE_OBJECT_POWER_EXTENSION NTAPI PopGetDope(IN PDEVICE_OBJECT DeviceObject)
Definition: povolume.c:36
unsigned int ULONG
Definition: retypes.h:1
#define IO_NO_INCREMENT
Definition: iotypes.h:566
#define UNIMPLEMENTED
Definition: debug.h:114
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define FILE_FLOPPY_DISKETTE
Definition: nt_native.h:809
#define IoGetDevObjExtension(DeviceObject)
Definition: io.h:125
#define VPB_MOUNTED
Definition: iotypes.h:1764
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define FILE_READ_ONLY_DEVICE
Definition: nt_native.h:808
VOID NTAPI PopFlushVolumeWorker(IN PVOID Context)
Definition: povolume.c:150
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14