struct dm_list *tag_list_copy(struct dm_pool *p, struct dm_list *tag_list) { struct dm_list *list; lvm_str_list_t *lsl; struct str_list *sl; if (!(list = dm_pool_zalloc(p, sizeof(*list)))) { log_errno(ENOMEM, "Memory allocation fail for dm_list."); return NULL; } dm_list_init(list); dm_list_iterate_items(sl, tag_list) { if (!(lsl = dm_pool_zalloc(p, sizeof(*lsl)))) { log_errno(ENOMEM, "Memory allocation fail for lvm_lv_list."); return NULL; } if (!(lsl->str = dm_pool_strdup(p, sl->str))) { log_errno(ENOMEM, "Memory allocation fail for lvm_lv_list->str."); return NULL; } dm_list_add(list, &lsl->list); } return list; }
static struct config_value *_clone_config_value(struct dm_pool *mem, const struct config_value *v) { struct config_value *new_cv; if (!v) return NULL; if (!(new_cv = _create_value(mem))) { log_error("Failed to clone config value."); return NULL; } new_cv->type = v->type; if (v->type == CFG_STRING) { if (!(new_cv->v.str = dm_pool_strdup(mem, v->v.str))) { log_error("Failed to clone config string value."); return NULL; } } else new_cv->v = v->v; if (v->next && !(new_cv->next = _clone_config_value(mem, v->next))) return_NULL; return new_cv; }
/* * public interface */ struct dm_config_tree *config_file_open(const char *filename, int keep_open) { struct dm_config_tree *cft = dm_config_create(); struct config_file *cf; if (!cft) return NULL; cf = dm_pool_zalloc(cft->mem, sizeof(struct config_file)); if (!cf) goto fail; cf->timestamp = 0; cf->exists = 0; cf->keep_open = keep_open; dm_config_set_custom(cft, cf); if (filename && !(cf->filename = dm_pool_strdup(cft->mem, filename))) { log_error("Failed to duplicate filename."); goto fail; } return cft; fail: dm_config_destroy(cft); return NULL; }
/* * dev_manager implementation. */ struct dev_manager *dev_manager_create(struct cmd_context *cmd, const char *vg_name) { struct dm_pool *mem; struct dev_manager *dm; if (!(mem = dm_pool_create("dev_manager", 16 * 1024))) return_NULL; if (!(dm = dm_pool_zalloc(mem, sizeof(*dm)))) goto_bad; dm->cmd = cmd; dm->mem = mem; if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name))) goto_bad; dm->target_state = NULL; dm_udev_set_sync_support(cmd->current_settings.udev_sync); return dm; bad: dm_pool_destroy(mem); return NULL; }
/* * public interface */ struct config_tree *create_config_tree(const char *filename, int keep_open) { struct cs *c; struct dm_pool *mem = dm_pool_create("config", 10 * 1024); if (!mem) { log_error("Failed to allocate config pool."); return 0; } if (!(c = dm_pool_zalloc(mem, sizeof(*c)))) { log_error("Failed to allocate config tree."); dm_pool_destroy(mem); return 0; } c->mem = mem; c->cft.root = (struct config_node *) NULL; c->timestamp = 0; c->exists = 0; c->keep_open = keep_open; c->dev = 0; if (filename) c->filename = dm_pool_strdup(c->mem, filename); return &c->cft; }
struct config_node *clone_config_node_with_mem(struct dm_pool *mem, const struct config_node *cn, int siblings) { struct config_node *new_cn; if (!cn) return NULL; if (!(new_cn = _create_node(mem))) { log_error("Failed to clone config node."); return NULL; } if ((cn->key && !(new_cn->key = dm_pool_strdup(mem, cn->key)))) { log_error("Failed to clone config node key."); return NULL; } if ((cn->v && !(new_cn->v = _clone_config_value(mem, cn->v))) || (cn->child && !(new_cn->child = clone_config_node_with_mem(mem, cn->child, 1))) || (siblings && cn->sib && !(new_cn->sib = clone_config_node_with_mem(mem, cn->sib, siblings)))) return_NULL; /* 'new_cn' released with mem pool */ return new_cn; }
/* Parse replicator site element */ static int _add_site(struct lv_segment *seg, const char *key, const struct dm_config_node *sn) { struct dm_pool *mem = seg->lv->vg->vgmem; const struct dm_config_node *cn; struct replicator_site *rsite; if (!(rsite = _get_site(seg->lv, key))) return_0; if (!dm_config_find_node(sn, "site_index")) return SEG_LOG_ERROR("Mandatory site_index is missing for"); rsite->state = _get_state(sn, "state", REPLICATOR_STATE_PASSIVE); rsite->site_index = _get_config_uint32(sn, "site_index", 0); if (rsite->site_index > seg->rsite_index_highest) return SEG_LOG_ERROR("site_index=%d > highest_site_index=%d for", rsite->site_index, seg->rsite_index_highest); rsite->fall_behind_data = _get_config_uint64(sn, "fall_behind_data", 0); rsite->fall_behind_ios = _get_config_uint32(sn, "fall_behind_ios", 0); rsite->fall_behind_timeout = _get_config_uint32(sn, "fall_behind_timeout", 0); rsite->op_mode = DM_REPLICATOR_SYNC; if (rsite->fall_behind_data || rsite->fall_behind_ios || rsite->fall_behind_timeout) { if (rsite->fall_behind_data && rsite->fall_behind_ios) return SEG_LOG_ERROR("Defined both fall_behind_data " "and fall_behind_ios in"); if (rsite->fall_behind_data && rsite->fall_behind_timeout) return SEG_LOG_ERROR("Defined both fall_behind_data " "and fall_behind_timeout in"); if (rsite->fall_behind_ios && rsite->fall_behind_timeout) return SEG_LOG_ERROR("Defined both fall_behind_ios " "and fall_behind_timeout in"); rsite->op_mode = _get_op_mode(sn, "operation_mode", rsite->op_mode); } if ((cn = dm_config_find_node(sn, "volume_group"))) { if (!cn->v || cn->v->type != DM_CFG_STRING) return SEG_LOG_ERROR("volume_group must be a string in"); if (!(rsite->vg_name = dm_pool_strdup(mem, cn->v->v.str))) return_0; } else if (rsite->site_index != 0) return SEG_LOG_ERROR("volume_group is mandatory for remote site in"); return 1; }
int dm_split_lvm_name(struct dm_pool *mem, const char *dmname, char **vgname, char **lvname, char **layer) { if (mem && !(*vgname = dm_pool_strdup(mem, dmname))) return 0; _unquote(*layer = _unquote(*lvname = _unquote(*vgname))); return 1; }
/* * Extracts the last part of a path. */ static char *_create_lv_name(struct dm_pool *mem, const char *full_name) { const char *ptr = strrchr(full_name, '/'); if (!ptr) ptr = full_name; else ptr++; return dm_pool_strdup(mem, ptr); }
const char *lvm_errmsg(lvm_t libh) { const char *rc = NULL; struct cmd_context *cmd = (struct cmd_context *)libh; struct saved_env e = store_user_env((struct cmd_context *)libh); const char *msg = stored_errmsg_with_clear(); if (msg) { rc = dm_pool_strdup(cmd->mem, msg); free((void *)msg); } restore_user_env(&e); return rc; }
struct dm_config_node *dm_config_create_node(struct dm_config_tree *cft, const char *key) { struct dm_config_node *cn; if (!(cn = _create_node(cft->mem))) { log_error("Failed to create config node."); return NULL; } if (!(cn->key = dm_pool_strdup(cft->mem, key))) { log_error("Failed to create config node's key."); return NULL; } cn->parent = NULL; cn->v = NULL; return cn; }
int read_tags(struct dm_pool *mem, struct dm_list *tags, struct config_value *cv) { if (cv->type == CFG_EMPTY_ARRAY) return 1; while (cv) { if (cv->type != CFG_STRING) { log_error("Found a tag that is not a string"); return 0; } if (!str_list_add(mem, tags, dm_pool_strdup(mem, cv->v.str))) return_0; cv = cv->next; } return 1; }
int dm_split_lvm_name(struct dm_pool *mem, const char *dmname, char **vgname, char **lvname, char **layer) { if (!vgname || !lvname || !layer) { log_error(INTERNAL_ERROR "dm_split_lvm_name: Forbidden NULL parameter detected."); return 0; } if (mem && (!dmname || !(*vgname = dm_pool_strdup(mem, dmname)))) { log_error("Failed to duplicate lvm name."); return 0; } else if (!*vgname) { log_error("Missing lvm name for split."); return 0; } _unquote(*layer = _unquote(*lvname = _unquote(*vgname))); return 1; }
static struct replicator_site *_get_site(struct logical_volume *replicator, const char *key) { struct dm_pool *mem = replicator->vg->vgmem; struct replicator_site *rsite; dm_list_iterate_items(rsite, &replicator->rsites) if (strcasecmp(rsite->name, key) == 0) return rsite; if (!(rsite = dm_pool_zalloc(mem, sizeof(*rsite)))) return_NULL; if (!(rsite->name = dm_pool_strdup(mem, key))) return_NULL; rsite->replicator = replicator; dm_list_init(&rsite->rdevices); dm_list_add(&replicator->rsites, &rsite->list); return rsite; }
/* * public interface */ struct dm_config_tree *config_open(config_source_t source, const char *filename, int keep_open) { struct dm_config_tree *cft = dm_config_create(); struct config_source *cs; struct config_file *cf; if (!cft) return NULL; if (!(cs = dm_pool_zalloc(cft->mem, sizeof(struct config_source)))) { log_error("Failed to allocate config source."); goto fail; } if ((source == CONFIG_FILE) || (source == CONFIG_PROFILE)) { if (!(cf = dm_pool_zalloc(cft->mem, sizeof(struct config_file)))) { log_error("Failed to allocate config file."); goto fail; } cf->keep_open = keep_open; if (filename && !(cf->filename = dm_pool_strdup(cft->mem, filename))) { log_error("Failed to duplicate filename."); goto fail; } cs->source.file = cf; } cs->type = source; dm_config_set_custom(cft, cs); return cft; fail: dm_config_destroy(cft); return NULL; }
int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls) { struct pool_list *pl; dm_list_iterate_items(pl, pls) { vg->extent_count += ((pl->pd.pl_blocks) / POOL_PE_SIZE); vg->free_count = vg->extent_count; vg->pv_count++; if (vg->name) continue; vg->name = dm_pool_strdup(mem, pl->pd.pl_pool_name); get_pool_vg_uuid(&vg->id, &pl->pd); vg->extent_size = POOL_PE_SIZE; vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED; vg->max_lv = 1; vg->max_pv = POOL_MAX_DEVICES; vg->alloc = ALLOC_NORMAL; }
struct config_node *create_config_node(struct config_tree *cft, const char *key) { struct cs *c = (struct cs *) cft; struct config_node *cn; if (!(cn = _create_node(c->mem))) { log_error("Failed to create config node."); return NULL; } if (!(cn->key = dm_pool_strdup(c->mem, key))) { log_error("Failed to create config node's key."); return NULL; } if (!(cn->v = _create_value(c->mem))) { log_error("Failed to create config node's value."); return NULL; } cn->parent = NULL; cn->v->type = CFG_INT; cn->v->v.i = 0; cn->v->next = NULL; return cn; }
int vgrename(struct cmd_context *cmd, int argc, char **argv) { struct vgrename_params vp = { 0 }; struct processing_handle *handle; const char *vg_name_new; const char *vg_name_old; struct id id; int ret; if (argc != 2) { log_error("Old and new volume group names need specifying"); return EINVALID_CMD_LINE; } vg_name_old = skip_dev_dir(cmd, argv[0], NULL); vg_name_new = skip_dev_dir(cmd, argv[1], NULL); if (!validate_vg_rename_params(cmd, vg_name_old, vg_name_new)) return_0; if (!(vp.vg_name_old = dm_pool_strdup(cmd->mem, vg_name_old))) return_ECMD_FAILED; if (!(vp.vg_name_new = dm_pool_strdup(cmd->mem, vg_name_new))) return_ECMD_FAILED; /* Needed change the global VG namespace. */ if (!lockd_gl(cmd, "ex", LDGL_UPDATE_NAMES)) return_ECMD_FAILED; /* * Special case where vg_name_old may be a UUID: * If vg_name_old is a UUID, then process_each may * translate it to an actual VG name that we don't * yet know. The lock ordering, and pre-locking, * needs to be done based on VG names. When * vg_name_old is a UUID, do not do any pre-locking * based on it, since it's likely to be wrong, and * defer all the locking to the _single function. * * When it's not a UUID, we know the two VG names, * and we can pre-lock the new VG name if the lock * ordering wants it locked before the old VG name * which will be locked by process_each. If lock * ordering wants the old name locked first, then * the _single function will lock the new VG name. */ if (!(vp.old_name_is_uuid = id_read_format_try(&id, vg_name_old))) { if (strcmp(vg_name_new, vg_name_old) < 0) { vp.lock_vg_old_first = 0; vp.unlock_new_name = 1; if (!_lock_new_vg_for_rename(cmd, vg_name_new)) return ECMD_FAILED; } else { /* The old VG is locked by process_each_vg. */ vp.lock_vg_old_first = 1; } } if (!(handle = init_processing_handle(cmd))) { log_error("Failed to initialize processing handle."); return ECMD_FAILED; } handle->custom_handle = &vp; ret = process_each_vg(cmd, 0, NULL, vg_name_old, READ_FOR_UPDATE | READ_ALLOW_EXPORTED, handle, _vgrename_single); /* Needed if process_each_vg returns error before calling _single. */ if (vp.unlock_new_name) unlock_vg(cmd, vg_name_new); destroy_processing_handle(cmd, handle); return ret; }
/* * <metadata block size> <#used metadata blocks>/<#total metadata blocks> * <cache block size> <#used cache blocks>/<#total cache blocks> * <#read hits> <#read misses> <#write hits> <#write misses> * <#demotions> <#promotions> <#dirty> <#features> <features>* * <#core args> <core args>* <policy name> <#policy args> <policy args>* * * metadata block size : Fixed block size for each metadata block in * sectors * #used metadata blocks : Number of metadata blocks used * #total metadata blocks : Total number of metadata blocks * cache block size : Configurable block size for the cache device * in sectors * #used cache blocks : Number of blocks resident in the cache * #total cache blocks : Total number of cache blocks * #read hits : Number of times a READ bio has been mapped * to the cache * #read misses : Number of times a READ bio has been mapped * to the origin * #write hits : Number of times a WRITE bio has been mapped * to the cache * #write misses : Number of times a WRITE bio has been * mapped to the origin * #demotions : Number of times a block has been removed * from the cache * #promotions : Number of times a block has been moved to * the cache * #dirty : Number of blocks in the cache that differ * from the origin * #feature args : Number of feature args to follow * feature args : 'writethrough' (optional) * #core args : Number of core arguments (must be even) * core args : Key/value pairs for tuning the core * e.g. migration_threshold * *policy name : Name of the policy * #policy args : Number of policy arguments to follow (must be even) * policy args : Key/value pairs * e.g. sequential_threshold */ int dm_get_status_cache(struct dm_pool *mem, const char *params, struct dm_status_cache **status) { int i, feature_argc; char *str; const char *p, *pp; struct dm_status_cache *s; if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_cache)))) return_0; /* Read in args that have definitive placement */ if (sscanf(params, " %" PRIu32 " %" PRIu64 "/%" PRIu64 " %" PRIu32 " %" PRIu64 "/%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %d", &s->metadata_block_size, &s->metadata_used_blocks, &s->metadata_total_blocks, &s->block_size, /* AKA, chunk_size */ &s->used_blocks, &s->total_blocks, &s->read_hits, &s->read_misses, &s->write_hits, &s->write_misses, &s->demotions, &s->promotions, &s->dirty_blocks, &feature_argc) != 14) goto bad; /* Now jump to "features" section */ if (!(p = _advance_to_next_word(params, 12))) goto bad; /* Read in features */ for (i = 0; i < feature_argc; i++) { if (!strncmp(p, "writethrough ", 13)) s->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH; else if (!strncmp(p, "writeback ", 10)) s->feature_flags |= DM_CACHE_FEATURE_WRITEBACK; else log_error("Unknown feature in status: %s", params); if (!(p = _advance_to_next_word(p, 1))) goto bad; } /* Read in core_args. */ if (sscanf(p, "%d ", &s->core_argc) != 1) goto bad; if (s->core_argc && (!(s->core_argv = dm_pool_zalloc(mem, sizeof(char *) * s->core_argc)) || !(p = _advance_to_next_word(p, 1)) || !(str = dm_pool_strdup(mem, p)) || !(p = _advance_to_next_word(p, s->core_argc)) || (dm_split_words(str, s->core_argc, 0, s->core_argv) != s->core_argc))) goto bad; /* Read in policy args */ pp = p; if (!(p = _advance_to_next_word(p, 1)) || !(s->policy_name = dm_pool_zalloc(mem, (p - pp)))) goto bad; if (sscanf(pp, "%s %d", s->policy_name, &s->policy_argc) != 2) goto bad; if (s->policy_argc && (!(s->policy_argv = dm_pool_zalloc(mem, sizeof(char *) * s->policy_argc)) || !(p = _advance_to_next_word(p, 1)) || !(str = dm_pool_strdup(mem, p)) || (dm_split_words(str, s->policy_argc, 0, s->policy_argv) != s->policy_argc))) goto bad; *status = s; return 1; bad: log_error("Failed to parse cache params: %s", params); dm_pool_free(mem, s); *status = NULL; return 0; }
int import_pv(const struct format_type *fmt, struct dm_pool *mem, struct device *dev, struct volume_group *vg, struct physical_volume *pv, struct pv_disk *pvd, struct vg_disk *vgd) { uint64_t size; memset(pv, 0, sizeof(*pv)); memcpy(&pv->id, pvd->pv_uuid, ID_LEN); pv->dev = dev; if (!*pvd->vg_name) pv->vg_name = fmt->orphan_vg_name; else if (!(pv->vg_name = dm_pool_strdup(mem, (char *)pvd->vg_name))) { log_error("Volume Group name allocation failed."); return 0; } memcpy(&pv->vgid, vgd->vg_uuid, sizeof(vg->id)); /* Store system_id from first PV if PV belongs to a VG */ if (vg && !*vg->lvm1_system_id) strncpy(vg->lvm1_system_id, (char *)pvd->system_id, NAME_LEN); if (vg && strncmp(vg->lvm1_system_id, (char *)pvd->system_id, sizeof(pvd->system_id))) log_very_verbose("System ID %s on %s differs from %s for " "volume group", pvd->system_id, pv_dev_name(pv), vg->lvm1_system_id); /* * If exported, we still need to flag in pv->status too because * we don't always have a struct volume_group when we need this. */ if (pvd->pv_status & VG_EXPORTED) pv->status |= EXPORTED_VG; if (pvd->pv_allocatable) pv->status |= ALLOCATABLE_PV; pv->size = pvd->pv_size; pv->pe_size = pvd->pe_size; pv->pe_start = pvd->pe_start; pv->pe_count = pvd->pe_total; pv->pe_alloc_count = 0; pv->pe_align = 0; pv->is_labelled = 0; /* format1 PVs have no label */ pv->label_sector = 0; /* Fix up pv size if missing or impossibly large */ if (!pv->size || pv->size > (1ULL << 62)) { if (!dev_get_size(dev, &pv->size)) { log_error("%s: Couldn't get size.", pv_dev_name(pv)); return 0; } log_verbose("Fixing up missing format1 size (%s) " "for PV %s", display_size(fmt->cmd, pv->size), pv_dev_name(pv)); if (vg) { size = pv->pe_count * (uint64_t) vg->extent_size + pv->pe_start; if (size > pv->size) log_warn("WARNING: Physical Volume %s is too " "large for underlying device", pv_dev_name(pv)); } } dm_list_init(&pv->tags); dm_list_init(&pv->segments); if (!alloc_pv_segment_whole_pv(mem, pv)) return_0; return 1; }
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; }