コード例 #1
0
ファイル: mutant.c プロジェクト: chunhualiu/OpenNT
VOID
ExpDeleteMutant (
    IN PVOID Mutant
    )

/*++

Routine Description:

    This function is called when an executive mutant object is about to
    be deleted. The mutant object is released with an abandoned status to
    ensure that it is removed from the owner thread's mutant list if the
    mutant object is currently owned by a thread.

Arguments:

    Mutant - Supplies a pointer to an executive mutant object.

Return Value:

    None.

--*/

{

    //
    // Release the mutant object with an abandoned status to ensure that it
    // is removed from the owner thread's mutant list if the mutant is
    // currently owned by a thread.
    //

    KeReleaseMutant((PKMUTANT)Mutant, MUTANT_INCREMENT, TRUE, FALSE);
    return;
}
コード例 #2
0
ファイル: mutex.c プロジェクト: Moteesh/reactos
/*
 * @implemented
 */
LONG
NTAPI
KeReleaseMutex(IN PKMUTEX Mutex,
               IN BOOLEAN Wait)
{
    ASSERT_MUTANT(Mutex);

    /* There's no difference at this level between the two */
    return KeReleaseMutant(Mutex, 1, FALSE, Wait);
}
コード例 #3
0
ファイル: mutntobj.c プロジェクト: BillTheBest/WinNT4
LONG
KeReleaseMutex (
    IN PRKMUTANT Mutex,
    IN BOOLEAN Wait
    )

/*++

Routine Description:

    This function releases a mutex object.

    N.B. Kernel mutex objects have been subsumed by mutant objects.

Arguments:

    Mutex - Supplies a pointer to a dispatcher object of type mutex.

    Wait - Supplies a boolean value that signifies whether the call to
        KeReleaseMutex will be immediately followed by a call to one
        of the kernel Wait functions.

Return Value:

    The previous signal state of the mutex object.

--*/

{

    ASSERT_MUTANT(Mutex);

    //
    // Release the specified mutex object with defaults for increment
    // and abandoned parameters.
    //

    return KeReleaseMutant(Mutex, 1, FALSE, Wait);
}
コード例 #4
0
ファイル: auxout.c プロジェクト: BuloZB/WinNT4
NTSTATUS
SoundAuxDispatch(
    IN OUT PLOCAL_DEVICE_INFO pLDI,
    IN    PIRP pIrp,
    IN    PIO_STACK_LOCATION IrpStack
)
/*++

Routine Description:

    AUX IOCTL call dispatcher

Arguments:

    pLDI - Pointer to local device data
    pIrp - Pointer to IO request packet
    IrpStack - Pointer to current stack location

Return Value:

    Return status from dispatched routine

--*/
{
    NTSTATUS Status;

    switch (IrpStack->MajorFunction) {
    case IRP_MJ_CREATE:
        Status = STATUS_SUCCESS;
        break;

    case IRP_MJ_CLOSE:

        Status = STATUS_SUCCESS;

        break;


    case IRP_MJ_DEVICE_CONTROL:

        //
        // Dispatch the IOCTL function
        //

        Status = STATUS_INTERNAL_ERROR;

        switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {

        case IOCTL_AUX_GET_CAPABILITIES:
            Status = (*pLDI->DeviceInit->DevCapsRoutine)(pLDI, pIrp, IrpStack);
            break;

        case IOCTL_AUX_SET_VOLUME:

#ifdef MASTERVOLUME
            //
            // If this is the master volume device then let everyone else know
            // (note that not all devices need a master volume because they
            //  may have a master volume control in hardware).
            //

            if (NT_SUCCESS(Status) && pLDI->MasterVolume) {
                //
                // Loop through all the driver's devices setting their
                // volume (including the master volume).
                //

                PDEVICE_OBJECT pDO;
                for    (pDO = IrpStack->DeviceObject->DriverObject->DeviceObject;
                     pDO != NULL;
                     pDO = pDO->NextDevice) {

                    NTSTATUS StatusCurrent;

                    PLOCAL_DEVICE_INFO pLDICurrent = pDO->DeviceExtension;

                    //
                    // Get the device mutant
                    //

                    KeWaitForSingleObject(pLDICurrent->DeviceMutant,
                                          Executive,
                                          KernelMode,
                                          FALSE,               // Not alertable
                                          NULL);

                    StatusCurrent =
                        SoundIoctlSetVolume(pLDICurrent, pIrp, IrpStack);

                    KeReleaseMutant(pLDICurrent->DeviceMutant, 0, FALSE, FALSE);

                    //
                    // Return the first error
                    //

                    if (!NT_SUCCESS(StatusCurrent) && NT_SUCCESS(Status)) {
                        Status = StatusCurrent;
                    }
                }
            } else {
#endif // MASTERVOLUME
                Status = SoundIoctlSetVolume(pLDI, pIrp, IrpStack);
#ifdef MASTERVOLUME
            }
#endif // MASTERVOLUME

            break;

        case IOCTL_AUX_GET_VOLUME:
            Status = SoundIoctlGetVolume(pLDI, pIrp, IrpStack);
            break;

        case IOCTL_SOUND_GET_CHANGED_VOLUME:
            Status = SoundIoctlGetChangedVolume(pLDI, pIrp, IrpStack);
            break;

        default:
            dprintf2(("Unimplemented IOCTL (%08lXH) requested", IrpStack->Parameters.DeviceIoControl.IoControlCode));
            Status = STATUS_NOT_IMPLEMENTED;
            break;
        }
        break;

    case IRP_MJ_CLEANUP:
        Status = STATUS_SUCCESS;
        break;


    default:
        dprintf1(("Unimplemented major function requested: %08lXH", IrpStack->MajorFunction));
        Status = STATUS_NOT_IMPLEMENTED;
        break;
    }

    return Status;
}
コード例 #5
0
ファイル: obwait.c プロジェクト: Gaikokujin/WinNT4
NTSTATUS
NtSignalAndWaitForSingleObject(
    IN HANDLE SignalHandle,
    IN HANDLE WaitHandle,
    IN BOOLEAN Alertable,
    IN PLARGE_INTEGER Timeout OPTIONAL
    )

