Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

507 lines
12 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. Pid.c
  5. Abstract:
  6. This module implements the routines for the NetWare
  7. redirector to map 32 bit NT pid values to unique 8 bit
  8. NetWare values.
  9. The technique used is to maintain a table of up to 256 entries.
  10. The index of each entry corresponds directly to the 8 bit pid
  11. values. Each table entry contains the 32 bit pid of the process
  12. that has obtained exclusive access to the pid and the number of
  13. handles opened by that process to this server.
  14. This architecture limits the number of processes on the NT machine
  15. communicating with any one server to 256.
  16. Note: This package assumes that the size that the PidTable grows is
  17. a factor of 256-<initial entries>. This ensures that running out of
  18. valid entries in the table will occur when 256 entries have been
  19. allocated.
  20. Author:
  21. Colin Watson [ColinW] 02-Mar-1993
  22. Revision History:
  23. --*/
  24. #include "Procs.h"
  25. //
  26. // The debug trace level
  27. //
  28. #define Dbg (DEBUG_TRACE_CREATE)
  29. #define INITIAL_MAPPID_ENTRIES 8
  30. #define MAPPID_INCREASE 8
  31. #define MAX_PIDS 256
  32. #define PID_FLAG_EOJ_REQUIRED 0x00000001 // EOJ required for this PID
  33. /*
  34. * The PID mapping table has been moved from a global to a per-SCB structure.
  35. * The limit of 256, or rather 8-bit NetWare task numbers, should be
  36. * only a problem on a per-connection basis. I.E. Each connection is
  37. * now limited to 256 concurrent tasks with a file open.
  38. *
  39. * An example of this working is NAS and OS/2 netx sessions. Each
  40. * netx started is going to use the PSP for the task ID. But each
  41. * netx session on these systems is in a VDM and so have duplicate
  42. * PSP's.
  43. *
  44. * Other than messiness, the only problem with this is that retrieving
  45. * the SCB may be a problem in some circumstances.
  46. *
  47. * P.S. The Resource stuff insists on being non-paged memory.
  48. *
  49. */
  50. #define PidResource pNpScb->RealPidResource //Terminal Server merge
  51. #ifdef ALLOC_PRAGMA
  52. #pragma alloc_text( PAGE, NwInitializePidTable )
  53. #pragma alloc_text( PAGE, NwUninitializePidTable )
  54. #pragma alloc_text( PAGE, NwMapPid )
  55. #pragma alloc_text( PAGE, NwSetEndOfJobRequired )
  56. #pragma alloc_text( PAGE, NwUnmapPid )
  57. #endif
  58. BOOLEAN
  59. NwInitializePidTable(
  60. IN PNONPAGED_SCB pNpScb
  61. )
  62. /*++
  63. Routine Description:
  64. Creates a table for the MapPid package. The initial table has room for
  65. INITIAL_MAPPID_ENTRIES entries.
  66. Arguments:
  67. Return Value:
  68. TRUE or FALSE signifying success or failure.
  69. --*/
  70. {
  71. int i;
  72. PNW_PID_TABLE TempPid =
  73. ALLOCATE_POOL( PagedPool,
  74. FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
  75. (sizeof(NW_PID_TABLE_ENTRY) * INITIAL_MAPPID_ENTRIES ));
  76. PAGED_CODE();
  77. if (TempPid == NULL) {
  78. return( FALSE );
  79. }
  80. TempPid->NodeByteSize = (CSHORT)(FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
  81. (sizeof(NW_PID_TABLE_ENTRY) * INITIAL_MAPPID_ENTRIES) );
  82. TempPid->NodeTypeCode = NW_NTC_PID;
  83. TempPid->ValidEntries = INITIAL_MAPPID_ENTRIES;
  84. //
  85. // Set the ref count for all PIDs to 0, except for pid 0. We
  86. // do this so that we don't allocate PID 0.
  87. //
  88. TempPid->PidTable[0].ReferenceCount = 1;
  89. for (i = 1; i < INITIAL_MAPPID_ENTRIES ; i++ ) {
  90. TempPid->PidTable[i].ReferenceCount = 0;
  91. }
  92. if (pNpScb) {
  93. pNpScb->PidTable = TempPid;
  94. }
  95. ExInitializeResourceLite( &PidResource );
  96. return( TRUE );
  97. }
  98. VOID
  99. NwUninitializePidTable(
  100. IN PNONPAGED_SCB pNpScb
  101. )
  102. /*++
  103. Routine Description:
  104. Deletes a table created by the MapPid package.
  105. Arguments:
  106. Pid - Supplies the table to be deleted.
  107. Return Value:
  108. --*/
  109. {
  110. #ifdef NWDBG
  111. int i;
  112. #endif
  113. PNW_PID_TABLE PidTable = NULL;
  114. PAGED_CODE();
  115. if (pNpScb) {
  116. PidTable = pNpScb->PidTable;
  117. }
  118. #ifdef NWDBG
  119. ASSERT(PidTable->NodeTypeCode == NW_NTC_PID);
  120. ASSERT(PidTable->PidTable[0].ReferenceCount == 1);
  121. for (i = 1; i < PidTable->ValidEntries; i++ ) {
  122. ASSERT(PidTable->PidTable[i].ReferenceCount == 0);
  123. }
  124. #endif
  125. ExAcquireResourceExclusiveLite( &PidResource, TRUE );
  126. if (PidTable) {
  127. FREE_POOL( PidTable );
  128. PidTable = NULL;
  129. }
  130. if (pNpScb) {
  131. pNpScb->PidTable = NULL;
  132. }
  133. ExReleaseResourceLite( &PidResource );
  134. ExDeleteResourceLite( &PidResource );
  135. return;
  136. }
  137. NTSTATUS
  138. NwMapPid(
  139. IN PNONPAGED_SCB pNpScb,
  140. IN ULONG_PTR Pid32,
  141. OUT PUCHAR Pid8
  142. )
  143. /*++
  144. Routine Description:
  145. Obtain an 8 bit unique pid for this process. Either use a previosly
  146. assigned pid for this process or assign an unused value.
  147. Arguments:
  148. Pid - Supplies the datastructure used by MapPid to assign pids for
  149. this server.
  150. Pid32 - Supplies the NT pid to be mapped.
  151. Pid8 - Returns the 8 bit Pid.
  152. Return Value:
  153. NTSTATUS of result.
  154. --*/
  155. {
  156. int i;
  157. int FirstFree = -1;
  158. int NewEntries;
  159. PNW_PID_TABLE TempPid;
  160. PNW_PID_TABLE PidTable;
  161. PAGED_CODE();
  162. ExAcquireResourceExclusiveLite( &PidResource, TRUE );
  163. ASSERT (pNpScb != NULL);
  164. if (pNpScb) {
  165. PidTable = pNpScb->PidTable;
  166. }
  167. // DebugTrace(0, Dbg, "NwMapPid for %08lx\n", Pid32);
  168. for (i=0; i < (PidTable)->ValidEntries ; i++ ) {
  169. if ((PidTable)->PidTable[i].Pid32 == Pid32) {
  170. //
  171. // This process already has an 8 bit pid value assigned.
  172. // Increment the reference and return.
  173. //
  174. (PidTable)->PidTable[i].ReferenceCount++;
  175. *Pid8 = (UCHAR) i;
  176. // DebugTrace(0, Dbg, "NwMapPid found %08lx\n", (DWORD)i);
  177. ExReleaseResourceLite( &PidResource );
  178. ASSERT( *Pid8 != 0 );
  179. return( STATUS_SUCCESS );
  180. }
  181. if ((FirstFree == -1) &&
  182. ((PidTable)->PidTable[i].ReferenceCount == 0)) {
  183. //
  184. // i is the lowest free 8 bit Pid.
  185. //
  186. FirstFree = i;
  187. }
  188. }
  189. //
  190. // This process does not have a pid assigned.
  191. //
  192. if ( FirstFree != -1 ) {
  193. //
  194. // We had an empty slot so assign it to this process.
  195. //
  196. (PidTable)->PidTable[FirstFree].ReferenceCount++;
  197. (PidTable)->PidTable[FirstFree].Pid32 = Pid32;
  198. *Pid8 = (UCHAR) FirstFree;
  199. DebugTrace(0, DEBUG_TRACE_ICBS, "NwMapPid maps %08lx\n", (DWORD)FirstFree);
  200. ExReleaseResourceLite( &PidResource );
  201. ASSERT( *Pid8 != 0 );
  202. return( STATUS_SUCCESS );
  203. }
  204. if ( (PidTable)->ValidEntries == MAX_PIDS ) {
  205. //
  206. // We've run out of 8 bit pids.
  207. //
  208. ExReleaseResourceLite( &PidResource );
  209. #ifdef NWDBG
  210. //
  211. // temporary code to find the PID leak.
  212. //
  213. DumpIcbs() ;
  214. ASSERT(FALSE) ;
  215. #endif
  216. return(STATUS_TOO_MANY_OPENED_FILES);
  217. }
  218. //
  219. // Grow the table by MAPPID_INCREASE entries.
  220. //
  221. NewEntries = (PidTable)->ValidEntries + MAPPID_INCREASE;
  222. TempPid =
  223. ALLOCATE_POOL( PagedPool,
  224. FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
  225. (sizeof(NW_PID_TABLE_ENTRY) * NewEntries ));
  226. if (TempPid == NULL) {
  227. ExReleaseResourceLite( &PidResource );
  228. return( STATUS_INSUFFICIENT_RESOURCES );
  229. }
  230. RtlMoveMemory(
  231. TempPid,
  232. (PidTable),
  233. FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
  234. (sizeof(NW_PID_TABLE_ENTRY) * (PidTable)->ValidEntries ));
  235. TempPid->NodeByteSize = (CSHORT)(FIELD_OFFSET( NW_PID_TABLE, PidTable[0] ) +
  236. (sizeof(NW_PID_TABLE_ENTRY) * NewEntries) );
  237. for ( i = (PidTable)->ValidEntries; i < NewEntries ; i++ ) {
  238. TempPid->PidTable[i].ReferenceCount = 0;
  239. }
  240. TempPid->ValidEntries = NewEntries;
  241. //
  242. // Save the index of the first free entry.
  243. //
  244. i = (PidTable)->ValidEntries;
  245. //
  246. // The new table is initialized. Free up the old table and return
  247. // the first of the new entries.
  248. //
  249. FREE_POOL(PidTable);
  250. PidTable = TempPid;
  251. (PidTable)->PidTable[i].ReferenceCount = 1;
  252. (PidTable)->PidTable[i].Pid32 = Pid32;
  253. *Pid8 = (UCHAR) i;
  254. ASSERT (pNpScb != NULL);
  255. if (pNpScb) {
  256. pNpScb->PidTable = PidTable;
  257. }
  258. DebugTrace(0, DEBUG_TRACE_ICBS, "NwMapPid grows & maps %08lx\n", (DWORD)i);
  259. ExReleaseResourceLite( &PidResource );
  260. return( STATUS_SUCCESS );
  261. }
  262. VOID
  263. NwSetEndOfJobRequired(
  264. IN PNONPAGED_SCB pNpScb,
  265. IN UCHAR Pid8
  266. )
  267. /*++
  268. Routine Description:
  269. Mark a PID as must send End Of Job when the pid reference count
  270. reaches zero.
  271. Arguments:
  272. Pid8 - The 8 bit Pid to mark.
  273. Return Value:
  274. None.
  275. --*/
  276. {
  277. PNW_PID_TABLE PidTable;
  278. PAGED_CODE();
  279. ASSERT( Pid8 != 0 );
  280. ASSERT (pNpScb != NULL);
  281. ExAcquireResourceExclusiveLite( &PidResource, TRUE );
  282. PidTable = pNpScb->PidTable;
  283. // DebugTrace(0, Dbg, "NwSetEndofJob for %08lx\n", (DWORD)Pid8);
  284. SetFlag( PidTable->PidTable[Pid8].Flags, PID_FLAG_EOJ_REQUIRED );
  285. ExReleaseResourceLite( &PidResource );
  286. return;
  287. }
  288. VOID
  289. NwUnmapPid(
  290. IN PNONPAGED_SCB pNpScb,
  291. IN UCHAR Pid8,
  292. IN PIRP_CONTEXT IrpContext OPTIONAL
  293. )
  294. /*++
  295. Routine Description:
  296. This routine dereference an 8 bit PID. If the reference count reaches
  297. zero and this PID is marked End Of Job required, this routine will
  298. also send an EOJ NCP for this PID.
  299. Arguments:
  300. Pid8 - The 8 bit Pid to mark.
  301. IrpContext - The IrpContext for the IRP in progress.
  302. Return Value:
  303. None.
  304. --*/
  305. {
  306. BOOLEAN EndOfJob;
  307. PNW_PID_TABLE PidTable;
  308. PAGED_CODE();
  309. ASSERT( Pid8 != 0 );
  310. // DebugTrace(0, Dbg, "NwUnmapPid %08lx\n", (DWORD)Pid8);
  311. // I think this can occur during shutdown and errors
  312. if ( pNpScb == NULL ) {
  313. return;
  314. }
  315. // This was reported as a problem.
  316. if ( !pNpScb->PidTable ) {
  317. return;
  318. }
  319. ExAcquireResourceExclusiveLite( &PidResource, TRUE ); // MP safety
  320. PidTable = pNpScb->PidTable;
  321. if ( BooleanFlagOn( PidTable->PidTable[Pid8].Flags, PID_FLAG_EOJ_REQUIRED ) &&
  322. IrpContext != NULL ) {
  323. ExReleaseResourceLite( &PidResource );
  324. //
  325. // The End of job flag is set. Obtain a position at the front of
  326. // the SCB queue, so that if we need to set an EOJ NCP, we needn't
  327. // wait for the SCB queue while holding the PID table lock.
  328. //
  329. EndOfJob = TRUE;
  330. NwAppendToQueueAndWait( IrpContext );
  331. if ( !pNpScb->PidTable ) {
  332. return;
  333. }
  334. ExAcquireResourceExclusiveLite( &PidResource, TRUE ); // MP safety
  335. } else {
  336. EndOfJob = FALSE;
  337. }
  338. //
  339. // The PidResource lock controls the reference counts.
  340. //
  341. ASSERT (pNpScb != NULL);
  342. //ExAcquireResourceExclusiveLite( &PidResource, TRUE );
  343. // WWM - Since we release the lock while we wait, pidtable may have moved
  344. PidTable = pNpScb->PidTable;
  345. if ( !PidTable ) {
  346. return;
  347. }
  348. if ( --(PidTable)->PidTable[Pid8].ReferenceCount == 0 ) {
  349. //
  350. // Done with this PID, send an EOJ if necessary.
  351. //
  352. // DebugTrace(0, Dbg, "NwUnmapPid (ref=0) %08lx\n", (DWORD)Pid8);
  353. (PidTable)->PidTable[Pid8].Flags = 0;
  354. (PidTable)->PidTable[Pid8].Pid32 = 0;
  355. if ( EndOfJob ) {
  356. (VOID) ExchangeWithWait(
  357. IrpContext,
  358. SynchronousResponseCallback,
  359. "F-",
  360. NCP_END_OF_JOB );
  361. }
  362. }
  363. if ( EndOfJob ) {
  364. NwDequeueIrpContext( IrpContext, FALSE );
  365. }
  366. ExReleaseResourceLite( &PidResource );
  367. }