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.

810 lines
24 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. //DbgPrint("FsRtlAssociateContextWithMid Context %lx ",pContext);
  480. // Scan the list of MID_MAP's which have free entries in them.
  481. if ((pMidMap = _GetFirstMidMap(&pMidAtlas->MidMapFreeList)) != NULL) {
  482. ASSERT(pMidMap->pFreeMidListHead != _MakeEntry(NULL,ENTRY_TYPE_FREE_MID_LIST));
  483. pMidMap->NumberOfMidsInUse++;
  484. pContextPointer = pMidMap->pFreeMidListHead;
  485. pMidMap->pFreeMidListHead = _GetEntryPointer(*(pMidMap->pFreeMidListHead));
  486. *pContextPointer = _MakeEntry(pContext,ENTRY_TYPE_VALID_CONTEXT);
  487. *pNewMid = ((USHORT)
  488. (pContextPointer - (PVOID *)&pMidMap->Entries)
  489. << pMidMap->IndexAlignmentCount) |
  490. pMidMap->BaseMid;
  491. // Check if the MID_MAP needs to be removed from the list of MID_MAP's with
  492. // free entries
  493. if (pMidMap->pFreeMidListHead == NULL) {
  494. _RemoveMidMap(pMidMap);
  495. // Check if it can be added to the expansion list.
  496. if (pMidAtlas->NumberOfLevels > pMidMap->Level) {
  497. _AddMidMap(&pMidAtlas->MidMapExpansionList,pMidMap);
  498. }
  499. }
  500. Status = STATUS_SUCCESS;
  501. } else if ((pMidMap = _GetFirstMidMap(&pMidAtlas->MidMapExpansionList)) != NULL) {
  502. PMID_MAP pNewMidMap;
  503. USHORT i;
  504. ULONG NewMidMapSize;
  505. // Locate the index in the mid map for the new mid map
  506. pMidMap = _GetFirstMidMap(&pMidAtlas->MidMapExpansionList);
  507. while (pMidMap != NULL) {
  508. for (i = 0; i < pMidMap->MaximumNumberOfMids; i++) {
  509. if (_GetEntryType(pMidMap->Entries[i]) != ENTRY_TYPE_MID_MAP) {
  510. break;
  511. }
  512. }
  513. if (i < pMidMap->MaximumNumberOfMids) {
  514. break;
  515. } else {
  516. pMidMap->Flags &= ~MID_MAP_FLAGS_CAN_BE_EXPANDED;
  517. _RemoveMidMap(pMidMap);
  518. pMidMap = _GetNextMidMap(&pMidAtlas->MidMapExpansionList,pMidMap);
  519. }
  520. }
  521. if (pMidMap != NULL) {
  522. USHORT NumberOfEntriesInMap = pMidAtlas->MaximumNumberOfMids -
  523. pMidAtlas->NumberOfMidsInUse;
  524. if (NumberOfEntriesInMap > pMidAtlas->MidQuantum) {
  525. NumberOfEntriesInMap = pMidAtlas->MidQuantum;
  526. }
  527. else if( NumberOfEntriesInMap == 1 )
  528. {
  529. // The MID_MAP design does not allow for maps of length 1. Extend to 2
  530. NumberOfEntriesInMap++;
  531. }
  532. if (NumberOfEntriesInMap > 0) {
  533. NewMidMapSize = FIELD_OFFSET(MID_MAP,Entries) +
  534. NumberOfEntriesInMap * sizeof(PVOID);
  535. pNewMidMap = (PMID_MAP)RxAllocatePoolWithTag(
  536. NonPagedPool,
  537. NewMidMapSize,
  538. MRXSMB_MIDATLAS_POOLTAG);
  539. if (pNewMidMap != NULL) {
  540. pNewMidMap->Flags = MID_MAP_FLAGS_FREE_POOL;
  541. pNewMidMap->MaximumNumberOfMids = NumberOfEntriesInMap;
  542. pNewMidMap->NumberOfMidsInUse = 0;
  543. pNewMidMap->BaseMid = (pMidMap->BaseMid |
  544. i << pMidMap->IndexAlignmentCount);
  545. pNewMidMap->IndexAlignmentCount = pMidMap->IndexAlignmentCount +
  546. pMidMap->IndexFieldWidth;
  547. pNewMidMap->IndexMask = (pMidAtlas->MidQuantum - 1) << pNewMidMap->IndexAlignmentCount;
  548. pNewMidMap->IndexFieldWidth = pMidAtlas->MidQuantumFieldWidth;
  549. _InitializeMidMapFreeList(pNewMidMap);
  550. //
  551. // After the RxInitializeMidMapFreeList call above the
  552. // pFreeMidListHead points to Entries[0]. We will be storing
  553. // the value pMidMap->Entries[i] at this location so we need
  554. // to make pFreeMidListHead point to Entries[1].
  555. //
  556. pNewMidMap->pFreeMidListHead = _GetEntryPointer(*(pNewMidMap->pFreeMidListHead));
  557. //
  558. // Set up the mid map appropriately.
  559. //
  560. pNewMidMap->NumberOfMidsInUse = 1;
  561. pNewMidMap->Entries[0] = pMidMap->Entries[i];
  562. pNewMidMap->Level = pMidMap->Level + 1;
  563. //
  564. // The new MinMap is stored at the pMidMap->Entries[i] location.
  565. //
  566. pMidMap->Entries[i] = _MakeEntry(pNewMidMap,ENTRY_TYPE_MID_MAP);
  567. //
  568. // Update the free list and the expansion list respectively.
  569. //
  570. _AddMidMap(&pMidAtlas->MidMapFreeList,pNewMidMap);
  571. pNewMidMap->NumberOfMidsInUse++;
  572. pContextPointer = pNewMidMap->pFreeMidListHead;
  573. pNewMidMap->pFreeMidListHead = _GetEntryPointer(*(pNewMidMap->pFreeMidListHead));
  574. *pContextPointer = _MakeEntry(pContext,ENTRY_TYPE_VALID_CONTEXT);
  575. *pNewMid = ((USHORT)
  576. (pContextPointer - (PVOID *)&pNewMidMap->Entries)
  577. << pNewMidMap->IndexAlignmentCount) |
  578. pNewMidMap->BaseMid;
  579. Status = STATUS_SUCCESS;
  580. } else {
  581. Status = STATUS_INSUFFICIENT_RESOURCES;
  582. }
  583. } else {
  584. Status = STATUS_UNSUCCESSFUL;
  585. }
  586. } else {
  587. Status = STATUS_UNSUCCESSFUL;
  588. }
  589. } else {
  590. Status = STATUS_UNSUCCESSFUL;
  591. }
  592. if (Status == RX_MAP_STATUS(SUCCESS)) {
  593. pMidAtlas->NumberOfMidsInUse++;
  594. }
  595. //DbgPrint("Mid %lx\n",*pNewMid);
  596. return Status;
  597. }