/*++

Routine Description:

    This function atomically signals the specified signal object and then
    waits until the specified wait object attains a state of Signaled. An
    optional timeout can also be specified. If a timeout is not specified,
    then the wait will not be satisfied until the wait object attains a
    state of Signaled. If a timeout is specified, and the wait object has
    not attained a state of Signaled when the timeout expires, then the
    wait is automatically satisfied. If an explicit timeout value of zero
    is specified, then no wait will occur if the wait cannot be satisfied
    immediately. The wait can also be specified as alertable.

Arguments:

    SignalHandle - supplies the handle of the signal object.

    WaitHandle  - Supplies the handle for the wait object.

    Alertable - Supplies a boolean value that specifies whether the wait
        is alertable.

    Timeout - Supplies an pointer to an absolute or relative time over
        which the wait is to occur.

Return Value:

    The wait completion status. A value of STATUS_TIMEOUT is returned if a
    timeout occurred. A value of STATUS_SUCCESS is returned if the specified
    object satisfied the wait. A value of STATUS_ALERTED is returned if the
    wait was aborted to deliver an alert to the current thread. A value of
    STATUS_USER_APC is returned if the wait was aborted to deliver a user
    APC to the current thread.

--*/

{

    OBJECT_HANDLE_INFORMATION HandleInformation;
    KPROCESSOR_MODE PreviousMode;
    PVOID RealObject;
    PVOID SignalObject;
    POBJECT_HEADER SignalObjectHeader;
    NTSTATUS Status;
    LARGE_INTEGER TimeoutValue;
    PVOID WaitObject;
    POBJECT_HEADER WaitObjectHeader;

    //
    // Establish an exception handler and probe the specified timeout value
    // if necessary. If the probe fails, then return the exception code as
    // the service status.
    //

    PreviousMode = KeGetPreviousMode();
    if ((ARGUMENT_PRESENT(Timeout)) && (PreviousMode != KernelMode)) {
        try {
            TimeoutValue = ProbeAndReadLargeInteger(Timeout);
            Timeout = &TimeoutValue;

        } except(EXCEPTION_EXECUTE_HANDLER) {
            return GetExceptionCode();
        }
    }

    //
    // Reference the signal object by handle.
    //

    Status = ObReferenceObjectByHandle(SignalHandle,
                                       0,
                                       NULL,
                                       PreviousMode,
                                       &SignalObject,
                                       &HandleInformation);

    //
    // If the reference was successful, then reference the wait object by
    // handle.
    //

    if (NT_SUCCESS(Status)) {
        Status = ObReferenceObjectByHandle(WaitHandle,
                                           SYNCHRONIZE,
                                           NULL,
                                           PreviousMode,
                                           &WaitObject,
                                           NULL);

        //
        // If the reference was successful, then determine the real wait
        // object, check the signal object access, signal the signal object,
        // and wait for the real wait object.
        //

        if (NT_SUCCESS(Status)) {
            WaitObjectHeader = OBJECT_TO_OBJECT_HEADER(WaitObject);
            RealObject = WaitObjectHeader->Type->DefaultObject;
            if ((LONG)RealObject >= 0) {
                RealObject = (PVOID)((PCHAR)WaitObject + (ULONG)RealObject);
            }

            //
            // If the signal object is an event, then check for modify access
            // and set the event. Otherwise, if the signal object is a mutant,
            // then attempt to release ownership of the mutant. Otherwise, if
            // the object is a semaphore, then check for modify access and
            // release the semaphore. Otherwise, the signal objet is invalid.
            //

            SignalObjectHeader = OBJECT_TO_OBJECT_HEADER(SignalObject);
            Status = STATUS_ACCESS_DENIED;
            if (SignalObjectHeader->Type == ExEventObjectType) {

                //
                // Check for access to the specified event object,
                //

                if ((PreviousMode != KernelMode) &&
                    (SeComputeDeniedAccesses(HandleInformation.GrantedAccess,
                                             EVENT_MODIFY_STATE) != 0)) {
                    goto WaitExit;
                }

                //
                // If the wait object is also an event, the wait is not
                // alertable, and no timeout was specified, then the event
                // pair path can be used. Otherwise, set the event and wait
                // atomically.
                //

                if ((WaitObjectHeader->Type == ExEventObjectType) &&
                    (Alertable == FALSE) &&
                    (Timeout == NULL)) {
                    Status = KiSetServerWaitClientEvent((PKEVENT)SignalObject,
                                                        (PKEVENT)RealObject,
                                                        PreviousMode);

                    goto WaitExit;
                }

                //
                // Set the specified event and wait atomically.
                //

                KeSetEvent((PKEVENT)SignalObject, EVENT_INCREMENT, TRUE);

            } else if (SignalObjectHeader->Type == ExMutantObjectType) {

                //
                // Release the specified mutant and wait atomically.
                //
                // N.B. The release will only be successful if the current
                //      thread is the owner of the mutant.
                //

                try {
                    KeReleaseMutant((PKMUTANT)SignalObject,
                                    MUTANT_INCREMENT,
                                    FALSE,
                                    TRUE);

                } except(EXCEPTION_EXECUTE_HANDLER) {
                    Status = GetExceptionCode();
                    goto WaitExit;
                }

            } else if (SignalObjectHeader->Type == ExSemaphoreObjectType) {

                //
                // Check for access to the specified semaphore object,
                //

                if ((PreviousMode != KernelMode) &&
                    (SeComputeDeniedAccesses(HandleInformation.GrantedAccess,
                                             SEMAPHORE_MODIFY_STATE) != 0)) {
                    goto WaitExit;
                }

                //
                // Release the specified semaphore and wait atomically.
                //

                try {

                    //
                    // If the wait object is also a semaphore, the wait is
                    // not alertable, and no timeout was specified, then
                    // the semaphore path can be used. Otherwise, release
                    // the semaphore and wait atomically.
                    //

                    if ((WaitObjectHeader->Type == ExSemaphoreObjectType) &&
                        (Alertable == FALSE) &&
                        (Timeout == NULL)) {
                        Status = KeReleaseWaitForSemaphore((PKSEMAPHORE)SignalObject,
                                                           (PKSEMAPHORE)RealObject,
                                                           UserRequest,
                                                           PreviousMode);

                        goto WaitExit;
                    }

                    //
                    // Release the specified semaphore and wait atomically.
                    //

                    KeReleaseSemaphore((PKSEMAPHORE)SignalObject,
                                       SEMAPHORE_INCREMENT,
                                       1,
                                       TRUE);

                } except(EXCEPTION_EXECUTE_HANDLER) {
                    Status = GetExceptionCode();
                    goto WaitExit;
                }

            } else {
                Status =
                STATUS_OBJECT_TYPE_MISMATCH;
                goto WaitExit;
            }

            Status = KeWaitForSingleObject(RealObject,
                                           UserRequest,
                                           PreviousMode,
                                           Alertable,
                                           Timeout);

        WaitExit:
            ObDereferenceObject(WaitObject);
        }
コード例 #6
0
ファイル: drvmgmt.c プロジェクト: HBelusca/NasuTek-Odyssey
/*
 * @implemented
 */
NTSTATUS
NTAPI
MmAddVerifierThunks(IN PVOID ThunkBuffer,
                    IN ULONG ThunkBufferSize)
{
    PDRIVER_VERIFIER_THUNK_PAIRS ThunkTable;
    ULONG ThunkCount;
    PDRIVER_SPECIFIED_VERIFIER_THUNKS DriverThunks;
    PLDR_DATA_TABLE_ENTRY LdrEntry;
    PVOID ModuleBase, ModuleEnd;
    ULONG i;
    NTSTATUS Status = STATUS_SUCCESS;
    PAGED_CODE();

    //
    // Make sure the driver verifier is initialized
    //
    if (!MiVerifierDriverAddedThunkListHead.Flink) return STATUS_NOT_SUPPORTED;

    //
    // Get the thunk pairs and count them
    //
    ThunkCount = ThunkBufferSize / sizeof(DRIVER_VERIFIER_THUNK_PAIRS);
    if (!ThunkCount) return STATUS_INVALID_PARAMETER_1;

    //
    // Now allocate our own thunk table
    //
    DriverThunks = ExAllocatePoolWithTag(PagedPool,
                                         sizeof(*DriverThunks) +
                                         ThunkCount *
                                         sizeof(DRIVER_VERIFIER_THUNK_PAIRS),
                                         'tVmM');
    if (!DriverThunks) return STATUS_INSUFFICIENT_RESOURCES;

    //
    // Now copy the driver-fed part
    //
    ThunkTable = (PDRIVER_VERIFIER_THUNK_PAIRS)(DriverThunks + 1);
    RtlCopyMemory(ThunkTable,
                  ThunkBuffer,
                  ThunkCount * sizeof(DRIVER_VERIFIER_THUNK_PAIRS));

    //
    // Acquire the system load lock
    //
    KeEnterCriticalRegion();
    KeWaitForSingleObject(&MmSystemLoadLock,
                          WrVirtualMemory,
                          KernelMode,
                          FALSE,
                          NULL);

    //
    // Get the loader entry
    //
    LdrEntry = MiLookupDataTableEntry(ThunkTable->PristineRoutine);
    if (!LdrEntry)
    {
        //
        // Fail
        //
        Status = STATUS_INVALID_PARAMETER_2;
        goto Cleanup;
    }

    //
    // Get driver base and end
    //
    ModuleBase = LdrEntry->DllBase;
    ModuleEnd = (PVOID)((ULONG_PTR)LdrEntry->DllBase + LdrEntry->SizeOfImage);

    //
    // Don't allow hooking the kernel or HAL
    //
    if (ModuleBase < (PVOID)(KSEG0_BASE + MmBootImageSize))
    {
        //
        // Fail
        //
        Status = STATUS_INVALID_PARAMETER_2;
        goto Cleanup;
    }

    //
    // Loop all the thunks
    //
    for (i = 0; i < ThunkCount; i++)
    {
        //
        // Make sure it's in the driver
        //
        if (((ULONG_PTR)ThunkTable->PristineRoutine < (ULONG_PTR)ModuleBase) ||
            ((ULONG_PTR)ThunkTable->PristineRoutine >= (ULONG_PTR)ModuleEnd))
        {
            //
            // Nope, fail
            //
            Status = STATUS_INVALID_PARAMETER_2;
            goto Cleanup;
        }
    }

    //
    // Otherwise, add this entry
    //
    DriverThunks->DataTableEntry = LdrEntry;
    DriverThunks->NumberOfThunks = ThunkCount;
    MiActiveVerifierThunks++;
    InsertTailList(&MiVerifierDriverAddedThunkListHead,
                   &DriverThunks->ListEntry);
    DriverThunks = NULL;

Cleanup:
    //
    // Release the lock
    //
    KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
    KeLeaveCriticalRegion();

    //
    // Free the table if we failed and return status
    //
    if (DriverThunks) ExFreePool(DriverThunks);
    return Status;
}
コード例 #7
0
ファイル: obinit.c プロジェクト: Gaikokujin/WinNT4
BOOLEAN
ObFindHandleForObject(
    IN PEPROCESS Process,
    IN PVOID Object OPTIONAL,
    IN POBJECT_TYPE ObjectType OPTIONAL,
    IN POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL,
    OUT PHANDLE Handle
    )

/*++

Routine Description:

    This routine searchs the handle table for the specified process,
    looking for a handle table entry that matches the passed parameters.
    If an an Object pointer is specified it must match.  If an
    ObjectType is specified it must match.  If HandleInformation is
    specified, then both the HandleAttributes and GrantedAccess mask
    must match.  If all three match parameters are NULL, then will
    match the first allocated handle for the specified process that
    matches the specified object pointer.

Arguments:

    Process - Specifies the process whose object table is to be searched.

    Object - Specifies the object pointer to look for.

    ObjectType - Specifies the object type to look for.

    HandleInformation - Specifies additional match criteria to look for.

    Handle - Specifies the location to receive the handle value whose handle
        entry matches the supplied object pointer and optional match criteria.

Return Value:

    TRUE if a match was found and FALSE otherwise.

--*/

{
    OBJECT_TABLE_ENTRY ObjectTableEntry;
    OBP_FIND_HANDLE_DATA EnumParameter;
    BOOLEAN Result;

    Result = FALSE;
    KeWaitForSingleObject( &ObpInitKillMutant,
                           Executive,
                           KernelMode,
                           FALSE,
                           NULL
                         );

    if (Process->ObjectTable != NULL) {
        if (ARGUMENT_PRESENT( Object )) {
            EnumParameter.ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
            }
        else {
            EnumParameter.ObjectHeader = NULL;
            }
        EnumParameter.ObjectType = ObjectType;
        EnumParameter.HandleInformation = HandleInformation;
        if (ExEnumHandleTable( Process->ObjectTable,
                               ObpEnumFindHandleProcedure,
                               &EnumParameter,
                               Handle
                             )
           ) {
            *Handle = MAKE_OBJECT_HANDLE( *Handle );
            Result = TRUE;
            }
        }

    KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
    return Result;
}
コード例 #8
0
ファイル: obinit.c プロジェクト: Gaikokujin/WinNT4
VOID
ObKillProcess(
    BOOLEAN AcquireLock,
    PEPROCESS Process
    )
/*++

Routine Description:

    This function is called whenever a process is destroyed.  It loops over
    the process' object table and closes all the handles.

Arguments:

    AcquireLock - TRUE if there are other pointers to this process and therefore
        this operation needs to be synchronized.  False if this is being called
        from the Process delete routine and therefore this is the only pointer
        to the process.

    Process - Pointer to the process that is being destroyed.

Return Value:

    None.

--*/
{
    PVOID ObjectTable;

    PAGED_CODE();

    ObpValidateIrql( "ObKillProcess" );

    if (AcquireLock) {
        KeWaitForSingleObject( &ObpInitKillMutant,
                               Executive,
                               KernelMode,
                               FALSE,
                               NULL
                             );
        }

    //
    // If the process does NOT have an object table, return
    //

    ObjectTable = Process->ObjectTable;
    if (ObjectTable != NULL) {
        //
        // For each valid entry in the object table, close the handle
        // that points to that entry.
        //
        ExDestroyHandleTable( ObjectTable, ObDestroyHandleProcedure );
        Process->ObjectTable = NULL;
        }

    if (AcquireLock) {
        KeReleaseMutant( &ObpInitKillMutant, 0, FALSE, FALSE );
        }

    return;
}
コード例 #9
0
ファイル: obinit.c プロジェクト: Gaikokujin/WinNT4
NTSTATUS
ObInitProcess(
    PEPROCESS ParentProcess OPTIONAL,
    PEPROCESS NewProcess
    )
/*++

Routine Description:

    This function initializes a process object table.  If the ParentProcess
    is specified, then all object handles with the OBJ_INHERIT attribute are
    copied from the parent object table to the new process' object table.
    The HandleCount field of each object copied is incremented by one.  Both
    object table mutexes remained locked for the duration of the copy
    operation.

Arguments:

    ParentProcess - optional pointer to a process object that is the
        parent process to inherit object handles from.

    NewProcess - pointer to the process object being initialized.

Return Value:

    Status code.

    The following errors can occur:

    - insufficient memory

--*/
{
    PHANDLE_TABLE OldObjectTable;
    PHANDLE_TABLE NewObjectTable;
    ULONG PoolCharges[ MaxPoolType ];
    SE_PROCESS_AUDIT_INFO ProcessAuditInfo;

    RtlZeroMemory( PoolCharges, sizeof( PoolCharges ) );
    if (ARGUMENT_PRESENT( ParentProcess )) {
        KeWaitForSingleObject( &ObpInitKillMutant,
                               Executive,
                               KernelMode,
                               FALSE,
                               NULL
                               );

        OldObjectTable = ParentProcess->ObjectTable;
        if ( !OldObjectTable ) {
            KeReleaseMutant(&ObpInitKillMutant,0,FALSE,FALSE);
            return STATUS_PROCESS_IS_TERMINATING;
            }
        NewObjectTable = ExDupHandleTable( NewProcess,
                                           OldObjectTable,
                                           ObDupHandleProcedure
                                         );
        }
    else {
        OldObjectTable = NULL;
        NewObjectTable = ExCreateHandleTable( NewProcess,
                                              0,
                                              0
                                            );
        }

    if (NewObjectTable) {
        NewProcess->ObjectTable = NewObjectTable;

        if ( SeDetailedAuditing ) {

            ProcessAuditInfo.Process = NewProcess;
            ProcessAuditInfo.Parent  = ParentProcess;

            ExEnumHandleTable(
                NewObjectTable,
                ObAuditInheritedHandleProcedure,
                (PVOID)&ProcessAuditInfo,
                (PHANDLE)NULL
                );
        }

        if ( OldObjectTable ) {
            KeReleaseMutant(&ObpInitKillMutant,0,FALSE,FALSE);
            }
        return( STATUS_SUCCESS );
        }
    else {
        NewProcess->ObjectTable = NULL;
        if ( OldObjectTable ) {
            KeReleaseMutant(&ObpInitKillMutant,0,FALSE,FALSE);
            }
        return( STATUS_INSUFFICIENT_RESOURCES );
        }
}
コード例 #10
0
ファイル: mutant.c プロジェクト: chunhualiu/OpenNT
NTSTATUS
NtReleaseMutant (
    IN HANDLE MutantHandle,
    OUT PLONG PreviousCount OPTIONAL
    )

/*++

Routine Description:

    This function releases a mutant object.

Arguments:

    Mutant - Supplies a handle to a mutant object.

    PreviousCount - Supplies an optional pointer to a variable that will
        receive the previous mutant count.

Return Value:

    TBS

--*/

{

    LONG Count;
    PVOID Mutant;
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;

    //
    // Establish an exception handler, probe the previous count address if
    // specified, reference the mutant object, and release the mutant object.
    // If the probe fails, then return the exception code as the service
    // status. Otherwise return the status value returned by the reference
    // object by handle routine.
    //

    try {

        //
        // Get previous processor mode and probe previous count address
        // if necessary.
        //

        PreviousMode = KeGetPreviousMode();
        if ((PreviousMode != KernelMode) && (ARGUMENT_PRESENT(PreviousCount))) {
            ProbeForWriteLong(PreviousCount);
        }

        //
        // Reference mutant object by handle.
        //
        // Note that the desired access is specified as zero since only the
        // owner can release a mutant object.
        //

        Status = ObReferenceObjectByHandle(MutantHandle,
                                           0,
                                           ExMutantObjectType,
                                           PreviousMode,
                                           &Mutant,
                                           NULL);

        //
        // If the reference was successful, then release the mutant object. If
        // an exception occurs because the caller is not the owner of the mutant
        // object, then dereference mutant object and return the exception code
        // as the service status. Otherise write the previous count value if
        // specified. If the write of the previous count fails, then do not
        // report an error. When the caller attempts to access the previous
        // count value, an access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            try {
                Count = KeReleaseMutant((PKMUTANT)Mutant, MUTANT_INCREMENT, FALSE, FALSE);
                ObDereferenceObject(Mutant);
                if (ARGUMENT_PRESENT(PreviousCount)) {
                    try {
                        *PreviousCount = Count;

                    } except(ExSystemExceptionFilter()) {
                    }
                }

            //
            // If an exception occurs because the caller is not the owner of
            // the mutant object, then always handle the exception, dereference
            // the mutant object, and return the exception code as the status
            // value.
            //

            } except(ExSystemExceptionFilter()) {
                ObDereferenceObject(Mutant);
                return GetExceptionCode();
            }
        }

    //
    // If an exception occurs during the probe of the previous count, then
    // always handle the exception and return the exception code as the status
    // value.
    //

    } except(ExSystemExceptionFilter()) {
        return GetExceptionCode();
    }

    //
    // Return service status.
    //

    return Status;
}
コード例 #11
0
ファイル: cachesup.c プロジェクト: Nevermore2015/ndas4windows
VOID
NtfsCreateInternalStreamCommon (
    IN PIRP_CONTEXT IrpContext,
    IN PSCB Scb,
    IN BOOLEAN UpdateScb,
    IN BOOLEAN CompressedStream,
    IN UNICODE_STRING const *StreamName
    )

