Leaked source code of windows server 2003
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.

817 lines
25 KiB

  1. /*++ BUILD Version: 0009 // Increment this if a change has global effects
  2. Copyright (c) 1987-1993 Microsoft Corporation
  3. Module Name:
  4. midatlas.c
  5. Abstract:
  6. This module defines the data structure used in mapping MIDS to the
  7. corresponding requests/contexts associated with them.
  8. Author:
  9. Balan Sethu Raman (SethuR) 26-Aug-95 Created
  10. Notes:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, _InitializeMidMapFreeList)
  16. #pragma alloc_text(PAGE, FsRtlCreateMidAtlas)
  17. #pragma alloc_text(PAGE, _UninitializeMidMap)
  18. #pragma alloc_text(PAGE, FsRtlDestroyMidAtlas)
  19. #endif
  20. #define ENTRY_TYPE_FREE_MID_LIST (0x1)
  21. #define ENTRY_TYPE_VALID_CONTEXT (0x2)
  22. #define ENTRY_TYPE_MID_MAP (0x3)
  23. #define ENTRY_TYPE_MASK (0x3)
  24. #define MID_MAP_FLAGS_CAN_BE_EXPANDED (0x1)
  25. #define MID_MAP_FLAGS_FREE_POOL (0x2)
  26. typedef struct _MID_MAP_ {
  27. LIST_ENTRY MidMapList; // the list of MID maps in the MID atlas
  28. USHORT MaximumNumberOfMids; // the maximum number of MIDs in this map
  29. USHORT NumberOfMidsInUse; // the number of MIDs in use
  30. USHORT BaseMid; // the base MID associated with the map
  31. USHORT IndexMask; // the index mask for this map
  32. UCHAR IndexAlignmentCount; // the bits by which the index field is to be shifted
  33. UCHAR IndexFieldWidth; // the index field width
  34. UCHAR Flags; // flags ...
  35. UCHAR Level; // the level associated with this map ( useful for expansion )
  36. PVOID *pFreeMidListHead; // the list of free mid entries in this map
  37. PVOID Entries[1]; // the MID map entries.
  38. } MID_MAP, *PMID_MAP;
  39. //INLINE ULONG _GetEntryType(PVOID pEntry)
  40. #define _GetEntryType(pEntry) \
  41. ((ULONG)((ULONG_PTR)pEntry) & ENTRY_TYPE_MASK)
  42. //INLINE PVOID _GetEntryPointer(PVOID pEntry)
  43. #define _GetEntryPointer(pEntry) \
  44. ((PVOID)((ULONG_PTR)pEntry & ~ENTRY_TYPE_MASK))
  45. #define _MakeEntry(pContext,EntryType) \
  46. (PVOID)((ULONG_PTR)(pContext) | (EntryType))
  47. //INLINE PMID_MAP _GetFirstMidMap()
  48. /*++
  49. Routine Description:
  50. This first MID_MAP instance in the list
  51. Return Value:
  52. a valid PMID_MAP, NULL if none exists.
  53. Notes:
  54. This routine assumes that the necessary concurrency control action has been taken
  55. --*/
  56. #define _GetFirstMidMap(pListHead) \
  57. (IsListEmpty(pListHead) \
  58. ? NULL \
  59. : (PMID_MAP) \
  60. (CONTAINING_RECORD((pListHead)->Flink, \
  61. MID_MAP, \
  62. MidMapList)))
  63. //INLINE PSMBCEDB_SERVER_ENTRY GetNextMidMap(PLIST_ENTRY pListHead, PMID_MAP pMidMap)
  64. /*++
  65. Routine Description:
  66. This routine returns the next MID_MAP in the list
  67. Arguments:
  68. pListHead - the list of MID_MAP's
  69. pMidMap - the current instance
  70. Return Value:
  71. a valid PMID_MAP, NULL if none exists.
  72. Notes:
  73. This routine assumes that the necessary concurrency control action has been taken
  74. --*/
  75. #define _GetNextMidMap(pListHead,pMidMap) \
  76. (((pMidMap)->MidMapList.Flink == pListHead) \
  77. ? NULL \
  78. : (PMID_MAP) \
  79. (CONTAINING_RECORD((pMidMap)->MidMapList.Flink, \
  80. MID_MAP, \
  81. MidMapList)))
  82. //INLINE VOID _AddMidMap(
  83. // PLIST_ENTRY pListHead,
  84. // PMID_MAP pMidMap)
  85. /*++
  86. Routine Description:
  87. This routine adds a MID_MAP instance to a list
  88. Arguments:
  89. pListHead - the list of MID_MAP's
  90. pMidMap - the MID_MAP to be added
  91. --*/
  92. #define _AddMidMap(pListHead,pMidMap) \
  93. { \
  94. PMID_MAP pPredecessor; \
  95. pPredecessor = _GetFirstMidMap(pListHead); \
  96. while (pPredecessor != NULL) { \
  97. if (pPredecessor->Level < pMidMap->Level) { \
  98. pPredecessor = _GetNextMidMap(pListHead,pPredecessor); \
  99. } else { \
  100. pPredecessor = (PMID_MAP) \
  101. CONTAINING_RECORD( \
  102. pPredecessor->MidMapList.Blink, \
  103. MID_MAP, \
  104. MidMapList); \
  105. break; \
  106. } \
  107. } \
  108. \
  109. if (pPredecessor == NULL) { \
  110. InsertTailList(pListHead,&((pMidMap)->MidMapList)); \
  111. } else { \
  112. (pMidMap)->MidMapList.Flink = pPredecessor->MidMapList.Flink; \
  113. pPredecessor->MidMapList.Flink = &(pMidMap)->MidMapList; \
  114. \
  115. (pMidMap)->MidMapList.Blink = &pPredecessor->MidMapList; \
  116. (pMidMap)->MidMapList.Flink->Blink = &(pMidMap)->MidMapList; \
  117. } \
  118. }
  119. //INLINE VOID _RemoveMidMap(PMID_MAP pMidMap)
  120. /*++
  121. Routine Description:
  122. This routine removes a MID_MAP instance from the list
  123. Arguments:
  124. pMidMap - the MID_MAP instance to be removed
  125. --*/
  126. #define _RemoveMidMap(pMidMap) \
  127. RemoveEntryList(&(pMidMap)->MidMapList)
  128. VOID
  129. _InitializeMidMapFreeList(PMID_MAP pMidMap)
  130. /*++
  131. Routine Description:
  132. This routine initializes a MID_MAP data structure.
  133. Arguments:
  134. pMidMap - the MID_MAP instance to be initialized.
  135. Notes:
  136. --*/
  137. {
  138. USHORT i;
  139. PVOID *pEntryValue = (PVOID *)&pMidMap->Entries[1];
  140. PVOID *pEntriesPointer = (PVOID *)&pMidMap->Entries;
  141. PAGED_CODE();
  142. //DbgPrint("_InitializeMidMapFreeList .. Entry\n");
  143. if (pMidMap->MaximumNumberOfMids > 0) {
  144. pMidMap->pFreeMidListHead = pMidMap->Entries;
  145. for (i = 1; i <= pMidMap->MaximumNumberOfMids - 1;i++,pEntryValue++) {
  146. *pEntriesPointer++ = _MakeEntry(pEntryValue,ENTRY_TYPE_FREE_MID_LIST);
  147. }
  148. *pEntriesPointer = _MakeEntry(NULL,ENTRY_TYPE_FREE_MID_LIST);
  149. }
  150. //DbgPrint("_InitializeMidMapFreeList .. Exit\n");
  151. }
  152. PMID_ATLAS
  153. FsRtlCreateMidAtlas(
  154. USHORT MaximumNumberOfMids,
  155. USHORT MidsAllocatedAtStart)
  156. /*++
  157. Routine Description:
  158. This routine allocates a new instance of MID_ATLAS data structure.
  159. Arguments:
  160. MaximumNumberOfMids - the maximum number of MIDS in the atlas.
  161. MidsAllocatedAtStart - the number of MIDS allocated at start
  162. Notes:
  163. --*/
  164. {
  165. PMID_ATLAS pMidAtlas;
  166. PMID_MAP pMidMap;
  167. ULONG AtlasSize;
  168. USHORT MidsAllocatedRoundedToPowerOf2;
  169. USHORT MaximumMidsRoundedToPowerOf2;
  170. UCHAR MidFieldWidth,MaximumMidFieldWidth;
  171. PAGED_CODE();
  172. // Round off the Mids allocated at Start to a power of two
  173. MaximumMidsRoundedToPowerOf2 = 0x100;
  174. MaximumMidFieldWidth = 8;
  175. if (MaximumMidsRoundedToPowerOf2 != MaximumNumberOfMids) {
  176. if (MaximumNumberOfMids > MaximumMidsRoundedToPowerOf2) {
  177. while (MaximumNumberOfMids > MaximumMidsRoundedToPowerOf2) {
  178. MaximumMidsRoundedToPowerOf2 = MaximumMidsRoundedToPowerOf2 << 1;
  179. MaximumMidFieldWidth++;
  180. }
  181. } else {
  182. while (MaximumNumberOfMids < MaximumMidsRoundedToPowerOf2) {
  183. MaximumMidsRoundedToPowerOf2 = MaximumMidsRoundedToPowerOf2 >> 1;
  184. MaximumMidFieldWidth--;
  185. }
  186. MaximumMidFieldWidth++;
  187. MaximumMidsRoundedToPowerOf2 = MaximumMidsRoundedToPowerOf2 << 1;
  188. }
  189. }
  190. MidsAllocatedRoundedToPowerOf2 = 0x100;
  191. MidFieldWidth = 8;
  192. if (MidsAllocatedRoundedToPowerOf2 != MidsAllocatedAtStart) {
  193. if (MidsAllocatedAtStart > MidsAllocatedRoundedToPowerOf2) {
  194. while (MidsAllocatedAtStart > MidsAllocatedRoundedToPowerOf2) {
  195. MidsAllocatedRoundedToPowerOf2 = MidsAllocatedRoundedToPowerOf2 << 1;
  196. MidFieldWidth++;
  197. }
  198. } else {
  199. while (MidsAllocatedAtStart < MidsAllocatedRoundedToPowerOf2) {
  200. MidsAllocatedRoundedToPowerOf2 = MidsAllocatedRoundedToPowerOf2 >> 1;
  201. MidFieldWidth--;
  202. }
  203. MidFieldWidth++;
  204. MidsAllocatedRoundedToPowerOf2 = MidsAllocatedRoundedToPowerOf2 << 1;
  205. }
  206. }
  207. AtlasSize = sizeof(MID_ATLAS) +
  208. FIELD_OFFSET(MID_MAP,Entries);
  209. if (MaximumNumberOfMids == MidsAllocatedAtStart) {
  210. AtlasSize += (sizeof(PVOID) * MidsAllocatedAtStart);
  211. } else {
  212. AtlasSize += (sizeof(PVOID) * MidsAllocatedRoundedToPowerOf2);
  213. }
  214. pMidAtlas = (PMID_ATLAS)RxAllocatePoolWithTag(
  215. NonPagedPool,
  216. AtlasSize,
  217. MRXSMB_MIDATLAS_POOLTAG);
  218. if (pMidAtlas != NULL) {
  219. pMidMap = (PMID_MAP)(pMidAtlas + 1);
  220. pMidMap->Flags = 0;
  221. pMidAtlas->MaximumNumberOfMids = MaximumNumberOfMids;
  222. pMidAtlas->MidsAllocated = MidsAllocatedAtStart;
  223. pMidAtlas->NumberOfMidsInUse = 0;
  224. pMidAtlas->NumberOfMidsDiscarded = 0;
  225. pMidAtlas->MaximumMidFieldWidth = MaximumMidFieldWidth;
  226. pMidMap->MaximumNumberOfMids = MidsAllocatedAtStart;
  227. pMidMap->NumberOfMidsInUse = 0;
  228. pMidMap->BaseMid = 0;
  229. pMidMap->IndexMask = MidsAllocatedRoundedToPowerOf2 - 1;
  230. pMidMap->IndexAlignmentCount = 0;
  231. pMidMap->IndexFieldWidth = MidFieldWidth;
  232. pMidMap->Level = 1;
  233. InitializeListHead(&pMidAtlas->MidMapFreeList);
  234. InitializeListHead(&pMidAtlas->MidMapExpansionList);
  235. _InitializeMidMapFreeList(pMidMap);
  236. _AddMidMap(&pMidAtlas->MidMapFreeList,pMidMap);
  237. pMidAtlas->pRootMidMap = pMidMap;
  238. if (MaximumNumberOfMids > MidsAllocatedAtStart) {
  239. // Round off the maximum number of MIDS to determine the level and the
  240. // size of the quantum ( allocation increments)
  241. pMidMap->Flags |= MID_MAP_FLAGS_CAN_BE_EXPANDED;
  242. pMidAtlas->MidQuantum = 32;
  243. pMidAtlas->MidQuantumFieldWidth = 5;
  244. MaximumMidsRoundedToPowerOf2 = MaximumMidsRoundedToPowerOf2 >> (pMidMap->IndexAlignmentCount + 5);
  245. if (MaximumMidsRoundedToPowerOf2 > 0) {
  246. pMidAtlas->NumberOfLevels = 3;
  247. } else {
  248. pMidAtlas->NumberOfLevels = 2;
  249. }
  250. } else {
  251. pMidAtlas->MidQuantum = 0;
  252. pMidAtlas->NumberOfLevels = 1;
  253. pMidMap->Flags &= ~MID_MAP_FLAGS_CAN_BE_EXPANDED;
  254. }
  255. }
  256. //DbgPrint("FsRtlAllocatMidAtlas .. Exit (pMidAtlas) %lx\n",pMidAtlas);
  257. return pMidAtlas;
  258. }
  259. VOID
  260. _UninitializeMidMap(
  261. PMID_MAP pMidMap,
  262. PCONTEXT_DESTRUCTOR pContextDestructor)
  263. /*++
  264. Routine Description:
  265. This routine uninitializes a MID_MAP data structure.
  266. Arguments:
  267. pMidMap -- the MID_MAP instance to be uninitialized.
  268. pContextDestructor -- the context destructor
  269. Notes:
  270. --*/
  271. {
  272. USHORT i;
  273. ULONG EntryType;
  274. PAGED_CODE();
  275. //DbgPrint("_UninitializeMidMap .. Entry No.Of MIDS in Use %ld\n",pMidMap->NumberOfMidsInUse);
  276. RxLog(("_UninitMidMap .. num= %ld\n",pMidMap->NumberOfMidsInUse));
  277. SmbLog(LOG,
  278. UninitializeMidMap,
  279. LOGXSHORT(pMidMap->NumberOfMidsInUse));
  280. for (i = 0; i < pMidMap->MaximumNumberOfMids; i++) {
  281. PMID_MAP pChildMidMap;
  282. EntryType = _GetEntryType(pMidMap->Entries[i]);
  283. switch (EntryType) {
  284. case ENTRY_TYPE_MID_MAP :
  285. {
  286. pChildMidMap = (PMID_MAP)_GetEntryPointer(pMidMap->Entries[i]);
  287. _UninitializeMidMap(pChildMidMap,pContextDestructor);
  288. }
  289. break;
  290. case ENTRY_TYPE_VALID_CONTEXT :
  291. {
  292. if (pContextDestructor != NULL) {
  293. PVOID pContext;
  294. pContext = _GetEntryPointer(pMidMap->Entries[i]);
  295. (pContextDestructor)(pContext);
  296. }
  297. }
  298. break;
  299. default:
  300. break;
  301. }
  302. }
  303. if (pMidMap->Flags & MID_MAP_FLAGS_FREE_POOL) {
  304. RxFreePool(pMidMap);
  305. }
  306. //DbgPrint("_UninitializeMidMap .. Exit\n");
  307. }
  308. VOID
  309. FsRtlDestroyMidAtlas(
  310. PMID_ATLAS pMidAtlas,
  311. PCONTEXT_DESTRUCTOR pContextDestructor)
  312. /*++
  313. Routine Description:
  314. This routine frees a MID_ATLAS instance. As a side effect it invokes the
  315. passed in context destructor on every valid context in the MID_ATLAS
  316. Arguments:
  317. pMidAtlas - the MID_ATLAS instance to be freed.
  318. PCONTEXT_DESTRUCTOR - the associated context destructor
  319. Notes:
  320. --*/
  321. {
  322. PAGED_CODE();
  323. //DbgPrint("FsRtlFreeMidAtlas .. Entry\n");
  324. _UninitializeMidMap(pMidAtlas->pRootMidMap,pContextDestructor);
  325. RxFreePool(pMidAtlas);
  326. //DbgPrint("FsRtlFreeMidAtlas .. Exit\n");
  327. }
  328. PVOID
  329. FsRtlMapMidToContext(
  330. PMID_ATLAS pMidAtlas,
  331. USHORT Mid)
  332. /*++
  333. Routine Description:
  334. This routine maps a MID to its associated context in a MID_ATLAS.
  335. Arguments:
  336. pMidAtlas - the MID_ATLAS instance.
  337. Mid - the MId to be mapped
  338. Return value:
  339. the associated context, NULL if none exists
  340. Notes:
  341. --*/
  342. {
  343. ULONG EntryType;
  344. PMID_MAP pMidMap = pMidAtlas->pRootMidMap;
  345. PVOID pContext;
  346. ULONG Index;
  347. //DbgPrint("FsRtlMapMidToContext Mid %lx ",Mid);
  348. for (;;) {
  349. Index = (Mid & pMidMap->IndexMask) >> pMidMap->IndexAlignmentCount;
  350. if (Index >= pMidMap->MaximumNumberOfMids) {
  351. pContext = NULL;
  352. break;
  353. }
  354. pContext = pMidMap->Entries[Index];
  355. EntryType = _GetEntryType(pContext);
  356. pContext = (PVOID)_GetEntryPointer(pContext);
  357. if (EntryType == ENTRY_TYPE_VALID_CONTEXT) {
  358. break;
  359. } else if (EntryType == ENTRY_TYPE_FREE_MID_LIST) {
  360. pContext = NULL;
  361. break;
  362. } else if (EntryType == ENTRY_TYPE_MID_MAP) {
  363. pMidMap = (PMID_MAP)pContext;
  364. } else {
  365. pContext = NULL;
  366. break;
  367. }
  368. }
  369. //DbgPrint("Context %lx \n",pContext);
  370. return pContext;
  371. }
  372. NTSTATUS
  373. FsRtlMapAndDissociateMidFromContext(
  374. PMID_ATLAS pMidAtlas,
  375. USHORT Mid,
  376. PVOID *pContextPointer)
  377. /*++
  378. Routine Description:
  379. This routine maps a MID to its associated context in a MID_ATLAS.
  380. Arguments:
  381. pMidAtlas - the MID_ATLAS instance.
  382. Mid - the MId to be mapped
  383. Return value:
  384. the associated context, NULL if none exists
  385. Notes:
  386. --*/
  387. {
  388. ULONG EntryType;
  389. PMID_MAP pMidMap = pMidAtlas->pRootMidMap;
  390. PVOID pContext;
  391. PVOID *pEntry;
  392. //DbgPrint("FsRtlMapAndDissociateMidFromContext Mid %lx ",Mid);
  393. for (;;) {
  394. pEntry = &pMidMap->Entries[
  395. (Mid & pMidMap->IndexMask) >> pMidMap->IndexAlignmentCount];
  396. pContext = *pEntry;
  397. EntryType = _GetEntryType(pContext);
  398. pContext = (PVOID)_GetEntryPointer(pContext);
  399. if (EntryType == ENTRY_TYPE_VALID_CONTEXT) {
  400. pMidMap->NumberOfMidsInUse--;
  401. if (pMidMap->pFreeMidListHead == NULL) {
  402. _RemoveMidMap(pMidMap);
  403. _AddMidMap(&pMidAtlas->MidMapFreeList,pMidMap);
  404. }
  405. *pEntry = _MakeEntry(pMidMap->pFreeMidListHead,ENTRY_TYPE_FREE_MID_LIST);
  406. pMidMap->pFreeMidListHead = pEntry;
  407. break;
  408. } else if (EntryType == ENTRY_TYPE_FREE_MID_LIST) {
  409. pContext = NULL;
  410. break;
  411. } else if (EntryType == ENTRY_TYPE_MID_MAP) {
  412. pMidMap = (PMID_MAP)pContext;
  413. }
  414. }
  415. pMidAtlas->NumberOfMidsInUse--;
  416. //DbgPrint("Context %lx\n",pContext);
  417. *pContextPointer = pContext;
  418. return STATUS_SUCCESS;
  419. }
  420. NTSTATUS
  421. FsRtlReassociateMid(
  422. PMID_ATLAS pMidAtlas,
  423. USHORT Mid,
  424. PVOID pNewContext)
  425. /*++
  426. Routine Description:
  427. This routine maps a MID to its associated context in a MID_ATLAS.
  428. Arguments:
  429. pMidAtlas - the MID_ATLAS instance.
  430. Mid - the MId to be mapped
  431. pNewContext - the new context
  432. Return value:
  433. the associated context, NULL if none exists
  434. Notes:
  435. --*/
  436. {
  437. ULONG EntryType;
  438. PMID_MAP pMidMap = pMidAtlas->pRootMidMap;
  439. PVOID pContext;
  440. //DbgPrint("FsRtlReassociateMid Mid %lx ",Mid);
  441. for (;;) {
  442. pContext = pMidMap->Entries[(Mid & pMidMap->IndexMask) >> pMidMap->IndexAlignmentCount];
  443. EntryType = _GetEntryType(pContext);
  444. pContext = (PVOID)_GetEntryPointer(pContext);
  445. if (EntryType == ENTRY_TYPE_VALID_CONTEXT) {
  446. pMidMap->Entries[(Mid & pMidMap->IndexMask) >> pMidMap->IndexAlignmentCount]
  447. = _MakeEntry(pNewContext,ENTRY_TYPE_VALID_CONTEXT);
  448. break;
  449. } else if (EntryType == ENTRY_TYPE_FREE_MID_LIST) {
  450. ASSERT(!"Valid MID Atlas");
  451. break;
  452. } else if (EntryType == ENTRY_TYPE_MID_MAP) {
  453. pMidMap = (PMID_MAP)pContext;
  454. }
  455. }
  456. //DbgPrint("New COntext %lx\n",pNewContext);
  457. return STATUS_SUCCESS;
  458. }
  459. NTSTATUS
  460. FsRtlAssociateContextWithMid(
  461. PMID_ATLAS pMidAtlas,
  462. PVOID pContext,
  463. PUSHORT pNewMid)
  464. /*++
  465. Routine Description:
  466. This routine initializes a MID_MAP data structure.
  467. Arguments:
  468. pMidMap - the MID_MAP instance to be initialized.
  469. Return Value:
  470. STATUS_SUCCESS if successful, otherwise one of the following errors
  471. STATUS_INSUFFICIENT_RESOURCES
  472. STATUS_UNSUCCESSFUL -- no mid could be associated
  473. Notes:
  474. --*/
  475. {
  476. NTSTATUS Status;
  477. PMID_MAP pMidMap;
  478. PVOID *pContextPointer;
  479. // Reject requests that exceed our MID limit
  480. if( pMidAtlas->NumberOfMidsInUse >= pMidAtlas->MaximumNumberOfMids )
  481. {
  482. return STATUS_UNSUCCESSFUL;
  483. }
  484. //DbgPrint("FsRtlAssociateContextWithMid Context %lx ",pContext);
  485. // Scan the list of MID_MAP's which have free entries in them.
  486. if ((pMidMap = _GetFirstMidMap(&pMidAtlas->MidMapFreeList)) != NULL) {
  487. ASSERT(pMidMap->pFreeMidListHead != _MakeEntry(NULL,ENTRY_TYPE_FREE_MID_LIST));
  488. pMidMap->NumberOfMidsInUse++;
  489. pContextPointer = pMidMap->pFreeMidListHead;
  490. pMidMap->pFreeMidListHead = _GetEntryPointer(*(pMidMap->pFreeMidListHead));
  491. *pContextPointer = _MakeEntry(pContext,ENTRY_TYPE_VALID_CONTEXT);
  492. *pNewMid = ((USHORT)
  493. (pContextPointer - (PVOID *)&pMidMap->Entries)
  494. << pMidMap->IndexAlignmentCount) |
  495. pMidMap->BaseMid;
  496. // Check if the MID_MAP needs to be removed from the list of MID_MAP's with
  497. // free entries
  498. if (pMidMap->pFreeMidListHead == NULL) {
  499. _RemoveMidMap(pMidMap);
  500. // Check if it can be added to the expansion list.
  501. if (pMidAtlas->NumberOfLevels > pMidMap->Level) {
  502. _AddMidMap(&pMidAtlas->MidMapExpansionList,pMidMap);
  503. }
  504. }
  505. Status = STATUS_SUCCESS;
  506. } else if ((pMidMap = _GetFirstMidMap(&pMidAtlas->MidMapExpansionList)) != NULL) {
  507. PMID_MAP pNewMidMap;
  508. USHORT i;
  509. ULONG NewMidMapSize;
  510. // Locate the index in the mid map for the new mid map
  511. pMidMap = _GetFirstMidMap(&pMidAtlas->MidMapExpansionList);
  512. while (pMidMap != NULL) {
  513. for (i = 0; i < pMidMap->MaximumNumberOfMids; i++) {
  514. if (_GetEntryType(pMidMap->Entries[i]) != ENTRY_TYPE_MID_MAP) {
  515. break;
  516. }
  517. }
  518. if (i < pMidMap->MaximumNumberOfMids) {
  519. break;
  520. } else {
  521. pMidMap->Flags &= ~MID_MAP_FLAGS_CAN_BE_EXPANDED;
  522. _RemoveMidMap(pMidMap);
  523. pMidMap = _GetNextMidMap(&pMidAtlas->MidMapExpansionList,pMidMap);
  524. }
  525. }
  526. if (pMidMap != NULL) {
  527. USHORT NumberOfEntriesInMap = pMidAtlas->MaximumNumberOfMids -
  528. pMidAtlas->NumberOfMidsInUse;
  529. if (NumberOfEntriesInMap > pMidAtlas->MidQuantum) {
  530. NumberOfEntriesInMap = pMidAtlas->MidQuantum;
  531. }
  532. // The smallest MIDMAP we can do is 3 given the MIDMAP logic
  533. if ( (NumberOfEntriesInMap > 0) && (NumberOfEntriesInMap < 3) ) {
  534. NumberOfEntriesInMap = 3;
  535. }
  536. if (NumberOfEntriesInMap > 0) {
  537. NewMidMapSize = FIELD_OFFSET(MID_MAP,Entries) +
  538. NumberOfEntriesInMap * sizeof(PVOID);
  539. pNewMidMap = (PMID_MAP)RxAllocatePoolWithTag(
  540. NonPagedPool,
  541. NewMidMapSize,
  542. MRXSMB_MIDATLAS_POOLTAG);
  543. if (pNewMidMap != NULL) {
  544. pNewMidMap->Flags = MID_MAP_FLAGS_FREE_POOL;
  545. pNewMidMap->MaximumNumberOfMids = NumberOfEntriesInMap;
  546. pNewMidMap->NumberOfMidsInUse = 0;
  547. pNewMidMap->BaseMid = (pMidMap->BaseMid |
  548. i << pMidMap->IndexAlignmentCount);
  549. pNewMidMap->IndexAlignmentCount = pMidMap->IndexAlignmentCount +
  550. pMidMap->IndexFieldWidth;
  551. pNewMidMap->IndexMask = (pMidAtlas->MidQuantum - 1) << pNewMidMap->IndexAlignmentCount;
  552. pNewMidMap->IndexFieldWidth = pMidAtlas->MidQuantumFieldWidth;
  553. _InitializeMidMapFreeList(pNewMidMap);
  554. //
  555. // After the RxInitializeMidMapFreeList call above the
  556. // pFreeMidListHead points to Entries[0]. We will be storing
  557. // the value pMidMap->Entries[i] at this location so we need
  558. // to make pFreeMidListHead point to Entries[1].
  559. //
  560. pNewMidMap->pFreeMidListHead = _GetEntryPointer(*(pNewMidMap->pFreeMidListHead));
  561. //
  562. // Set up the mid map appropriately.
  563. //
  564. pNewMidMap->NumberOfMidsInUse = 1;
  565. pNewMidMap->Entries[0] = pMidMap->Entries[i];
  566. pNewMidMap->Level = pMidMap->Level + 1;
  567. //
  568. // The new MinMap is stored at the pMidMap->Entries[i] location.
  569. //
  570. pMidMap->Entries[i] = _MakeEntry(pNewMidMap,ENTRY_TYPE_MID_MAP);
  571. //
  572. // Update the free list and the expansion list respectively.
  573. //
  574. _AddMidMap(&pMidAtlas->MidMapFreeList,pNewMidMap);
  575. pNewMidMap->NumberOfMidsInUse++;
  576. pContextPointer = pNewMidMap->pFreeMidListHead;
  577. pNewMidMap->pFreeMidListHead = _GetEntryPointer(*(pNewMidMap->pFreeMidListHead));
  578. *pContextPointer = _MakeEntry(pContext,ENTRY_TYPE_VALID_CONTEXT);
  579. *pNewMid = ((USHORT)
  580. (pContextPointer - (PVOID *)&pNewMidMap->Entries)
  581. << pNewMidMap->IndexAlignmentCount) |
  582. pNewMidMap->BaseMid;
  583. Status = STATUS_SUCCESS;
  584. } else {
  585. Status = STATUS_INSUFFICIENT_RESOURCES;
  586. }
  587. } else {
  588. Status = STATUS_UNSUCCESSFUL;
  589. }
  590. } else {
  591. Status = STATUS_UNSUCCESSFUL;
  592. }
  593. } else {
  594. Status = STATUS_UNSUCCESSFUL;
  595. }
  596. if (Status == RX_MAP_STATUS(SUCCESS)) {
  597. pMidAtlas->NumberOfMidsInUse++;
  598. }
  599. //DbgPrint("Mid %lx\n",*pNewMid);
  600. return Status;
  601. }