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 int _detach_pvmove_mirror(struct cmd_context *cmd, struct logical_volume *lv_mirr) { uint32_t mimage_to_remove = 0; struct dm_list lvs_completed; struct lv_list *lvl; /* Update metadata to remove mirror segments and break dependencies */ dm_list_init(&lvs_completed); if (arg_is_set(cmd, abort_ARG) && (seg_type(first_seg(lv_mirr), 0) == AREA_LV)) mimage_to_remove = 1; /* remove the second mirror leg */ if (!lv_remove_mirrors(cmd, lv_mirr, 1, 0, _is_pvmove_image_removable, &mimage_to_remove, PVMOVE) || !remove_layers_for_segments_all(cmd, lv_mirr, PVMOVE, &lvs_completed)) { return 0; } dm_list_iterate_items(lvl, &lvs_completed) /* FIXME Assumes only one pvmove at a time! */ lvl->lv->status &= ~LOCKED; return 1; }
int pvremove(struct cmd_context *cmd, int argc, char **argv) { int i; unsigned force_count; unsigned prompt; struct dm_list pv_names; if (!argc) { log_error("Please enter a physical volume path"); return EINVALID_CMD_LINE; } force_count = arg_count(cmd, force_ARG); prompt = arg_count(cmd, yes_ARG); dm_list_init(&pv_names); /* Needed to change the set of orphan PVs. */ if (!lockd_gl(cmd, "ex", 0)) return_ECMD_FAILED; for (i = 0; i < argc; i++) { dm_unescape_colons_and_at_signs(argv[i], NULL, NULL); if (!str_list_add(cmd->mem, &pv_names, argv[i])) return_ECMD_FAILED; } if (!pvremove_many(cmd, &pv_names, force_count, prompt)) return_ECMD_FAILED; return ECMD_PROCESSED; }
static struct cb_set *_cb_set_create(unsigned nr) { int i; struct cb_set *cbs = malloc(sizeof(*cbs)); if (!cbs) return NULL; cbs->vec = malloc(nr * sizeof(*cbs->vec)); if (!cbs->vec) { free(cbs); return NULL; } dm_list_init(&cbs->free); dm_list_init(&cbs->allocated); for (i = 0; i < nr; i++) dm_list_add(&cbs->free, &cbs->vec[i].list); return cbs; }
static void __update_lvmcache(const struct format_type *fmt, struct disk_list *dl, struct device *dev, const char *vgid, unsigned exported) { struct lvmcache_info *info; const char *vgname = *((char *)dl->pvd.vg_name) ? (char *)dl->pvd.vg_name : fmt->orphan_vg_name; if (!(info = lvmcache_add(fmt->labeller, (char *)dl->pvd.pv_uuid, dev, vgname, vgid, exported ? EXPORTED_VG : 0))) { stack; return; } info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT; dm_list_init(&info->mdas); info->status &= ~CACHE_INVALID; }
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; }
/* Allocate/free the status structure for a monitoring thread. */ static struct thread_status *_alloc_thread_status(struct message_data *data, struct dso_data *dso_data) { struct thread_status *ret = (typeof(ret)) dm_malloc(sizeof(*ret)); if (!ret) return NULL; memset(ret, 0, sizeof(*ret)); if (!(ret->device.uuid = dm_strdup(data->device_uuid))) { dm_free(ret); return NULL; } ret->current_task = NULL; ret->device.name = NULL; ret->device.major = ret->device.minor = 0; ret->dso_data = dso_data; ret->events = data->events.field; ret->timeout = data->timeout.secs; dm_list_init(&ret->timeout_list); return ret; }
void internal_filter_clear(void) { dm_list_init(&_allow_devs); }
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; }
static int _pv_resize_single(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv, const uint64_t new_size) { struct pv_list *pvl; uint64_t size = 0; uint32_t new_pe_count = 0; int r = 0; struct dm_list mdas; const char *pv_name = pv_dev_name(pv); const char *vg_name; struct lvmcache_info *info; int mda_count = 0; struct volume_group *old_vg = vg; dm_list_init(&mdas); if (is_orphan_vg(pv_vg_name(pv))) { vg_name = VG_ORPHANS; if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { log_error("Can't get lock for orphans"); return 0; } if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) { unlock_vg(cmd, vg_name); log_error("Unable to read PV \"%s\"", pv_name); return 0; } mda_count = dm_list_size(&mdas); } else { vg_name = pv_vg_name(pv); vg = vg_read_for_update(cmd, vg_name, NULL, 0); if (vg_read_error(vg)) goto bad; if (!(pvl = find_pv_in_vg(vg, pv_name))) { log_error("Unable to find \"%s\" in volume group \"%s\"", pv_name, vg->name); goto bad; } pv = pvl->pv; if (!(info = info_from_pvid(pv->dev->pvid, 0))) { log_error("Can't get info for PV %s in volume group %s", pv_name, vg->name); goto bad; } mda_count = dm_list_size(&info->mdas); if (!archive(vg)) goto bad; } /* FIXME Create function to test compatibility properly */ if (mda_count > 1) { log_error("%s: too many metadata areas for pvresize", pv_name); goto bad; } if (!(pv->fmt->features & FMT_RESIZE_PV)) { log_error("Physical volume %s format does not support resizing.", pv_name); goto bad; } /* Get new size */ if (!dev_get_size(pv_dev(pv), &size)) { log_error("%s: Couldn't get size.", pv_name); goto bad; } if (new_size) { if (new_size > size) log_warn("WARNING: %s: Overriding real size. " "You could lose data.", pv_name); log_verbose("%s: Pretending size is %" PRIu64 " not %" PRIu64 " sectors.", pv_name, new_size, pv_size(pv)); size = new_size; } if (size < PV_MIN_SIZE) { log_error("%s: Size must exceed minimum of %ld sectors.", pv_name, PV_MIN_SIZE); goto bad; } if (size < pv_pe_start(pv)) { log_error("%s: Size must exceed physical extent start of " "%" PRIu64 " sectors.", pv_name, pv_pe_start(pv)); goto bad; } pv->size = size; if (vg) { pv->size -= pv_pe_start(pv); new_pe_count = pv_size(pv) / vg->extent_size; if (!new_pe_count) { log_error("%s: Size must leave space for at " "least one physical extent of " "%" PRIu32 " sectors.", pv_name, pv_pe_size(pv)); goto bad; } if (!pv_resize(pv, vg, new_pe_count)) goto_bad; } log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.", pv_name, pv_size(pv)); log_verbose("Updating physical volume \"%s\"", pv_name); if (!is_orphan_vg(pv_vg_name(pv))) { if (!vg_write(vg) || !vg_commit(vg)) { log_error("Failed to store physical volume \"%s\" in " "volume group \"%s\"", pv_name, vg->name); goto bad; } backup(vg); } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) { log_error("Failed to store physical volume \"%s\"", pv_name); goto bad;; } log_print("Physical volume \"%s\" changed", pv_name); r = 1; bad: unlock_vg(cmd, vg_name); if (!old_vg) vg_release(vg); return r; }
/* Real locking */ static int _lock_resource(const char *resource, int mode, int flags, int *lockid) { /* DLM table of allowed transition states */ static const int _dlm_table[6][6] = { /* Mode NL CR CW PR PW EX */ /* NL */ { 1, 1, 1, 1, 1, 1}, /* CR */ { 1, 1, 1, 1, 1, 0}, /* CW */ { 1, 1, 1, 0, 0, 0}, /* PR */ { 1, 1, 0, 1, 0, 0}, /* PW */ { 1, 1, 0, 0, 0, 0}, /* EX */ { 1, 0, 0, 0, 0, 0} }; struct lock *lck = NULL, *lckt; struct dm_list *head; DEBUGLOG("Locking resource %s, flags=0x%02x (%s%s%s), mode=%s (%d)\n", resource, flags, (flags & LCKF_NOQUEUE) ? "NOQUEUE" : "", ((flags & (LCKF_NOQUEUE | LCKF_CONVERT)) == (LCKF_NOQUEUE | LCKF_CONVERT)) ? "|" : "", (flags & LCKF_CONVERT) ? "CONVERT" : "", _get_mode(mode), mode); mode &= LCK_TYPE_MASK; pthread_mutex_lock(&_lock_mutex); retry: pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */ if (!(head = dm_hash_lookup(_locks, resource))) { if (flags & LCKF_CONVERT) { /* In real DLM, lock is identified only by lockid, resource is not used */ DEBUGLOG("Unlocked resource %s cannot be converted\n", resource); goto_bad; } /* Add new locked resource */ if (!(head = dm_malloc(sizeof(struct dm_list))) || !dm_hash_insert(_locks, resource, head)) { dm_free(head); goto_bad; } dm_list_init(head); } else /* Update/convert locked resource */ dm_list_iterate_items(lck, head) { /* Check is all locks are compatible with requested lock */ if (flags & LCKF_CONVERT) { if (lck->lockid != *lockid) continue; DEBUGLOG("Converting resource %s lockid=%d mode:%s -> %s...\n", resource, lck->lockid, _get_mode(lck->mode), _get_mode(mode)); dm_list_iterate_items(lckt, head) { if ((lckt->lockid != *lockid) && !_dlm_table[mode][lckt->mode]) { if (!(flags & LCKF_NOQUEUE) && /* TODO: Real dlm uses here conversion queues */ !pthread_cond_wait(&_lock_cond, &_lock_mutex) && _locks) /* End of the game? */ goto retry; goto bad; } } lck->mode = mode; /* Lock is now converted */ goto out; } else if (!_dlm_table[mode][lck->mode]) { DEBUGLOG("Resource %s already locked lockid=%d, mode:%s\n", resource, lck->lockid, _get_mode(lck->mode)); if (!(flags & LCKF_NOQUEUE) && !pthread_cond_wait(&_lock_cond, &_lock_mutex) && _locks) { /* End of the game? */ DEBUGLOG("Resource %s retrying lock in mode:%s...\n", resource, _get_mode(mode)); goto retry; } goto bad; } }
/* * Decide whether it is "safe" to wipe the labels on this device. * 0 indicates we may not. */ static int pvremove_check(struct cmd_context *cmd, const char *name) { struct physical_volume *pv; struct dm_list mdas; dm_list_init(&mdas); /* FIXME Check partition type is LVM unless --force is given */ /* Is there a pv here already? */ /* If not, this is an error unless you used -f. */ if (!(pv = pv_read(cmd, name, &mdas, NULL, 1, 0))) { if (arg_count(cmd, force_ARG)) return 1; log_error("Physical Volume %s not found", name); return 0; } /* * If a PV has no MDAs it may appear to be an * orphan until the metadata is read off * another PV in the same VG. Detecting this * means checking every VG by scanning every * PV on the system. */ if (is_orphan(pv) && !dm_list_size(&mdas)) { if (!scan_vgs_for_pvs(cmd)) { log_error("Rescan for PVs without metadata areas " "failed."); return 0; } if (!(pv = pv_read(cmd, name, NULL, NULL, 1, 0))) { log_error("Failed to read physical volume %s", name); return 0; } } /* orphan ? */ if (is_orphan(pv)) return 1; /* Allow partial & exported VGs to be destroyed. */ /* we must have -ff to overwrite a non orphan */ if (arg_count(cmd, force_ARG) < 2) { log_error("Can't pvremove physical volume \"%s\" of " "volume group \"%s\" without -ff", name, pv_vg_name(pv)); return 0; } /* prompt */ if (!arg_count(cmd, yes_ARG) && yes_no_prompt(_really_wipe, name, pv_vg_name(pv)) == 'n') { log_error("%s: physical volume label not removed", name); return 0; } if (arg_count(cmd, force_ARG)) { log_warn("WARNING: Wiping physical volume label from " "%s%s%s%s", name, !is_orphan(pv) ? " of volume group \"" : "", !is_orphan(pv) ? pv_vg_name(pv) : "", !is_orphan(pv) ? "\"" : ""); } return 1; }
static struct disk_list *__read_disk(const struct format_type *fmt, struct device *dev, struct dm_pool *mem, const char *vg_name) { struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl)); const char *name = dev_name(dev); if (!dl) return_NULL; dl->dev = dev; dl->mem = mem; dm_list_init(&dl->uuids); dm_list_init(&dl->lvds); if (!_read_pvd(dev, &dl->pvd)) goto_bad; /* * is it an orphan ? */ if (!*dl->pvd.vg_name) { log_very_verbose("%s is not a member of any format1 VG", name); __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); return (vg_name) ? NULL : dl; } if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) { log_error("Failed to read VG data from PV (%s)", name); __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); goto bad; } if (vg_name && strcmp(vg_name, (char *)dl->pvd.vg_name)) { log_very_verbose("%s is not a member of the VG %s", name, vg_name); __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0); goto bad; } __update_lvmcache(fmt, dl, dev, (char *)dl->vgd.vg_uuid, dl->vgd.vg_status & VG_EXPORTED); if (!_read_uuids(dl)) { log_error("Failed to read PV uuid list from %s", name); goto bad; } if (!_read_lvs(dl)) { log_error("Failed to read LV's from %s", name); goto bad; } if (!_read_extents(dl)) { log_error("Failed to read extents from %s", name); goto bad; } log_very_verbose("Found %s in %sVG %s", name, (dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "", dl->pvd.vg_name); return dl; bad: dm_pool_free(dl->mem, dl); return NULL; }