ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

povolume.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.