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.

863 lines
30 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. hivebin.c
  5. Abstract:
  6. This module implements HvpAddBin - used to grow a hive.
  7. Author:
  8. Bryan M. Willman (bryanwi) 27-Mar-92
  9. Environment:
  10. Revision History:
  11. --*/
  12. #include "cmp.h"
  13. //
  14. // Private function prototypes
  15. //
  16. BOOLEAN
  17. HvpCoalesceDiscardedBins(
  18. IN PHHIVE Hive,
  19. IN ULONG NeededSize,
  20. IN HSTORAGE_TYPE Type
  21. );
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE,HvpAddBin)
  24. #pragma alloc_text(PAGE,HvpCoalesceDiscardedBins)
  25. #endif
  26. PHBIN
  27. HvpAddBin(
  28. IN PHHIVE Hive,
  29. IN ULONG NewSize,
  30. IN HSTORAGE_TYPE Type
  31. )
  32. /*++
  33. Routine Description:
  34. Grows either the Stable or Volatile storage of a hive by adding
  35. a new bin. Bin will be allocated space in Stable store (e.g. file)
  36. if Type == Stable. Memory image will be allocated and initialized.
  37. Map will be grown and filled in to describe the new bin.
  38. WARNING:
  39. When adding a new bin, if the CM_VIEW_SIZE boundary is crossed:
  40. - add a free bin with the remaining space to the first CM_VIEW_SIZE barrier
  41. - from the next CM_VIEW_SIZE window, add a new bin of the desired size.
  42. Of course, this applies only to stable storage.
  43. Arguments:
  44. Hive - supplies a pointer to the hive control structure for the
  45. hive of interest
  46. NewSize - size of the object caller wishes to put in the hive. New
  47. bin will be at least large enough to hold this.
  48. Type - Stable or Volatile
  49. Return Value:
  50. Pointer to the new BIN if we succeeded, NULL if we failed.
  51. --*/
  52. {
  53. BOOLEAN UseForIo;
  54. PHBIN NewBin;
  55. PHBIN RemainingBin;
  56. ULONG OldLength;
  57. ULONG NewLength;
  58. ULONG CheckLength;
  59. ULONG OldMap;
  60. ULONG NewMap;
  61. ULONG OldTable;
  62. ULONG NewTable;
  63. PHMAP_DIRECTORY Dir = NULL;
  64. PHMAP_TABLE newt = NULL;
  65. PHMAP_ENTRY Me;
  66. PHCELL t;
  67. ULONG i;
  68. ULONG j;
  69. PULONG NewVector = NULL;
  70. PLIST_ENTRY Entry;
  71. PFREE_HBIN FreeBin = NULL;
  72. ULONG TotalDiscardedSize;
  73. PCMHIVE CmHive;
  74. PAGED_CODE();
  75. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvpAddBin:\n"));
  76. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"\tHive=%p NewSize=%08lx\n",Hive,NewSize));
  77. CmHive = (PCMHIVE)CONTAINING_RECORD(Hive, CMHIVE, Hive);
  78. RemainingBin = NULL;
  79. //
  80. // Round size up to account for bin overhead. Caller should
  81. // have accounted for cell overhead.
  82. //
  83. NewSize += sizeof(HBIN);
  84. if ((NewSize < HCELL_BIG_ROUND) &&
  85. ((NewSize % HBLOCK_SIZE) > HBIN_THRESHOLD)) {
  86. NewSize += HBLOCK_SIZE;
  87. }
  88. //
  89. // Try not to create HBINs smaller than the page size of the machine
  90. // (it is not illegal to have bins smaller than the page size, but it
  91. // is less efficient)
  92. //
  93. NewSize = ROUND_UP(NewSize, ((HBLOCK_SIZE >= PAGE_SIZE) ? HBLOCK_SIZE : PAGE_SIZE));
  94. //
  95. // see if there's a discarded HBIN of the right size
  96. //
  97. TotalDiscardedSize = 0;
  98. Retry:
  99. Entry = Hive->Storage[Type].FreeBins.Flink;
  100. while (Entry != &Hive->Storage[Type].FreeBins) {
  101. FreeBin = CONTAINING_RECORD(Entry,
  102. FREE_HBIN,
  103. ListEntry);
  104. TotalDiscardedSize += FreeBin->Size;
  105. if ((FreeBin->Size >= NewSize) && ((CmHive->GrowOnlyMode == FALSE) || (Type == Volatile)) ) {
  106. if (!HvMarkDirty(Hive,
  107. FreeBin->FileOffset + (Type * HCELL_TYPE_MASK),
  108. FreeBin->Size,TRUE)) {
  109. goto ErrorExit1;
  110. }
  111. NewSize = FreeBin->Size;
  112. ASSERT_LISTENTRY(&FreeBin->ListEntry);
  113. RemoveEntryList(&FreeBin->ListEntry);
  114. #ifdef HV_TRACK_FREE_SPACE
  115. Hive->Storage[Type].FreeStorage -= (NewSize - sizeof(HBIN));
  116. ASSERT( (LONG)(Hive->Storage[Type].FreeStorage) >= 0 );
  117. #endif
  118. if ( FreeBin->Flags & FREE_HBIN_DISCARDABLE ) {
  119. //
  120. // HBIN is still in memory, don't need any more allocs, just
  121. // fill in the block addresses.
  122. //
  123. Me = NULL;
  124. for (i=0;i<NewSize;i+=HBLOCK_SIZE) {
  125. Me = HvpGetCellMap(Hive, FreeBin->FileOffset+i+(Type*HCELL_TYPE_MASK));
  126. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FreeBin->FileOffset+i+(Type*HCELL_TYPE_MASK));
  127. Me->BlockAddress = HBIN_BASE(Me->BinAddress)+i;
  128. Me->BinAddress &= ~HMAP_DISCARDABLE;
  129. // we cannot have the FREE_BIN_DISCARDABLE flag set
  130. // and FREE_HBIN_INVIEW not set on a mapped bin.
  131. ASSERT( Me->BinAddress & HMAP_INPAGEDPOOL );
  132. // we don't need to set it to NULL - just for debug purposes
  133. ASSERT( (Me->CmView = NULL) == NULL );
  134. }
  135. (Hive->Free)(FreeBin, sizeof(FREE_HBIN));
  136. #if DBG
  137. {
  138. UNICODE_STRING HiveName;
  139. RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName);
  140. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) reusing FreeBin %p at FileOffset %lx; Type = %lu\n",
  141. Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,HBIN_BASE(Me->BinAddress),((PHBIN)HBIN_BASE(Me->BinAddress))->FileOffset,(ULONG)Type));
  142. }
  143. #endif
  144. return (PHBIN)HBIN_BASE(Me->BinAddress);
  145. }
  146. break;
  147. }
  148. Entry = Entry->Flink;
  149. }
  150. if ((Entry == &Hive->Storage[Type].FreeBins) &&
  151. (TotalDiscardedSize >= NewSize)) {
  152. //
  153. // No sufficiently large discarded bin was found,
  154. // but the total discarded space is large enough.
  155. // Attempt to coalesce adjacent discarded bins into
  156. // a larger bin and retry.
  157. //
  158. if (HvpCoalesceDiscardedBins(Hive, NewSize, Type)) {
  159. goto Retry;
  160. }
  161. }
  162. //
  163. // we need these sooner to do the computations in case we allocate a new bin
  164. //
  165. OldLength = Hive->Storage[Type].Length;
  166. CheckLength = OldLength;
  167. //
  168. // Attempt to allocate the bin.
  169. //
  170. UseForIo = (BOOLEAN)((Type == Stable) ? TRUE : FALSE);
  171. if (Entry != &Hive->Storage[Type].FreeBins) {
  172. if( Type == Volatile ) {
  173. //
  174. // old plain method for volatile storage
  175. //
  176. //
  177. // Note we use ExAllocatePool directly here to avoid
  178. // charging quota for this bin again. When a bin
  179. // is discarded, its quota is not returned. This prevents
  180. // sparse hives from requiring more quota after
  181. // a reboot than on a running system.
  182. //
  183. NewBin = ExAllocatePoolWithTag((UseForIo) ? PagedPoolCacheAligned : PagedPool,
  184. NewSize,
  185. CM_HVBIN_TAG);
  186. if (NewBin == NULL) {
  187. InsertHeadList(&Hive->Storage[Type].FreeBins, Entry);
  188. #ifdef HV_TRACK_FREE_SPACE
  189. Hive->Storage[Type].FreeStorage += (NewSize - sizeof(HBIN));
  190. #endif
  191. // this call is a nop
  192. //HvMarkClean(Hive, FreeBin->FileOffset, FreeBin->Size);
  193. goto ErrorExit1;
  194. }
  195. } else {
  196. //
  197. // for Stable, map the view containing the bin in memory
  198. // and fix the map
  199. //
  200. Me = HvpGetCellMap(Hive, FreeBin->FileOffset);
  201. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FreeBin->FileOffset);
  202. if( Me->BinAddress & HMAP_INPAGEDPOOL ) {
  203. ASSERT( (Me->BinAddress & HMAP_INVIEW) == 0 );
  204. //
  205. // bin is in paged pool; allocate backing store
  206. //
  207. NewBin = (Hive->Allocate)(NewSize, UseForIo,CM_FIND_LEAK_TAG15);
  208. if (NewBin == NULL) {
  209. InsertHeadList(&Hive->Storage[Type].FreeBins, Entry);
  210. #ifdef HV_TRACK_FREE_SPACE
  211. Hive->Storage[Type].FreeStorage += (NewSize - sizeof(HBIN));
  212. #endif
  213. goto ErrorExit1;
  214. }
  215. } else {
  216. //
  217. // The view containing this bin has been unmapped; map it again
  218. //
  219. if( (Me->BinAddress & HMAP_INVIEW) == 0 ) {
  220. ASSERT( (Me->BinAddress & HMAP_INPAGEDPOOL) == 0 );
  221. //
  222. // map the bin
  223. //
  224. if( !NT_SUCCESS(CmpMapThisBin((PCMHIVE)Hive,FreeBin->FileOffset,TRUE)) ) {
  225. InsertHeadList(&Hive->Storage[Type].FreeBins, Entry);
  226. #ifdef HV_TRACK_FREE_SPACE
  227. Hive->Storage[Type].FreeStorage += (NewSize - sizeof(HBIN));
  228. #endif
  229. return NULL;
  230. }
  231. }
  232. ASSERT( Me->BinAddress & HMAP_INVIEW );
  233. NewBin = (PHBIN)HBIN_BASE(Me->BinAddress);
  234. }
  235. }
  236. } else {
  237. #if 0
  238. //
  239. // this is no longer neccesssary as Mm is faulting one page at a time for MNW streams
  240. //
  241. ASSERT( (CM_VIEW_SIZE >= PAGE_SIZE) && (CM_VIEW_SIZE >= HBLOCK_SIZE) );
  242. //
  243. // Don't do unneccessary work for volatile storage or volatile hives
  244. //
  245. if( (Type == Stable) && (!(Hive->HiveFlags & HIVE_VOLATILE)) ) {
  246. ULONG RealHiveSize = OldLength + HBLOCK_SIZE;
  247. if( RealHiveSize != (RealHiveSize & (~(CM_VIEW_SIZE - 1)) ) ) {
  248. //
  249. // Hive size does not follow the CM_VIEW_SIZE increments pattern
  250. //
  251. ULONG FillUpSize;
  252. FillUpSize = ((OldLength + HBLOCK_SIZE + CM_VIEW_SIZE - 1) & (~(CM_VIEW_SIZE - 1))) - (OldLength + HBLOCK_SIZE);
  253. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"HvpAddBin for (%p) NewSize (%lx) ",Hive,NewSize));
  254. if( FillUpSize >= NewSize ) {
  255. //
  256. // there is plenty of space in the remaining to the CM_VIEW_SIZE boundary to accomodate this bin
  257. // adjust the size of the bin
  258. //
  259. NewSize = FillUpSize;
  260. ASSERT( HvpCheckViewBoundary(CheckLength,CheckLength + NewSize - 1) == TRUE );
  261. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Fits in the remaining to boundary, Adjusting size to %lx",NewSize));
  262. } else {
  263. //
  264. // we don't have space to fit this bin in the remaining to the CM_VIEW_SIZE boundary
  265. // FillUpSize will be enlisted as a free bin. round up to CM_VIEW_SIZE
  266. //
  267. ASSERT( HvpCheckViewBoundary(CheckLength,CheckLength + NewSize - 1) == FALSE );
  268. NewSize = ROUND_UP(NewSize, CM_VIEW_SIZE);
  269. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Does not fit in the remaining to boundary, Rounding size to %lx",NewSize));
  270. }
  271. } else {
  272. //
  273. // Hive already follows the CM_VIEW_SIZE boundary pattern; don't break it
  274. //
  275. NewSize = ROUND_UP(NewSize, CM_VIEW_SIZE);
  276. CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"hive size already aligned, Rounding size to %lx",NewSize));
  277. }
  278. }
  279. #endif
  280. //
  281. // this is a totally new bin. Allocate it from paged pool
  282. //
  283. NewBin = (Hive->Allocate)(NewSize, UseForIo,CM_FIND_LEAK_TAG16);
  284. if (NewBin == NULL) {
  285. goto ErrorExit1;
  286. }
  287. }
  288. //
  289. // Init the bin
  290. //
  291. NewBin->Signature = HBIN_SIGNATURE;
  292. NewBin->Size = NewSize;
  293. NewBin->Spare = 0;
  294. t = (PHCELL)((PUCHAR)NewBin + sizeof(HBIN));
  295. t->Size = NewSize - sizeof(HBIN);
  296. if (USE_OLD_CELL(Hive)) {
  297. t->u.OldCell.Last = (ULONG)HBIN_NIL;
  298. }
  299. if (Entry != &Hive->Storage[Type].FreeBins) {
  300. //
  301. // found a discarded HBIN we can use, just fill in the map and we
  302. // are done.
  303. //
  304. for (i=0;i<NewSize;i+=HBLOCK_SIZE) {
  305. Me = HvpGetCellMap(Hive, FreeBin->FileOffset+i+(Type*HCELL_TYPE_MASK));
  306. VALIDATE_CELL_MAP(__LINE__,Me,Hive,FreeBin->FileOffset+i+(Type*HCELL_TYPE_MASK));
  307. Me->BlockAddress = (ULONG_PTR)NewBin + i;
  308. //
  309. // make sure to preserve the following flags:
  310. // HMAP_INVIEW|HMAP_INPAGEDPOOL
  311. // and to clear the flag
  312. // HMAP_DISCARDABLE
  313. //
  314. Me->BinAddress = (ULONG_PTR)((ULONG_PTR)NewBin | (Me->BinAddress&(HMAP_INVIEW|HMAP_INPAGEDPOOL)));
  315. Me->BinAddress &= ~HMAP_DISCARDABLE;
  316. if (i==0) {
  317. Me->BinAddress |= HMAP_NEWALLOC;
  318. Me->MemAlloc = NewSize;
  319. } else {
  320. Me->MemAlloc = 0;
  321. }
  322. }
  323. NewBin->FileOffset = FreeBin->FileOffset;
  324. (Hive->Free)(FreeBin, sizeof(FREE_HBIN));
  325. #if DBG
  326. {
  327. UNICODE_STRING HiveName;
  328. RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName);
  329. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) reusing FreeBin %p at FileOffset %lx; Type = %lu\n",
  330. Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,NewBin,NewBin->FileOffset,(ULONG)Type));
  331. }
  332. #endif
  333. return(NewBin);
  334. }
  335. //
  336. // Compute map growth needed, grow the map
  337. //
  338. if( (HvpCheckViewBoundary(CheckLength,CheckLength + NewSize - 1) == FALSE) &&
  339. (NewSize < CM_VIEW_SIZE) // don't bother if we attempt to allocate a cell bigger then the view size
  340. // it'll cross the boundary anyway.
  341. ) {
  342. //
  343. // the bin to be allocated doesn't fit into the remaining
  344. // of this CM_VIEW_SIZE window. Allocate it from the next CM_VIEW_SIZE window
  345. // and add the remaining of this to the free bin list
  346. //
  347. CheckLength += (NewSize+HBLOCK_SIZE);
  348. CheckLength &= (~(CM_VIEW_SIZE - 1));
  349. CheckLength -= HBLOCK_SIZE;
  350. #if DBG
  351. {
  352. UNICODE_STRING HiveName;
  353. RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName);
  354. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) crossing boundary at %lx Size %lx, newoffset= %lx\n",Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,OldLength,NewSize,CheckLength));
  355. }
  356. #endif
  357. }
  358. NewLength = CheckLength + NewSize;
  359. NewBin->FileOffset = CheckLength;
  360. //CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"OldLength = %lx;NewLength = %lx (Type = %lx)\n",OldLength,NewLength,(ULONG)Type));
  361. if( CmpCanGrowSystemHive(Hive,NewLength) == FALSE ) {
  362. //
  363. // OOPS! we have reached the hard quota limit on the system hive
  364. //
  365. goto ErrorExit2;
  366. }
  367. ASSERT((OldLength % HBLOCK_SIZE) == 0);
  368. ASSERT((CheckLength % HBLOCK_SIZE) == 0);
  369. ASSERT((NewLength % HBLOCK_SIZE) == 0);
  370. if (OldLength == 0) {
  371. //
  372. // Need to create the first table
  373. //
  374. newt = (PVOID)((Hive->Allocate)(sizeof(HMAP_TABLE), FALSE,CM_FIND_LEAK_TAG17));
  375. if (newt == NULL) {
  376. goto ErrorExit2;
  377. }
  378. RtlZeroMemory(newt, sizeof(HMAP_TABLE));
  379. Hive->Storage[Type].SmallDir = newt;
  380. Hive->Storage[Type].Map = (PHMAP_DIRECTORY)&(Hive->Storage[Type].SmallDir);
  381. }
  382. if (OldLength > 0) {
  383. OldMap = (OldLength-1) / HBLOCK_SIZE;
  384. } else {
  385. OldMap = 0;
  386. }
  387. NewMap = (NewLength-1) / HBLOCK_SIZE;
  388. OldTable = OldMap / HTABLE_SLOTS;
  389. NewTable = NewMap / HTABLE_SLOTS;
  390. #if DBG
  391. if( Type == Stable ) {
  392. UNICODE_STRING HiveName;
  393. RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName);
  394. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) Adding new bin %p at FileOffset %lx; Type = %lu\n",Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,NewBin,NewBin->FileOffset,(ULONG)Type));
  395. }
  396. #endif
  397. if (NewTable != OldTable) {
  398. //
  399. // Need some new Tables
  400. //
  401. if (OldTable == 0) {
  402. //
  403. // We can get here even if the real directory has already been created.
  404. // This can happen if we create the directory then fail on something
  405. // later. So we need to handle the case where a directory already exists.
  406. //
  407. if (Hive->Storage[Type].Map == (PHMAP_DIRECTORY)&Hive->Storage[Type].SmallDir) {
  408. ASSERT(Hive->Storage[Type].SmallDir != NULL);
  409. //
  410. // Need a real directory
  411. //
  412. Dir = (Hive->Allocate)(sizeof(HMAP_DIRECTORY), FALSE,CM_FIND_LEAK_TAG18);
  413. if (Dir == NULL) {
  414. goto ErrorExit2;
  415. }
  416. RtlZeroMemory(Dir, sizeof(HMAP_DIRECTORY));
  417. Dir->Directory[0] = Hive->Storage[Type].SmallDir;
  418. Hive->Storage[Type].SmallDir = NULL;
  419. Hive->Storage[Type].Map = Dir;
  420. } else {
  421. ASSERT(Hive->Storage[Type].SmallDir == NULL);
  422. }
  423. }
  424. Dir = Hive->Storage[Type].Map;
  425. //
  426. // Fill in directory with new tables
  427. //
  428. if (HvpAllocateMap(Hive, Dir, OldTable+1, NewTable) == FALSE) {
  429. goto ErrorExit3;
  430. }
  431. }
  432. //
  433. // If Type == Stable, and the hive is not marked WholeHiveVolatile,
  434. // grow the file, the log, and the DirtyVector
  435. //
  436. if( !NT_SUCCESS(HvpAdjustHiveFreeDisplay(Hive,NewLength,Type)) ) {
  437. goto ErrorExit3;
  438. }
  439. Hive->Storage[Type].Length = NewLength;
  440. if ((Type == Stable) && (!(Hive->HiveFlags & HIVE_VOLATILE))) {
  441. //
  442. // Grow the dirtyvector
  443. //
  444. NewVector = (PULONG)(Hive->Allocate)(ROUND_UP(NewMap+1,sizeof(ULONG)), TRUE,CM_FIND_LEAK_TAG19);
  445. if (NewVector == NULL) {
  446. goto ErrorExit3;
  447. }
  448. RtlZeroMemory(NewVector, NewMap+1);
  449. if (Hive->DirtyVector.Buffer != NULL) {
  450. RtlCopyMemory(
  451. (PVOID)NewVector,
  452. (PVOID)Hive->DirtyVector.Buffer,
  453. OldMap+1
  454. );
  455. (Hive->Free)(Hive->DirtyVector.Buffer, Hive->DirtyAlloc);
  456. }
  457. RtlInitializeBitMap(
  458. &(Hive->DirtyVector),
  459. NewVector,
  460. NewLength / HSECTOR_SIZE
  461. );
  462. Hive->DirtyAlloc = ROUND_UP(NewMap+1,sizeof(ULONG));
  463. //
  464. // Grow the log
  465. //
  466. if ( ! (HvpGrowLog2(Hive, NewSize))) {
  467. goto ErrorExit4;
  468. }
  469. //
  470. // Grow the primary
  471. //
  472. if ( ! (Hive->FileSetSize)(
  473. Hive,
  474. HFILE_TYPE_PRIMARY,
  475. NewLength+HBLOCK_SIZE,
  476. OldLength+HBLOCK_SIZE
  477. ) )
  478. {
  479. goto ErrorExit4;
  480. }
  481. //
  482. // Mark new bin dirty so all control structures get written at next sync
  483. //
  484. ASSERT( ((NewLength - OldLength) % HBLOCK_SIZE) == 0 );
  485. if ( ! HvMarkDirty(Hive, OldLength,NewLength - OldLength,FALSE)) {
  486. //
  487. // we have grown the hive, so the new bins are in paged pool !!!
  488. //
  489. goto ErrorExit4;
  490. }
  491. }
  492. //
  493. // Add the remaining to the free bin list
  494. //
  495. if( CheckLength != OldLength ) {
  496. //
  497. // Allocate the bin from pagedpool (first flush will update the file image and free the memory)
  498. //
  499. RemainingBin = (Hive->Allocate)(CheckLength - OldLength, UseForIo,CM_FIND_LEAK_TAG20);
  500. if (RemainingBin == NULL) {
  501. goto ErrorExit4;
  502. }
  503. RemainingBin->Signature = HBIN_SIGNATURE;
  504. RemainingBin->Size = CheckLength - OldLength;
  505. RemainingBin->FileOffset = OldLength;
  506. RemainingBin->Spare = 0;
  507. t = (PHCELL)((PUCHAR)RemainingBin + sizeof(HBIN));
  508. t->Size = RemainingBin->Size - sizeof(HBIN);
  509. if (USE_OLD_CELL(Hive)) {
  510. t->u.OldCell.Last = (ULONG)HBIN_NIL;
  511. }
  512. //
  513. // add the free bin to the free bin list and update the map.
  514. //
  515. FreeBin = (Hive->Allocate)(sizeof(FREE_HBIN), FALSE,CM_FIND_LEAK_TAG21);
  516. if (FreeBin == NULL) {
  517. goto ErrorExit5;
  518. }
  519. FreeBin->Size = CheckLength - OldLength;
  520. FreeBin->FileOffset = OldLength;
  521. FreeBin->Flags = FREE_HBIN_DISCARDABLE;
  522. InsertHeadList(&Hive->Storage[Type].FreeBins, &FreeBin->ListEntry);
  523. #ifdef HV_TRACK_FREE_SPACE
  524. Hive->Storage[Type].FreeStorage += (FreeBin->Size - sizeof(HBIN));
  525. ASSERT( Hive->Storage[Type].FreeStorage <= Hive->Storage[Type].Length );
  526. #endif
  527. ASSERT_LISTENTRY(&FreeBin->ListEntry);
  528. ASSERT_LISTENTRY(FreeBin->ListEntry.Flink);
  529. for (i = OldLength; i < CheckLength; i += HBLOCK_SIZE) {
  530. Me = HvpGetCellMap(Hive, i + (Type*HCELL_TYPE_MASK));
  531. VALIDATE_CELL_MAP(__LINE__,Me,Hive,i + (Type*HCELL_TYPE_MASK));
  532. Me->BinAddress = (ULONG_PTR)RemainingBin | HMAP_DISCARDABLE | HMAP_INPAGEDPOOL;
  533. if( i == OldLength ) {
  534. Me->BinAddress |= HMAP_NEWALLOC;
  535. Me->MemAlloc = CheckLength - OldLength;
  536. } else {
  537. Me->MemAlloc = 0;
  538. }
  539. Me->BlockAddress = (ULONG_PTR)FreeBin;
  540. // we don't need to set it to NULL - just for debug purposes
  541. ASSERT( (Me->CmView = NULL) == NULL );
  542. }
  543. #if DBG
  544. {
  545. if( Type == Stable ) {
  546. UNICODE_STRING HiveName;
  547. RtlInitUnicodeString(&HiveName, (PCWSTR)Hive->BaseBlock->FileName);
  548. CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvpAddBin for (%p) (%.*S) adding bin starting at %lx size %lx to FreeBinList\n",Hive,HiveName.Length / sizeof(WCHAR),HiveName.Buffer,FreeBin->FileOffset,FreeBin->Size));
  549. }
  550. }
  551. #endif
  552. }
  553. //
  554. // Fill in the map, mark new allocation.
  555. //
  556. j = 0;
  557. for (i = CheckLength; i < NewLength; i += HBLOCK_SIZE) {
  558. Me = HvpGetCellMap(Hive, i + (Type*HCELL_TYPE_MASK));
  559. VALIDATE_CELL_MAP(__LINE__,Me,Hive,i + (Type*HCELL_TYPE_MASK));
  560. Me->BlockAddress = (ULONG_PTR)NewBin + j;
  561. Me->BinAddress = (ULONG_PTR)NewBin;
  562. Me->BinAddress |= HMAP_INPAGEDPOOL;
  563. // we don't need to set it to NULL - just for debug purposes
  564. ASSERT( (Me->CmView = NULL) == NULL );
  565. if (j == 0) {
  566. //
  567. // First block of allocation, mark it.
  568. //
  569. Me->BinAddress |= HMAP_NEWALLOC;
  570. Me->MemAlloc = NewSize;
  571. } else {
  572. Me->MemAlloc = 0;
  573. }
  574. j += HBLOCK_SIZE;
  575. }
  576. if( Type == Stable) {
  577. CmpUpdateSystemHiveHysteresis(Hive,NewLength,OldLength);
  578. }
  579. return NewBin;
  580. ErrorExit5:
  581. if( RemainingBin != NULL ){
  582. (Hive->Free)(RemainingBin, RemainingBin->Size);
  583. }
  584. ErrorExit4:
  585. if((Type == Stable) && (!(Hive->HiveFlags & HIVE_VOLATILE))) {
  586. RtlInitializeBitMap(&Hive->DirtyVector,
  587. NewVector,
  588. OldLength / HSECTOR_SIZE);
  589. Hive->DirtyCount = RtlNumberOfSetBits(&Hive->DirtyVector);
  590. }
  591. ErrorExit3:
  592. Hive->Storage[Type].Length = OldLength;
  593. HvpFreeMap(Hive, Dir, OldTable+1, NewTable);
  594. ErrorExit2:
  595. (Hive->Free)(NewBin, NewSize);
  596. if( newt != NULL ) {
  597. (Hive->Free)(newt,sizeof(HMAP_TABLE));
  598. }
  599. ErrorExit1:
  600. return NULL;
  601. }
  602. // Dragos: Modified functions
  603. BOOLEAN
  604. HvpCoalesceDiscardedBins(
  605. IN PHHIVE Hive,
  606. IN ULONG NeededSize,
  607. IN HSTORAGE_TYPE Type
  608. )
  609. /*++
  610. Routine Description:
  611. Walks through the list of discarded bins and attempts to
  612. coalesce adjacent discarded bins into one larger bin in
  613. order to satisfy an allocation request.
  614. It doesn't coalesce bins over the CM_VIEW_SIZE boundary.
  615. It doesn't coalesce bins from paged pool with bins mapped in
  616. system cache views.
  617. Arguments:
  618. Hive - Supplies pointer to hive control block.
  619. NeededSize - Supplies size of allocation needed.
  620. Type - Stable or Volatile
  621. Return Value:
  622. TRUE - A bin of the desired size was created.
  623. FALSE - No bin of the desired size could be created.
  624. --*/
  625. {
  626. PLIST_ENTRY List;
  627. PFREE_HBIN FreeBin;
  628. PFREE_HBIN PreviousFreeBin;
  629. PFREE_HBIN NextFreeBin;
  630. PHMAP_ENTRY Map;
  631. PHMAP_ENTRY PreviousMap;
  632. PHMAP_ENTRY NextMap;
  633. ULONG MapBlock;
  634. List = Hive->Storage[Type].FreeBins.Flink;
  635. while (List != &Hive->Storage[Type].FreeBins) {
  636. FreeBin = CONTAINING_RECORD(List, FREE_HBIN, ListEntry);
  637. if ((FreeBin->Flags & FREE_HBIN_DISCARDABLE)==0) {
  638. Map = HvpGetCellMap(Hive, FreeBin->FileOffset);
  639. VALIDATE_CELL_MAP(__LINE__,Map,Hive,FreeBin->FileOffset);
  640. //
  641. // Scan backwards, coalescing previous discarded bins
  642. //
  643. while (FreeBin->FileOffset > 0) {
  644. PreviousMap = HvpGetCellMap(Hive, FreeBin->FileOffset - HBLOCK_SIZE);
  645. VALIDATE_CELL_MAP(__LINE__,PreviousMap,Hive,FreeBin->FileOffset - HBLOCK_SIZE);
  646. if( (BIN_MAP_ALLOCATION_TYPE(Map) != BIN_MAP_ALLOCATION_TYPE(PreviousMap)) || // different allocation type
  647. ((PreviousMap->BinAddress & HMAP_DISCARDABLE) == 0) // previous bin is not discardable
  648. ){
  649. break;
  650. }
  651. PreviousFreeBin = (PFREE_HBIN)PreviousMap->BlockAddress;
  652. if (PreviousFreeBin->Flags & FREE_HBIN_DISCARDABLE) {
  653. //
  654. // this bin has not yet been discarded; can't coalesce with it.
  655. //
  656. break;
  657. }
  658. if( HvpCheckViewBoundary(PreviousFreeBin->FileOffset,FreeBin->Size + PreviousFreeBin->Size - 1) == FALSE ) {
  659. //
  660. // don't coalesce bins over the CM_VIEW_SIZE boundary
  661. //
  662. // substract 1 because addresses are from 0 to size - 1 !!!
  663. //
  664. break;
  665. }
  666. RemoveEntryList(&PreviousFreeBin->ListEntry);
  667. //
  668. // Fill in all the old map entries with the new one.
  669. //
  670. for (MapBlock = 0; MapBlock < PreviousFreeBin->Size; MapBlock += HBLOCK_SIZE) {
  671. PreviousMap = HvpGetCellMap(Hive, PreviousFreeBin->FileOffset + MapBlock);
  672. VALIDATE_CELL_MAP(__LINE__,PreviousMap,Hive,PreviousFreeBin->FileOffset + MapBlock);
  673. PreviousMap->BlockAddress = (ULONG_PTR)FreeBin;
  674. }
  675. FreeBin->FileOffset = PreviousFreeBin->FileOffset;
  676. FreeBin->Size += PreviousFreeBin->Size;
  677. (Hive->Free)(PreviousFreeBin, sizeof(FREE_HBIN));
  678. }
  679. //
  680. // Scan forwards, coalescing subsequent discarded bins
  681. //
  682. while ((FreeBin->FileOffset + FreeBin->Size) < Hive->Storage[Type].Length) {
  683. NextMap = HvpGetCellMap(Hive, FreeBin->FileOffset + FreeBin->Size);
  684. VALIDATE_CELL_MAP(__LINE__,NextMap,Hive,FreeBin->FileOffset + FreeBin->Size);
  685. if( (BIN_MAP_ALLOCATION_TYPE(Map) != BIN_MAP_ALLOCATION_TYPE(NextMap)) || // different allocation type
  686. ((NextMap->BinAddress & HMAP_DISCARDABLE) == 0) // previous bin is not discardable
  687. ){
  688. break;
  689. }
  690. NextFreeBin = (PFREE_HBIN)NextMap->BlockAddress;
  691. if (NextFreeBin->Flags & FREE_HBIN_DISCARDABLE) {
  692. //
  693. // this bin has not yet been discarded; can't coalesce with it.
  694. //
  695. break;
  696. }
  697. if( HvpCheckViewBoundary(FreeBin->FileOffset,FreeBin->Size + NextFreeBin->Size - 1) == FALSE ) {
  698. //
  699. // don't coalesce bins over the CM_VIEW_SIZE boundary
  700. //
  701. // substract 1 because addresses are from 0 to size - 1 !!!
  702. //
  703. break;
  704. }
  705. RemoveEntryList(&NextFreeBin->ListEntry);
  706. //
  707. // Fill in all the old map entries with the new one.
  708. //
  709. for (MapBlock = 0; MapBlock < NextFreeBin->Size; MapBlock += HBLOCK_SIZE) {
  710. NextMap = HvpGetCellMap(Hive, NextFreeBin->FileOffset + MapBlock);
  711. VALIDATE_CELL_MAP(__LINE__,NextMap,Hive,NextFreeBin->FileOffset + MapBlock);
  712. NextMap->BlockAddress = (ULONG_PTR)FreeBin;
  713. }
  714. FreeBin->Size += NextFreeBin->Size;
  715. (Hive->Free)(NextFreeBin, sizeof(FREE_HBIN));
  716. }
  717. if (FreeBin->Size >= NeededSize) {
  718. return(TRUE);
  719. }
  720. }
  721. List=List->Flink;
  722. }
  723. return(FALSE);
  724. }