/* * memblock_rebuild_state -- fills in the runtime-state related fields of a * memory block structure * * This function must be called on all memory blocks that were created by hand * (as opposed to retrieved from memblock_from_offset function). */ void memblock_rebuild_state(struct palloc_heap *heap, struct memory_block *m) { m->heap = heap; m->header_type = memblock_header_type(m); m->type = memblock_detect_type(heap, m); m->m_ops = &mb_ops[m->type]; }
/* * memblock_from_offset -- resolves a memory block data from an offset that * originates from the heap */ struct memory_block memblock_from_offset_opt(struct palloc_heap *heap, uint64_t off, int size) { struct memory_block m = MEMORY_BLOCK_NONE; m.heap = heap; off -= HEAP_PTR_TO_OFF(heap, &heap->layout->zone0); m.zone_id = (uint32_t)(off / ZONE_MAX_SIZE); off -= (ZONE_MAX_SIZE * m.zone_id) + sizeof(struct zone); m.chunk_id = (uint32_t)(off / CHUNKSIZE); struct chunk_header *hdr = &ZID_TO_ZONE(heap->layout, m.zone_id) ->chunk_headers[m.chunk_id]; if (hdr->type == CHUNK_TYPE_RUN_DATA) m.chunk_id -= hdr->size_idx; off -= CHUNKSIZE * m.chunk_id; m.header_type = memblock_header_type(&m); off -= header_type_to_size[m.header_type]; m.type = off != 0 ? MEMORY_BLOCK_RUN : MEMORY_BLOCK_HUGE; #ifdef DEBUG enum memory_block_type t = memblock_detect_type(&m, heap->layout); ASSERTeq(t, m.type); #endif m.m_ops = &mb_ops[m.type]; uint64_t unit_size = m.m_ops->block_size(&m); if (off != 0) { /* run */ off -= RUN_METASIZE; m.block_off = (uint16_t)(off / unit_size); off -= m.block_off * unit_size; } m.size_idx = !size ? 0 : CALC_SIZE_IDX(unit_size, memblock_header_ops[m.header_type].get_size(&m)); ASSERTeq(off, 0); return m; }
/* * memblock_from_offset -- resolves a memory block data from an offset that * originates from the heap */ struct memory_block memblock_from_offset_opt(struct palloc_heap *heap, uint64_t off, int size) { struct memory_block m = MEMORY_BLOCK_NONE; m.heap = heap; off -= HEAP_PTR_TO_OFF(heap, &heap->layout->zone0); m.zone_id = (uint32_t)(off / ZONE_MAX_SIZE); off -= (ZONE_MAX_SIZE * m.zone_id) + sizeof(struct zone); m.chunk_id = (uint32_t)(off / CHUNKSIZE); struct chunk_header *hdr = heap_get_chunk_hdr(heap, &m); if (hdr->type == CHUNK_TYPE_RUN_DATA) m.chunk_id -= hdr->size_idx; off -= CHUNKSIZE * m.chunk_id; m.header_type = memblock_header_type(&m); off -= header_type_to_size[m.header_type]; m.type = off != 0 ? MEMORY_BLOCK_RUN : MEMORY_BLOCK_HUGE; ASSERTeq(memblock_detect_type(heap, &m), m.type); m.m_ops = &mb_ops[m.type]; uint64_t unit_size = m.m_ops->block_size(&m); if (off != 0) { /* run */ struct chunk_run *run = heap_get_chunk_run(heap, &m); off -= run_get_alignment_padding(hdr, run, m.header_type); off -= RUN_METASIZE; m.block_off = (uint16_t)(off / unit_size); off -= m.block_off * unit_size; } m.size_idx = !size ? 0 : CALC_SIZE_IDX(unit_size, memblock_header_ops[m.header_type].get_size(&m)); ASSERTeq(off, 0); return m; }
/* * memblock_validate_offset -- checks the state of any arbtirary offset within * the heap. * * This function traverses an entire zone, so use with caution. */ enum memblock_state memblock_validate_offset(struct palloc_heap *heap, uint64_t off) { struct memory_block m = MEMORY_BLOCK_NONE; m.heap = heap; off -= HEAP_PTR_TO_OFF(heap, &heap->layout->zone0); m.zone_id = (uint32_t)(off / ZONE_MAX_SIZE); off -= (ZONE_MAX_SIZE * m.zone_id) + sizeof(struct zone); m.chunk_id = (uint32_t)(off / CHUNKSIZE); struct zone *z = ZID_TO_ZONE(heap->layout, m.zone_id); struct chunk_header *hdr = &z->chunk_headers[m.chunk_id]; if (hdr->type == CHUNK_TYPE_RUN_DATA) m.chunk_id -= hdr->size_idx; off -= CHUNKSIZE * m.chunk_id; for (uint32_t i = 0; i < z->header.size_idx; ) { hdr = &z->chunk_headers[i]; if (i + hdr->size_idx > m.chunk_id && i < m.chunk_id) { return MEMBLOCK_STATE_UNKNOWN; /* invalid chunk */ } else if (m.chunk_id == i) { break; } i += hdr->size_idx; } ASSERTne(hdr, NULL); m.header_type = memblock_header_type(&m); if (hdr->type != CHUNK_TYPE_RUN) { if (header_type_to_size[m.header_type] != off) return MEMBLOCK_STATE_UNKNOWN; else if (hdr->type == CHUNK_TYPE_USED) return MEMBLOCK_ALLOCATED; else if (hdr->type == CHUNK_TYPE_FREE) return MEMBLOCK_FREE; else return MEMBLOCK_STATE_UNKNOWN; } if (header_type_to_size[m.header_type] > off) return MEMBLOCK_STATE_UNKNOWN; off -= header_type_to_size[m.header_type]; m.type = off != 0 ? MEMORY_BLOCK_RUN : MEMORY_BLOCK_HUGE; #ifdef DEBUG enum memory_block_type t = memblock_detect_type(&m, heap->layout); ASSERTeq(t, m.type); #endif m.m_ops = &mb_ops[m.type]; uint64_t unit_size = m.m_ops->block_size(&m); if (off != 0) { /* run */ off -= RUN_METASIZE; m.block_off = (uint16_t)(off / unit_size); off -= m.block_off * unit_size; } m.size_idx = CALC_SIZE_IDX(unit_size, memblock_header_ops[m.header_type].get_size(&m)); ASSERTeq(off, 0); return m.m_ops->get_state(&m); }