/* * pmemobj_strndup -- allocates a new object with duplicate of the string s. */ int pmemobj_strdup(PMEMobjpool *pop, PMEMoid *oidp, const char *s, unsigned int type_num) { LOG(3, "pop %p oidp %p string %s type_num %u", pop, oidp, s, type_num); /* log notice message if used inside a transaction */ _POBJ_DEBUG_NOTICE_IN_TX(); if (type_num >= PMEMOBJ_NUM_OID_TYPES) { errno = EINVAL; ERR("!pmemobj_strdup"); LOG(2, "type_num has to be in range [0, %i]", PMEMOBJ_NUM_OID_TYPES - 1); return -1; } if (NULL == s) { errno = EINVAL; return -1; } struct carg_strdup carg; carg.size = (strlen(s) + 1) * sizeof (char); carg.s = s; return obj_alloc_construct(pop, oidp, carg.size, type_num, constructor_strdup, &carg); }
/* * pmemobj_zalloc -- allocates a new zeroed object */ int pmemobj_zalloc(PMEMobjpool *pop, PMEMoid *oidp, size_t size, unsigned int type_num) { LOG(3, "pop %p oidp %p size %zu type_num %u", pop, oidp, size, type_num); /* log notice message if used inside a transaction */ _POBJ_DEBUG_NOTICE_IN_TX(); if (size == 0) { ERR("allocation with size 0"); errno = EINVAL; return -1; } if (type_num >= PMEMOBJ_NUM_OID_TYPES) { errno = EINVAL; ERR("invalid type_num %u", type_num); return -1; } return obj_alloc_construct(pop, oidp, size, (type_num_t)type_num, 1, NULL, NULL); }
/* * pmemobj_alloc -- allocates a new object */ int pmemobj_alloc(PMEMobjpool *pop, PMEMoid *oidp, size_t size, unsigned int type_num, void (*constructor)(PMEMobjpool *pop, void *ptr, void *arg), void *arg) { LOG(3, "pop %p oidp %p size %zu type_num %u constructor %p arg %p", pop, oidp, size, type_num, constructor, arg); /* log notice message if used inside a transaction */ _POBJ_DEBUG_NOTICE_IN_TX(); if (size == 0) { ERR("allocation with size 0"); errno = EINVAL; return -1; } return obj_alloc_construct(pop, oidp, size, type_num, constructor, arg); }
/* * pmemobj_zalloc -- allocates a new zeroed object */ int pmemobj_zalloc(PMEMobjpool *pop, PMEMoid *oidp, size_t size, unsigned int type_num) { LOG(3, "pop %p oidp %p size %zu type_num %u", pop, oidp, size, type_num); /* log notice message if used inside a transaction */ _POBJ_DEBUG_NOTICE_IN_TX(); if (size == 0) { ERR("allocation with size 0"); errno = EINVAL; return -1; } struct carg_alloc carg; carg.size = size; return obj_alloc_construct(pop, oidp, size, type_num, constructor_zalloc, &carg); }
/* * obj_realloc_common -- (internal) common routine for resizing * existing objects */ static int obj_realloc_common(PMEMobjpool *pop, struct object_store *store, PMEMoid *oidp, size_t size, unsigned int type_num, void (*constr_alloc)(PMEMobjpool *pop, void *ptr, void *arg), void (*constr_realloc)(PMEMobjpool *pop, void *ptr, void *arg)) { /* if OID is NULL just allocate memory */ if (OBJ_OID_IS_NULL(*oidp)) { struct carg_alloc carg; carg.size = size; /* if size is 0 - do nothing */ if (size == 0) return 0; return obj_alloc_construct(pop, oidp, size, type_num, constr_alloc, &carg); } if (size > PMEMOBJ_MAX_ALLOC_SIZE) { ERR("requested size too large"); errno = ENOMEM; return -1; } /* if size is 0 just free */ if (size == 0) { obj_free(pop, oidp); return 0; } struct carg_realloc carg; carg.ptr = OBJ_OFF_TO_PTR(pop, oidp->off); carg.new_size = size; carg.old_size = pmemobj_alloc_usable_size(*oidp); carg.user_type = type_num; carg.constructor = NULL; carg.arg = NULL; struct oob_header *pobj = OOB_HEADER_FROM_OID(pop, *oidp); uint16_t user_type_old = pobj->data.user_type; ASSERT(user_type_old < PMEMOBJ_NUM_OID_TYPES); if (type_num >= PMEMOBJ_NUM_OID_TYPES) { errno = EINVAL; ERR("!obj_realloc_construct"); LOG(2, "type_num has to be in range [0, %u]", PMEMOBJ_NUM_OID_TYPES - 1); return -1; } struct list_head *lhead_old = &store->bytype[user_type_old].head; if (type_num == user_type_old) { int ret = list_realloc(pop, lhead_old, 0, NULL, size, constr_realloc, &carg, 0, 0, oidp); if (ret) LOG(2, "list_realloc failed"); return ret; } else { struct list_head *lhead_new = &store->bytype[type_num].head; /* * Redo log updates 8 byte entries, so we have to prepare * full 8-byte value even if we want to update smaller field * (here: user_type). */ struct oob_header_data d = pobj->data; d.user_type = type_num; uint64_t data_offset = OOB_OFFSET_OF(*oidp, data); int ret = list_realloc_move(pop, lhead_old, lhead_new, 0, NULL, size, constr_realloc, &carg, data_offset, *((uint64_t *)&d), oidp); if (ret) LOG(2, "list_realloc_move failed"); return ret; } }
/* * obj_realloc_common -- (internal) common routine for resizing * existing objects */ static int obj_realloc_common(PMEMobjpool *pop, struct object_store *store, PMEMoid *oidp, size_t size, type_num_t type_num, int zero_init) { /* if OID is NULL just allocate memory */ if (OBJ_OID_IS_NULL(*oidp)) { /* if size is 0 - do nothing */ if (size == 0) return 0; return obj_alloc_construct(pop, oidp, size, type_num, zero_init, NULL, NULL); } if (size > PMEMOBJ_MAX_ALLOC_SIZE) { ERR("requested size too large"); errno = ENOMEM; return -1; } /* if size is 0 just free */ if (size == 0) { obj_free(pop, oidp); return 0; } struct carg_realloc carg; carg.ptr = OBJ_OFF_TO_PTR(pop, oidp->off); carg.new_size = size; carg.old_size = pmemobj_alloc_usable_size(*oidp); carg.user_type = type_num; carg.constructor = NULL; carg.arg = NULL; carg.zero_init = zero_init; struct oob_header *pobj = OOB_HEADER_FROM_OID(pop, *oidp); type_num_t user_type_old = pobj->data.user_type; /* callers should have checked this */ ASSERT(type_num < PMEMOBJ_NUM_OID_TYPES); ASSERT(user_type_old < PMEMOBJ_NUM_OID_TYPES); struct list_head *lhead_old = &store->bytype[user_type_old].head; if (type_num == user_type_old) { int ret = list_realloc(pop, lhead_old, 0, NULL, size, constructor_realloc, &carg, 0, 0, oidp); if (ret) LOG(2, "list_realloc failed"); /* oidp could be different, so we need to get the ptr again */ VALGRIND_DO_MAKE_MEM_NOACCESS(pop, &OOB_HEADER_FROM_OID(pop, *oidp)->data.padding, sizeof (OOB_HEADER_FROM_OID(pop, *oidp)->data.padding)); return ret; } else { struct list_head *lhead_new = &store->bytype[type_num].head; /* * Header padding doubles as a red zone to check for header * overwrites. Disable it temporarily so we can modify the type * number. */ VALGRIND_DO_MAKE_MEM_DEFINED(pop, &OOB_HEADER_FROM_OID(pop, *oidp)->data.padding, sizeof (OOB_HEADER_FROM_OID(pop, *oidp)->data.padding)); /* * Redo log updates 8 byte entries, so we have to prepare * full 8-byte value even if we want to update smaller field * (here: user_type). */ struct oob_header_data d = pobj->data; d.user_type = type_num; uint64_t data_offset = OOB_OFFSET_OF(*oidp, data); int ret = list_realloc_move(pop, lhead_old, lhead_new, 0, NULL, size, constructor_realloc, &carg, data_offset, *((uint64_t *)&d), oidp); if (ret) LOG(2, "list_realloc_move failed"); /* oidp could be different, so we need to get the ptr again */ VALGRIND_DO_MAKE_MEM_NOACCESS(pop, &OOB_HEADER_FROM_OID(pop, *oidp)->data.padding, sizeof (OOB_HEADER_FROM_OID(pop, *oidp)->data.padding)); return ret; } }