:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / ntoskrnl / mm / pagefile.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * PROJECT:         ReactOS kernel
22  * FILE:            ntoskrnl/mm/pagefile.c
23  * PURPOSE:         Paging file functions
24  * PROGRAMMER:      David Welch (welch@mcmail.com)
25  * UPDATE HISTORY:
26  *                  Created 22/05/98
27  */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <internal/io.h>
33 #include <internal/mm.h>
34 #include <napi/core.h>
35 #include <internal/ps.h>
36
37 #define NDEBUG
38 #include <internal/debug.h>
39
40 /* TYPES *********************************************************************/
41
42 typedef struct _PAGINGFILE
43 {
44    LIST_ENTRY PagingFileListEntry;
45    PFILE_OBJECT FileObject;
46    LARGE_INTEGER MaximumSize;
47    LARGE_INTEGER CurrentSize;
48    ULONG FreePages;
49    ULONG UsedPages;
50    PULONG AllocMap;
51    KSPIN_LOCK AllocMapLock;
52    ULONG AllocMapSize;
53 } PAGINGFILE, *PPAGINGFILE;
54
55 /* GLOBALS *******************************************************************/
56
57 #define MAX_PAGING_FILES  (32)
58
59 /* List of paging files, both used and free */
60 static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
61
62 /* Lock for examining the list of paging files */
63 static KSPIN_LOCK PagingFileListLock;
64
65 /* Number of paging files */
66 static ULONG MiPagingFileCount;
67
68 /* Number of pages that are available for swapping */
69 static ULONG MiFreeSwapPages;
70
71 /* Number of pages that have been allocated for swapping */
72 static ULONG MiUsedSwapPages;
73
74 /* 
75  * Number of pages that have been reserved for swapping but not yet allocated 
76  */
77 static ULONG MiReservedSwapPages;
78
79 /* 
80  * Ratio between reserved and available swap pages, e.g. setting this to five
81  * forces one swap page to be available for every five swap pages that are
82  * reserved. Setting this to zero turns off commit checking altogether.
83  */
84 #define MM_PAGEFILE_COMMIT_RATIO      (1)
85
86 /*
87  * Number of pages that can be used for potentially swapable memory without
88  * pagefile space being reserved. The intention is that this allows smss
89  * to start up and create page files while ordinarily having a commit
90  * ratio of one.
91  */
92 #define MM_PAGEFILE_COMMIT_GRACE      (256)
93
94 static PVOID MmCoreDumpPageFrame;
95 static PULONG MmCoreDumpBlockMap;
96 static ULONG MmCoreDumpSize;
97 static PULONG MmCoreDumpBlockMap = NULL;
98 static MM_DUMP_POINTERS MmCoreDumpDeviceFuncs;
99 ULONG MmCoreDumpType;
100
101 /*
102  * Translate between a swap entry and a file and offset pair.
103  */
104 #define FILE_FROM_ENTRY(i) ((i) >> 24)
105 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
106 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
107
108 static BOOLEAN MmSwapSpaceMessage = FALSE;
109
110 /* FUNCTIONS *****************************************************************/
111
112 VOID
113 MmShowOutOfSpaceMessagePagingFile(VOID)
114 {
115   if (!MmSwapSpaceMessage)
116     {
117       DPRINT1("MM: Out of swap space.\n");
118       MmSwapSpaceMessage = TRUE;
119     }
120 }
121
122 NTSTATUS MmWriteToSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
123 {
124    ULONG i, offset;
125    LARGE_INTEGER file_offset;
126    IO_STATUS_BLOCK Iosb;
127    NTSTATUS Status;
128    KEVENT Event;
129    
130    if (SwapEntry == 0)
131      {
132         KeBugCheck(0);
133         return(STATUS_UNSUCCESSFUL);
134      }
135    
136    i = FILE_FROM_ENTRY(SwapEntry);
137    offset = OFFSET_FROM_ENTRY(SwapEntry);
138
139    if (i > MAX_PAGING_FILES)
140      {
141        DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
142        KeBugCheck(0);
143      }
144    if (PagingFileList[i]->FileObject == NULL ||
145        PagingFileList[i]->FileObject->DeviceObject == NULL)
146      {
147        DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
148        KeBugCheck(0);
149      }
150    
151    file_offset.QuadPart = offset * 4096;
152    KeInitializeEvent(&Event, NotificationEvent, FALSE);
153    Status = IoPageWrite(PagingFileList[i]->FileObject,
154                         Mdl,
155                         &file_offset,
156                         &Event,
157                         &Iosb);
158    if (Status == STATUS_PENDING)
159    {
160       KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
161       return(Iosb.Status);
162    }
163    return(Status);
164 }
165
166 NTSTATUS MmReadFromSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
167 {
168    ULONG i, offset;
169    LARGE_INTEGER file_offset;
170    IO_STATUS_BLOCK Iosb;
171    NTSTATUS Status;
172    KEVENT Event;
173    
174    if (SwapEntry == 0)
175      {
176         KeBugCheck(0);
177         return(STATUS_UNSUCCESSFUL);
178      }
179    
180    i = FILE_FROM_ENTRY(SwapEntry);
181    offset = OFFSET_FROM_ENTRY(SwapEntry);
182
183    if (i > MAX_PAGING_FILES)
184      {
185        DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
186        KeBugCheck(0);
187      }
188    if (PagingFileList[i]->FileObject == NULL ||
189        PagingFileList[i]->FileObject->DeviceObject == NULL)
190      {
191        DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
192        KeBugCheck(0);
193      }
194    
195    file_offset.QuadPart = offset * 4096;
196    KeInitializeEvent(&Event, NotificationEvent, FALSE);
197    Status = IoPageRead(PagingFileList[i]->FileObject,
198                        Mdl,
199                        &file_offset,
200                        &Event,
201                        &Iosb);
202    if (Status == STATUS_PENDING)
203    {
204       KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
205       return(Iosb.Status);
206    }
207    return(Status);
208 }
209
210 VOID 
211 MmInitPagingFile(VOID)
212 {
213    ULONG i;
214    
215    KeInitializeSpinLock(&PagingFileListLock);
216    
217    MiFreeSwapPages = 0;
218    MiUsedSwapPages = 0;
219    MiReservedSwapPages = 0;
220    
221    for (i = 0; i < MAX_PAGING_FILES; i++)
222      {
223         PagingFileList[i] = NULL;
224      }
225    MiPagingFileCount = 0;
226
227    /*
228     * Initialize the crash dump support.
229     */
230    MmCoreDumpPageFrame = MmAllocateSection(PAGE_SIZE);
231    if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
232      {
233        MmCoreDumpSize = MmStats.NrTotalPages * 4096 + 1024 * 1024;
234      }
235    else
236      {
237        MmCoreDumpSize = 1024 * 1024;
238      }
239 }
240
241 BOOLEAN
242 MmReserveSwapPages(ULONG Nr)
243 {
244    KIRQL oldIrql;
245    ULONG MiAvailSwapPages;
246    
247    KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
248    MiAvailSwapPages =
249      (MiFreeSwapPages * MM_PAGEFILE_COMMIT_RATIO) + MM_PAGEFILE_COMMIT_GRACE;
250    MiReservedSwapPages = MiReservedSwapPages + Nr;
251    if (MM_PAGEFILE_COMMIT_RATIO != 0 && MiAvailSwapPages < MiReservedSwapPages)
252      {
253        KeReleaseSpinLock(&PagingFileListLock, oldIrql);
254        return(FALSE);
255      }   
256    KeReleaseSpinLock(&PagingFileListLock, oldIrql);
257    return(TRUE);
258 }
259
260 VOID 
261 MmDereserveSwapPages(ULONG Nr)
262 {
263    KIRQL oldIrql;
264    
265    KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
266    MiReservedSwapPages = MiReservedSwapPages - Nr;
267    KeReleaseSpinLock(&PagingFileListLock, oldIrql);
268 }
269
270 static ULONG 
271 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
272 {
273    KIRQL oldIrql;
274    ULONG i, j;
275    
276    KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
277    
278    for (i = 0; i < PagingFile->AllocMapSize; i++)
279      {
280        for (j = 0; j < 32; j++)
281          {
282            if (!(PagingFile->AllocMap[i] & (1 << j)))
283              {
284                break;
285              }
286          }
287        if (j == 32)
288          {
289            continue;
290          }
291        PagingFile->AllocMap[i] |= (1 << j);
292        PagingFile->UsedPages++;
293        PagingFile->FreePages--;
294        KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
295        return((i * 32) + j);
296      }
297    
298    KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
299    return(0xFFFFFFFF);
300 }
301
302 VOID 
303 MmFreeSwapPage(SWAPENTRY Entry)
304 {
305    ULONG i;
306    ULONG off;
307    KIRQL oldIrql;
308    
309    i = FILE_FROM_ENTRY(Entry);
310    off = OFFSET_FROM_ENTRY(Entry);
311    
312    KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
313    if (PagingFileList[i] == NULL)
314      {
315        KeBugCheck(0);
316      }
317    KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock);
318    
319    PagingFileList[i]->AllocMap[off / 32] &= (~(1 << (off % 32)));
320    
321    PagingFileList[i]->FreePages++;
322    PagingFileList[i]->UsedPages--;
323    
324    MiFreeSwapPages++;
325    MiUsedSwapPages--;
326    
327    KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock);
328    KeReleaseSpinLock(&PagingFileListLock, oldIrql);
329 }
330
331 BOOLEAN
332 MmIsAvailableSwapPage(VOID)
333 {
334   return(MiFreeSwapPages > 0);
335 }
336
337 SWAPENTRY 
338 MmAllocSwapPage(VOID)
339 {
340    KIRQL oldIrql;
341    ULONG i;
342    ULONG off;
343    SWAPENTRY entry;   
344    
345    KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
346    
347    if (MiFreeSwapPages == 0)
348      {
349         KeReleaseSpinLock(&PagingFileListLock, oldIrql);        
350         return(0);
351      }
352    
353    for (i = 0; i < MAX_PAGING_FILES; i++)
354      {
355         if (PagingFileList[i] != NULL &&
356             PagingFileList[i]->FreePages >= 1)
357           {          
358              off = MiAllocPageFromPagingFile(PagingFileList[i]);
359              if (off == 0xFFFFFFFF)
360                {
361                   KeBugCheck(0);
362                   KeReleaseSpinLock(&PagingFileListLock, oldIrql);
363                   return(STATUS_UNSUCCESSFUL);
364                }
365              MiUsedSwapPages++;
366              MiFreeSwapPages--;
367              KeReleaseSpinLock(&PagingFileListLock, oldIrql);
368              
369              entry = ENTRY_FROM_FILE_OFFSET(i, off);
370              return(entry);
371           }
372      }
373    
374    KeReleaseSpinLock(&PagingFileListLock, oldIrql); 
375    KeBugCheck(0);
376    return(0);
377 }
378
379 NTSTATUS STDCALL 
380 MmDumpToPagingFile(ULONG BugCode,
381                    ULONG BugCodeParameter1,
382                    ULONG BugCodeParameter2,
383                    ULONG BugCodeParameter3,
384                    ULONG BugCodeParameter4,
385                    PKTRAP_FRAME TrapFrame)
386 {
387   PMM_CORE_DUMP_HEADER Headers;
388   PVOID Context;
389   NTSTATUS Status;
390   UCHAR MdlBase[sizeof(MDL) + sizeof(PVOID)];
391   PMDL Mdl = (PMDL)MdlBase;
392   PETHREAD Thread = PsGetCurrentThread();
393   ULONG StackSize;
394   PULONG MdlMap;
395   ULONG NextOffset = 0;
396   ULONG i;
397
398   if (MmCoreDumpBlockMap == NULL)
399     {
400       return(STATUS_UNSUCCESSFUL);
401     }
402
403   DbgPrint("MM: Dumping core");
404
405   /* Prepare the dump headers. */
406   Headers = (PMM_CORE_DUMP_HEADER)MmCoreDumpPageFrame;
407   Headers->Magic = MM_CORE_DUMP_HEADER_MAGIC;
408   Headers->Version = MM_CORE_DUMP_HEADER_VERSION;
409   Headers->Type = MmCoreDumpType;
410   if (TrapFrame != NULL)
411     {
412       if (!(TrapFrame->Eflags & (1 << 17)))
413         {
414           memcpy(&Headers->TrapFrame, TrapFrame, 
415                  sizeof(KTRAP_FRAME) - (4 * sizeof(DWORD)));
416         }
417       else
418         {
419           memcpy(&Headers->TrapFrame, TrapFrame, sizeof(KTRAP_FRAME));
420         }
421     }
422   Headers->BugCheckCode = BugCode;
423   Headers->BugCheckParameters[0] = BugCodeParameter1;
424   Headers->BugCheckParameters[1] = BugCodeParameter2;
425   Headers->BugCheckParameters[2] = BugCodeParameter3;
426   Headers->BugCheckParameters[3] = BugCodeParameter4;
427   Headers->FaultingStackBase = (PVOID)Thread->Tcb.StackLimit;
428   Headers->FaultingStackSize = StackSize =
429     (ULONG)(Thread->Tcb.StackBase - Thread->Tcb.StackLimit);
430   Headers->PhysicalMemorySize = MmStats.NrTotalPages * PAGE_SIZE;
431
432   /* Initialize the dump device. */
433   Context = MmCoreDumpDeviceFuncs.Context;
434   Status = MmCoreDumpDeviceFuncs.DeviceInit(Context);
435   if (!NT_SUCCESS(Status))
436     {
437       DPRINT1("MM: Failed to initialize core dump device.\n");
438       return(Status);
439     }
440
441   /* Initialize the MDL. */
442   Mdl->Next = NULL;
443   Mdl->Size = sizeof(MDL) + sizeof(PVOID);
444   Mdl->MdlFlags = MDL_SOURCE_IS_NONPAGED_POOL;
445   Mdl->Process = NULL;
446   Mdl->MappedSystemVa = MmCoreDumpPageFrame;
447   Mdl->StartVa = NULL;
448   Mdl->ByteCount = PAGE_SIZE;
449   Mdl->ByteOffset = 0;
450   MdlMap = (PULONG)(Mdl + 1);
451
452   /* Dump the header. */
453   MdlMap[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame).u.LowPart;
454   Status = MmCoreDumpDeviceFuncs.DeviceWrite(Context, 
455                                              MmCoreDumpBlockMap[NextOffset], 
456                                              Mdl);
457   if (!NT_SUCCESS(Status))
458     {
459       DPRINT1("MM: Failed to write core dump header\n.");
460     }
461   NextOffset++;
462   DbgPrint(".");
463
464   /* Write out the kernel mode stack of the faulting thread. */
465   for (i = 0; i < (StackSize / PAGE_SIZE); i++)
466     {
467       Mdl->MappedSystemVa = (PVOID)(Thread->Tcb.StackLimit + (i * PAGE_SIZE));
468       MdlMap[0] = MmGetPhysicalAddress(Mdl->MappedSystemVa).u.LowPart;      
469       Status = 
470         MmCoreDumpDeviceFuncs.DeviceWrite(Context, 
471                                           MmCoreDumpBlockMap[NextOffset],
472                                           Mdl);
473       if (!NT_SUCCESS(Status))
474         {
475           DPRINT1("MM: Failed to write page to core dump.\n");
476           return(Status);
477         }
478       DbgPrint(".");
479       NextOffset++;
480     }
481
482   /* Write out the contents of physical memory. */
483   if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
484     {
485       for (i = 0; i < MmStats.NrTotalPages; i++)
486         {
487           LARGE_INTEGER PhysicalAddress;
488           PhysicalAddress.QuadPart = i * PAGE_SIZE;
489           MdlMap[0] = i * PAGE_SIZE;
490           MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame,
491                                           PAGE_READWRITE,
492                                           PhysicalAddress);
493           Status = 
494             MmCoreDumpDeviceFuncs.DeviceWrite(Context, 
495                                               MmCoreDumpBlockMap[NextOffset],
496                                               Mdl);
497           if (!NT_SUCCESS(Status))
498             {
499               DPRINT1("MM: Failed to write page to core dump.\n");
500               return(Status);
501             }
502           DbgPrint(".");
503           NextOffset++;
504         }
505     }
506
507   DbgPrint("\n");
508   return(STATUS_SUCCESS);
509 }
510
511 NTSTATUS STDCALL
512 NtCreatePagingFile(IN PUNICODE_STRING FileName,
513                    IN PLARGE_INTEGER InitialSize,
514                    IN PLARGE_INTEGER MaximumSize,
515                    IN ULONG Reserved)
516 {
517    NTSTATUS Status;
518    OBJECT_ATTRIBUTES ObjectAttributes;
519    HANDLE FileHandle;
520    IO_STATUS_BLOCK IoStatus;
521    PFILE_OBJECT FileObject;
522    PPAGINGFILE PagingFile;
523    KIRQL oldIrql;
524    ULONG AllocMapSize;
525    ULONG i;
526
527    DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
528           FileName, InitialSize->QuadPart);
529    
530    if (MiPagingFileCount >= MAX_PAGING_FILES)
531      {
532        return(STATUS_TOO_MANY_PAGING_FILES);
533      }
534    
535    InitializeObjectAttributes(&ObjectAttributes,
536                               FileName,
537                               0,
538                               NULL,
539                               NULL);
540    
541    Status = IoCreateFile(&FileHandle,
542                          FILE_ALL_ACCESS,
543                          &ObjectAttributes,
544                          &IoStatus,
545                          NULL,
546                          0,
547                          0,
548                          FILE_OPEN_IF,
549                          FILE_SYNCHRONOUS_IO_NONALERT,
550                          NULL,
551                          0,
552                          CreateFileTypeNone,
553                          NULL,
554                          SL_OPEN_PAGING_FILE);
555    if (!NT_SUCCESS(Status))
556      {
557         return(Status);
558      }
559
560    Status = NtSetInformationFile(FileHandle,
561                                  &IoStatus,
562                                  InitialSize,
563                                  sizeof(LARGE_INTEGER),
564                                  FileAllocationInformation);
565    if (!NT_SUCCESS(Status))
566      {
567        ZwClose(FileHandle);
568        return(Status);
569      }
570
571    Status = ObReferenceObjectByHandle(FileHandle,
572                                       FILE_ALL_ACCESS,
573                                       IoFileObjectType,
574                                       UserMode,
575                                       (PVOID*)&FileObject,
576                                       NULL);
577    if (!NT_SUCCESS(Status))
578      {
579         NtClose(FileHandle);
580         return(Status);
581      }
582    
583    PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
584    if (PagingFile == NULL)
585      {
586         ObDereferenceObject(FileObject);
587         NtClose(FileHandle);
588         return(STATUS_NO_MEMORY);
589      }
590    
591    PagingFile->FileObject = FileObject;
592    PagingFile->MaximumSize.QuadPart = MaximumSize->QuadPart;
593    PagingFile->CurrentSize.QuadPart = InitialSize->QuadPart;
594    PagingFile->FreePages = InitialSize->QuadPart / PAGE_SIZE;
595    PagingFile->UsedPages = 0;
596    KeInitializeSpinLock(&PagingFile->AllocMapLock);
597    
598    AllocMapSize = (PagingFile->FreePages / 32) + 1;
599    PagingFile->AllocMap = ExAllocatePool(NonPagedPool, 
600                                          AllocMapSize * sizeof(ULONG));
601    PagingFile->AllocMapSize = AllocMapSize;
602    
603    if (PagingFile->AllocMap == NULL)
604      {
605        ExFreePool(PagingFile);
606        ObDereferenceObject(FileObject);
607        NtClose(FileHandle);
608        return(STATUS_NO_MEMORY);
609      }
610    
611    KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
612    for (i = 0; i < MAX_PAGING_FILES; i++)
613      {
614         if (PagingFileList[i] == NULL)
615           {
616              PagingFileList[i] = PagingFile;
617              break;
618           }
619      }
620    MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
621    MiPagingFileCount++;
622    KeReleaseSpinLock(&PagingFileListLock, oldIrql);
623    
624    /* Check whether this pagefile can be a crash dump target. */
625    if (PagingFile->CurrentSize.QuadPart >= MmCoreDumpSize &&
626        MmCoreDumpBlockMap != NULL)
627      {
628        MmCoreDumpBlockMap = 
629          ExAllocatePool(NonPagedPool, 
630                         (MmCoreDumpSize / PAGE_SIZE) * sizeof(ULONG));
631        if (MmCoreDumpBlockMap == NULL)
632          {
633            DPRINT1("Failed to allocate block map.\n");
634            NtClose(FileHandle);
635            return(STATUS_SUCCESS);
636          }
637        Status = ZwFsControlFile(FileHandle,
638                                 NULL,
639                                 NULL,
640                                 NULL,
641                                 &IoStatus,
642                                 FSCTL_GET_DUMP_BLOCK_MAP,
643                                 &MmCoreDumpSize,
644                                 sizeof(ULONG),
645                                 MmCoreDumpBlockMap,
646                                 (MmCoreDumpSize / PAGE_SIZE) * sizeof(ULONG));
647        if (!NT_SUCCESS(Status))
648          {
649            DPRINT1("Failed to get dump block map (Status %X)\n", Status);
650            NtClose(FileHandle);
651            ExFreePool(MmCoreDumpBlockMap);
652            MmCoreDumpBlockMap = NULL;
653            return(STATUS_SUCCESS);
654          }
655        Status = ZwDeviceIoControlFile(FileHandle,
656                                       NULL,
657                                       NULL,
658                                       NULL,
659                                       &IoStatus,
660                                       IOCTL_GET_DUMP_POINTERS,
661                                       NULL,
662                                       0,
663                                       &MmCoreDumpDeviceFuncs,
664                                       sizeof(MmCoreDumpDeviceFuncs));
665        if (!NT_SUCCESS(Status))
666          {
667            DPRINT1("Failed to get dump block map (Status %X)\n", Status);
668            NtClose(FileHandle);
669            ExFreePool(MmCoreDumpBlockMap);
670            MmCoreDumpBlockMap = NULL;
671            return(STATUS_SUCCESS);
672          }
673      }
674    NtClose(FileHandle);
675
676    MmSwapSpaceMessage = FALSE;
677
678    return(STATUS_SUCCESS);
679 }
680
681
682 /* EOF */
683
684
685
686
687
688
689