/*++

Routine Description:

    This routine is called to prepare a stream file associated with a
    particular attribute of a file.  On return, the Scb for the attribute
    will have an associated stream file object.  On return, this
    stream file will have been initialized through the cache manager.

    TEMPCODE  The following assumptions have been made or if open issue,
    still unresolved.

        - Assume.  The call to create Scb will initialize the Mcb for
          the non-resident case.

        - Assume.  When this file is created I increment the open count
          but not the unclean count for this Scb.  When we are done with
          the stream file, we should uninitialize it and dereference it.
          We also set the file object pointer to NULL.  Close will then
          do the correct thing.

        - Assume.  Since this call is likely to be followed shortly by
          either a read or write, the cache map is initialized here.

Arguments:

    Scb - Supplies the address to store the Scb for this attribute and
          stream file.  This will exist on return from this function.

    UpdateScb - Indicates if the caller wants to update the Scb from the
                attribute.

    CompressedStream - Supplies TRUE if caller wishes to create the
                       compressed stream.

    StreamName - Internal stream name or NULL is there isn't one available.
                 This is a constant value so we don't have to allocate any pool.

Return Value:

    None.

--*/

{
    PVCB Vcb = Scb->Vcb;

    CC_FILE_SIZES CcFileSizes;
    PFILE_OBJECT CallersFileObject;
    PFILE_OBJECT *FileObjectPtr = &Scb->FileObject;
    PFILE_OBJECT UnwindStreamFile = NULL;

    BOOLEAN UnwindInitializeCacheMap = FALSE;
    BOOLEAN DecrementScbCleanup = FALSE;

    BOOLEAN AcquiredMutex = FALSE;

    ASSERT_IRP_CONTEXT( IrpContext );

    PAGED_CODE();

    DebugTrace( +1, Dbg2, ("NtfsCreateInternalAttributeStream\n") );
    DebugTrace( 0, Dbg2, ("Scb        -> %08lx\n", Scb) );

    //
    //  Change FileObjectPtr if he wants the compressed stream
    //
#if (__NDAS_NTFS_DBG__ && __NDAS_NTFS_SECONDARY__) 
	if (FlagOn(Scb->Fcb->NdasNtfsFlags, NDAS_NTFS_FCB_FLAG_SECONDARY))
		ASSERT( FALSE );
#endif

#ifdef  COMPRESS_ON_WIRE
    if (CompressedStream) {
        FileObjectPtr = &Scb->Header.FileObjectC;
    }
#endif

    //
    //  If there is no file object, we create one and initialize
    //  it.
    //

    if (*FileObjectPtr == NULL) {

        //
        //  Only acquire the mutex if we don't have the file exclusive.
        //

        if (!NtfsIsExclusiveScb( Scb )) {

            KeWaitForSingleObject( &StreamFileCreationMutex, Executive, KernelMode, FALSE, NULL );
            AcquiredMutex = TRUE;
        }

        try {

            //
            //  Someone could have gotten there first.
            //

            if (*FileObjectPtr == NULL) {

                UnwindStreamFile = IoCreateStreamFileObjectLite( NULL, Scb->Vcb->Vpb->RealDevice);

                if (ARGUMENT_PRESENT( StreamName )) {
                    UnwindStreamFile->FileName.MaximumLength = StreamName->MaximumLength;
                    UnwindStreamFile->FileName.Length = StreamName->Length;
                    UnwindStreamFile->FileName.Buffer = StreamName->Buffer;
                }

                //
                //  Propagate any flags from the caller's FileObject to our
                //  stream file that the Cache Manager may look at, so we do not
                //  miss hints like sequential only or temporary.
                //

                if (!FlagOn(Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE) &&
                    (IrpContext->OriginatingIrp != NULL) &&
                    (CallersFileObject = IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)->FileObject)) {

                    SetFlag( UnwindStreamFile->Flags,
                             CallersFileObject->Flags & NTFS_FO_PROPAGATE_TO_STREAM );
                }

                UnwindStreamFile->SectionObjectPointer = &Scb->NonpagedScb->SegmentObject;

                //
                //  For a compressed stream, we have to use separate section
                //  object pointers.
                //

#ifdef  COMPRESS_ON_WIRE
                if (CompressedStream) {
                    UnwindStreamFile->SectionObjectPointer = &Scb->NonpagedScb->SegmentObjectC;

                }
#endif

                //
                //  If we have created the stream file, we set it to type
                //  'StreamFileOpen'
                //

                NtfsSetFileObject( UnwindStreamFile,
                                   StreamFileOpen,
                                   Scb,
                                   NULL );

                if (FlagOn( Scb->ScbState, SCB_STATE_TEMPORARY )) {

                    SetFlag( UnwindStreamFile->Flags, FO_TEMPORARY_FILE );
                }

                //
                //  Initialize the fields of the file object.
                //

                UnwindStreamFile->ReadAccess = TRUE;
                UnwindStreamFile->WriteAccess = TRUE;
                UnwindStreamFile->DeleteAccess = TRUE;

                //
                //  Increment the open count and set the section
                //  object pointers.  We don't set the unclean count as the
                //  cleanup call has already occurred.
                //

                NtfsIncrementCloseCounts( Scb, TRUE, FALSE );

                //
                //  Increment the cleanup count in this Scb to prevent the
                //  Scb from going away if the cache call fails.
                //

                InterlockedIncrement( &Scb->CleanupCount );
                DecrementScbCleanup = TRUE;

                //
                //  If the Scb header has not been initialized, we will do so now.
                //

                if (UpdateScb
                    && !FlagOn( Scb->ScbState, SCB_STATE_HEADER_INITIALIZED )) {

                    NtfsUpdateScbFromAttribute( IrpContext, Scb, NULL );
                }

                //
                //  If this is a compressed stream and the file is not already
                //  marked as MODIFIED_NO_WRITE then do it now.  Use the
                //  Extended flag field in the Fsrtl header for this.  Since this
                //  is the only place we make this call with FsContext2 == NULL,
                //  it does not matter how we leave the FsRtl header flag.!
                //

                NtfsAcquireFsrtlHeader( Scb );
                ClearFlag(Scb->Header.Flags2, FSRTL_FLAG2_DO_MODIFIED_WRITE);
                if (!FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE ) &&
                    !FlagOn( Scb->Header.Flags2, FSRTL_FLAG2_DO_MODIFIED_WRITE ) &&
                    !CompressedStream) {

                    SetFlag(Scb->Header.Flags2, FSRTL_FLAG2_DO_MODIFIED_WRITE);
                }
                NtfsReleaseFsrtlHeader( Scb );

                //
                //  Check if we need to initialize the cache map for the stream file.
                //  The size of the section to map will be the current allocation
                //  for the stream file.
                //

                if (UnwindStreamFile->PrivateCacheMap == NULL) {

                    BOOLEAN PinAccess;

                    CcFileSizes = *(PCC_FILE_SIZES)&Scb->Header.AllocationSize;

                    //
                    //  If this is a stream with Usa protection, we want to tell
                    //  the Cache Manager we do not need to get any valid data
                    //  callbacks.  We do this by having xxMax sitting in
                    //  ValidDataLength for the call, but we have to restore the
                    //  correct value afterwards.
                    //
                    //  We also do this for all of the stream files created during
                    //  restart.  This has the effect of telling Mm to always
                    //  fault the page in from disk.  Don't generate a zero page if
                    //  push up the file size during restart.
                    //

                    if (FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE )) {

                        CcFileSizes.ValidDataLength.QuadPart = MAXLONGLONG;
                    }

                    PinAccess =
                        (BOOLEAN) (Scb->AttributeTypeCode != $DATA ||
                                   FlagOn(Scb->Fcb->FcbState, FCB_STATE_PAGING_FILE | FCB_STATE_SYSTEM_FILE) ||
                                   FlagOn( Scb->Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS ) ||
                                   CompressedStream);

                    //
                    //  Bias this for the Usn journal.
                    //

                    if (FlagOn( Scb->ScbPersist, SCB_PERSIST_USN_JOURNAL )) {

                        CcFileSizes.AllocationSize.QuadPart -= Vcb->UsnCacheBias;
                        CcFileSizes.FileSize.QuadPart -= Vcb->UsnCacheBias;
                    }

                    CcInitializeCacheMap( UnwindStreamFile,
                                          &CcFileSizes,
                                          PinAccess,
                                          &NtfsData.CacheManagerCallbacks,
                                          (PCHAR)Scb + CompressedStream );

                    UnwindInitializeCacheMap = TRUE;
                }

                //
                //  Now call Cc to set the log handle for the file.
                //

                if (FlagOn( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE ) &&
                    (Scb != Vcb->LogFileScb)) {

                    CcSetLogHandleForFile( UnwindStreamFile,
                                           Vcb->LogHandle,
                                           &LfsFlushToLsn );
                }

                //
                //  It is now safe to store the stream file in the Scb.  We wait
                //  until now because we don't want an unsafe tester to use the
                //  file object until the cache is initialized.
                //

                *FileObjectPtr = UnwindStreamFile;
            }

        } finally {

            DebugUnwind( NtfsCreateInternalAttributeStream );

            //
            //  Undo our work if an error occurred.
            //

            if (AbnormalTermination()) {

                //
                //  Uninitialize the cache file if we initialized it.
                //

                if (UnwindInitializeCacheMap) {

                    CcUninitializeCacheMap( UnwindStreamFile, NULL, NULL );
                }

                //
                //  Dereference the stream file if we created it.
                //

                if (UnwindStreamFile != NULL) {

                    //
                    //  Clear the internal file name constant
                    //

                    NtfsClearInternalFilename( UnwindStreamFile );

                    ObDereferenceObject( UnwindStreamFile );
                }
            }

            //
            //  Restore the Scb cleanup count.
            //

            if (DecrementScbCleanup) {

                InterlockedDecrement( &Scb->CleanupCount );
            }

            if (AcquiredMutex) {

                KeReleaseMutant( &StreamFileCreationMutex, IO_NO_INCREMENT, FALSE, FALSE );
            }

            DebugTrace( -1, Dbg2, ("NtfsCreateInternalAttributeStream -> VOID\n") );
        }
    }

    return;
}
コード例 #12
0
ファイル: cachesup.c プロジェクト: Nevermore2015/ndas4windows
BOOLEAN
NtfsDeleteInternalAttributeStream (
    IN PSCB Scb,
    IN ULONG ForceClose,
    IN ULONG CompressedStreamOnly
    )

