605 lines
15 KiB
C
605 lines
15 KiB
C
/***********
|
||
//joejoe
|
||
|
||
Joelinn 2-13-95
|
||
|
||
This is the pits......i have to pull in the browser in order to be started form
|
||
the lanman network provider DLL. the browser should be moved elsewhere........
|
||
|
||
**********************/
|
||
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
disccode.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code to manage the NT redirectors discardable
|
||
code sections.
|
||
|
||
|
||
Author:
|
||
|
||
Larry Osterman (larryo) 12-Nov-1993
|
||
|
||
Environment:
|
||
|
||
Kernel mode.
|
||
|
||
Revision History:
|
||
|
||
12-Nov-1993
|
||
|
||
Created
|
||
|
||
--*/
|
||
|
||
//
|
||
// Include modules
|
||
//
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
#include <ntbowsif.h>
|
||
|
||
//
|
||
// The Bug check file id for this module
|
||
//
|
||
|
||
#define BugCheckFileId (RDBSS_BUG_CHECK_NTBOWSIF)
|
||
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_DISCCODE)
|
||
|
||
|
||
BOOLEAN DiscCodeInitialized = FALSE;
|
||
|
||
VOID
|
||
RdrDiscardableCodeRoutine(
|
||
IN PVOID Context
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, RdrReferenceDiscardableCode)
|
||
#pragma alloc_text(PAGE, RdrDereferenceDiscardableCode)
|
||
#pragma alloc_text(PAGE, RdrDiscardableCodeRoutine)
|
||
#pragma alloc_text(INIT, RdrInitializeDiscardableCode)
|
||
#pragma alloc_text(PAGE, RdrUninitializeDiscardableCode)
|
||
#endif
|
||
|
||
//
|
||
// These 7 variables maintain the state needed to manage the redirector
|
||
// discardable code section.
|
||
//
|
||
// The redirector discardable code section is referenced via a call to
|
||
// RdrReferenceDiscardableCodeSection, and dereferenced via a call to
|
||
// RdrDereferenceDiscardableCodeSection.
|
||
//
|
||
// If the discardable code section is already mapped into memory, then
|
||
// referencing the discardable code section is extremely quick.
|
||
//
|
||
// When the reference count on the discardable code section drops to 0, a
|
||
// timer is set that will actually perform the work needed to uninitalize the
|
||
// section. This means that if the reference count goes from 0 to 1 to 0
|
||
// frequently, we won't thrash inside MmLockPagableCodeSection.
|
||
//
|
||
|
||
#define POOL_DISCTIMER 'wbxR'
|
||
|
||
ERESOURCE
|
||
RdrDiscardableCodeLock = {0};
|
||
|
||
ULONG
|
||
RdrDiscardableCodeTimeout = 10;
|
||
|
||
RDR_SECTION
|
||
RdrSectionInfo[RdrMaxDiscardableSection] = {0};
|
||
|
||
extern
|
||
PVOID
|
||
BowserAllocateViewBuffer(VOID);
|
||
|
||
extern
|
||
VOID
|
||
BowserNetlogonCopyMessage(int,int);
|
||
|
||
VOID
|
||
RdrReferenceDiscardableCode(
|
||
DISCARDABLE_SECTION_NAME SectionName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
RdrReferenceDiscardableCode is called to reference the redirectors
|
||
discardable code section.
|
||
|
||
If the section is not present in memory, MmLockPagableCodeSection is
|
||
called to fault the section into memory.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
#if DBG
|
||
PVOID caller, callersCaller;
|
||
#endif
|
||
PRDR_SECTION Section = &RdrSectionInfo[SectionName];
|
||
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
|
||
|
||
ASSERT( DiscCodeInitialized );
|
||
|
||
#if DBG
|
||
RtlGetCallersAddress(&caller, &callersCaller);
|
||
|
||
//dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n", SectionName, caller, callersCaller));
|
||
RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n",
|
||
SectionName, caller, callersCaller ));
|
||
#endif
|
||
|
||
//
|
||
// If the reference count is already non zero, just increment it and
|
||
// return.
|
||
//
|
||
|
||
if (Section->ReferenceCount) {
|
||
Section->ReferenceCount += 1;
|
||
|
||
//dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %d: Early out, Refcount now %ld\n", SectionName, Section->ReferenceCount));
|
||
RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %d: Early out, Refcount now %ld\n",
|
||
SectionName, Section->ReferenceCount ));
|
||
|
||
//
|
||
// Wait for the pages to be faulted in.
|
||
//
|
||
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
|
||
return;
|
||
}
|
||
|
||
Section->ReferenceCount += 1;
|
||
|
||
//
|
||
// Cancel the timer, if it is running, we won't be discarding the code
|
||
// at this time.
|
||
//
|
||
// If the cancel timer fails, this is not a problem, since we will be
|
||
// bumping a reference count in the MmLockPagableCodeSection, so when
|
||
// the timer actually runs and the call to MmUnlockPagableImageSection
|
||
// is called, we will simply unlock it.
|
||
//
|
||
|
||
if (Section->Timer != NULL) {
|
||
|
||
Section->TimerCancelled = TRUE;
|
||
|
||
if (KeCancelTimer(Section->Timer)) {
|
||
|
||
//
|
||
// Free the timer and DPC, they aren't going to fire anymore.
|
||
//
|
||
|
||
RxFreePool(Section->Timer);
|
||
Section->Timer = NULL;
|
||
|
||
//
|
||
// Set the active event to the signalled state, since we're
|
||
// done canceling the timer.
|
||
//
|
||
|
||
KeSetEvent(&Section->TimerDoneEvent, 0, FALSE);
|
||
|
||
} else {
|
||
|
||
//
|
||
// The timer was active, and we weren't able to cancel it.
|
||
// But we marked it for cancellation, and the timer routine
|
||
// will recognize this and leave the section locked.
|
||
//
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the discardable code section is still locked, then we're done,
|
||
// and we can return right away.
|
||
//
|
||
|
||
if (Section->Locked) {
|
||
|
||
//dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %d: Already locked, Refcount now %ld\n", SectionName, Section->ReferenceCount));
|
||
RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %d: Already locked, Refcount now %ld\n",
|
||
SectionName, Section->ReferenceCount ));
|
||
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
|
||
return;
|
||
}
|
||
|
||
ASSERT (Section->CodeHandle == NULL);
|
||
ASSERT (Section->DataHandle == NULL);
|
||
|
||
//
|
||
// Lock down the pagable image section.
|
||
//
|
||
|
||
//dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %d: Lock, Refcount now %ld\n", SectionName, Section->ReferenceCount));
|
||
RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %d: Lock, Refcount now %ld\n",
|
||
SectionName, Section->ReferenceCount ));
|
||
|
||
if (Section->CodeBase != NULL) {
|
||
Section->CodeHandle = MmLockPagableCodeSection(Section->CodeBase);
|
||
ASSERT (Section->CodeHandle != NULL);
|
||
}
|
||
|
||
if (Section->DataBase != NULL) {
|
||
Section->DataHandle = MmLockPagableDataSection(Section->DataBase);
|
||
ASSERT (Section->DataHandle != NULL);
|
||
}
|
||
|
||
|
||
Section->Locked = TRUE;
|
||
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
RdrDiscardableCodeDpcRoutine(
|
||
IN PKDPC Dpc,
|
||
IN PVOID Context,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
This routine is called when the timeout expires. It is called at Dpc level
|
||
to queue a WorkItem to a system worker thread.
|
||
|
||
Arguments:
|
||
|
||
IN PKDPC Dpc,
|
||
IN PVOID Context,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
|
||
Return Value
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PWORK_QUEUE_ITEM discardableWorkItem = Context;
|
||
|
||
ExQueueWorkItem(discardableWorkItem, CriticalWorkQueue);
|
||
|
||
UNREFERENCED_PARAMETER(Dpc);
|
||
UNREFERENCED_PARAMETER(SystemArgument1);
|
||
UNREFERENCED_PARAMETER(SystemArgument2);
|
||
|
||
}
|
||
|
||
VOID
|
||
RdrDiscardableCodeRoutine(
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
RdrDiscardableCodeRoutine is called at task time after the redirector
|
||
discardable code timer has fired to actually perform the unlock on the
|
||
discardable code section.
|
||
|
||
Arguments:
|
||
|
||
Context - Ignored.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PRDR_SECTION Section = Context;
|
||
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
|
||
|
||
if (Section->TimerCancelled) {
|
||
|
||
//
|
||
// The timer was cancelled after it was scheduled to run.
|
||
// Don't unlock the section.
|
||
//
|
||
|
||
} else if (Section->Locked) {
|
||
|
||
//
|
||
// The timer was not cancelled. Unlock the section.
|
||
//
|
||
|
||
Section->Locked = FALSE;
|
||
|
||
ASSERT (Section->CodeHandle != NULL ||
|
||
Section->DataHandle != NULL);
|
||
|
||
//dprintf(DPRT_DISCCODE, ("RDR: Unlock %x\n", Section));
|
||
RxDbgTrace(0,Dbg,("RDR: Unlock %x\n", Section));
|
||
|
||
if (Section->CodeHandle != NULL) {
|
||
MmUnlockPagableImageSection(Section->CodeHandle);
|
||
Section->CodeHandle = NULL;
|
||
}
|
||
|
||
if (Section->DataHandle != NULL) {
|
||
MmUnlockPagableImageSection(Section->DataHandle);
|
||
Section->DataHandle = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Free the timer and DPC, they aren't going to fire anymore.
|
||
//
|
||
|
||
RxFreePool(Section->Timer);
|
||
Section->Timer = NULL;
|
||
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
|
||
KeSetEvent(&Section->TimerDoneEvent, 0, FALSE);
|
||
}
|
||
|
||
|
||
VOID
|
||
RdrDereferenceDiscardableCode(
|
||
DISCARDABLE_SECTION_NAME SectionName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
RdrDereferenceDiscardableCode is called to dereference the redirectors
|
||
discardable code section.
|
||
|
||
When the reference count drops to 0, a timer is set that will fire in <n>
|
||
seconds, after which time the section will be unlocked.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
#if DBG
|
||
PVOID caller, callersCaller;
|
||
#endif
|
||
PRDR_SECTION Section = &RdrSectionInfo[SectionName];
|
||
LARGE_INTEGER discardableCodeTimeout;
|
||
PKTIMER Timer;
|
||
PKDPC Dpc;
|
||
PWORK_QUEUE_ITEM WorkItem;
|
||
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
|
||
|
||
ASSERT( DiscCodeInitialized );
|
||
|
||
#if DBG
|
||
RtlGetCallersAddress(&caller, &callersCaller);
|
||
|
||
//dprintf(DPRT_DISCCODE, ("RdrDereferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n", SectionName, caller, callersCaller));
|
||
RxDbgTrace(0, Dbg,("RdrDereferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n",
|
||
SectionName, caller, callersCaller ));
|
||
#endif
|
||
|
||
ASSERT (Section->ReferenceCount > 0);
|
||
|
||
//
|
||
// If the reference count is above 1, just decrement it and
|
||
// return.
|
||
//
|
||
|
||
Section->ReferenceCount -= 1;
|
||
|
||
if (Section->ReferenceCount) {
|
||
|
||
//dprintf(DPRT_DISCCODE, ("RdrDereferenceDiscardableCode: %d: Early out, Refcount now %ld\n", SectionName, Section->ReferenceCount));
|
||
RxDbgTrace(0, Dbg, ("RdrDereferenceDiscardableCode: %d: Early out, Refcount now %ld\n",
|
||
SectionName, Section->ReferenceCount ));
|
||
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// If the discardable code timer is still active (which might happen if
|
||
// the RdrReferenceDiscardableCode failed to cancel the timer), we just
|
||
// want to bail out and let the timer do the work. It means that we
|
||
// discard the code sooner, but that shouldn't be that big a deal.
|
||
//
|
||
|
||
if (Section->Timer != NULL) {
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// The reference count just went to 0, set a timer to fire in
|
||
// RdrDiscardableCodeTimeout seconds. When the timer fires,
|
||
// we queue a request to a worker thread and it will lock down
|
||
// the pagable code.
|
||
//
|
||
|
||
ASSERT (Section->Timer == NULL);
|
||
|
||
Timer = RxAllocatePoolWithTag(NonPagedPool,
|
||
sizeof(KTIMER) + sizeof(KDPC) + sizeof(WORK_QUEUE_ITEM),
|
||
POOL_DISCTIMER
|
||
);
|
||
|
||
if (Timer == NULL) {
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
return;
|
||
}
|
||
|
||
Section->Timer = Timer;
|
||
KeInitializeTimer(Timer);
|
||
|
||
Dpc = (PKDPC)(Timer + 1);
|
||
WorkItem = (PWORK_QUEUE_ITEM)(Dpc + 1);
|
||
|
||
KeClearEvent(&Section->TimerDoneEvent);
|
||
Section->TimerCancelled = FALSE;
|
||
|
||
ExInitializeWorkItem(WorkItem, RdrDiscardableCodeRoutine, Section);
|
||
|
||
KeInitializeDpc(Dpc, RdrDiscardableCodeDpcRoutine, WorkItem);
|
||
|
||
discardableCodeTimeout.QuadPart = Int32x32To64(RdrDiscardableCodeTimeout, 1000 * -10000);
|
||
KeSetTimer(Timer, discardableCodeTimeout, Dpc);
|
||
|
||
//dprintf(DPRT_DISCCODE, ("RdrDereferenceDiscardableCode: %d: Set timer, Refcount now %ld\n", SectionName, Section->ReferenceCount));
|
||
RxDbgTrace(0, Dbg, ("RdrDereferenceDiscardableCode: %d: Set timer, Refcount now %ld\n",
|
||
SectionName, Section->ReferenceCount ));
|
||
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
}
|
||
|
||
VOID
|
||
RdrInitializeDiscardableCode(
|
||
VOID
|
||
)
|
||
{
|
||
DISCARDABLE_SECTION_NAME SectionName;
|
||
PRDR_SECTION Section;
|
||
|
||
for (SectionName = 0, Section = &RdrSectionInfo[0];
|
||
SectionName < RdrMaxDiscardableSection;
|
||
SectionName += 1, Section++ ) {
|
||
KeInitializeEvent(&Section->TimerDoneEvent,
|
||
NotificationEvent,
|
||
TRUE);
|
||
}
|
||
|
||
RdrSectionInfo[RdrFileDiscardableSection].CodeBase = NULL; //RdrBackOff;
|
||
RdrSectionInfo[RdrFileDiscardableSection].DataBase = NULL;
|
||
RdrSectionInfo[RdrVCDiscardableSection].CodeBase = NULL; //RdrTdiDisconnectHandler;
|
||
RdrSectionInfo[RdrVCDiscardableSection].DataBase = NULL; //RdrSmbErrorMap;
|
||
RdrSectionInfo[RdrConnectionDiscardableSection].CodeBase = NULL; //RdrReferenceServer;
|
||
RdrSectionInfo[RdrConnectionDiscardableSection].DataBase = NULL;
|
||
RdrSectionInfo[BowserDiscardableCodeSection].CodeBase = BowserAllocateViewBuffer;
|
||
RdrSectionInfo[BowserDiscardableCodeSection].DataBase = NULL;
|
||
RdrSectionInfo[BowserNetlogonDiscardableCodeSection].CodeBase = BowserNetlogonCopyMessage;
|
||
RdrSectionInfo[BowserNetlogonDiscardableCodeSection].DataBase = NULL;
|
||
|
||
ExInitializeResource(&RdrDiscardableCodeLock);
|
||
|
||
DiscCodeInitialized = TRUE;
|
||
|
||
}
|
||
|
||
VOID
|
||
RdrUninitializeDiscardableCode(
|
||
VOID
|
||
)
|
||
{
|
||
DISCARDABLE_SECTION_NAME SectionName;
|
||
PRDR_SECTION Section;
|
||
|
||
PAGED_CODE();
|
||
|
||
ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
|
||
|
||
DiscCodeInitialized = FALSE;
|
||
|
||
for (SectionName = 0, Section = &RdrSectionInfo[0];
|
||
SectionName < RdrMaxDiscardableSection;
|
||
SectionName += 1, Section++ ) {
|
||
|
||
//
|
||
// Cancel the timer if it is running.
|
||
//
|
||
|
||
if (Section->Timer != NULL) {
|
||
if (!KeCancelTimer(Section->Timer)) {
|
||
|
||
//
|
||
// The timer was active, and we weren't able to cancel it,
|
||
// wait until the timer finishes firing.
|
||
//
|
||
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
KeWaitForSingleObject(&Section->TimerDoneEvent,
|
||
KernelMode, Executive, FALSE, NULL);
|
||
ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
|
||
} else {
|
||
RxFreePool(Section->Timer);
|
||
Section->Timer = NULL;
|
||
}
|
||
}
|
||
|
||
if (Section->Locked) {
|
||
|
||
//
|
||
// Unlock the section.
|
||
//
|
||
|
||
Section->Locked = FALSE;
|
||
|
||
ASSERT (Section->CodeHandle != NULL ||
|
||
Section->DataHandle != NULL);
|
||
|
||
//dprintf(DPRT_DISCCODE, ("RDR: Uninitialize unlock %x\n", Section));
|
||
RxDbgTrace(0,Dbg,("RDR: Uninitialize unlock %x\n", Section));
|
||
|
||
if (Section->CodeHandle != NULL) {
|
||
MmUnlockPagableImageSection(Section->CodeHandle);
|
||
Section->CodeHandle = NULL;
|
||
}
|
||
|
||
if (Section->DataHandle != NULL) {
|
||
MmUnlockPagableImageSection(Section->DataHandle);
|
||
Section->DataHandle = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
ExReleaseResource(&RdrDiscardableCodeLock);
|
||
|
||
ExDeleteResource(&RdrDiscardableCodeLock);
|
||
}
|
||
|