void Test_RtlFindNextForwardRunClear(void) { RTL_BITMAP BitMapHeader; ULONG *Buffer; ULONG Index; Buffer = AllocateGuarded(2 * sizeof(*Buffer)); Buffer[0] = 0xF9F078B2; Buffer[1] = 0x3F303F30; RtlInitializeBitMap(&BitMapHeader, Buffer, 0); ok_int(RtlFindNextForwardRunClear(&BitMapHeader, 0, &Index), 0); ok_int(Index, 0); ok_int(RtlFindNextForwardRunClear(&BitMapHeader, 1, &Index), 0); ok_int(Index, 1); Index = -1; RtlInitializeBitMap(&BitMapHeader, Buffer, 8); ok_int(RtlFindNextForwardRunClear(&BitMapHeader, 0, &Index), 1); ok_int(Index, 0); ok_int(RtlFindNextForwardRunClear(&BitMapHeader, 1, &Index), 2); ok_int(Index, 2); ok_int(RtlFindNextForwardRunClear(&BitMapHeader, 7, &Index), 0); ok_int(Index, 8); ok_int(RtlFindNextForwardRunClear(&BitMapHeader, 17, &Index), 0); ok_int(Index, 17); ok_int(RtlFindNextForwardRunClear(&BitMapHeader, 39, &Index), 0); ok_int(Index, 39); FreeGuarded(Buffer); }
static UCHAR InitSystemHandle(USHORT NumPages) { // // FIXME: This is an adapted copy of EmsAlloc!! // ULONG i, CurrentIndex = 0; PEMS_HANDLE HandleEntry = &HandleTable[EMS_SYSTEM_HANDLE]; /* The system handle must never have been initialized before */ ASSERT(!HandleEntry->Allocated); /* Now allocate it */ HandleEntry->Allocated = TRUE; while (HandleEntry->PageCount < NumPages) { ULONG RunStart; ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart); if (RunSize == 0) { /* Free what's been allocated already and report failure */ EmsFree(EMS_SYSTEM_HANDLE); // FIXME: For this function (and EmsAlloc as well), // use instead an internal function that just uses // PEMS_HANDLE pointers instead. It's only in the // EMS interrupt handler that we should do the // unfolding. return EMS_STATUS_INSUFFICIENT_PAGES; } else if ((HandleEntry->PageCount + RunSize) > NumPages) { /* We don't need the entire run */ RunSize = NumPages - HandleEntry->PageCount; } CurrentIndex = RunStart + RunSize; HandleEntry->PageCount += RunSize; RtlSetBits(&AllocBitmap, RunStart, RunSize); for (i = 0; i < RunSize; i++) { PageTable[RunStart + i].Handle = EMS_SYSTEM_HANDLE; InsertTailList(&HandleEntry->PageList, &PageTable[RunStart + i].Entry); } } return EMS_STATUS_SUCCESS; }
static WORD XmsGetLargestFreeBlock(VOID) { WORD Result = 0; DWORD CurrentIndex = 0; ULONG RunStart; ULONG RunSize; while (CurrentIndex < XMS_BLOCKS) { RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart); if (RunSize == 0) break; /* Update the maximum */ if (RunSize > Result) Result = RunSize; /* Go to the next run */ CurrentIndex = RunStart + RunSize; } return Result; }
static UCHAR EmsAlloc(USHORT NumPages, PUSHORT Handle) { ULONG i, CurrentIndex = 0; PEMS_HANDLE HandleEntry; if (NumPages == 0) return EMS_STATUS_ZERO_PAGES; HandleEntry = CreateHandle(Handle); if (!HandleEntry) return EMS_STATUS_NO_MORE_HANDLES; while (HandleEntry->PageCount < NumPages) { ULONG RunStart; ULONG RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart); if (RunSize == 0) { /* Free what's been allocated already and report failure */ EmsFree(*Handle); return EMS_STATUS_INSUFFICIENT_PAGES; } else if ((HandleEntry->PageCount + RunSize) > NumPages) { /* We don't need the entire run */ RunSize = NumPages - HandleEntry->PageCount; } CurrentIndex = RunStart + RunSize; HandleEntry->PageCount += RunSize; RtlSetBits(&AllocBitmap, RunStart, RunSize); for (i = 0; i < RunSize; i++) { PageTable[RunStart + i].Handle = *Handle; InsertTailList(&HandleEntry->PageList, &PageTable[RunStart + i].Entry); } } return EMS_STATUS_SUCCESS; }
/** * NtfsAllocateClusters * Allocates a run of clusters. The run allocated might be smaller than DesiredClusters. */ NTSTATUS NtfsAllocateClusters(PDEVICE_EXTENSION DeviceExt, ULONG FirstDesiredCluster, ULONG DesiredClusters, PULONG FirstAssignedCluster, PULONG AssignedClusters) { NTSTATUS Status; PFILE_RECORD_HEADER BitmapRecord; PNTFS_ATTR_CONTEXT DataContext; ULONGLONG BitmapDataSize; PUCHAR BitmapData; ULONGLONG FreeClusters = 0; RTL_BITMAP Bitmap; ULONG AssignedRun; ULONG LengthWritten; DPRINT1("NtfsAllocateClusters(%p, %lu, %lu, %p, %p)\n", DeviceExt, FirstDesiredCluster, DesiredClusters, FirstAssignedCluster, AssignedClusters); BitmapRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList); if (BitmapRecord == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord); if (!NT_SUCCESS(Status)) { ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord); return Status; } Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL); if (!NT_SUCCESS(Status)) { ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord); return Status; } BitmapDataSize = AttributeDataLength(DataContext->pRecord); BitmapDataSize = min(BitmapDataSize, 0xffffffff); ASSERT((BitmapDataSize * 8) >= DeviceExt->NtfsInfo.ClusterCount); BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS); if (BitmapData == NULL) { ReleaseAttributeContext(DataContext); ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord); return STATUS_INSUFFICIENT_RESOURCES; } DPRINT1("Total clusters: %I64x\n", DeviceExt->NtfsInfo.ClusterCount); DPRINT1("Total clusters in bitmap: %I64x\n", BitmapDataSize * 8); DPRINT1("Diff in size: %I64d B\n", ((BitmapDataSize * 8) - DeviceExt->NtfsInfo.ClusterCount) * DeviceExt->NtfsInfo.SectorsPerCluster * DeviceExt->NtfsInfo.BytesPerSector); ReadAttribute(DeviceExt, DataContext, 0, (PCHAR)BitmapData, (ULONG)BitmapDataSize); RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.ClusterCount); FreeClusters = RtlNumberOfClearBits(&Bitmap); if (FreeClusters < DesiredClusters) { ReleaseAttributeContext(DataContext); ExFreePoolWithTag(BitmapData, TAG_NTFS); ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord); return STATUS_DISK_FULL; } // TODO: Observe MFT reservation zone // Can we get one contiguous run? AssignedRun = RtlFindClearBitsAndSet(&Bitmap, DesiredClusters, FirstDesiredCluster); if (AssignedRun != 0xFFFFFFFF) { *FirstAssignedCluster = AssignedRun; *AssignedClusters = DesiredClusters; } else { // we can't get one contiguous run *AssignedClusters = RtlFindNextForwardRunClear(&Bitmap, FirstDesiredCluster, FirstAssignedCluster); if (*AssignedClusters == 0) { // we couldn't find any runs starting at DesiredFirstCluster *AssignedClusters = RtlFindLongestRunClear(&Bitmap, FirstAssignedCluster); } } Status = WriteAttribute(DeviceExt, DataContext, 0, BitmapData, (ULONG)BitmapDataSize, &LengthWritten, BitmapRecord); ReleaseAttributeContext(DataContext); ExFreePoolWithTag(BitmapData, TAG_NTFS); ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord); return Status; }
static UCHAR XmsRealloc(WORD Handle, WORD NewSize) { DWORD BlockNumber; PXMS_HANDLE HandleEntry = GetHandleRecord(Handle); DWORD CurrentIndex = 0; ULONG RunStart; ULONG RunSize; if (!ValidateHandle(HandleEntry)) return XMS_STATUS_INVALID_HANDLE; if (HandleEntry->LockCount) return XMS_STATUS_LOCKED; /* Get the block number */ BlockNumber = (HandleEntry->Address - XMS_ADDRESS) / XMS_BLOCK_SIZE; if (NewSize < HandleEntry->Size) { /* Just reduce the size of this block */ RtlClearBits(&AllocBitmap, BlockNumber + NewSize, HandleEntry->Size - NewSize); FreeBlocks += HandleEntry->Size - NewSize; HandleEntry->Size = NewSize; } else if (NewSize > HandleEntry->Size) { /* Check if we can expand in-place */ if (RtlAreBitsClear(&AllocBitmap, BlockNumber + HandleEntry->Size, NewSize - HandleEntry->Size)) { /* Just increase the size of this block */ RtlSetBits(&AllocBitmap, BlockNumber + HandleEntry->Size, NewSize - HandleEntry->Size); FreeBlocks -= NewSize - HandleEntry->Size; HandleEntry->Size = NewSize; /* We're done */ return XMS_STATUS_SUCCESS; } /* Deallocate the current block range */ RtlClearBits(&AllocBitmap, BlockNumber, HandleEntry->Size); /* Find a new place for this block */ while (CurrentIndex < XMS_BLOCKS) { RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart); if (RunSize == 0) break; if (RunSize >= NewSize) { /* Allocate the new range */ RtlSetBits(&AllocBitmap, RunStart, NewSize); /* Move the data to the new location */ RtlMoveMemory((PVOID)REAL_TO_PHYS(XMS_ADDRESS + RunStart * XMS_BLOCK_SIZE), (PVOID)REAL_TO_PHYS(HandleEntry->Address), HandleEntry->Size * XMS_BLOCK_SIZE); /* Update the handle entry */ HandleEntry->Address = XMS_ADDRESS + RunStart * XMS_BLOCK_SIZE; HandleEntry->Size = NewSize; /* Update the free block counter */ FreeBlocks -= NewSize - HandleEntry->Size; return XMS_STATUS_SUCCESS; } /* Keep searching */ CurrentIndex = RunStart + RunSize; } /* Restore the old block range */ RtlSetBits(&AllocBitmap, BlockNumber, HandleEntry->Size); return XMS_STATUS_OUT_OF_MEMORY; } return XMS_STATUS_SUCCESS; }
static UCHAR XmsAlloc(WORD Size, PWORD Handle) { BYTE i; PXMS_HANDLE HandleEntry; DWORD CurrentIndex = 0; ULONG RunStart; ULONG RunSize; if (Size > FreeBlocks) return XMS_STATUS_OUT_OF_MEMORY; for (i = 0; i < XMS_MAX_HANDLES; i++) { HandleEntry = &HandleTable[i]; if (HandleEntry->Handle == 0) { *Handle = i + 1; break; } } if (i == XMS_MAX_HANDLES) return XMS_STATUS_OUT_OF_HANDLES; /* Optimize blocks */ for (i = 0; i < XMS_MAX_HANDLES; i++) { /* Skip free and locked blocks */ if (HandleEntry->Handle == 0 || HandleEntry->LockCount > 0) continue; CurrentIndex = (HandleEntry->Address - XMS_ADDRESS) / XMS_BLOCK_SIZE; /* Check if there is any free space before this block */ RunSize = RtlFindLastBackwardRunClear(&AllocBitmap, CurrentIndex, &RunStart); if (RunSize == 0) break; /* Move this block back */ RtlMoveMemory((PVOID)REAL_TO_PHYS(HandleEntry->Address - RunSize * XMS_BLOCK_SIZE), (PVOID)REAL_TO_PHYS(HandleEntry->Address), RunSize * XMS_BLOCK_SIZE); /* Update the address */ HandleEntry->Address -= RunSize * XMS_BLOCK_SIZE; } while (CurrentIndex < XMS_BLOCKS) { RunSize = RtlFindNextForwardRunClear(&AllocBitmap, CurrentIndex, &RunStart); if (RunSize == 0) break; if (RunSize >= HandleEntry->Size) { /* Allocate it here */ HandleEntry->Handle = i + 1; HandleEntry->LockCount = 0; HandleEntry->Size = Size; HandleEntry->Address = XMS_ADDRESS + RunStart * XMS_BLOCK_SIZE; FreeBlocks -= Size; RtlSetBits(&AllocBitmap, RunStart, HandleEntry->Size); return XMS_STATUS_SUCCESS; } /* Keep searching */ CurrentIndex = RunStart + RunSize; } return XMS_STATUS_OUT_OF_MEMORY; }
ULONG NtdllBitmap::FindNextForwardRunClear( ULONG from_index, PULONG starting_run_index ) { assert(RtlFindNextForwardRunClear != NULL); return RtlFindNextForwardRunClear(this, from_index, starting_run_index); }