/* Checks that freed chunks are marked NOACCESS */ static void check_free2() { struct dm_pool *p = dm_pool_create("", 900); /* 900 will get * rounded up to 1024, * 1024 would have got * rounded up to * 2048 */ char *data1, *data2; assert(p); data1 = dm_pool_alloc(p, 123); assert(data1); data1 = dm_pool_alloc(p, 1024); assert(data1); data2 = dm_pool_alloc(p, 123); assert(data2); data2[0] = 'A'; /* should work fine */ dm_pool_free(p, data1); /* * so now the first chunk is active, the second chunk has become * the free one. */ data2[0] = 'B'; /* should prompt an invalid write error */ dm_pool_destroy(p); }
/* * Looking at the code I'm not sure allocations that are near the chunk * size are working. So this test is trying to exhibit a specific problem. */ static void check_allocation_near_chunk_size() { int i; char *data; struct dm_pool *p = dm_pool_create("", 900); /* * allocate a lot and then free everything so we know there * is a spare chunk. */ for (i = 0; i < 1000; i++) { data = dm_pool_alloc(p, 37); memset(data, 0, 37); assert(data); } dm_pool_empty(p); /* now we allocate something close to the chunk size ... */ data = dm_pool_alloc(p, 1020); assert(data); memset(data, 0, 1020); dm_pool_destroy(p); }
static int _read_lvs(struct disk_list *data) { unsigned int i, lvs_read = 0; uint64_t pos; struct lvd_list *ll; struct vg_disk *vgd = &data->vgd; for (i = 0; (i < vgd->lv_max) && (lvs_read < vgd->lv_cur); i++) { pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk)); ll = dm_pool_alloc(data->mem, sizeof(*ll)); if (!ll) return_0; if (!_read_lvd(data->dev, pos, &ll->lvd)) return_0; if (!_check_lvd(&ll->lvd)) continue; lvs_read++; dm_list_add(&data->lvds, &ll->list); } return 1; }
static int _read_uuids(struct disk_list *data) { unsigned num_read = 0; struct uuid_list *ul; char buffer[NAME_LEN] __attribute__((aligned(8))); uint64_t pos = data->pvd.pv_uuidlist_on_disk.base; uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size; while (pos < end && num_read < data->vgd.pv_cur) { if (!dev_read(data->dev, pos, sizeof(buffer), buffer)) return_0; if (!(ul = dm_pool_alloc(data->mem, sizeof(*ul)))) return_0; memcpy(ul->uuid, buffer, NAME_LEN); ul->uuid[NAME_LEN - 1] = '\0'; dm_list_add(&data->uuids, &ul->list); pos += NAME_LEN; num_read++; } return 1; }
struct config_tree *create_config_tree_from_string(const char *config_settings) { struct cs *c; struct config_tree *cft; struct parser *p; if (!(cft = create_config_tree(NULL, 0))) return_NULL; c = (struct cs *) cft; if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) { log_error("Failed to allocate config tree parser."); destroy_config_tree(cft); return NULL; } p->mem = c->mem; p->fb = config_settings; p->fe = config_settings + strlen(config_settings); if (!_parse_config_file(p, cft)) { destroy_config_tree(cft); return_NULL; } return cft; }
static int detach_metadata_devices(struct lv_segment *seg, struct dm_list *list) { uint32_t s; uint32_t num_meta_lvs; struct cmd_context *cmd = seg->lv->vg->cmd; struct lv_list *lvl; num_meta_lvs = seg_is_raid(seg) ? seg->area_count : !!seg->log_lv; if (!num_meta_lvs) return_0; if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl) * num_meta_lvs))) return_0; if (seg_is_raid(seg)) { for (s = 0; s < seg->area_count; s++) { if (!seg_metalv(seg, s)) return_0; /* Trap this future possibility */ lvl[s].lv = seg_metalv(seg, s); lv_set_visible(lvl[s].lv); dm_list_add(list, &lvl[s].list); } return 1; } lvl[0].lv = detach_mirror_log(seg); dm_list_add(list, &lvl[0].list); return 1; }
/* FIXME: test the dbg_malloc at exit (this test should be in dbg_malloc) */ static void check_leak_detection() { int i; struct dm_pool *p = dm_pool_create("", 1024); for (i = 0; i < 10; i++) dm_pool_alloc(p, (i + 1) * 37); }
static char *_dup_token(struct dm_pool *mem, const char *b, const char *e) { size_t len = e - b; char *str = dm_pool_alloc(mem, len + 1); if (!str) { log_error("Failed to duplicate token."); return 0; } memcpy(str, b, len); str[len] = '\0'; return str; }
static char *_dup_tok(struct parser *p) { size_t len = p->te - p->tb; char *str = dm_pool_alloc(p->mem, len + 1); if (!str) { log_error("Failed to duplicate token."); return 0; } memcpy(str, p->tb, len); str[len] = '\0'; return str; }
int internal_filter_allow(struct dm_pool *mem, struct device *dev) { struct device_list *devl; if (!(devl = dm_pool_alloc(mem, sizeof(*devl)))) { log_error("device_list element allocation failed"); return 0; } devl->dev = dev; dm_list_add(&_allow_devs, &devl->list); return 1; }
static struct mirror_state *_mirrored_init_target(struct dm_pool *mem, struct cmd_context *cmd) { struct mirror_state *mirr_state; if (!(mirr_state = dm_pool_alloc(mem, sizeof(*mirr_state)))) { log_error("struct mirr_state allocation failed"); return NULL; } mirr_state->default_region_size = 2 * find_config_tree_int(cmd, "activation/mirror_region_size", DEFAULT_MIRROR_REGION_SIZE); return mirr_state; }
static int _read_extents(struct disk_list *data) { size_t len = sizeof(struct pe_disk) * data->pvd.pe_total; struct pe_disk *extents = dm_pool_alloc(data->mem, len); uint64_t pos = data->pvd.pe_on_disk.base; if (!extents) return_0; if (!dev_read(data->dev, pos, len, extents)) return_0; _xlate_extents(extents, data->pvd.pe_total); data->extents = extents; return 1; }
char *dm_build_dm_uuid(struct dm_pool *mem, const char *uuid_prefix, const char *lvid, const char *layer) { char *dmuuid; size_t len; if (!layer) layer = ""; len = strlen(uuid_prefix) + strlen(lvid) + strlen(layer) + 2; if (!(dmuuid = dm_pool_alloc(mem, len))) { log_error("build_dm_name: Allocation failed for %" PRIsize_t " %s %s.", len, lvid, layer); return NULL; } sprintf(dmuuid, "%s%s%s%s", uuid_prefix, lvid, (*layer) ? "-" : "", layer); return dmuuid; }
int dm_config_parse(struct dm_config_tree *cft, const char *start, const char *end) { /* TODO? if (start == end) return 1; */ struct parser *p; if (!(p = dm_pool_alloc(cft->mem, sizeof(*p)))) return_0; p->mem = cft->mem; p->fb = start; p->fe = end; p->tb = p->te = p->fb; p->line = 1; _get_token(p, TOK_SECTION_E); if (!(cft->root = _file(p))) return_0; return 1; }
static void check_free() { int i; char *blocks[COUNT]; struct dm_pool *p = dm_pool_create("blah", 1024); for (i = 0; i < COUNT; i++) blocks[i] = dm_pool_alloc(p, 37); /* check we can access the last block */ blocks[COUNT - 1][0] = 'E'; if (blocks[COUNT - 1][0] == 'E') printf("first branch worked (as expected)\n"); dm_pool_free(p, blocks[5]); if (blocks[COUNT - 1][0] == 'E') printf("second branch worked (valgrind should have flagged this as an error)\n"); dm_pool_destroy(p); }
/* * <vg>-<lv>-<layer> or if !layer just <vg>-<lv>. */ char *dm_build_dm_name(struct dm_pool *mem, const char *vgname, const char *lvname, const char *layer) { size_t len = 1; int hyphens = 1; char *r, *out; _count_chars(vgname, &len, &hyphens, '-', 0); _count_chars(lvname, &len, &hyphens, '-', 0); if (layer && *layer) { _count_chars(layer, &len, &hyphens, '-', 0); hyphens++; } len += hyphens; if (!(r = dm_pool_alloc(mem, len))) { log_error("build_dm_name: Allocation failed for %" PRIsize_t " for %s %s %s.", len, vgname, lvname, layer); return NULL; } out = r; _quote_hyphens(&out, vgname); *out++ = '-'; _quote_hyphens(&out, lvname); if (layer && *layer) { /* No hyphen if the layer begins with _ e.g. _mlog */ if (*layer != '_') *out++ = '-'; _quote_hyphens(&out, layer); } *out = '\0'; return r; }
int read_config_fd(struct config_tree *cft, struct device *dev, off_t offset, size_t size, off_t offset2, size_t size2, checksum_fn_t checksum_fn, uint32_t checksum) { struct cs *c = (struct cs *) cft; struct parser *p; int r = 0; int use_mmap = 1; off_t mmap_offset = 0; char *buf = NULL; if (!(p = dm_pool_alloc(c->mem, sizeof(*p)))) return_0; p->mem = c->mem; /* Only use mmap with regular files */ if (!(dev->flags & DEV_REGULAR) || size2) use_mmap = 0; if (use_mmap) { mmap_offset = offset % lvm_getpagesize(); /* memory map the file */ p->fb = mmap((caddr_t) 0, size + mmap_offset, PROT_READ, MAP_PRIVATE, dev_fd(dev), offset - mmap_offset); if (p->fb == (caddr_t) (-1)) { log_sys_error("mmap", dev_name(dev)); goto out; } p->fb = p->fb + mmap_offset; } else { if (!(buf = dm_malloc(size + size2))) return_0; if (!dev_read_circular(dev, (uint64_t) offset, size, (uint64_t) offset2, size2, buf)) { goto out; } p->fb = buf; } if (checksum_fn && checksum != (checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)p->fb, size), (const uint8_t *)(p->fb + size), size2))) { log_error("%s: Checksum error", dev_name(dev)); goto out; } p->fe = p->fb + size + size2; if (!_parse_config_file(p, cft)) goto_out; r = 1; out: if (!use_mmap) dm_free(buf); else { /* unmap the file */ if (munmap((char *) (p->fb - mmap_offset), size + mmap_offset)) { log_sys_error("munmap", dev_name(dev)); r = 0; } } return r; }
static int _report(struct cmd_context *cmd, int argc, char **argv, report_type_t report_type) { void *report_handle; const char *opts; char *str; const char *keys = NULL, *options = NULL, *separator; int r = ECMD_PROCESSED; int aligned, buffered, headings; unsigned args_are_pvs; aligned = find_config_tree_int(cmd, "report/aligned", DEFAULT_REP_ALIGNED); buffered = find_config_tree_int(cmd, "report/buffered", DEFAULT_REP_BUFFERED); headings = find_config_tree_int(cmd, "report/headings", DEFAULT_REP_HEADINGS); separator = find_config_tree_str(cmd, "report/separator", DEFAULT_REP_SEPARATOR); args_are_pvs = (report_type == PVS || report_type == PVSEGS) ? 1 : 0; switch (report_type) { case LVS: keys = find_config_tree_str(cmd, "report/lvs_sort", DEFAULT_LVS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/lvs_cols", DEFAULT_LVS_COLS); else options = find_config_tree_str(cmd, "report/lvs_cols_verbose", DEFAULT_LVS_COLS_VERB); break; case VGS: keys = find_config_tree_str(cmd, "report/vgs_sort", DEFAULT_VGS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/vgs_cols", DEFAULT_VGS_COLS); else options = find_config_tree_str(cmd, "report/vgs_cols_verbose", DEFAULT_VGS_COLS_VERB); break; case PVS: keys = find_config_tree_str(cmd, "report/pvs_sort", DEFAULT_PVS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/pvs_cols", DEFAULT_PVS_COLS); else options = find_config_tree_str(cmd, "report/pvs_cols_verbose", DEFAULT_PVS_COLS_VERB); break; case SEGS: keys = find_config_tree_str(cmd, "report/segs_sort", DEFAULT_SEGS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/segs_cols", DEFAULT_SEGS_COLS); else options = find_config_tree_str(cmd, "report/segs_cols_verbose", DEFAULT_SEGS_COLS_VERB); break; case PVSEGS: keys = find_config_tree_str(cmd, "report/pvsegs_sort", DEFAULT_PVSEGS_SORT); if (!arg_count(cmd, verbose_ARG)) options = find_config_tree_str(cmd, "report/pvsegs_cols", DEFAULT_PVSEGS_COLS); else options = find_config_tree_str(cmd, "report/pvsegs_cols_verbose", DEFAULT_PVSEGS_COLS_VERB); break; } /* If -o supplied use it, else use default for report_type */ if (arg_count(cmd, options_ARG)) { opts = arg_str_value(cmd, options_ARG, ""); if (!opts || !*opts) { log_error("Invalid options string: %s", opts); return 0; } if (*opts == '+') { if (!(str = dm_pool_alloc(cmd->mem, strlen(options) + strlen(opts) + 1))) { log_error("options string allocation failed"); return 0; } strcpy(str, options); strcat(str, ","); strcat(str, opts + 1); options = str; } else options = opts; } /* -O overrides default sort settings */ if (arg_count(cmd, sort_ARG)) keys = arg_str_value(cmd, sort_ARG, ""); if (arg_count(cmd, separator_ARG)) separator = arg_str_value(cmd, separator_ARG, " "); if (arg_count(cmd, separator_ARG)) aligned = 0; if (arg_count(cmd, aligned_ARG)) aligned = 1; if (arg_count(cmd, unbuffered_ARG) && !arg_count(cmd, sort_ARG)) buffered = 0; if (arg_count(cmd, noheadings_ARG)) headings = 0; if (!(report_handle = report_init(cmd, options, keys, &report_type, separator, aligned, buffered, headings))) return_0; /* Ensure options selected are compatible */ if (report_type & SEGS) report_type |= LVS; if (report_type & PVSEGS) report_type |= PVS; if ((report_type & LVS) && (report_type & PVS)) { log_error("Can't report LV and PV fields at the same time"); dm_report_free(report_handle); return 0; } /* Change report type if fields specified makes this necessary */ if (report_type & SEGS) report_type = SEGS; else if (report_type & LVS) report_type = LVS; else if (report_type & PVSEGS) report_type = PVSEGS; else if (report_type & PVS) report_type = PVS; switch (report_type) { case LVS: r = process_each_lv(cmd, argc, argv, LCK_VG_READ, report_handle, &_lvs_single); break; case VGS: r = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, report_handle, &_vgs_single); break; case PVS: if (args_are_pvs) r = process_each_pv(cmd, argc, argv, NULL, report_handle, &_pvs_single); else r = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, report_handle, &_pvs_in_vg); break; case SEGS: r = process_each_lv(cmd, argc, argv, LCK_VG_READ, report_handle, &_lvsegs_single); break; case PVSEGS: if (args_are_pvs) r = process_each_pv(cmd, argc, argv, NULL, report_handle, &_pvsegs_single); else r = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, report_handle, &_pvsegs_in_vg); break; } dm_report_output(report_handle); dm_report_free(report_handle); return r; }
const char *dm_size_to_string(struct dm_pool *mem, uint64_t size, char unit_type, int use_si_units, uint64_t unit_factor, int include_suffix, dm_size_suffix_t suffix_type) { unsigned base = BASE_UNKNOWN; unsigned s; int precision; uint64_t byte = UINT64_C(0); uint64_t units = UINT64_C(1024); char *size_buf = NULL; char new_unit_type = '\0', unit_type_buf[2]; const char * const size_str[][3] = { /* BASE_UNKNOWN */ {" ", " ", " "}, /* [0] */ /* BASE_SHARED - Used if use_si_units = 0 */ {" Exabyte", " EB", "E"}, /* [1] */ {" Petabyte", " PB", "P"}, /* [2] */ {" Terabyte", " TB", "T"}, /* [3] */ {" Gigabyte", " GB", "G"}, /* [4] */ {" Megabyte", " MB", "M"}, /* [5] */ {" Kilobyte", " KB", "K"}, /* [6] */ {" Byte ", " B", "B"}, /* [7] */ /* BASE_1024 - Used if use_si_units = 1 */ {" Exbibyte", " EiB", "e"}, /* [8] */ {" Pebibyte", " PiB", "p"}, /* [9] */ {" Tebibyte", " TiB", "t"}, /* [10] */ {" Gibibyte", " GiB", "g"}, /* [11] */ {" Mebibyte", " MiB", "m"}, /* [12] */ {" Kibibyte", " KiB", "k"}, /* [13] */ {" Byte ", " B", "b"}, /* [14] */ /* BASE_1000 - Used if use_si_units = 1 */ {" Exabyte", " EB", "E"}, /* [15] */ {" Petabyte", " PB", "P"}, /* [16] */ {" Terabyte", " TB", "T"}, /* [17] */ {" Gigabyte", " GB", "G"}, /* [18] */ {" Megabyte", " MB", "M"}, /* [19] */ {" Kilobyte", " kB", "K"}, /* [20] */ /* BASE_SPECIAL */ {" Byte ", " B ", "B"}, /* [21] (shared with BASE_1000) */ {" Units ", " Un", "U"}, /* [22] */ {" Sectors ", " Se", "S"}, /* [23] */ }; if (!(size_buf = dm_pool_alloc(mem, SIZE_BUF))) { log_error("no memory for size display buffer"); return ""; } if (!use_si_units) { /* Case-independent match */ for (s = 0; s < NUM_UNIT_PREFIXES; s++) if (toupper((int) unit_type) == *size_str[BASE_SHARED + s][2]) { base = BASE_SHARED; break; } } else { /* Case-dependent match for powers of 1000 */ for (s = 0; s < NUM_UNIT_PREFIXES; s++) if (unit_type == *size_str[BASE_1000 + s][2]) { base = BASE_1000; break; } /* Case-dependent match for powers of 1024 */ if (base == BASE_UNKNOWN) for (s = 0; s < NUM_UNIT_PREFIXES; s++) if (unit_type == *size_str[BASE_1024 + s][2]) { base = BASE_1024; break; } } if (base == BASE_UNKNOWN) /* Check for special units - s, b or u */ for (s = 0; s < NUM_SPECIAL; s++) if (toupper((int) unit_type) == *size_str[BASE_SPECIAL + s][2]) { base = BASE_SPECIAL; break; } if (size == UINT64_C(0)) { if (base == BASE_UNKNOWN) s = 0; sprintf(size_buf, "0%s", include_suffix ? size_str[base + s][suffix_type] : ""); return size_buf; } size *= UINT64_C(512); if (base != BASE_UNKNOWN) { if (!unit_factor) { unit_type_buf[0] = unit_type; unit_type_buf[1] = '\0'; if (!(unit_factor = dm_units_to_factor(&unit_type_buf[0], &new_unit_type, 1, NULL)) || unit_type != new_unit_type) { /* The two functions should match (and unrecognised units get treated like 'h'). */ log_error(INTERNAL_ERROR "Inconsistent units: %c and %c.", unit_type, new_unit_type); return ""; } } byte = unit_factor; } else { /* Human-readable style */ if (unit_type == 'H') { units = UINT64_C(1000); base = BASE_1000; } else { units = UINT64_C(1024); base = BASE_1024; } if (!use_si_units) base = BASE_SHARED; byte = units * units * units * units * units * units; for (s = 0; s < NUM_UNIT_PREFIXES && size < byte; s++) byte /= units; include_suffix = 1; } /* FIXME Make precision configurable */ switch (toupper(*size_str[base + s][DM_SIZE_UNIT])) { case 'B': case 'S': precision = 0; break; default: precision = 2; } snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision, (double) size / byte, include_suffix ? size_str[base + s][suffix_type] : ""); return size_buf; }
int dm_get_status_mirror(struct dm_pool *mem, const char *params, struct dm_status_mirror **status) { struct dm_status_mirror *s; const char *p, *pos = params; unsigned num_devs, argc, i; int used; if (!(s = dm_pool_zalloc(mem, sizeof(*s)))) { log_error("Failed to alloc mem pool to parse mirror status."); return 0; } if (sscanf(pos, "%u %n", &num_devs, &used) != 1) goto_out; pos += used; if (num_devs > DM_MIRROR_MAX_IMAGES) { log_error(INTERNAL_ERROR "More then " DM_TO_STRING(DM_MIRROR_MAX_IMAGES) " reported in mirror status."); goto out; } if (!(s->devs = dm_pool_alloc(mem, num_devs * sizeof(*(s->devs))))) { log_error("Allocation of devs failed."); goto out; } for (i = 0; i < num_devs; ++i, pos += used) if (sscanf(pos, "%u:%u %n", &(s->devs[i].major), &(s->devs[i].minor), &used) != 2) goto_out; if (sscanf(pos, FMTu64 "/" FMTu64 "%n", &s->insync_regions, &s->total_regions, &used) != 2) goto_out; pos += used; if (sscanf(pos, "%u %n", &argc, &used) != 1) goto_out; pos += used; for (i = 0; i < num_devs ; ++i) s->devs[i].health = pos[i]; if (!(pos = _advance_to_next_word(pos, argc))) goto_out; if (sscanf(pos, "%u %n", &argc, &used) != 1) goto_out; pos += used; if (argc == 1) { /* core, cluster-core */ if (!(s->log_type = dm_pool_strdup(mem, pos))) { log_error("Allocation of log type string failed."); goto out; } } else { if (!(p = _advance_to_next_word(pos, 1))) goto_out; /* disk, cluster-disk */ if (!(s->log_type = dm_pool_strndup(mem, pos, p - pos - 1))) { log_error("Allocation of log type string failed."); goto out; } pos = p; if ((argc > 2) && !strcmp(s->log_type, "disk")) { s->log_count = argc - 2; if (!(s->logs = dm_pool_alloc(mem, s->log_count * sizeof(*(s->logs))))) { log_error("Allocation of logs failed."); goto out; } for (i = 0; i < s->log_count; ++i, pos += used) if (sscanf(pos, "%u:%u %n", &s->logs[i].major, &s->logs[i].minor, &used) != 2) goto_out; for (i = 0; i < s->log_count; ++i) s->logs[i].health = pos[i]; } } s->dev_count = num_devs; *status = s; return 1; out: log_error("Failed to parse mirror status %s.", params); dm_pool_free(mem, s); *status = NULL; return 0; }