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.

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