/*++

Routine Description:

    This routine is the inverse of NtfsCreateInternalAttributeStream.  It
    uninitializes the cache map and dereferences the stream file object.
    It is coded defensively, in case the stream file object does not exist
    or the cache map has not been initialized.

Arguments:

    Scb - Supplies the Scb for which the stream file is to be deleted.

    ForceClose - Indicates if we to immediately close everything down or
        if we are willing to let Mm slowly migrate things out.

    CompressedStreamOnly - Indicates if we only want to delete the compressed
        stream.

Return Value:

    BOOLEAN - TRUE if we dereference a file object, FALSE otherwise.

--*/

{
    PFILE_OBJECT FileObject;
#ifdef  COMPRESS_ON_WIRE
    PFILE_OBJECT FileObjectC;
#endif

    BOOLEAN Dereferenced = FALSE;

    PAGED_CODE();

    //
    //  We normally already have the paging Io resource.  If we do
    //  not, then it is typically some cleanup path of create or
    //  whatever.  This code assumes that if we cannot get the paging
    //  Io resource, then there is other activity still going on,
    //  and it is ok to not delete the stream!  For example, it could
    //  be the lazy writer, who definitely needs the stream.
    //

    if (
#ifdef  COMPRESS_ON_WIRE
        ((Scb->FileObject != NULL) || (Scb->Header.FileObjectC != NULL)) &&
#else
        (Scb->FileObject != NULL) &&
#endif
        ((Scb->Header.PagingIoResource == NULL) ||
         ExAcquireResourceExclusiveLite( Scb->Header.PagingIoResource, FALSE ))) {


        KeWaitForSingleObject( &StreamFileCreationMutex, Executive, KernelMode, FALSE, NULL );

        //
        //  Capture both file objects and clear the fields so no one else
        //  can access them.
        //

        if (CompressedStreamOnly) {

            FileObject = NULL;

        } else {

            FileObject = Scb->FileObject;
            Scb->FileObject = NULL;

            //
            //  Clear the internal file name constant
            //

            NtfsClearInternalFilename( FileObject );
        }

#ifdef  COMPRESS_ON_WIRE
        FileObjectC = Scb->Header.FileObjectC;
        Scb->Header.FileObjectC = NULL;
#endif

        KeReleaseMutant( &StreamFileCreationMutex, IO_NO_INCREMENT, FALSE, FALSE );

        if (Scb->Header.PagingIoResource != NULL) {
            ExReleaseResourceLite( Scb->Header.PagingIoResource );
        }

        //
        //  Now dereference each file object.
        //

        if (FileObject != NULL) {

            //
            //  We shouldn't be deleting the internal stream objects of the MFT & co, unless
            //  we are in the dismounting, restarting or mounting path.
            //

            ASSERT( (((PSCB) FileObject->FsContext)->Header.NodeTypeCode != NTFS_NTC_SCB_MFT) ||
                     FlagOn( Scb->Vcb->VcbState, VCB_STATE_RESTART_IN_PROGRESS ) ||
                     FlagOn( Scb->Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT ) ||
                     !FlagOn( Scb->Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED ) ||
                     Scb->Vcb->RootIndexScb == NULL );

            if (FileObject->PrivateCacheMap != NULL) {

                CcUninitializeCacheMap( FileObject,
                                        (ForceClose ? &Li0 : NULL),
                                        NULL );
            }

            ObDereferenceObject( FileObject );
            Dereferenced = TRUE;
        }

#ifdef  COMPRESS_ON_WIRE
        if (FileObjectC != NULL) {

            if (FileObjectC->PrivateCacheMap != NULL) {

                CcUninitializeCacheMap( FileObjectC,
                                        (ForceClose ? &Li0 : NULL),
                                        NULL );
            }

            //
            //  For the compressed stream, deallocate the additional
            //  section object pointers.
            //

            ObDereferenceObject( FileObjectC );
            Dereferenced = TRUE;
        }
#endif
    }

    return Dereferenced;
}
コード例 #13
0
ファイル: shutdown.c プロジェクト: BaoYu0721/WRK-1.2
BOOLEAN
MiShutdownSystem (
    VOID
    )

