|
|
/*++
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 ); }
|