Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpovolume.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/po/povolume.c 00005 * PURPOSE: Power Manager DOPE and Volume Management 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 /* GLOBALS *******************************************************************/ 00016 00017 typedef struct _POP_FLUSH_VOLUME 00018 { 00019 LIST_ENTRY List; 00020 LONG Count; 00021 KEVENT Wait; 00022 } POP_FLUSH_VOLUME, *PPOP_FLUSH_VOLUME; 00023 00024 ULONG PopFlushPolicy = 0; 00025 00026 KGUARDED_MUTEX PopVolumeLock; 00027 LIST_ENTRY PopVolumeDevices; 00028 KSPIN_LOCK PopDopeGlobalLock; 00029 00030 /* PRIVATE FUNCTIONS *********************************************************/ 00031 00032 PDEVICE_OBJECT_POWER_EXTENSION 00033 NTAPI 00034 PopGetDope(IN PDEVICE_OBJECT DeviceObject) 00035 { 00036 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension; 00037 PDEVICE_OBJECT_POWER_EXTENSION Dope; 00038 KIRQL OldIrql; 00039 PAGED_CODE(); 00040 00041 /* If the device already has the dope, return it */ 00042 DeviceExtension = IoGetDevObjExtension(DeviceObject); 00043 if (DeviceExtension->Dope) goto Return; 00044 00045 /* Allocate some dope for the device */ 00046 Dope = ExAllocatePoolWithTag(NonPagedPool, 00047 sizeof(DEVICE_OBJECT_POWER_EXTENSION), 00048 'Dope'); 00049 if (!Dope) goto Return; 00050 00051 /* Initialize the initial contents of the dope */ 00052 RtlZeroMemory(Dope, sizeof(DEVICE_OBJECT_POWER_EXTENSION)); 00053 Dope->DeviceObject = DeviceObject; 00054 Dope->State = PowerDeviceUnspecified; 00055 InitializeListHead(&Dope->IdleList); 00056 00057 /* Make sure only one caller can assign dope to a device */ 00058 KeAcquireSpinLock(&PopDopeGlobalLock, &OldIrql); 00059 00060 /* Make sure the device still has no dope */ 00061 if (!DeviceExtension->Dope) 00062 { 00063 /* Give the local dope to this device, and remember we won the race */ 00064 DeviceExtension->Dope = (PVOID)Dope; 00065 Dope = NULL; 00066 } 00067 00068 /* Allow other dope transactions now */ 00069 KeReleaseSpinLock(&PopDopeGlobalLock, OldIrql); 00070 00071 /* Check if someone other than us already assigned the dope, so free ours */ 00072 if (Dope) ExFreePoolWithTag(Dope, 'Dope'); 00073 00074 /* Return the dope to the caller */ 00075 Return: 00076 return (PDEVICE_OBJECT_POWER_EXTENSION)DeviceExtension->Dope; 00077 } 00078 00079 VOID 00080 NTAPI 00081 PoVolumeDevice(IN PDEVICE_OBJECT DeviceObject) 00082 { 00083 PDEVICE_OBJECT_POWER_EXTENSION Dope; 00084 PAGED_CODE(); 00085 00086 /* Get dope from the device (if the device has no dope, it will receive some) */ 00087 Dope = PopGetDope(DeviceObject); 00088 if (Dope) 00089 { 00090 /* Make sure we can flush safely */ 00091 KeAcquireGuardedMutex(&PopVolumeLock); 00092 00093 /* Add this volume into the list of power-manager volumes */ 00094 if (!Dope->Volume.Flink) InsertTailList(&PopVolumeDevices, &Dope->Volume); 00095 00096 /* Allow flushes to go through */ 00097 KeReleaseGuardedMutex(&PopVolumeLock); 00098 } 00099 } 00100 00101 VOID 00102 NTAPI 00103 PopFlushVolumeWorker(IN PVOID Context) 00104 { 00105 PPOP_FLUSH_VOLUME FlushContext = (PPOP_FLUSH_VOLUME)Context; 00106 PDEVICE_OBJECT_POWER_EXTENSION Dope; 00107 PLIST_ENTRY NextEntry; 00108 NTSTATUS Status; 00109 UCHAR Buffer[sizeof(OBJECT_NAME_INFORMATION) + 512]; 00110 POBJECT_NAME_INFORMATION NameInfo = (PVOID)Buffer; 00111 ULONG Length; 00112 OBJECT_ATTRIBUTES ObjectAttributes; 00113 HANDLE VolumeHandle; 00114 IO_STATUS_BLOCK IoStatusBlock; 00115 00116 /* Acquire the flush lock since we're messing with the list */ 00117 KeAcquireGuardedMutex(&PopVolumeLock); 00118 00119 /* Loop the flush list */ 00120 while (!IsListEmpty(&FlushContext->List)) 00121 { 00122 /* Grab the next (ie: current) entry and remove it */ 00123 NextEntry = FlushContext->List.Flink; 00124 RemoveEntryList(NextEntry); 00125 00126 /* Add it back on the volume list */ 00127 InsertTailList(&PopVolumeDevices, NextEntry); 00128 00129 /* Done touching the volume list */ 00130 KeReleaseGuardedMutex(&PopVolumeLock); 00131 00132 /* Get the dope from the volume link */ 00133 Dope = CONTAINING_RECORD(NextEntry, DEVICE_OBJECT_POWER_EXTENSION, Volume); 00134 00135 /* Get the name */ 00136 Status = ObQueryNameString(Dope->DeviceObject, 00137 NameInfo, 00138 sizeof(Buffer), 00139 &Length); 00140 if ((NT_SUCCESS(Status)) && (NameInfo->Name.Buffer)) 00141 { 00142 /* Open the volume */ 00143 DPRINT1("Opening: %wZ\n", &NameInfo->Name); 00144 InitializeObjectAttributes(&ObjectAttributes, 00145 &NameInfo->Name, 00146 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00147 0, 00148 0); 00149 Status = ZwCreateFile(&VolumeHandle, 00150 SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, 00151 &ObjectAttributes, 00152 &IoStatusBlock, 00153 NULL, 00154 GENERIC_READ | GENERIC_WRITE, 00155 FILE_SHARE_READ | FILE_SHARE_WRITE, 00156 FILE_OPEN, 00157 0, 00158 NULL, 00159 0); 00160 if (NT_SUCCESS(Status)) 00161 { 00162 /* Flush it and close it */ 00163 DPRINT1("Sending flush to: %lx\n", VolumeHandle); 00164 ZwFlushBuffersFile(VolumeHandle, &IoStatusBlock); 00165 ZwClose(VolumeHandle); 00166 } 00167 } 00168 00169 /* Acquire the flush lock again since we'll touch the list */ 00170 KeAcquireGuardedMutex(&PopVolumeLock); 00171 } 00172 00173 /* One more flush completed... if it was the last, signal the caller */ 00174 if (!--FlushContext->Count) KeSetEvent(&FlushContext->Wait, IO_NO_INCREMENT, FALSE); 00175 00176 /* Serialize with flushers */ 00177 KeReleaseGuardedMutex(&PopVolumeLock); 00178 } 00179 00180 VOID 00181 NTAPI 00182 PopFlushVolumes(IN BOOLEAN ShuttingDown) 00183 { 00184 POP_FLUSH_VOLUME FlushContext = {{0}}; 00185 ULONG FlushPolicy; 00186 UNICODE_STRING RegistryName = RTL_CONSTANT_STRING(L"\\Registry"); 00187 OBJECT_ATTRIBUTES ObjectAttributes; 00188 HANDLE RegistryHandle; 00189 PLIST_ENTRY NextEntry; 00190 PDEVICE_OBJECT_POWER_EXTENSION Dope; 00191 ULONG VolumeCount = 0; 00192 NTSTATUS Status; 00193 HANDLE ThreadHandle; 00194 ULONG ThreadCount; 00195 00196 /* Setup the flush context */ 00197 InitializeListHead(&FlushContext.List); 00198 KeInitializeEvent(&FlushContext.Wait, NotificationEvent, FALSE); 00199 00200 /* What to flush */ 00201 FlushPolicy = ShuttingDown ? 1 | 2 : PopFlushPolicy; 00202 if ((FlushPolicy & 1)) 00203 { 00204 /* Registry flush requested, so open it */ 00205 DPRINT1("Opening registry\n"); 00206 InitializeObjectAttributes(&ObjectAttributes, 00207 &RegistryName, 00208 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00209 NULL, 00210 NULL); 00211 Status = ZwOpenKey(&RegistryHandle, KEY_READ, &ObjectAttributes); 00212 if (NT_SUCCESS(Status)) 00213 { 00214 /* Flush the registry */ 00215 DPRINT1("Flushing registry\n"); 00216 ZwFlushKey(RegistryHandle); 00217 ZwClose(RegistryHandle); 00218 } 00219 } 00220 00221 /* Serialize with other flushes */ 00222 KeAcquireGuardedMutex(&PopVolumeLock); 00223 00224 /* Scan the volume list */ 00225 NextEntry = PopVolumeDevices.Flink; 00226 while (NextEntry != &PopVolumeDevices) 00227 { 00228 /* Get the dope from the link */ 00229 Dope = CONTAINING_RECORD(NextEntry, DEVICE_OBJECT_POWER_EXTENSION, Volume); 00230 00231 /* Grab the next entry now, since we'll be modifying the list */ 00232 NextEntry = NextEntry->Flink; 00233 00234 /* Make sure the object is mounted, writable, exists, and is not a floppy */ 00235 if (!(Dope->DeviceObject->Vpb->Flags & VPB_MOUNTED) || 00236 (Dope->DeviceObject->Characteristics & FILE_FLOPPY_DISKETTE) || 00237 (Dope->DeviceObject->Characteristics & FILE_READ_ONLY_DEVICE) || 00238 ((Dope->DeviceObject->Vpb->RealDevice) && 00239 (Dope->DeviceObject->Vpb->RealDevice->Characteristics & FILE_FLOPPY_DISKETTE))) 00240 { 00241 /* Not flushable */ 00242 continue; 00243 } 00244 00245 /* Remove it from the dope and add it to the flush context list */ 00246 RemoveEntryList(&Dope->Volume); 00247 InsertTailList(&FlushContext.List, &Dope->Volume); 00248 00249 /* Next */ 00250 VolumeCount++; 00251 } 00252 00253 /* Check if we should skip non-removable devices */ 00254 if (!(FlushPolicy & 2)) 00255 { 00256 /* ReactOS only implements this routine for shutdown, which requires it */ 00257 UNIMPLEMENTED; 00258 while (TRUE); 00259 } 00260 00261 /* Check if there were no volumes at all */ 00262 if (!VolumeCount) 00263 { 00264 /* Nothing to do */ 00265 KeReleaseGuardedMutex(&PopVolumeLock); 00266 return; 00267 } 00268 00269 /* Allocate up to 8 flusher threads */ 00270 ThreadCount = min(VolumeCount, 8); 00271 InitializeObjectAttributes(&ObjectAttributes, 00272 NULL, 00273 OBJ_KERNEL_HANDLE, 00274 NULL, 00275 NULL); 00276 00277 /* We will ourselves become a flusher thread */ 00278 FlushContext.Count = 1; 00279 ThreadCount--; 00280 00281 /* Look for any extra ones we might need */ 00282 while (ThreadCount > 0) 00283 { 00284 /* Create a new one */ 00285 ThreadCount--; 00286 DPRINT1("Creating flush thread\n"); 00287 Status = PsCreateSystemThread(&ThreadHandle, 00288 THREAD_ALL_ACCESS, 00289 &ObjectAttributes, 00290 0L, 00291 NULL, 00292 PopFlushVolumeWorker, 00293 &FlushContext); 00294 if (NT_SUCCESS(Status)) 00295 { 00296 /* One more created... */ 00297 FlushContext.Count++; 00298 ZwClose(ThreadHandle); 00299 } 00300 } 00301 00302 /* Allow flushes to go through */ 00303 KeReleaseGuardedMutex(&PopVolumeLock); 00304 00305 /* Enter the flush work */ 00306 DPRINT1("Local flush\n"); 00307 PopFlushVolumeWorker(&FlushContext); 00308 00309 /* Wait for all flushes to be over */ 00310 DPRINT1("Waiting for flushes\n"); 00311 KeWaitForSingleObject(&FlushContext.Wait, Executive, KernelMode, FALSE, NULL); 00312 DPRINT1("Flushes have completed\n"); 00313 } 00314 00315 VOID 00316 NTAPI 00317 PoInitializeDeviceObject(IN OUT PDEVOBJ_EXTENSION DeviceObjectExtension) 00318 { 00319 PEXTENDED_DEVOBJ_EXTENSION DeviceExtension = (PVOID)DeviceObjectExtension; 00320 PAGED_CODE(); 00321 00322 /* Initialize the power flags */ 00323 DeviceExtension->PowerFlags = PowerSystemUnspecified & 0xF; 00324 DeviceExtension->PowerFlags |= ((PowerDeviceUnspecified << 4) & 0xF0); 00325 00326 /* The device object is not on drugs yet */ 00327 DeviceExtension->Dope = NULL; 00328 } 00329 00330 /* PUBLIC FUNCTIONS **********************************************************/ 00331 Generated on Sun May 27 2012 04:37:40 for ReactOS by
1.7.6.1
|