/* * pool_hdr_uuid_links -- (internal) check UUID links values */ static int pool_hdr_uuid_links(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); /* * If the pool header is valid and there is not other parts or replicas * in the poolset its uuid links are also valid. */ if (loc->hdr_valid && loc->single_repl && loc->single_part) return 0; uuid_t *links[] = { &loc->hdr.next_part_uuid, &loc->hdr.prev_part_uuid, &loc->hdr.next_repl_uuid, &loc->hdr.prev_repl_uuid}; uuid_t *uuids[] = { &loc->next_part_hdrp->uuid, &loc->prev_part_hdrp->uuid, &loc->next_repl_hdrp->uuid, &loc->prev_repl_hdrp->uuid }; uint32_t questions[] = { Q_NEXT_PART_UUID_SET, Q_PREV_PART_UUID_SET, Q_NEXT_REPL_UUID_SET, Q_PREV_REPL_UUID_SET }; const char *fields[] = { "pool_hdr.next_part_uuid", "pool_hdr.prev_part_uuid", "pool_hdr.next_repl_uuid", "pool_hdr.prev_repl_uuid" }; COMPILE_ERROR_ON(ARRAY_SIZE(links) != ARRAY_SIZE(uuids)); COMPILE_ERROR_ON(ARRAY_SIZE(links) != ARRAY_SIZE(questions)); COMPILE_ERROR_ON(ARRAY_SIZE(links) != ARRAY_SIZE(fields)); for (uint64_t i = 0; i < ARRAY_SIZE(links); ++i) { if (uuidcmp(*links[i], *uuids[i]) == 0) continue; if (CHECK_IS(ppc, REPAIR)) { CHECK_ASK(ppc, questions[i], "%sinvalid %s.|Do you want to set it to a " "valid value?", loc->prefix, fields[i]); } else { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "%sinvalid %s", loc->prefix, fields[i]); } } return check_questions_sequence_validate(ppc); }
/* * alloc_class_find_or_create -- (internal) searches for the * biggest allocation class for which unit_size is evenly divisible by n. * If no such class exists, create one. */ static struct alloc_class * alloc_class_find_or_create(struct alloc_class_collection *ac, size_t n) { LOG(10, NULL); COMPILE_ERROR_ON(MAX_ALLOCATION_CLASSES > UINT8_MAX); uint64_t required_size_bytes = n * RUN_MIN_NALLOCS; uint32_t required_size_idx = 1; if (required_size_bytes > RUNSIZE) { required_size_bytes -= RUNSIZE; required_size_idx += CALC_SIZE_IDX(CHUNKSIZE, required_size_bytes); if (required_size_idx > RUN_SIZE_IDX_CAP) required_size_idx = RUN_SIZE_IDX_CAP; } for (int i = MAX_ALLOCATION_CLASSES - 1; i >= 0; --i) { struct alloc_class *c = ac->aclasses[i]; if (c == NULL || c->type == CLASS_HUGE || c->run.size_idx < required_size_idx) continue; if (n % c->unit_size == 0 && n / c->unit_size <= RUN_UNIT_MAX_ALLOC) return c; } /* * In order to minimize the wasted space at the end of the run the * run data size must be divisible by the allocation class unit size * with the smallest possible remainder, preferably 0. */ size_t runsize_bytes = RUN_SIZE_BYTES(required_size_idx); while ((runsize_bytes % n) > MAX_RUN_WASTED_BYTES) { n += ALLOC_BLOCK_SIZE_GEN; } /* * Now that the desired unit size is found the existing classes need * to be searched for possible duplicates. If a class that can handle * the calculated size already exists, simply return that. */ for (int i = 1; i < MAX_ALLOCATION_CLASSES; ++i) { struct alloc_class *c = ac->aclasses[i]; if (c == NULL || c->type == CLASS_HUGE) continue; if (n / c->unit_size <= RUN_UNIT_MAX_ALLOC && n % c->unit_size == 0) return c; if (c->unit_size == n) return c; } return alloc_class_new(-1, ac, CLASS_RUN, HEADER_COMPACT, n, 0, required_size_idx); }
/* * obj_init -- initialization of obj * * Called by constructor. */ void obj_init(void) { LOG(3, NULL); COMPILE_ERROR_ON(sizeof (struct pmemobjpool) != 8192); pools = cuckoo_new(); if (pools == NULL) FATAL("!cuckoo_new"); }
/* * pmalloc_boot -- initializes allocator section */ static int pmalloc_boot(PMEMobjpool *pop) { COMPILE_ERROR_ON(PALLOC_DATA_OFF != OBJ_OOB_SIZE); COMPILE_ERROR_ON(ALLOC_BLOCK_SIZE != _POBJ_CL_ALIGNMENT); int ret = palloc_boot(&pop->heap, (char *)pop + pop->heap_offset, pop->heap_size, pop, &pop->p_ops); if (ret) return ret; #ifdef USE_VG_MEMCHECK palloc_heap_vg_open(&pop->heap, obj_vg_register, pop, pop->vg_boot); #endif ret = palloc_buckets_init(&pop->heap); if (ret) palloc_heap_cleanup(&pop->heap); return ret; }
/* * shutdown_state_init -- initializes shutdown_state struct */ int shutdown_state_init(struct shutdown_state *sds, struct pool_replica *rep) { /* check if we didn't change size of shutdown_state accidentally */ COMPILE_ERROR_ON(sizeof(struct shutdown_state) != 64); LOG(3, "sds %p", sds); memset(sds, 0, sizeof(*sds)); shutdown_state_checksum(sds, rep); return 0; }
/* * palloc_reserve -- creates a single reservation */ int palloc_reserve(struct palloc_heap *heap, size_t size, palloc_constr constructor, void *arg, uint64_t extra_field, uint16_t object_flags, uint16_t class_id, struct pobj_action *act) { COMPILE_ERROR_ON(sizeof(struct pobj_action) != sizeof(struct pobj_action_internal)); act->type = POBJ_ACTION_TYPE_HEAP; return palloc_reservation_create(heap, size, constructor, arg, extra_field, object_flags, class_id, (struct pobj_action_internal *)act); }
/* * chunk_get_chunk_hdr_value -- (internal) get value of a header for redo log */ static uint64_t chunk_get_chunk_hdr_value(uint16_t type, uint32_t size_idx) { uint64_t val; COMPILE_ERROR_ON(sizeof(struct chunk_header) != sizeof(uint64_t)); struct chunk_header hdr; hdr.type = type; hdr.size_idx = size_idx; hdr.flags = 0; memcpy(&val, &hdr, sizeof(val)); return val; }
/* * obj_init -- initialization of obj * * Called by constructor. */ void obj_init(void) { LOG(3, NULL); COMPILE_ERROR_ON(sizeof (struct pmemobjpool) != 8192); #ifdef USE_COW_ENV char *env = getenv("PMEMOBJ_COW"); if (env) Open_cow = atoi(env); #endif pools_ht = cuckoo_new(); if (pools_ht == NULL) FATAL("!cuckoo_new"); pools_tree = ctree_new(); if (pools_tree == NULL) FATAL("!ctree_new"); }
/* * util_map_part -- map a header of a pool set */ int util_map_hdr(struct pool_set_part *part, int flags) { LOG(3, "part %p flags %d", part, flags); COMPILE_ERROR_ON(POOL_HDR_SIZE == 0); ASSERTeq(POOL_HDR_SIZE % Pagesize, 0); void *hdrp = mmap(NULL, POOL_HDR_SIZE, PROT_READ|PROT_WRITE, flags, part->fd, 0); if (hdrp == MAP_FAILED) { ERR("!mmap: %s", part->path); return -1; } part->hdrsize = POOL_HDR_SIZE; part->hdr = hdrp; VALGRIND_REGISTER_PMEM_MAPPING(part->hdr, part->hdrsize); VALGRIND_REGISTER_PMEM_FILE(part->fd, part->hdr, part->hdrsize, 0); return 0; }
/* * memblock_header_compact_write -- * (internal) writes a compact header of an object */ static void memblock_header_compact_write(const struct memory_block *m, size_t size, uint64_t extra, uint16_t flags) { COMPILE_ERROR_ON(ALLOC_HDR_COMPACT_SIZE > CACHELINE_SIZE); struct { struct allocation_header_compact hdr; uint8_t padding[CACHELINE_SIZE - ALLOC_HDR_COMPACT_SIZE]; } padded; padded.hdr.size = size | ((uint64_t)flags << ALLOC_HDR_SIZE_SHIFT); padded.hdr.extra = extra; struct allocation_header_compact *hdrp = m->m_ops->get_real_data(m); VALGRIND_DO_MAKE_MEM_UNDEFINED(hdrp, sizeof(*hdrp)); /* * If possible write the entire header with a single memcpy, this allows * the copy implementation to avoid a cache miss on a partial cache line * write. */ size_t hdr_size = ALLOC_HDR_COMPACT_SIZE; if ((uintptr_t)hdrp % CACHELINE_SIZE == 0 && size >= sizeof(padded)) hdr_size = sizeof(padded); VALGRIND_ADD_TO_TX(hdrp, hdr_size); pmemops_memcpy(&m->heap->p_ops, hdrp, &padded, hdr_size, PMEMOBJ_F_MEM_WC | PMEMOBJ_F_MEM_NODRAIN | PMEMOBJ_F_RELAXED); VALGRIND_DO_MAKE_MEM_UNDEFINED((char *)hdrp + ALLOC_HDR_COMPACT_SIZE, hdr_size - ALLOC_HDR_COMPACT_SIZE); VALGRIND_REMOVE_FROM_TX(hdrp, hdr_size); }
/* * pool_hdr_uuid_find -- (internal) check UUID value */ static int pool_hdr_uuid_find(PMEMpoolcheck *ppc, location *loc) { LOG(3, NULL); /* * If the pool header is valid and there is not other parts or replicas * in the poolset its uuid is also valid. */ if (loc->hdr_valid && loc->single_repl && loc->single_part) return 0; int hdrs_valid[] = { loc->next_part_hdr_valid, loc->prev_part_hdr_valid, loc->next_repl_hdr_valid, loc->prev_repl_hdr_valid}; uuid_t *uuids[] = { &loc->next_part_hdrp->prev_part_uuid, &loc->prev_part_hdrp->next_part_uuid, &loc->next_repl_hdrp->prev_repl_uuid, &loc->prev_repl_hdrp->next_repl_uuid }; /* * if all valid poolset part files have the same uuid links to this part * file it is valid uuid * if all links have the same uuid and it is single file pool it is also * the valid uuid */ loc->valid_uuid = NULL; if (loc->hdr_valid) loc->valid_uuid = &loc->hdr.uuid; uuid_t *common_uuid = uuids[0]; COMPILE_ERROR_ON(ARRAY_SIZE(uuids) != ARRAY_SIZE(hdrs_valid)); COMPILE_ERROR_ON(COMPARE_TO_FIRST_PART_ONLY >= ARRAY_SIZE(uuids)); for (unsigned i = 0; i < ARRAY_SIZE(uuids); ++i) { if (i > 0 && common_uuid != NULL) { if (uuidcmp(*common_uuid, *uuids[i]) != 0) { common_uuid = NULL; } } if (i >= COMPARE_TO_FIRST_PART_ONLY && loc->part != 0) continue; if (!hdrs_valid[i]) continue; if (!loc->valid_uuid) { loc->valid_uuid = uuids[i]; } else if (uuidcmp(*loc->valid_uuid, *uuids[i]) != 0) { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, "%sambiguous pool_hdr.uuid", loc->prefix); } } if (!loc->valid_uuid && common_uuid) loc->valid_uuid = common_uuid; if (loc->valid_uuid != NULL) { if (uuidcmp(*loc->valid_uuid, loc->hdr.uuid) != 0) { CHECK_ASK(ppc, Q_UUID_SET, INVALID_UUID ".|Do you want " "to set it to %s from a valid part file?", loc->prefix, check_get_uuid_str(*loc->valid_uuid)); } } else if (CHECK_IS(ppc, ADVANCED)) { CHECK_ASK(ppc, Q_UUID_REGENERATE, INVALID_UUID ".|Do you want " "to regenerate it?", loc->prefix); } else if (CHECK_IS(ppc, REPAIR)) { ppc->result = CHECK_RESULT_CANNOT_REPAIR; CHECK_INFO(ppc, "%s" REQUIRE_ADVANCED, loc->prefix); return CHECK_ERR(ppc, INVALID_UUID, loc->prefix); } else { ppc->result = CHECK_RESULT_NOT_CONSISTENT; return CHECK_ERR(ppc, INVALID_UUID, loc->prefix); } return check_questions_sequence_validate(ppc); }