static int lvchange_alloc(struct cmd_context *cmd, struct logical_volume *lv) { int want_contiguous = 0; alloc_policy_t alloc; want_contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n"); alloc = want_contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT; alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, alloc); if (alloc == lv->alloc) { log_error("Allocation policy of logical volume \"%s\" is " "already %s", lv->name, get_alloc_string(alloc)); return 0; } lv->alloc = alloc; /* FIXME If contiguous, check existing extents already are */ log_verbose("Setting contiguous allocation policy for \"%s\" to %s", lv->name, get_alloc_string(alloc)); log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); /* No need to suspend LV for this change */ if (!vg_write(lv->vg) || !vg_commit(lv->vg)) return_0; backup(lv->vg); return 1; }
static int _lvchange_activate(struct cmd_context *cmd, struct logical_volume *lv) { int activate; activate = arg_uint_value(cmd, activate_ARG, 0); if (lv_is_cow(lv) && !lv_is_virtual_origin(origin_from_cow(lv))) lv = origin_from_cow(lv); if (activate == CHANGE_AAY) { if (!lv_passes_auto_activation_filter(cmd, lv)) return 1; activate = CHANGE_ALY; } if (activate == CHANGE_ALN) { log_verbose("Deactivating logical volume \"%s\" locally", lv->name); if (!deactivate_lv_local(cmd, lv)) return_0; } else if (activate == CHANGE_AN) { log_verbose("Deactivating logical volume \"%s\"", lv->name); if (!deactivate_lv(cmd, lv)) return_0; } else { if ((activate == CHANGE_AE) || lv_is_origin(lv) || lv_is_thin_type(lv)) { log_verbose("Activating logical volume \"%s\" " "exclusively", lv->name); if (!activate_lv_excl(cmd, lv)) return_0; } else if (activate == CHANGE_ALY) { log_verbose("Activating logical volume \"%s\" locally", lv->name); if (!activate_lv_local(cmd, lv)) return_0; } else { log_verbose("Activating logical volume \"%s\"", lv->name); if (!activate_lv(cmd, lv)) return_0; } if (background_polling()) lv_spawn_background_polling(cmd, lv); } return 1; }
static int _read_size_params(struct lvcreate_params *lp, struct lvcreate_cmdline_params *lcp, struct cmd_context *cmd) { if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) { log_error("Please specify either size or extents (not both)"); return 0; } if (arg_count(cmd, extents_ARG)) { if (arg_sign_value(cmd, extents_ARG, 0) == SIGN_MINUS) { log_error("Negative number of extents is invalid"); return 0; } lp->extents = arg_uint_value(cmd, extents_ARG, 0); lcp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE); } /* Size returned in kilobyte units; held in sectors */ if (arg_count(cmd, size_ARG)) { if (arg_sign_value(cmd, size_ARG, 0) == SIGN_MINUS) { log_error("Negative size is invalid"); return 0; } lcp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)); lcp->percent = PERCENT_NONE; } /* Size returned in kilobyte units; held in sectors */ if (arg_count(cmd, virtualsize_ARG)) { if (arg_sign_value(cmd, virtualsize_ARG, 0) == SIGN_MINUS) { log_error("Negative virtual origin size is invalid"); return 0; } lp->voriginsize = arg_uint64_value(cmd, virtualsize_ARG, UINT64_C(0)); if (!lp->voriginsize) { log_error("Virtual origin size may not be zero"); return 0; } } return 1; }
static int lvchange_availability(struct cmd_context *cmd, struct logical_volume *lv) { int activate; activate = arg_uint_value(cmd, available_ARG, 0); if (activate == CHANGE_ALN) { log_verbose("Deactivating logical volume \"%s\" locally", lv->name); if (!deactivate_lv_local(cmd, lv)) return_0; } else if (activate == CHANGE_AN) { log_verbose("Deactivating logical volume \"%s\"", lv->name); if (!deactivate_lv(cmd, lv)) return_0; } else { if (lv_is_origin(lv) || (activate == CHANGE_AE)) { log_verbose("Activating logical volume \"%s\" " "exclusively", lv->name); if (!activate_lv_excl(cmd, lv)) return_0; } else if (activate == CHANGE_ALY) { log_verbose("Activating logical volume \"%s\" locally", lv->name); if (!activate_lv_local(cmd, lv)) return_0; } else { log_verbose("Activating logical volume \"%s\"", lv->name); if (!activate_lv(cmd, lv)) return_0; } if (background_polling()) lv_spawn_background_polling(cmd, lv); } return 1; }
static int lvchange_readahead(struct cmd_context *cmd, struct logical_volume *lv) { unsigned read_ahead = 0; unsigned pagesize = (unsigned) lvm_getpagesize() >> SECTOR_SHIFT; int r = 0; read_ahead = arg_uint_value(cmd, readahead_ARG, 0); if (read_ahead != DM_READ_AHEAD_AUTO && (lv->vg->fid->fmt->features & FMT_RESTRICTED_READAHEAD) && (read_ahead < 2 || read_ahead > 120)) { log_error("Metadata only supports readahead values between 2 and 120."); return 0; } if (read_ahead != DM_READ_AHEAD_AUTO && read_ahead != DM_READ_AHEAD_NONE && read_ahead % pagesize) { if (read_ahead < pagesize) read_ahead = pagesize; else read_ahead = (read_ahead / pagesize) * pagesize; log_warn("WARNING: Overriding readahead to %u sectors, a multiple " "of %uK page size.", read_ahead, pagesize >> 1); } if (lv->read_ahead == read_ahead) { if (read_ahead == DM_READ_AHEAD_AUTO) log_error("Read ahead is already auto for \"%s\"", lv->name); else log_error("Read ahead is already %u for \"%s\"", read_ahead, lv->name); return 0; } lv->read_ahead = read_ahead; log_verbose("Setting read ahead to %u for \"%s\"", read_ahead, lv->name); log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg)) return_0; if (!suspend_lv(cmd, lv)) { log_error("Failed to lock %s", lv->name); vg_revert(lv->vg); goto out; } if (!vg_commit(lv->vg)) { if (!resume_lv(cmd, lv)) stack; goto_out; } log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name); if (!resume_lv(cmd, lv)) { log_error("Problem reactivating %s", lv->name); goto out; } r = 1; out: backup(lv->vg); return r; }
static int lvchange_permission(struct cmd_context *cmd, struct logical_volume *lv) { uint32_t lv_access; struct lvinfo info; int r = 0; lv_access = arg_uint_value(cmd, permission_ARG, 0); if ((lv_access & LVM_WRITE) && (lv->status & LVM_WRITE)) { log_error("Logical volume \"%s\" is already writable", lv->name); return 0; } if (!(lv_access & LVM_WRITE) && !(lv->status & LVM_WRITE)) { log_error("Logical volume \"%s\" is already read only", lv->name); return 0; } if ((lv->status & MIRRORED) && (vg_is_clustered(lv->vg)) && lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) { log_error("Cannot change permissions of mirror \"%s\" " "while active.", lv->name); return 0; } /* Not allowed to change permissions on RAID sub-LVs directly */ if ((lv->status & RAID_META) || (lv->status & RAID_IMAGE)) { log_error("Cannot change permissions of RAID %s \"%s\"", (lv->status & RAID_IMAGE) ? "image" : "metadata area", lv->name); return 0; } if (lv_access & LVM_WRITE) { lv->status |= LVM_WRITE; log_verbose("Setting logical volume \"%s\" read/write", lv->name); } else { lv->status &= ~LVM_WRITE; log_verbose("Setting logical volume \"%s\" read-only", lv->name); } log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name); if (!vg_write(lv->vg)) return_0; if (!suspend_lv(cmd, lv)) { log_error("Failed to lock %s", lv->name); vg_revert(lv->vg); goto out; } if (!vg_commit(lv->vg)) { if (!resume_lv(cmd, lv)) stack; goto_out; } log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name); if (!resume_lv(cmd, lv)) { log_error("Problem reactivating %s", lv->name); goto out; } r = 1; out: backup(lv->vg); return r; }
static int _read_size_params(struct lvcreate_params *lp, struct lvcreate_cmdline_params *lcp, struct cmd_context *cmd) { if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) { log_error("Please specify either size or extents (not both)"); return 0; } if (!lp->thin && !lp->snapshot && !arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG)) { log_error("Please specify either size or extents"); return 0; } if (arg_count(cmd, extents_ARG)) { if (arg_sign_value(cmd, extents_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative number of extents is invalid"); return 0; } lp->extents = arg_uint_value(cmd, extents_ARG, 0); lcp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE); } /* Size returned in kilobyte units; held in sectors */ if (arg_count(cmd, size_ARG)) { if (arg_sign_value(cmd, size_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative size is invalid"); return 0; } lcp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)); lcp->percent = PERCENT_NONE; } /* If size/extents given with thin, then we are creating a thin pool */ if (seg_is_thin(lp) && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG))) lp->create_pool = 1; if (!lp->create_pool && arg_count(cmd, poolmetadatasize_ARG)) { log_error("--poolmetadatasize may only be specified when allocating the pool."); return 0; } if (arg_count(cmd, virtualsize_ARG)) { if (seg_is_thin_pool(lp)) { log_error("Virtual size in incompatible with thin_pool segment type."); return 0; } if (arg_sign_value(cmd, virtualsize_ARG, SIGN_NONE) == SIGN_MINUS) { log_error("Negative virtual origin size is invalid"); return 0; } /* Size returned in kilobyte units; held in sectors */ lp->voriginsize = arg_uint64_value(cmd, virtualsize_ARG, UINT64_C(0)); if (!lp->voriginsize) { log_error("Virtual origin size may not be zero"); return 0; } } else { /* No virtual size given and no snapshot, so no thin LV to create. */ if (seg_is_thin_volume(lp) && !lp->snapshot && !(lp->segtype = get_segtype_from_string(cmd, "thin-pool"))) return_0; lp->thin = 0; } return 1; }
int vgcreate(struct cmd_context *cmd, int argc, char **argv) { size_t max_lv, max_pv; uint32_t extent_size; char *vg_name; struct volume_group *vg; const char *tag; alloc_policy_t alloc; int clustered; if (!argc) { log_error("Please provide volume group name and " "physical volumes"); return EINVALID_CMD_LINE; } if (argc == 1) { log_error("Please enter physical volume name(s)"); return EINVALID_CMD_LINE; } vg_name = skip_dev_dir(cmd, argv[0], NULL); max_lv = arg_uint_value(cmd, maxlogicalvolumes_ARG, 0); max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, 0); alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL); if (alloc == ALLOC_INHERIT) { log_error("Volume Group allocation policy cannot inherit " "from anything"); return EINVALID_CMD_LINE; } if (!(cmd->fmt->features & FMT_UNLIMITED_VOLS)) { if (!max_lv) max_lv = 255; if (!max_pv) max_pv = 255; if (max_lv > 255 || max_pv > 255) { log_error("Number of volumes may not exceed 255"); return EINVALID_CMD_LINE; } } if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) { log_error("Physical extent size may not be negative"); return EINVALID_CMD_LINE; } if (arg_sign_value(cmd, maxlogicalvolumes_ARG, 0) == SIGN_MINUS) { log_error("Max Logical Volumes may not be negative"); return EINVALID_CMD_LINE; } if (arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) { log_error("Max Physical Volumes may not be negative"); return EINVALID_CMD_LINE; } /* Units of 512-byte sectors */ extent_size = arg_uint_value(cmd, physicalextentsize_ARG, DEFAULT_EXTENT) * 2; if (!extent_size) { log_error("Physical extent size may not be zero"); return EINVALID_CMD_LINE; } if (!validate_vg_name(cmd, vg_name)) { log_error("New volume group name \"%s\" is invalid", vg_name); return ECMD_FAILED; } /* Create the new VG */ if (!(vg = vg_create(cmd, vg_name, extent_size, max_pv, max_lv, alloc, argc - 1, argv + 1))) return ECMD_FAILED; if (max_lv != vg->max_lv) log_warn("WARNING: Setting maxlogicalvolumes to %d " "(0 means unlimited)", vg->max_lv); if (max_pv != vg->max_pv) log_warn("WARNING: Setting maxphysicalvolumes to %d " "(0 means unlimited)", vg->max_pv); if (arg_count(cmd, addtag_ARG)) { if (!(tag = arg_str_value(cmd, addtag_ARG, NULL))) { log_error("Failed to get tag"); return ECMD_FAILED; } if (!(vg->fid->fmt->features & FMT_TAGS)) { log_error("Volume group format does not support tags"); return ECMD_FAILED; } if (!str_list_add(cmd->mem, &vg->tags, tag)) { log_error("Failed to add tag %s to volume group %s", tag, vg_name); return ECMD_FAILED; } } if (arg_count(cmd, clustered_ARG)) clustered = !strcmp(arg_str_value(cmd, clustered_ARG, "n"), "y"); else /* Default depends on current locking type */ clustered = locking_is_clustered(); if (clustered) vg->status |= CLUSTERED; else vg->status &= ~CLUSTERED; if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) { log_error("Can't get lock for orphan PVs"); return ECMD_FAILED; } if (!lock_vol(cmd, vg_name, LCK_VG_WRITE | LCK_NONBLOCK)) { log_error("Can't get lock for %s", vg_name); unlock_vg(cmd, ORPHAN); return ECMD_FAILED; } if (!archive(vg)) { unlock_vg(cmd, vg_name); unlock_vg(cmd, ORPHAN); return ECMD_FAILED; } /* Store VG on disk(s) */ if (!vg_write(vg) || !vg_commit(vg)) { unlock_vg(cmd, vg_name); unlock_vg(cmd, ORPHAN); return ECMD_FAILED; } unlock_vg(cmd, vg_name); unlock_vg(cmd, ORPHAN); backup(vg); log_print("Volume group \"%s\" successfully created", vg->name); return ECMD_PROCESSED; }
static int lvchange_pool_update(struct cmd_context *cmd, struct logical_volume *lv) { int r = 0; int update = 0; unsigned val; thin_discards_t discards; if (!lv_is_thin_pool(lv)) { log_error("Logical volume \"%s\" is not a thin pool.", lv->name); return 0; } if (arg_count(cmd, discards_ARG)) { discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_IGNORE); if (discards != first_seg(lv)->discards) { if ((discards != THIN_DISCARDS_IGNORE) && (first_seg(lv)->chunk_size & (first_seg(lv)->chunk_size - 1))) log_error("Cannot change discards state for " "logical volume \"%s\" " "with non power of 2 chunk size.", lv->name); else if (((discards == THIN_DISCARDS_IGNORE) || (first_seg(lv)->discards == THIN_DISCARDS_IGNORE)) && lv_is_active(lv)) log_error("Cannot change discards state for active " "logical volume \"%s\".", lv->name); else { first_seg(lv)->discards = discards; update++; } } else log_error("Logical volume \"%s\" already uses --discards %s.", lv->name, get_pool_discards_name(discards)); } if (arg_count(cmd, zero_ARG)) { val = arg_uint_value(cmd, zero_ARG, 1); if (val != first_seg(lv)->zero_new_blocks) { first_seg(lv)->zero_new_blocks = val; update++; } else log_error("Logical volume \"%s\" already %szero new blocks.", lv->name, val ? "" : "does not "); } if (!update) return 0; log_very_verbose("Updating logical volume \"%s\" on disk(s).", lv->name); if (!vg_write(lv->vg)) return_0; if (!suspend_lv_origin(cmd, lv)) { log_error("Failed to update active %s/%s (deactivation is needed).", lv->vg->name, lv->name); vg_revert(lv->vg); goto out; } if (!vg_commit(lv->vg)) { if (!resume_lv_origin(cmd, lv)) stack; goto_out; } if (!resume_lv_origin(cmd, lv)) { log_error("Problem reactivating %s.", lv->name); goto out; } r = 1; out: backup(lv->vg); return r; }