2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/io/iomgr/iomgr.c
5 * PURPOSE: I/O Manager Initialization and Misc Utility Functions
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
10 /* INCLUDES ****************************************************************/
16 ULONG IopTraceLevel
= 0;
17 BOOLEAN PnpSystemInit
= FALSE
;
23 IN PVOID DeferredContext
,
24 IN PVOID SystemArgument1
,
25 IN PVOID SystemArgument2
33 /* DATA ********************************************************************/
35 POBJECT_TYPE IoDeviceObjectType
= NULL
;
36 POBJECT_TYPE IoFileObjectType
= NULL
;
37 extern POBJECT_TYPE IoControllerObjectType
;
38 BOOLEAN IoCountOperations
= TRUE
;
39 ULONG IoReadOperationCount
= 0;
40 LARGE_INTEGER IoReadTransferCount
= {{0, 0}};
41 ULONG IoWriteOperationCount
= 0;
42 LARGE_INTEGER IoWriteTransferCount
= {{0, 0}};
43 ULONG IoOtherOperationCount
= 0;
44 LARGE_INTEGER IoOtherTransferCount
= {{0, 0}};
45 KSPIN_LOCK IoStatisticsLock
= 0;
46 ULONG IopNumTriageDumpDataBlocks
;
47 PVOID IopTriageDumpDataBlocks
[64];
49 GENERIC_MAPPING IopFileMapping
= {
55 extern LIST_ENTRY ShutdownListHead
;
56 extern LIST_ENTRY LastChanceShutdownListHead
;
57 extern KSPIN_LOCK ShutdownListLock
;
58 extern POBJECT_TYPE IoAdapterObjectType
;
59 extern ERESOURCE IopDatabaseResource
;
60 ERESOURCE IopSecurityResource
;
61 extern ERESOURCE IopDriverLoadResource
;
62 extern LIST_ENTRY IopDiskFileSystemQueueHead
;
63 extern LIST_ENTRY IopCdRomFileSystemQueueHead
;
64 extern LIST_ENTRY IopTapeFileSystemQueueHead
;
65 extern LIST_ENTRY IopNetworkFileSystemQueueHead
;
66 extern LIST_ENTRY DriverBootReinitListHead
;
67 extern LIST_ENTRY DriverReinitListHead
;
68 extern LIST_ENTRY IopFsNotifyChangeQueueHead
;
69 extern LIST_ENTRY IopErrorLogListHead
;
70 extern LIST_ENTRY IopTimerQueueHead
;
71 extern KDPC IopTimerDpc
;
72 extern KTIMER IopTimer
;
73 extern KSPIN_LOCK IoStatisticsLock
;
74 extern KSPIN_LOCK DriverReinitListLock
;
75 extern KSPIN_LOCK DriverBootReinitListLock
;
76 extern KSPIN_LOCK IopLogListLock
;
77 extern KSPIN_LOCK IopTimerLock
;
79 extern PDEVICE_OBJECT IopErrorLogObject
;
80 extern BOOLEAN PnPBootDriversInitialized
;
82 GENERAL_LOOKASIDE IoLargeIrpLookaside
;
83 GENERAL_LOOKASIDE IoSmallIrpLookaside
;
84 GENERAL_LOOKASIDE IopMdlLookasideList
;
85 extern GENERAL_LOOKASIDE IoCompletionPacketLookaside
;
87 PLOADER_PARAMETER_BLOCK IopLoaderBlock
;
89 /* INIT FUNCTIONS ************************************************************/
94 IopInitLookasideLists(VOID
)
96 ULONG LargeIrpSize
, SmallIrpSize
, MdlSize
;
99 PGENERAL_LOOKASIDE CurrentList
= NULL
;
101 /* Calculate the sizes */
102 LargeIrpSize
= sizeof(IRP
) + (8 * sizeof(IO_STACK_LOCATION
));
103 SmallIrpSize
= sizeof(IRP
) + sizeof(IO_STACK_LOCATION
);
104 MdlSize
= sizeof(MDL
) + (23 * sizeof(PFN_NUMBER
));
106 /* Initialize the Lookaside List for I\O Completion */
107 ExInitializeSystemLookasideList(&IoCompletionPacketLookaside
,
109 sizeof(IOP_MINI_COMPLETION_PACKET
),
112 &ExSystemLookasideListHead
);
114 /* Initialize the Lookaside List for Large IRPs */
115 ExInitializeSystemLookasideList(&IoLargeIrpLookaside
,
120 &ExSystemLookasideListHead
);
123 /* Initialize the Lookaside List for Small IRPs */
124 ExInitializeSystemLookasideList(&IoSmallIrpLookaside
,
129 &ExSystemLookasideListHead
);
131 /* Initialize the Lookaside List for MDLs */
132 ExInitializeSystemLookasideList(&IopMdlLookasideList
,
137 &ExSystemLookasideListHead
);
139 /* Allocate the global lookaside list buffer */
140 CurrentList
= ExAllocatePoolWithTag(NonPagedPool
,
141 4 * KeNumberProcessors
*
142 sizeof(GENERAL_LOOKASIDE
),
145 /* Loop all processors */
146 for (i
= 0; i
< KeNumberProcessors
; i
++)
148 /* Get the PRCB for this CPU */
149 Prcb
= KiProcessorBlock
[i
];
150 DPRINT("Setting up lookaside for CPU: %x, PRCB: %p\n", i
, Prcb
);
152 /* Write IRP credit limit */
153 Prcb
->LookasideIrpFloat
= 512 / KeNumberProcessors
;
155 /* Set the I/O Completion List */
156 Prcb
->PPLookasideList
[LookasideCompletionList
].L
= &IoCompletionPacketLookaside
;
159 /* Initialize the Lookaside List for mini-packets */
160 ExInitializeSystemLookasideList(CurrentList
,
162 sizeof(IOP_MINI_COMPLETION_PACKET
),
165 &ExSystemLookasideListHead
);
166 Prcb
->PPLookasideList
[LookasideCompletionList
].P
= CurrentList
;
172 Prcb
->PPLookasideList
[LookasideCompletionList
].P
= &IoCompletionPacketLookaside
;
175 /* Set the Large IRP List */
176 Prcb
->PPLookasideList
[LookasideLargeIrpList
].L
= &IoLargeIrpLookaside
;
179 /* Initialize the Lookaside List for Large IRPs */
180 ExInitializeSystemLookasideList(CurrentList
,
185 &ExSystemLookasideListHead
);
186 Prcb
->PPLookasideList
[LookasideLargeIrpList
].P
= CurrentList
;
192 Prcb
->PPLookasideList
[LookasideLargeIrpList
].P
= &IoLargeIrpLookaside
;
195 /* Set the Small IRP List */
196 Prcb
->PPLookasideList
[LookasideSmallIrpList
].L
= &IoSmallIrpLookaside
;
199 /* Initialize the Lookaside List for Small IRPs */
200 ExInitializeSystemLookasideList(CurrentList
,
205 &ExSystemLookasideListHead
);
206 Prcb
->PPLookasideList
[LookasideSmallIrpList
].P
= CurrentList
;
212 Prcb
->PPLookasideList
[LookasideSmallIrpList
].P
= &IoSmallIrpLookaside
;
215 /* Set the MDL Completion List */
216 Prcb
->PPLookasideList
[LookasideMdlList
].L
= &IopMdlLookasideList
;
219 /* Initialize the Lookaside List for MDLs */
220 ExInitializeSystemLookasideList(CurrentList
,
225 &ExSystemLookasideListHead
);
227 Prcb
->PPLookasideList
[LookasideMdlList
].P
= CurrentList
;
233 Prcb
->PPLookasideList
[LookasideMdlList
].P
= &IopMdlLookasideList
;
241 IopCreateObjectTypes(VOID
)
243 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
246 /* Initialize default settings */
247 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
248 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
249 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
250 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
251 ObjectTypeInitializer
.ValidAccessMask
= FILE_ALL_ACCESS
;
252 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
253 ObjectTypeInitializer
.GenericMapping
= IopFileMapping
;
255 /* Do the Adapter Type */
256 RtlInitUnicodeString(&Name
, L
"Adapter");
257 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
258 &ObjectTypeInitializer
,
260 &IoAdapterObjectType
))) return FALSE
;
262 /* Do the Controller Type */
263 RtlInitUnicodeString(&Name
, L
"Controller");
264 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(CONTROLLER_OBJECT
);
265 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
266 &ObjectTypeInitializer
,
268 &IoControllerObjectType
))) return FALSE
;
270 /* Do the Device Type */
271 RtlInitUnicodeString(&Name
, L
"Device");
272 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(DEVICE_OBJECT
);
273 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteDevice
;
274 ObjectTypeInitializer
.ParseProcedure
= IopParseDevice
;
275 ObjectTypeInitializer
.SecurityProcedure
= IopGetSetSecurityObject
;
276 ObjectTypeInitializer
.CaseInsensitive
= TRUE
;
277 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
278 &ObjectTypeInitializer
,
280 &IoDeviceObjectType
))) return FALSE
;
282 /* Initialize the Driver object type */
283 RtlInitUnicodeString(&Name
, L
"Driver");
284 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(DRIVER_OBJECT
);
285 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteDriver
;
286 ObjectTypeInitializer
.ParseProcedure
= NULL
;
287 ObjectTypeInitializer
.SecurityProcedure
= NULL
;
288 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
289 &ObjectTypeInitializer
,
291 &IoDriverObjectType
))) return FALSE
;
293 /* Initialize the I/O Completion object type */
294 RtlInitUnicodeString(&Name
, L
"IoCompletion");
295 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(KQUEUE
);
296 ObjectTypeInitializer
.ValidAccessMask
= IO_COMPLETION_ALL_ACCESS
;
297 ObjectTypeInitializer
.InvalidAttributes
|= OBJ_PERMANENT
;
298 ObjectTypeInitializer
.GenericMapping
= IopCompletionMapping
;
299 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteIoCompletion
;
300 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
301 &ObjectTypeInitializer
,
303 &IoCompletionType
))) return FALSE
;
305 /* Initialize the File object type */
306 RtlInitUnicodeString(&Name
, L
"File");
307 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(FILE_OBJECT
);
308 ObjectTypeInitializer
.InvalidAttributes
|= OBJ_EXCLUSIVE
;
309 ObjectTypeInitializer
.MaintainHandleCount
= TRUE
;
310 ObjectTypeInitializer
.ValidAccessMask
= FILE_ALL_ACCESS
;
311 ObjectTypeInitializer
.GenericMapping
= IopFileMapping
;
312 ObjectTypeInitializer
.CloseProcedure
= IopCloseFile
;
313 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteFile
;
314 ObjectTypeInitializer
.SecurityProcedure
= IopGetSetSecurityObject
;
315 ObjectTypeInitializer
.QueryNameProcedure
= IopQueryName
;
316 ObjectTypeInitializer
.ParseProcedure
= IopParseFile
;
317 ObjectTypeInitializer
.UseDefaultObject
= FALSE
;
318 if (!NT_SUCCESS(ObCreateObjectType(&Name
,
319 &ObjectTypeInitializer
,
321 &IoFileObjectType
))) return FALSE
;
330 IopCreateRootDirectories(VOID
)
332 OBJECT_ATTRIBUTES ObjectAttributes
;
333 UNICODE_STRING DirName
;
337 /* Create the '\Driver' object directory */
338 RtlInitUnicodeString(&DirName
, L
"\\Driver");
339 InitializeObjectAttributes(&ObjectAttributes
,
344 Status
= NtCreateDirectoryObject(&Handle
,
345 DIRECTORY_ALL_ACCESS
,
347 if (!NT_SUCCESS(Status
))
349 DPRINT1("Failed to create \\Driver directory: 0x%lx\n", Status
);
354 /* Create the '\FileSystem' object directory */
355 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
356 InitializeObjectAttributes(&ObjectAttributes
,
361 Status
= NtCreateDirectoryObject(&Handle
,
362 DIRECTORY_ALL_ACCESS
,
364 if (!NT_SUCCESS(Status
))
366 DPRINT1("Failed to create \\FileSystem directory: 0x%lx\n", Status
);
371 /* Create the '\FileSystem' object directory */
372 RtlInitUnicodeString(&DirName
, L
"\\FileSystem\\Filters");
373 InitializeObjectAttributes(&ObjectAttributes
,
378 Status
= NtCreateDirectoryObject(&Handle
,
379 DIRECTORY_ALL_ACCESS
,
381 if (!NT_SUCCESS(Status
))
383 DPRINT1("Failed to create \\FileSystem\\Filters directory: 0x%lx\n", Status
);
395 IopMarkBootPartition(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
397 OBJECT_ATTRIBUTES ObjectAttributes
;
400 UNICODE_STRING DeviceName
;
403 IO_STATUS_BLOCK IoStatusBlock
;
404 PFILE_OBJECT FileObject
;
406 /* Build the ARC device name */
407 sprintf(Buffer
, "\\ArcName\\%s", LoaderBlock
->ArcBootDeviceName
);
408 RtlInitAnsiString(&DeviceString
, Buffer
);
409 Status
= RtlAnsiStringToUnicodeString(&DeviceName
, &DeviceString
, TRUE
);
410 if (!NT_SUCCESS(Status
)) return FALSE
;
413 InitializeObjectAttributes(&ObjectAttributes
,
415 OBJ_CASE_INSENSITIVE
,
418 Status
= ZwOpenFile(&FileHandle
,
419 FILE_READ_ATTRIBUTES
,
423 FILE_NON_DIRECTORY_FILE
);
424 if (!NT_SUCCESS(Status
))
427 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE
,
428 (ULONG_PTR
)&DeviceName
,
435 Status
= ObReferenceObjectByHandle(FileHandle
,
439 (PVOID
*)&FileObject
,
441 if (!NT_SUCCESS(Status
))
444 RtlFreeUnicodeString(&DeviceName
);
448 /* Mark it as the boot partition */
449 FileObject
->DeviceObject
->Flags
|= DO_SYSTEM_BOOT_PARTITION
;
451 /* Save a copy of the DO for the I/O Error Logger */
452 ObReferenceObject(FileObject
->DeviceObject
);
453 IopErrorLogObject
= FileObject
->DeviceObject
;
455 /* Cleanup and return success */
456 RtlFreeUnicodeString(&DeviceName
);
458 ObDereferenceObject(FileObject
);
465 IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
467 LARGE_INTEGER ExpireTime
;
470 ANSI_STRING NtBootPath
, RootString
;
472 /* Initialize empty NT Boot Path */
473 RtlInitEmptyAnsiString(&NtBootPath
, Buffer
, sizeof(Buffer
));
475 /* Initialize the lookaside lists */
476 IopInitLookasideLists();
478 /* Initialize all locks and lists */
479 ExInitializeResourceLite(&IopDatabaseResource
);
480 ExInitializeResourceLite(&IopSecurityResource
);
481 ExInitializeResourceLite(&IopDriverLoadResource
);
482 InitializeListHead(&IopDiskFileSystemQueueHead
);
483 InitializeListHead(&IopCdRomFileSystemQueueHead
);
484 InitializeListHead(&IopTapeFileSystemQueueHead
);
485 InitializeListHead(&IopNetworkFileSystemQueueHead
);
486 InitializeListHead(&DriverBootReinitListHead
);
487 InitializeListHead(&DriverReinitListHead
);
488 InitializeListHead(&ShutdownListHead
);
489 InitializeListHead(&LastChanceShutdownListHead
);
490 InitializeListHead(&IopFsNotifyChangeQueueHead
);
491 InitializeListHead(&IopErrorLogListHead
);
492 KeInitializeSpinLock(&IoStatisticsLock
);
493 KeInitializeSpinLock(&DriverReinitListLock
);
494 KeInitializeSpinLock(&DriverBootReinitListLock
);
495 KeInitializeSpinLock(&ShutdownListLock
);
496 KeInitializeSpinLock(&IopLogListLock
);
498 /* Initialize PnP notifications */
499 PiInitializeNotifications();
501 /* Initialize the reserve IRP */
502 if (!IopInitializeReserveIrp(&IopReserveIrpAllocator
))
504 DPRINT1("IopInitializeReserveIrp failed!\n");
508 /* Initialize Timer List Lock */
509 KeInitializeSpinLock(&IopTimerLock
);
511 /* Initialize Timer List */
512 InitializeListHead(&IopTimerQueueHead
);
514 /* Initialize the DPC/Timer which will call the other Timer Routines */
515 ExpireTime
.QuadPart
= -10000000;
516 KeInitializeDpc(&IopTimerDpc
, IopTimerDispatch
, NULL
);
517 KeInitializeTimerEx(&IopTimer
, SynchronizationTimer
);
518 KeSetTimerEx(&IopTimer
, ExpireTime
, 1000, &IopTimerDpc
);
520 /* Create Object Types */
521 if (!IopCreateObjectTypes())
523 DPRINT1("IopCreateObjectTypes failed!\n");
527 /* Create Object Directories */
528 if (!IopCreateRootDirectories())
530 DPRINT1("IopCreateRootDirectories failed!\n");
534 /* Initialize PnP manager */
535 IopInitializePlugPlayServices();
537 /* Initialize SHIM engine */
538 ApphelpCacheInitialize();
543 /* Initialize HAL Root Bus Driver */
546 /* Reenumerate what HAL has added (synchronously)
547 * This function call should eventually become a 2nd stage of the PnP initialization */
548 PiQueueDeviceAction(IopRootDeviceNode
->PhysicalDeviceObject
,
549 PiActionEnumRootDevices
,
553 /* Make loader block available for the whole kernel */
554 IopLoaderBlock
= LoaderBlock
;
556 /* Load boot start drivers */
557 IopInitializeBootDrivers();
559 /* Call back drivers that asked for */
560 IopReinitializeBootDrivers();
562 /* Check if this was a ramdisk boot */
563 if (!_strnicmp(LoaderBlock
->ArcBootDeviceName
, "ramdisk(0)", 10))
565 /* Initialize the ramdisk driver */
566 IopStartRamdisk(LoaderBlock
);
569 /* No one should need loader block any longer */
570 IopLoaderBlock
= NULL
;
572 /* Create ARC names for boot devices */
573 Status
= IopCreateArcNames(LoaderBlock
);
574 if (!NT_SUCCESS(Status
))
576 DPRINT1("IopCreateArcNames failed: %lx\n", Status
);
580 /* Mark the system boot partition */
581 if (!IopMarkBootPartition(LoaderBlock
))
583 DPRINT1("IopMarkBootPartition failed!\n");
587 /* The disk subsystem is initialized here and the SystemRoot is set too.
588 * We can finally load other drivers from the boot volume. */
589 PnPBootDriversInitialized
= TRUE
;
591 /* Load system start drivers */
592 IopInitializeSystemDrivers();
593 PnpSystemInit
= TRUE
;
595 /* Reinitialize drivers that requested it */
596 IopReinitializeDrivers();
598 /* Convert SystemRoot from ARC to NT path */
599 Status
= IopReassignSystemRoot(LoaderBlock
, &NtBootPath
);
600 if (!NT_SUCCESS(Status
))
602 DPRINT1("IopReassignSystemRoot failed: %lx\n", Status
);
606 /* Set the ANSI_STRING for the root path */
607 RootString
.MaximumLength
= NtSystemRoot
.MaximumLength
/ sizeof(WCHAR
);
608 RootString
.Length
= 0;
609 RootString
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
610 RootString
.MaximumLength
,
613 /* Convert the path into the ANSI_STRING */
614 Status
= RtlUnicodeStringToAnsiString(&RootString
, &NtSystemRoot
, FALSE
);
615 if (!NT_SUCCESS(Status
))
617 DPRINT1("RtlUnicodeStringToAnsiString failed: %lx\n", Status
);
621 /* Assign drive letters */
622 IoAssignDriveLetters(LoaderBlock
,
624 (PUCHAR
)RootString
.Buffer
,
627 /* Update system root */
628 Status
= RtlAnsiStringToUnicodeString(&NtSystemRoot
, &RootString
, FALSE
);
629 if (!NT_SUCCESS(Status
))
631 DPRINT1("RtlAnsiStringToUnicodeString failed: %lx\n", Status
);
635 /* Load the System DLL and its entrypoints */
636 Status
= PsLocateSystemDll();
637 if (!NT_SUCCESS(Status
))
639 DPRINT1("PsLocateSystemDll failed: %lx\n", Status
);
649 IoInitializeCrashDump(IN HANDLE PageFileHandle
)