/* * alloc_class_from_params -- (internal) creates a new allocation class */ static struct alloc_class * alloc_class_from_params(struct alloc_class_collection *ac, enum alloc_class_type type, size_t unit_size, unsigned unit_max, unsigned unit_max_alloc, uint32_t size_idx) { struct alloc_class c; c.unit_size = unit_size; c.header_type = HEADER_COMPACT; c.type = type; switch (type) { case CLASS_HUGE: c.id = DEFAULT_ALLOC_CLASS_ID; break; case CLASS_RUN: alloc_class_generate_run_proto(&c.run, unit_size, size_idx); uint8_t slot; if (alloc_class_find_first_free_slot(ac, &slot) != 0) { return NULL; } c.id = slot; break; default: ASSERT(0); } return alloc_class_register(ac, &c); }
/* * alloc_class_new -- creates a new allocation class */ struct alloc_class * alloc_class_new(int id, struct alloc_class_collection *ac, enum alloc_class_type type, enum header_type htype, size_t unit_size, size_t alignment, uint32_t size_idx) { LOG(10, NULL); struct alloc_class *c = Malloc(sizeof(*c)); if (c == NULL) goto error_class_alloc; c->unit_size = unit_size; c->header_type = htype; c->type = type; c->flags = (uint16_t) (header_type_to_flag[c->header_type] | (alignment ? CHUNK_FLAG_ALIGNED : 0)); switch (type) { case CLASS_HUGE: id = DEFAULT_ALLOC_CLASS_ID; break; case CLASS_RUN: alloc_class_generate_run_proto(&c->run, unit_size, size_idx, alignment); uint8_t slot = (uint8_t)id; if (id < 0 && alloc_class_find_first_free_slot(ac, &slot) != 0) goto error_class_alloc; id = slot; size_t map_idx = SIZE_TO_CLASS_MAP_INDEX(c->unit_size, ac->granularity); ASSERT(map_idx <= UINT32_MAX); uint32_t map_idx_s = (uint32_t)map_idx; ASSERT(c->run.size_idx <= UINT16_MAX); uint16_t size_idx_s = (uint16_t)c->run.size_idx; uint16_t flags_s = (uint16_t)c->flags; uint64_t k = RUN_CLASS_KEY_PACK(map_idx_s, flags_s, size_idx_s); if (cuckoo_insert(ac->class_map_by_unit_size, k, c) != 0) { ERR("unable to register allocation class"); goto error_map_insert; } break; default: ASSERT(0); } c->id = (uint8_t)id; ac->aclasses[c->id] = c; return c; error_map_insert: Free(c); error_class_alloc: if (id >= 0) alloc_class_reservation_clear(ac, id); return NULL; }
/* * CTL_WRITE_HANDLER(proto) -- creates a new allocation class */ static int CTL_WRITE_HANDLER(desc)(void *ctx, enum ctl_query_source source, void *arg, struct ctl_indexes *indexes) { PMEMobjpool *pop = ctx; uint8_t id; struct alloc_class_collection *ac = heap_alloc_classes(&pop->heap); struct pobj_alloc_class_desc *p = arg; if (p->unit_size <= 0 || p->unit_size > PMEMOBJ_MAX_ALLOC_SIZE || p->units_per_block <= 0) { errno = EINVAL; return -1; } if (p->alignment != 0 && p->unit_size % p->alignment != 0) { ERR("unit size must be evenly divisible by alignment"); errno = EINVAL; return -1; } if (p->alignment > (MEGABYTE * 2)) { ERR("alignment cannot be larger than 2 megabytes"); errno = EINVAL; return -1; } enum header_type lib_htype = MAX_HEADER_TYPES; switch (p->header_type) { case POBJ_HEADER_LEGACY: lib_htype = HEADER_LEGACY; break; case POBJ_HEADER_COMPACT: lib_htype = HEADER_COMPACT; break; case POBJ_HEADER_NONE: lib_htype = HEADER_NONE; break; case MAX_POBJ_HEADER_TYPES: default: ERR("invalid header type"); errno = EINVAL; return -1; } if (SLIST_EMPTY(indexes)) { if (alloc_class_find_first_free_slot(ac, &id) != 0) { ERR("no available free allocation class identifier"); errno = EINVAL; return -1; } } else { struct ctl_index *idx = SLIST_FIRST(indexes); ASSERTeq(strcmp(idx->name, "class_id"), 0); if (idx->value < 0 || idx->value >= MAX_ALLOCATION_CLASSES) { ERR("class id outside of the allowed range"); errno = ERANGE; return -1; } id = (uint8_t)idx->value; if (alloc_class_reserve(ac, id) != 0) { ERR("attempted to overwrite an allocation class"); errno = EEXIST; return -1; } } size_t runsize_bytes = CHUNK_ALIGN_UP((p->units_per_block * p->unit_size) + RUN_BASE_METADATA_SIZE); /* aligning the buffer might require up-to to 'alignment' bytes */ if (p->alignment != 0) runsize_bytes += p->alignment; uint32_t size_idx = (uint32_t)(runsize_bytes / CHUNKSIZE); if (size_idx > UINT16_MAX) size_idx = UINT16_MAX; struct alloc_class *c = alloc_class_new(id, heap_alloc_classes(&pop->heap), CLASS_RUN, lib_htype, p->unit_size, p->alignment, size_idx); if (c == NULL) { errno = EINVAL; return -1; } if (heap_create_alloc_class_buckets(&pop->heap, c) != 0) { alloc_class_delete(ac, c); return -1; } p->class_id = c->id; p->units_per_block = c->run.nallocs; return 0; }