508 lines
12 KiB
C
508 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
Pid.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the routines for the NetWare
|
|||
|
redirector to map 32 bit NT pid values to unique 8 bit
|
|||
|
NetWare values.
|
|||
|
|
|||
|
The technique used is to maintain a table of up to 256 entries.
|
|||
|
The index of each entry corresponds directly to the 8 bit pid
|
|||
|
values. Each table entry contains the 32 bit pid of the process
|
|||
|
that has obtained exclusive access to the pid and the number of
|
|||
|
handles opened by that process to this server.
|
|||
|
|
|||
|
This architecture limits the number of processes on the NT machine
|
|||
|
communicating with any one server to 256.
|
|||
|
|
|||
|
Note: This package assumes that the size that the PidTable grows is
|
|||
|
a factor of 256-<initial entries>. This ensures that running out of
|
|||
|
valid entries in the table will occur when 256 entries have been
|
|||
|
allocated.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Colin Watson [ColinW] 02-Mar-1993
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "Procs.h"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The debug trace level
|
|||
|
//
|
|||
|
|
|||
|
#define Dbg (DEBUG_TRACE_CREATE)
|
|||
|
|
|||
|
#define INITIAL_MAPPID_ENTRIES 8
|
|||
|
#define MAPPID_INCREASE 8
|
|||
|
#define MAX_PIDS 256
|
|||
|
|
|||
|
#define PID_FLAG_EOJ_REQUIRED 0x00000001 // EOJ required for this PID
|
|||
|
|
|||
|
/*
|
|||
|
* The PID mapping table has been moved from a global to a per-SCB structure.
|
|||
|
* The limit of 256, or rather 8-bit NetWare task numbers, should be
|
|||
|
* only a problem on a per-connection basis. I.E. Each connection is
|
|||
|
* now limited to 256 concurrent tasks with a file open.
|
|||
|
*
|
|||
|
* An example of this working is NAS and OS/2 netx sessions. Each
|
|||
|
* netx started is going to use the PSP for the task ID. But each
|
|||
|
* netx session on these systems is in a VDM and so have duplicate
|
|||
|
* PSP's.
|
|||
|
*
|
|||
|
* Other than messiness, the only problem with this is that retrieving
|
|||
|
* the SCB may be a problem in some circumstances.
|
|||
|
*
|
|||
|
* P.S. The Resource stuff insists on being non-paged memory.
|
|||
|
*
|
|||
|
*/
|
|||
|
|
|||
|
#define PidResource pNpScb->RealPidResource //Terminal Server merge
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text( PAGE, NwInitializePidTable )
|
|||
|
#pragma alloc_text( PAGE, NwUninitializePidTable )
|
|||
|
#pragma alloc_text( PAGE, NwMapPid )
|
|||
|
#pragma alloc_text( PAGE, NwSetEndOfJobRequired )
|
|||
|
#pragma alloc_text( PAGE, NwUnmapPid )
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
NwInitializePidTable(
|
|||
|
IN PNONPAGED_SCB pNpScb
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Creates a table for the MapPid package. The initial table has room for
|
|||
|
INITIAL_MAPPID_ENTRIES entries.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE or FALSE signifying success or failure.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
int i;
|
|||
|
PNW_PID_TABLE TempPid =
|
|||
|
ALLOCATE_POOL( PagedPool,
|
|||
|
FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
|
|||
|
(sizeof(NW_PID_TABLE_ENTRY) * INITIAL_MAPPID_ENTRIES ));
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
if (TempPid == NULL) {
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
TempPid->NodeByteSize = (CSHORT)(FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
|
|||
|
(sizeof(NW_PID_TABLE_ENTRY) * INITIAL_MAPPID_ENTRIES) );
|
|||
|
|
|||
|
TempPid->NodeTypeCode = NW_NTC_PID;
|
|||
|
|
|||
|
TempPid->ValidEntries = INITIAL_MAPPID_ENTRIES;
|
|||
|
|
|||
|
//
|
|||
|
// Set the ref count for all PIDs to 0, except for pid 0. We
|
|||
|
// do this so that we don't allocate PID 0.
|
|||
|
//
|
|||
|
|
|||
|
TempPid->PidTable[0].ReferenceCount = 1;
|
|||
|
for (i = 1; i < INITIAL_MAPPID_ENTRIES ; i++ ) {
|
|||
|
TempPid->PidTable[i].ReferenceCount = 0;
|
|||
|
}
|
|||
|
if (pNpScb) {
|
|||
|
pNpScb->PidTable = TempPid;
|
|||
|
}
|
|||
|
|
|||
|
ExInitializeResourceLite( &PidResource );
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NwUninitializePidTable(
|
|||
|
IN PNONPAGED_SCB pNpScb
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Deletes a table created by the MapPid package.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pid - Supplies the table to be deleted.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
#ifdef NWDBG
|
|||
|
int i;
|
|||
|
#endif
|
|||
|
PNW_PID_TABLE PidTable = NULL;
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
if (pNpScb) {
|
|||
|
PidTable = pNpScb->PidTable;
|
|||
|
}
|
|||
|
#ifdef NWDBG
|
|||
|
ASSERT(PidTable->NodeTypeCode == NW_NTC_PID);
|
|||
|
ASSERT(PidTable->PidTable[0].ReferenceCount == 1);
|
|||
|
|
|||
|
for (i = 1; i < PidTable->ValidEntries; i++ ) {
|
|||
|
ASSERT(PidTable->PidTable[i].ReferenceCount == 0);
|
|||
|
}
|
|||
|
#endif
|
|||
|
ExAcquireResourceExclusiveLite( &PidResource, TRUE );
|
|||
|
if (PidTable) {
|
|||
|
FREE_POOL( PidTable );
|
|||
|
PidTable = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (pNpScb) {
|
|||
|
pNpScb->PidTable = NULL;
|
|||
|
}
|
|||
|
|
|||
|
ExReleaseResourceLite( &PidResource );
|
|||
|
|
|||
|
ExDeleteResourceLite( &PidResource );
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NwMapPid(
|
|||
|
IN PNONPAGED_SCB pNpScb,
|
|||
|
IN ULONG_PTR Pid32,
|
|||
|
OUT PUCHAR Pid8
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Obtain an 8 bit unique pid for this process. Either use a previosly
|
|||
|
assigned pid for this process or assign an unused value.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pid - Supplies the datastructure used by MapPid to assign pids for
|
|||
|
this server.
|
|||
|
|
|||
|
Pid32 - Supplies the NT pid to be mapped.
|
|||
|
|
|||
|
Pid8 - Returns the 8 bit Pid.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS of result.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
int i;
|
|||
|
int FirstFree = -1;
|
|||
|
int NewEntries;
|
|||
|
PNW_PID_TABLE TempPid;
|
|||
|
PNW_PID_TABLE PidTable;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite( &PidResource, TRUE );
|
|||
|
ASSERT (pNpScb != NULL);
|
|||
|
if (pNpScb) {
|
|||
|
PidTable = pNpScb->PidTable;
|
|||
|
}
|
|||
|
// DebugTrace(0, Dbg, "NwMapPid for %08lx\n", Pid32);
|
|||
|
|
|||
|
for (i=0; i < (PidTable)->ValidEntries ; i++ ) {
|
|||
|
|
|||
|
if ((PidTable)->PidTable[i].Pid32 == Pid32) {
|
|||
|
|
|||
|
//
|
|||
|
// This process already has an 8 bit pid value assigned.
|
|||
|
// Increment the reference and return.
|
|||
|
//
|
|||
|
|
|||
|
(PidTable)->PidTable[i].ReferenceCount++;
|
|||
|
*Pid8 = (UCHAR) i;
|
|||
|
|
|||
|
// DebugTrace(0, Dbg, "NwMapPid found %08lx\n", (DWORD)i);
|
|||
|
|
|||
|
ExReleaseResourceLite( &PidResource );
|
|||
|
ASSERT( *Pid8 != 0 );
|
|||
|
return( STATUS_SUCCESS );
|
|||
|
}
|
|||
|
|
|||
|
if ((FirstFree == -1) &&
|
|||
|
((PidTable)->PidTable[i].ReferenceCount == 0)) {
|
|||
|
|
|||
|
//
|
|||
|
// i is the lowest free 8 bit Pid.
|
|||
|
//
|
|||
|
|
|||
|
FirstFree = i;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This process does not have a pid assigned.
|
|||
|
//
|
|||
|
|
|||
|
if ( FirstFree != -1 ) {
|
|||
|
|
|||
|
//
|
|||
|
// We had an empty slot so assign it to this process.
|
|||
|
//
|
|||
|
|
|||
|
(PidTable)->PidTable[FirstFree].ReferenceCount++;
|
|||
|
(PidTable)->PidTable[FirstFree].Pid32 = Pid32;
|
|||
|
*Pid8 = (UCHAR) FirstFree;
|
|||
|
|
|||
|
DebugTrace(0, DEBUG_TRACE_ICBS, "NwMapPid maps %08lx\n", (DWORD)FirstFree);
|
|||
|
|
|||
|
ExReleaseResourceLite( &PidResource );
|
|||
|
ASSERT( *Pid8 != 0 );
|
|||
|
return( STATUS_SUCCESS );
|
|||
|
}
|
|||
|
|
|||
|
if ( (PidTable)->ValidEntries == MAX_PIDS ) {
|
|||
|
|
|||
|
//
|
|||
|
// We've run out of 8 bit pids.
|
|||
|
//
|
|||
|
|
|||
|
ExReleaseResourceLite( &PidResource );
|
|||
|
|
|||
|
#ifdef NWDBG
|
|||
|
//
|
|||
|
// temporary code to find the PID leak.
|
|||
|
//
|
|||
|
DumpIcbs() ;
|
|||
|
ASSERT(FALSE) ;
|
|||
|
#endif
|
|||
|
|
|||
|
return(STATUS_TOO_MANY_OPENED_FILES);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Grow the table by MAPPID_INCREASE entries.
|
|||
|
//
|
|||
|
|
|||
|
NewEntries = (PidTable)->ValidEntries + MAPPID_INCREASE;
|
|||
|
|
|||
|
TempPid =
|
|||
|
ALLOCATE_POOL( PagedPool,
|
|||
|
FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
|
|||
|
(sizeof(NW_PID_TABLE_ENTRY) * NewEntries ));
|
|||
|
|
|||
|
if (TempPid == NULL) {
|
|||
|
ExReleaseResourceLite( &PidResource );
|
|||
|
return( STATUS_INSUFFICIENT_RESOURCES );
|
|||
|
}
|
|||
|
|
|||
|
RtlMoveMemory(
|
|||
|
TempPid,
|
|||
|
(PidTable),
|
|||
|
FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
|
|||
|
(sizeof(NW_PID_TABLE_ENTRY) * (PidTable)->ValidEntries ));
|
|||
|
|
|||
|
|
|||
|
TempPid->NodeByteSize = (CSHORT)(FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
|
|||
|
(sizeof(NW_PID_TABLE_ENTRY) * NewEntries) );
|
|||
|
|
|||
|
for ( i = (PidTable)->ValidEntries; i < NewEntries ; i++ ) {
|
|||
|
TempPid->PidTable[i].ReferenceCount = 0;
|
|||
|
}
|
|||
|
|
|||
|
TempPid->ValidEntries = NewEntries;
|
|||
|
|
|||
|
//
|
|||
|
// Save the index of the first free entry.
|
|||
|
//
|
|||
|
|
|||
|
i = (PidTable)->ValidEntries;
|
|||
|
|
|||
|
//
|
|||
|
// The new table is initialized. Free up the old table and return
|
|||
|
// the first of the new entries.
|
|||
|
//
|
|||
|
|
|||
|
FREE_POOL(PidTable);
|
|||
|
PidTable = TempPid;
|
|||
|
|
|||
|
(PidTable)->PidTable[i].ReferenceCount = 1;
|
|||
|
(PidTable)->PidTable[i].Pid32 = Pid32;
|
|||
|
*Pid8 = (UCHAR) i;
|
|||
|
|
|||
|
ASSERT (pNpScb != NULL);
|
|||
|
if (pNpScb) {
|
|||
|
pNpScb->PidTable = PidTable;
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(0, DEBUG_TRACE_ICBS, "NwMapPid grows & maps %08lx\n", (DWORD)i);
|
|||
|
|
|||
|
ExReleaseResourceLite( &PidResource );
|
|||
|
return( STATUS_SUCCESS );
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
NwSetEndOfJobRequired(
|
|||
|
IN PNONPAGED_SCB pNpScb,
|
|||
|
IN UCHAR Pid8
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Mark a PID as must send End Of Job when the pid reference count
|
|||
|
reaches zero.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pid8 - The 8 bit Pid to mark.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PNW_PID_TABLE PidTable;
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT( Pid8 != 0 );
|
|||
|
ASSERT (pNpScb != NULL);
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite( &PidResource, TRUE );
|
|||
|
PidTable = pNpScb->PidTable;
|
|||
|
|
|||
|
// DebugTrace(0, Dbg, "NwSetEndofJob for %08lx\n", (DWORD)Pid8);
|
|||
|
SetFlag( PidTable->PidTable[Pid8].Flags, PID_FLAG_EOJ_REQUIRED );
|
|||
|
ExReleaseResourceLite( &PidResource );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NwUnmapPid(
|
|||
|
IN PNONPAGED_SCB pNpScb,
|
|||
|
IN UCHAR Pid8,
|
|||
|
IN PIRP_CONTEXT IrpContext OPTIONAL
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine dereference an 8 bit PID. If the reference count reaches
|
|||
|
zero and this PID is marked End Of Job required, this routine will
|
|||
|
also send an EOJ NCP for this PID.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pid8 - The 8 bit Pid to mark.
|
|||
|
|
|||
|
IrpContext - The IrpContext for the IRP in progress.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOLEAN EndOfJob;
|
|||
|
PNW_PID_TABLE PidTable;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
ASSERT( Pid8 != 0 );
|
|||
|
// DebugTrace(0, Dbg, "NwUnmapPid %08lx\n", (DWORD)Pid8);
|
|||
|
|
|||
|
// I think this can occur during shutdown and errors
|
|||
|
if ( pNpScb == NULL ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
// This was reported as a problem.
|
|||
|
if ( !pNpScb->PidTable ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite( &PidResource, TRUE ); // MP safety
|
|||
|
PidTable = pNpScb->PidTable;
|
|||
|
|
|||
|
if ( BooleanFlagOn( PidTable->PidTable[Pid8].Flags, PID_FLAG_EOJ_REQUIRED ) &&
|
|||
|
IrpContext != NULL ) {
|
|||
|
ExReleaseResourceLite( &PidResource );
|
|||
|
//
|
|||
|
// The End of job flag is set. Obtain a position at the front of
|
|||
|
// the SCB queue, so that if we need to set an EOJ NCP, we needn't
|
|||
|
// wait for the SCB queue while holding the PID table lock.
|
|||
|
//
|
|||
|
|
|||
|
EndOfJob = TRUE;
|
|||
|
NwAppendToQueueAndWait( IrpContext );
|
|||
|
|
|||
|
if ( !pNpScb->PidTable ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
ExAcquireResourceExclusiveLite( &PidResource, TRUE ); // MP safety
|
|||
|
|
|||
|
} else {
|
|||
|
EndOfJob = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The PidResource lock controls the reference counts.
|
|||
|
//
|
|||
|
ASSERT (pNpScb != NULL);
|
|||
|
//ExAcquireResourceExclusiveLite( &PidResource, TRUE );
|
|||
|
// WWM - Since we release the lock while we wait, pidtable may have moved
|
|||
|
PidTable = pNpScb->PidTable;
|
|||
|
if ( !PidTable ) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if ( --(PidTable)->PidTable[Pid8].ReferenceCount == 0 ) {
|
|||
|
|
|||
|
//
|
|||
|
// Done with this PID, send an EOJ if necessary.
|
|||
|
//
|
|||
|
|
|||
|
// DebugTrace(0, Dbg, "NwUnmapPid (ref=0) %08lx\n", (DWORD)Pid8);
|
|||
|
(PidTable)->PidTable[Pid8].Flags = 0;
|
|||
|
(PidTable)->PidTable[Pid8].Pid32 = 0;
|
|||
|
|
|||
|
if ( EndOfJob ) {
|
|||
|
(VOID) ExchangeWithWait(
|
|||
|
IrpContext,
|
|||
|
SynchronousResponseCallback,
|
|||
|
"F-",
|
|||
|
NCP_END_OF_JOB );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( EndOfJob ) {
|
|||
|
NwDequeueIrpContext( IrpContext, FALSE );
|
|||
|
}
|
|||
|
|
|||
|
ExReleaseResourceLite( &PidResource );
|
|||
|
}
|
|||
|
|