https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a3c58ca76f21f896df855…
commit a3c58ca76f21f896df8551df8b6175dccb3e4813
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sat Feb 24 14:50:23 2018 +0100
Commit: Pierre Schweitzer <pierre(a)reactos.org>
CommitDate: Sat Feb 24 14:52:04 2018 +0100
[NTOSKRNL] Implement the support for reserve IRP in IO
The reserve IRP is an IRP which is allocated on system boot and kept during
the whole system life. Its purpose is to allow page reads in case of
low-memory situations where the system doesn't have enough memory left
to allocate an IRP to read from the page file (would be catastrophic situation).
---
ntoskrnl/include/internal/io.h | 25 +++++++++++++
ntoskrnl/io/iomgr/iofunc.c | 28 ++++++++++++++-
ntoskrnl/io/iomgr/iomgr.c | 7 ++++
ntoskrnl/io/iomgr/irp.c | 79 +++++++++++++++++++++++++++++++++++++++++-
4 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/ntoskrnl/include/internal/io.h b/ntoskrnl/include/internal/io.h
index 2a4c62f42d..86ddbda17a 100644
--- a/ntoskrnl/include/internal/io.h
+++ b/ntoskrnl/include/internal/io.h
@@ -513,6 +513,18 @@ typedef struct _DEVICETREE_TRAVERSE_CONTEXT
PVOID Context;
} DEVICETREE_TRAVERSE_CONTEXT, *PDEVICETREE_TRAVERSE_CONTEXT;
+//
+// Reserve IRP allocator
+// Used for read paging IOs in low-memory situations
+//
+typedef struct _RESERVE_IRP_ALLOCATOR
+{
+ PIRP ReserveIrp;
+ volatile LONG ReserveIrpInUse;
+ KEVENT WaitEvent;
+ CCHAR StackSize;
+} RESERVE_IRP_ALLOCATOR, *PRESERVE_IRP_ALLOCATOR;
+
//
// Resource code
//
@@ -920,6 +932,18 @@ IopAllocateIrpMustSucceed(
IN CCHAR StackSize
);
+BOOLEAN
+NTAPI
+IopInitializeReserveIrp(
+ IN PRESERVE_IRP_ALLOCATOR ReserveIrpAllocator
+);
+
+PIRP
+NTAPI
+IopAllocateReserveIrp(
+ IN CCHAR StackSize
+);
+
//
// Shutdown routines
//
@@ -1317,6 +1341,7 @@ extern PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList;
extern PDRIVER_OBJECT IopRootDriverObject;
extern KSPIN_LOCK IopDeviceRelationsSpinLock;
extern LIST_ENTRY IopDeviceRelationsRequestList;
+extern RESERVE_IRP_ALLOCATOR IopReserveIrpAllocator;
//
// Inlined Functions
diff --git a/ntoskrnl/io/iomgr/iofunc.c b/ntoskrnl/io/iomgr/iofunc.c
index aa08bf7232..fa4886976d 100644
--- a/ntoskrnl/io/iomgr/iofunc.c
+++ b/ntoskrnl/io/iomgr/iofunc.c
@@ -17,6 +17,9 @@
#include <debug.h>
#include "internal/io_i.h"
+volatile LONG IoPageReadIrpAllocationFailure = 0;
+volatile LONG IoPageReadNonPagefileIrpAllocationFailure = 0;
+
/* PRIVATE FUNCTIONS *********************************************************/
VOID
@@ -1099,7 +1102,30 @@ IoPageRead(IN PFILE_OBJECT FileObject,
/* Allocate IRP */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
+ /* If allocation failed, try to see whether we can use
+ * the reserve IRP
+ */
+ if (Irp == NULL)
+ {
+ /* We will use it only for paging file */
+ if (MmIsFileObjectAPagingFile(FileObject))
+ {
+ InterlockedExchangeAdd(&IoPageReadIrpAllocationFailure, 1);
+ Irp = IopAllocateReserveIrp(DeviceObject->StackSize);
+ }
+ else
+ {
+ InterlockedExchangeAdd(&IoPageReadNonPagefileIrpAllocationFailure, 1);
+ }
+
+ /* If allocation failed (not a paging file or too big stack size)
+ * Fail for real
+ */
+ if (Irp == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
/* Get the Stack */
StackPtr = IoGetNextIrpStackLocation(Irp);
diff --git a/ntoskrnl/io/iomgr/iomgr.c b/ntoskrnl/io/iomgr/iomgr.c
index 0676e97464..47defcab70 100644
--- a/ntoskrnl/io/iomgr/iomgr.c
+++ b/ntoskrnl/io/iomgr/iomgr.c
@@ -502,6 +502,13 @@ IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
KeInitializeSpinLock(&ShutdownListLock);
KeInitializeSpinLock(&IopLogListLock);
+ /* Initialize the reserve IRP */
+ if (!IopInitializeReserveIrp(&IopReserveIrpAllocator))
+ {
+ DPRINT1("IopInitializeReserveIrp failed!\n");
+ return FALSE;
+ }
+
/* Initialize Timer List Lock */
KeInitializeSpinLock(&IopTimerLock);
diff --git a/ntoskrnl/io/iomgr/irp.c b/ntoskrnl/io/iomgr/irp.c
index 856aae2c2b..b1de62da03 100644
--- a/ntoskrnl/io/iomgr/irp.c
+++ b/ntoskrnl/io/iomgr/irp.c
@@ -6,6 +6,7 @@
* PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
* Gunnar Dalsnes
* Filip Navara (navaraf(a)reactos.org)
+ * Pierre Schweitzer (pierre(a)reactos.org)
*/
/* INCLUDES ****************************************************************/
@@ -15,6 +16,7 @@
#include <debug.h>
PIRP IopDeadIrp;
+RESERVE_IRP_ALLOCATOR IopReserveIrpAllocator;
/* PRIVATE FUNCTIONS ********************************************************/
@@ -542,6 +544,67 @@ IopCompleteRequest(IN PKAPC Apc,
}
}
+BOOLEAN
+NTAPI
+IopInitializeReserveIrp(IN PRESERVE_IRP_ALLOCATOR ReserveIrpAllocator)
+{
+ /* Our allocated stack size */
+ ReserveIrpAllocator->StackSize = 20;
+
+ /* Allocate the IRP now */
+ ReserveIrpAllocator->ReserveIrp = IoAllocateIrp(ReserveIrpAllocator->StackSize,
FALSE);
+ /* If we cannot, abort system boot */
+ if (ReserveIrpAllocator->ReserveIrp == NULL)
+ {
+ return FALSE;
+ }
+
+ /* It's not in use */
+ ReserveIrpAllocator->ReserveIrpInUse = 0;
+ /* And init the event */
+ KeInitializeEvent(&ReserveIrpAllocator->WaitEvent, SynchronizationEvent,
FALSE);
+
+ /* All good, keep booting */
+ return TRUE;
+}
+
+PIRP
+NTAPI
+IopAllocateReserveIrp(IN CCHAR StackSize)
+{
+ /* If we need a stack size higher than what was allocated, then fail */
+ if (StackSize > IopReserveIrpAllocator.StackSize)
+ {
+ return NULL;
+ }
+
+ /* Now, wait until the IRP becomes available and reserve it immediately */
+ while (InterlockedExchange(&IopReserveIrpAllocator.ReserveIrpInUse, 1) == 1)
+ {
+ KeWaitForSingleObject(&IopReserveIrpAllocator.WaitEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ }
+
+ /* It's ours! Initialize it */
+ IoInitializeIrp(IopReserveIrpAllocator.ReserveIrp, IoSizeOfIrp(StackSize),
StackSize);
+
+ /* And return it to the caller */
+ return IopReserveIrpAllocator.ReserveIrp;
+}
+
+VOID
+IopFreeReserveIrp(IN CCHAR PriorityBoost)
+{
+ /* Mark we don't use the IRP anymore */
+ InterlockedExchange(&IopReserveIrpAllocator.ReserveIrpInUse, 0);
+
+ /* And set the event if someone is waiting on the IRP */
+ KeSetEvent(&IopReserveIrpAllocator.WaitEvent, PriorityBoost, FALSE);
+}
+
/* FUNCTIONS *****************************************************************/
/*
@@ -1423,7 +1486,21 @@ IofCompleteRequest(IN PIRP Irp,
KeSetEvent(Irp->UserEvent, PriorityBoost, FALSE);
/* Free the IRP for a Paging I/O Only, Close is handled by us */
- if (Flags) IoFreeIrp(Irp);
+ if (Flags)
+ {
+ /* If we were using the reserve IRP, then call the appropriate
+ * free function (to make the IRP available again)
+ */
+ if (Irp == IopReserveIrpAllocator.ReserveIrp)
+ {
+ IopFreeReserveIrp(PriorityBoost);
+ }
+ /* Otherwise, free for real! */
+ else
+ {
+ IoFreeIrp(Irp);
+ }
+ }
}
else
{