/*++

Routine Description:

    This function performs the shutdown of memory management.  This
    is accomplished by writing out all modified pages which are
    destined for files other than the paging file.

    All processes have already been killed, the registry shutdown and
    shutdown IRPs already sent.  On return from this phase all mapped
    file data must be flushed and the unused segment list emptied.
    This releases all the Mm references to file objects, allowing many
    drivers (especially the network) to unload.

Arguments:

    None.

Return Value:

    TRUE if the pages were successfully written, FALSE otherwise.

--*/

{
    SIZE_T ImportListSize;
    PLOAD_IMPORTS ImportList;
    PLOAD_IMPORTS ImportListNonPaged;
    PLIST_ENTRY NextEntry;
    PKLDR_DATA_TABLE_ENTRY DataTableEntry;
    PFN_NUMBER ModifiedPage;
    PMMPFN Pfn1;
    PSUBSECTION Subsection;
    PCONTROL_AREA ControlArea;
    PPFN_NUMBER Page;
    PFILE_OBJECT FilePointer;
    ULONG ConsecutiveFileLockFailures;
    PFN_NUMBER MdlHack[(sizeof(MDL)/sizeof(PFN_NUMBER)) + MM_MAXIMUM_WRITE_CLUSTER];
    PMDL Mdl;
    NTSTATUS Status;
    KEVENT IoEvent;
    IO_STATUS_BLOCK IoStatus;
    KIRQL OldIrql;
    LARGE_INTEGER StartingOffset;
    ULONG count;
    ULONG i;

    //
    // Don't do this more than once.
    //

    if (MmSystemShutdown == 0) {

        Mdl = (PMDL) MdlHack;
        Page = (PPFN_NUMBER)(Mdl + 1);

        KeInitializeEvent (&IoEvent, NotificationEvent, FALSE);

        MmInitializeMdl (Mdl, NULL, PAGE_SIZE);

        Mdl->MdlFlags |= MDL_PAGES_LOCKED;

        MmLockPageableSectionByHandle (ExPageLockHandle);

        LOCK_PFN (OldIrql);

        ModifiedPage = MmModifiedPageListHead.Flink;

        while (ModifiedPage != MM_EMPTY_LIST) {

            //
            // There are modified pages.
            //

            Pfn1 = MI_PFN_ELEMENT (ModifiedPage);

            if (Pfn1->OriginalPte.u.Soft.Prototype == 1) {

                //
                // This page is destined for a file.
                //

                Subsection = MiGetSubsectionAddress (&Pfn1->OriginalPte);
                ControlArea = Subsection->ControlArea;
                if ((!ControlArea->u.Flags.Image) &&
                   (!ControlArea->u.Flags.NoModifiedWriting)) {

                    MiUnlinkPageFromList (Pfn1);

                    //
                    // Issue the write.
                    //

                    MI_SET_MODIFIED (Pfn1, 0, 0x28);

                    //
                    // Up the reference count for the physical page as there
                    // is I/O in progress.
                    //

                    MI_ADD_LOCKED_PAGE_CHARGE_FOR_MODIFIED_PAGE (Pfn1);

                    *Page = ModifiedPage;
                    ControlArea->NumberOfMappedViews += 1;
                    ControlArea->NumberOfPfnReferences += 1;

                    UNLOCK_PFN (OldIrql);

                    StartingOffset.QuadPart = MiStartingOffset (Subsection,
                                                                Pfn1->PteAddress);
                    Mdl->StartVa = NULL;

                    ConsecutiveFileLockFailures = 0;
                    FilePointer = ControlArea->FilePointer;

retry:
                    KeClearEvent (&IoEvent);

                    Status = FsRtlAcquireFileForCcFlushEx (FilePointer);

                    if (NT_SUCCESS(Status)) {
                        Status = IoSynchronousPageWrite (FilePointer,
                                                         Mdl,
                                                         &StartingOffset,
                                                         &IoEvent,
                                                         &IoStatus);

                        //
                        // Release the file we acquired.
                        //

                        FsRtlReleaseFileForCcFlush (FilePointer);
                    }

                    if (!NT_SUCCESS(Status)) {

                        //
                        // Only try the request more than once if the
                        // filesystem said it had a deadlock.
                        //

                        if (Status == STATUS_FILE_LOCK_CONFLICT) {
                            ConsecutiveFileLockFailures += 1;
                            if (ConsecutiveFileLockFailures < 5) {
                                KeDelayExecutionThread (KernelMode,
                                                        FALSE,
                                                        (PLARGE_INTEGER)&MmShortTime);
                                goto retry;
                            }
                            goto wait_complete;
                        }

                        //
                        // Ignore all I/O failures - there is nothing that
                        // can be done at this point.
                        //

                        KeSetEvent (&IoEvent, 0, FALSE);
                    }

                    Status = KeWaitForSingleObject (&IoEvent,
                                                    WrPageOut,
                                                    KernelMode,
                                                    FALSE,
                                                    (PLARGE_INTEGER)&MmTwentySeconds);

wait_complete:

                    if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) {
                        MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
                    }

                    if (Status == STATUS_TIMEOUT) {

                        //
                        // The write did not complete in 20 seconds, assume
                        // that the file systems are hung and return an
                        // error.
                        //

                        LOCK_PFN (OldIrql);

                        MI_SET_MODIFIED (Pfn1, 1, 0xF);

                        MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF (Pfn1);
                        ControlArea->NumberOfMappedViews -= 1;
                        ControlArea->NumberOfPfnReferences -= 1;

                        //
                        // This routine returns with the PFN lock released!
                        //

                        MiCheckControlArea (ControlArea, OldIrql);

                        MmUnlockPageableImageSection (ExPageLockHandle);

                        return FALSE;
                    }

                    LOCK_PFN (OldIrql);
                    MI_REMOVE_LOCKED_PAGE_CHARGE_AND_DECREF (Pfn1);
                    ControlArea->NumberOfMappedViews -= 1;
                    ControlArea->NumberOfPfnReferences -= 1;

                    //
                    // This routine returns with the PFN lock released!
                    //

                    MiCheckControlArea (ControlArea, OldIrql);
                    LOCK_PFN (OldIrql);

                    //
                    // Restart scan at the front of the list.
                    //

                    ModifiedPage = MmModifiedPageListHead.Flink;
                    continue;
                }
            }
            ModifiedPage = Pfn1->u1.Flink;
        }

        UNLOCK_PFN (OldIrql);

        //
        // Indicate to the modified page writer that the system has
        // shutdown.
        //

        MmSystemShutdown = 1;

        //
        // Check to see if the paging file should be overwritten.
        // Only free blocks are written.
        //

        if (MmZeroPageFile) {
            MiZeroAllPageFiles ();
        }

        MmUnlockPageableImageSection (ExPageLockHandle);
    }

    if (PoCleanShutdownEnabled ()) {

        //
        // Empty the unused segment list.
        //

        LOCK_PFN (OldIrql);
        MmUnusedSegmentForceFree = (ULONG)-1;
        KeSetEvent (&MmUnusedSegmentCleanup, 0, FALSE);

        //
        // Give it 5 seconds to empty otherwise assume the filesystems are
        // hung and march on.
        //

        for (count = 0; count < 500; count += 1) {

            if (IsListEmpty(&MmUnusedSegmentList)) {
                break;
            }

            UNLOCK_PFN (OldIrql);

            KeDelayExecutionThread (KernelMode,
                                    FALSE,
                                    (PLARGE_INTEGER)&MmShortTime);
            LOCK_PFN (OldIrql);

#if DBG
            if (count == 400) {

                //
                // Everything should have been flushed by now.  Give the
                // filesystem team a chance to debug this on checked builds.
                //

                ASSERT (FALSE);
            }
#endif

            //
            // Resignal if needed in case more closed file objects triggered
            // additional entries.
            //

            if (MmUnusedSegmentForceFree == 0) {
                MmUnusedSegmentForceFree = (ULONG)-1;
                KeSetEvent (&MmUnusedSegmentCleanup, 0, FALSE);
            }
        }

        UNLOCK_PFN (OldIrql);

        //
        // Get rid of any paged pool references as they will be illegal
        // by the time MmShutdownSystem is called again since the filesystems
        // will have shutdown.
        //

        KeWaitForSingleObject (&MmSystemLoadLock,
                               WrVirtualMemory,
                               KernelMode,
                               FALSE,
                               (PLARGE_INTEGER)NULL);

        NextEntry = PsLoadedModuleList.Flink;
        while (NextEntry != &PsLoadedModuleList) {

            DataTableEntry = CONTAINING_RECORD (NextEntry,
                                                KLDR_DATA_TABLE_ENTRY,
                                                InLoadOrderLinks);

            ImportList = (PLOAD_IMPORTS)DataTableEntry->LoadedImports;

            if ((ImportList != (PVOID)LOADED_AT_BOOT) &&
                (ImportList != (PVOID)NO_IMPORTS_USED) &&
                (!SINGLE_ENTRY(ImportList))) {

                ImportListSize = ImportList->Count * sizeof(PVOID) + sizeof(SIZE_T);
                ImportListNonPaged = (PLOAD_IMPORTS) ExAllocatePoolWithTag (NonPagedPool,
                                                                    ImportListSize,
                                                                    'TDmM');

                if (ImportListNonPaged != NULL) {
                    RtlCopyMemory (ImportListNonPaged, ImportList, ImportListSize);
                    ExFreePool (ImportList);
                    DataTableEntry->LoadedImports = ImportListNonPaged;
                }
                else {

                    //
                    // Don't bother with the clean shutdown at this point.
                    //

                    PopShutdownCleanly = FALSE;
                    break;
                }
            }

            //
            // Free the full DLL name as it is pageable.
            //

            if (DataTableEntry->FullDllName.Buffer != NULL) {
                ExFreePool (DataTableEntry->FullDllName.Buffer);
                DataTableEntry->FullDllName.Buffer = NULL;
            }

            NextEntry = NextEntry->Flink;
        }

        KeReleaseMutant (&MmSystemLoadLock, 1, FALSE, FALSE);

        //
        // Close all the pagefile handles, note we still have an object
        // reference to each keeping the underlying object resident.
        // At the end of Phase1 shutdown we'll release those references
        // to trigger the storage stack unload.  The handle close must be
        // done here however as it will reference pageable structures.
        //

        for (i = 0; i < MmNumberOfPagingFiles; i += 1) {

            //
            // Free each pagefile name now as it resides in paged pool and
            // may need to be inpaged to be freed.  Since the paging files
            // are going to be shutdown shortly, now is the time to access
            // pageable stuff and get rid of it.  Zeroing the buffer pointer
            // is sufficient as the only accesses to this are from the
            // try-except-wrapped GetSystemInformation APIs and all the
            // user processes are gone already.
            //
        
            ASSERT (MmPagingFile[i]->PageFileName.Buffer != NULL);
            ExFreePool (MmPagingFile[i]->PageFileName.Buffer);
            MmPagingFile[i]->PageFileName.Buffer = NULL;

            ZwClose (MmPagingFile[i]->FileHandle);
        }
    }

    return TRUE;
}