summaryrefslogtreecommitdiff
path: root/tools/lvcreate.c
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2013-03-05 01:43:20 -0800
committerAnas Nashif <anas.nashif@intel.com>2013-03-05 01:43:20 -0800
commit8bd28eea831fd5215c12e6fcecc8e9a772398ed9 (patch)
tree2579ba0d9921953cadfc17006c47ff419382898a /tools/lvcreate.c
downloaddevice-mapper-8bd28eea831fd5215c12e6fcecc8e9a772398ed9.tar.gz
device-mapper-8bd28eea831fd5215c12e6fcecc8e9a772398ed9.tar.bz2
device-mapper-8bd28eea831fd5215c12e6fcecc8e9a772398ed9.zip
Imported Upstream version 2.02.79upstream/2.02.79
Diffstat (limited to 'tools/lvcreate.c')
-rw-r--r--tools/lvcreate.c566
1 files changed, 566 insertions, 0 deletions
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
new file mode 100644
index 0000000..13b5926
--- /dev/null
+++ b/tools/lvcreate.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of LVM2.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License v.2.1.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "tools.h"
+#include "lv_alloc.h"
+
+#include <fcntl.h>
+
+struct lvcreate_cmdline_params {
+ percent_type_t percent;
+ uint64_t size;
+ char **pvs;
+ int pv_count;
+};
+
+static int _lvcreate_name_params(struct lvcreate_params *lp,
+ struct cmd_context *cmd,
+ int *pargc, char ***pargv)
+{
+ int argc = *pargc;
+ char **argv = *pargv, *ptr;
+ char *vg_name;
+
+ lp->lv_name = arg_str_value(cmd, name_ARG, NULL);
+
+ if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) {
+ if (!argc) {
+ log_error("Please specify a logical volume to act as "
+ "the snapshot origin.");
+ return 0;
+ }
+
+ lp->origin = argv[0];
+ (*pargv)++, (*pargc)--;
+ if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) {
+ log_error("The origin name should include the "
+ "volume group.");
+ return 0;
+ }
+
+ /* Strip the volume group from the origin */
+ if ((ptr = strrchr(lp->origin, (int) '/')))
+ lp->origin = ptr + 1;
+
+ } else {
+ /*
+ * If VG not on command line, try -n arg and then
+ * environment.
+ */
+ if (!argc) {
+ if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
+ log_error("Please provide a volume group name");
+ return 0;
+ }
+
+ } else {
+ vg_name = skip_dev_dir(cmd, argv[0], NULL);
+ if (strrchr(vg_name, '/')) {
+ log_error("Volume group name expected "
+ "(no slash)");
+ return 0;
+ }
+
+ /*
+ * Ensure lv_name doesn't contain a
+ * different VG.
+ */
+ if (lp->lv_name && strchr(lp->lv_name, '/')) {
+ if (!(lp->vg_name =
+ extract_vgname(cmd, lp->lv_name)))
+ return 0;
+
+ if (strcmp(lp->vg_name, vg_name)) {
+ log_error("Inconsistent volume group "
+ "names "
+ "given: \"%s\" and \"%s\"",
+ lp->vg_name, vg_name);
+ return 0;
+ }
+ }
+
+ lp->vg_name = vg_name;
+ (*pargv)++, (*pargc)--;
+ }
+ }
+
+ if (!validate_name(lp->vg_name)) {
+ log_error("Volume group name %s has invalid characters",
+ lp->vg_name);
+ return 0;
+ }
+
+ if (lp->lv_name) {
+ if ((ptr = strrchr(lp->lv_name, '/')))
+ lp->lv_name = ptr + 1;
+
+ if (!apply_lvname_restrictions(lp->lv_name))
+ return_0;
+
+ if (!validate_name(lp->lv_name)) {
+ log_error("Logical volume name \"%s\" is invalid",
+ lp->lv_name);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Update extents parameters based on other parameters which affect the size
+ * calcuation.
+ * NOTE: We must do this here because of the percent_t typedef and because we
+ * need the vg.
+ */
+static int _update_extents_params(struct volume_group *vg,
+ struct lvcreate_params *lp,
+ struct lvcreate_cmdline_params *lcp)
+{
+ uint32_t pv_extent_count;
+ struct logical_volume *origin = NULL;
+
+ if (lcp->size &&
+ !(lp->extents = extents_from_size(vg->cmd, lcp->size,
+ vg->extent_size)))
+ return_0;
+
+ if (lp->voriginsize &&
+ !(lp->voriginextents = extents_from_size(vg->cmd, lp->voriginsize,
+ vg->extent_size)))
+ return_0;
+
+ /*
+ * Create the pv list before we parse lcp->percent - might be
+ * PERCENT_PVSs
+ */
+ if (lcp->pv_count) {
+ if (!(lp->pvh = create_pv_list(vg->cmd->mem, vg,
+ lcp->pv_count, lcp->pvs, 1)))
+ return_0;
+ } else
+ lp->pvh = &vg->pvs;
+
+ switch(lcp->percent) {
+ case PERCENT_VG:
+ lp->extents = lp->extents * vg->extent_count / 100;
+ break;
+ case PERCENT_FREE:
+ lp->extents = lp->extents * vg->free_count / 100;
+ break;
+ case PERCENT_PVS:
+ if (!lcp->pv_count)
+ lp->extents = lp->extents * vg->extent_count / 100;
+ else {
+ pv_extent_count = pv_list_extents_free(lp->pvh);
+ lp->extents = lp->extents * pv_extent_count / 100;
+ }
+ break;
+ case PERCENT_LV:
+ log_error("Please express size as %%VG, %%PVS, or "
+ "%%FREE.");
+ return 0;
+ case PERCENT_ORIGIN:
+ if (lp->snapshot && lp->origin &&
+ !(origin = find_lv(vg, lp->origin))) {
+ log_error("Couldn't find origin volume '%s'.",
+ lp->origin);
+ return 0;
+ }
+ if (!origin) {
+ log_error(INTERNAL_ERROR "Couldn't find origin volume.");
+ return 0;
+ }
+ lp->extents = lp->extents * origin->le_count / 100;
+ break;
+ case PERCENT_NONE:
+ break;
+ }
+ 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;
+}
+
+/*
+ * Generic mirror parameter checks.
+ * FIXME: Should eventually be moved into lvm library.
+ */
+static int _validate_mirror_params(const struct cmd_context *cmd __attribute__((unused)),
+ const struct lvcreate_params *lp)
+{
+ int pagesize = lvm_getpagesize();
+
+ if (lp->region_size & (lp->region_size - 1)) {
+ log_error("Region size (%" PRIu32 ") must be a power of 2",
+ lp->region_size);
+ return 0;
+ }
+
+ if (lp->region_size % (pagesize >> SECTOR_SHIFT)) {
+ log_error("Region size (%" PRIu32 ") must be a multiple of "
+ "machine memory page size (%d)",
+ lp->region_size, pagesize >> SECTOR_SHIFT);
+ return 0;
+ }
+
+ if (!lp->region_size) {
+ log_error("Non-zero region size must be supplied.");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _read_mirror_params(struct lvcreate_params *lp,
+ struct cmd_context *cmd)
+{
+ int region_size;
+ const char *mirrorlog;
+ int corelog = arg_count(cmd, corelog_ARG);
+
+ mirrorlog = arg_str_value(cmd, mirrorlog_ARG,
+ corelog ? "core" : DEFAULT_MIRRORLOG);
+
+ if (strcmp("core", mirrorlog) && corelog) {
+ log_error("Please use only one of --mirrorlog or --corelog");
+ return 0;
+ }
+
+ if (!strcmp("mirrored", mirrorlog)) {
+ lp->log_count = 2;
+ } else if (!strcmp("disk", mirrorlog)) {
+ lp->log_count = 1;
+ } else if (!strcmp("core", mirrorlog))
+ lp->log_count = 0;
+ else {
+ log_error("Unknown mirrorlog type: %s", mirrorlog);
+ return 0;
+ }
+
+ log_verbose("Setting logging type to %s", mirrorlog);
+
+ lp->nosync = arg_is_set(cmd, nosync_ARG);
+
+ if (arg_count(cmd, regionsize_ARG)) {
+ if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
+ log_error("Negative regionsize is invalid");
+ return 0;
+ }
+ lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0);
+ } else {
+ region_size = 2 * find_config_tree_int(cmd,
+ "activation/mirror_region_size",
+ DEFAULT_MIRROR_REGION_SIZE);
+ if (region_size < 0) {
+ log_error("Negative regionsize in configuration file "
+ "is invalid");
+ return 0;
+ }
+ lp->region_size = region_size;
+ }
+
+ if (!_validate_mirror_params(cmd, lp))
+ return 0;
+
+ return 1;
+}
+
+static int _lvcreate_params(struct lvcreate_params *lp,
+ struct lvcreate_cmdline_params *lcp,
+ struct cmd_context *cmd,
+ int argc, char **argv)
+{
+ int contiguous;
+ unsigned pagesize;
+ struct arg_value_group_list *current_group;
+ const char *tag;
+
+ memset(lp, 0, sizeof(*lp));
+ memset(lcp, 0, sizeof(*lcp));
+ dm_list_init(&lp->tags);
+
+ /*
+ * Check selected options are compatible and determine segtype
+ */
+ lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "striped"));
+
+ if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp) ||
+ arg_count(cmd, virtualsize_ARG))
+ lp->snapshot = 1;
+
+ lp->mirrors = 1;
+
+ /* Default to 2 mirrored areas if --type mirror */
+ if (seg_is_mirrored(lp))
+ lp->mirrors = 2;
+
+ if (arg_count(cmd, mirrors_ARG)) {
+ lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
+ if (lp->mirrors == 1)
+ log_print("Redundant mirrors argument: default is 0");
+ if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
+ log_error("Mirrors argument may not be negative");
+ return 0;
+ }
+ }
+
+ if (lp->snapshot) {
+ if (arg_count(cmd, zero_ARG)) {
+ log_error("-Z is incompatible with snapshots");
+ return 0;
+ }
+ if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
+ log_error("Negative chunk size is invalid");
+ return 0;
+ }
+ lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
+ if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
+ (lp->chunk_size & (lp->chunk_size - 1))) {
+ log_error("Chunk size must be a power of 2 in the "
+ "range 4K to 512K");
+ return 0;
+ }
+ log_verbose("Setting chunksize to %d sectors.", lp->chunk_size);
+
+ if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
+ return_0;
+ } else {
+ if (arg_count(cmd, chunksize_ARG)) {
+ log_error("-c is only available with snapshots");
+ return 0;
+ }
+ }
+
+ if (lp->mirrors > 1) {
+ if (lp->snapshot) {
+ log_error("mirrors and snapshots are currently "
+ "incompatible");
+ return 0;
+ }
+
+ if (!(lp->segtype = get_segtype_from_string(cmd, "striped")))
+ return_0;
+ } else {
+ if (arg_count(cmd, corelog_ARG)) {
+ log_error("--corelog is only available with mirrors");
+ return 0;
+ }
+
+ if (arg_count(cmd, mirrorlog_ARG)) {
+ log_error("--mirrorlog is only available with mirrors");
+ return 0;
+ }
+
+ if (arg_count(cmd, nosync_ARG)) {
+ log_error("--nosync is only available with mirrors");
+ return 0;
+ }
+ }
+
+ if (activation() && lp->segtype->ops->target_present &&
+ !lp->segtype->ops->target_present(cmd, NULL, NULL)) {
+ log_error("%s: Required device-mapper target(s) not "
+ "detected in your kernel", lp->segtype->name);
+ return 0;
+ }
+
+ if (!get_activation_monitoring_mode(cmd, NULL,
+ &lp->activation_monitoring))
+ return_0;
+
+ if (!_lvcreate_name_params(lp, cmd, &argc, &argv) ||
+ !_read_size_params(lp, lcp, cmd) ||
+ !get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) ||
+ !_read_mirror_params(lp, cmd))
+ return_0;
+
+ /*
+ * Should we zero the lv.
+ */
+ lp->zero = strcmp(arg_str_value(cmd, zero_ARG,
+ (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n");
+
+ /*
+ * Alloc policy
+ */
+ contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
+
+ lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
+
+ lp->alloc = arg_uint_value(cmd, alloc_ARG, lp->alloc);
+
+ if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) {
+ log_error("Conflicting contiguous and alloc arguments");
+ return 0;
+ }
+
+ if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) {
+ log_error("Only up to %d images in mirror supported currently.",
+ DEFAULT_MIRROR_MAX_IMAGES);
+ return 0;
+ }
+
+ /*
+ * Read ahead.
+ */
+ lp->read_ahead = arg_uint_value(cmd, readahead_ARG,
+ cmd->default_settings.read_ahead);
+ pagesize = lvm_getpagesize() >> SECTOR_SHIFT;
+ if (lp->read_ahead != DM_READ_AHEAD_AUTO &&
+ lp->read_ahead != DM_READ_AHEAD_NONE &&
+ lp->read_ahead % pagesize) {
+ if (lp->read_ahead < pagesize)
+ lp->read_ahead = pagesize;
+ else
+ lp->read_ahead = (lp->read_ahead / pagesize) * pagesize;
+ log_warn("WARNING: Overriding readahead to %u sectors, a multiple "
+ "of %uK page size.", lp->read_ahead, pagesize >> 1);
+ }
+
+ /*
+ * Permissions.
+ */
+ lp->permission = arg_uint_value(cmd, permission_ARG,
+ LVM_READ | LVM_WRITE);
+
+ /* Must not zero read only volume */
+ if (!(lp->permission & LVM_WRITE))
+ lp->zero = 0;
+
+ lp->minor = arg_int_value(cmd, minor_ARG, -1);
+ lp->major = arg_int_value(cmd, major_ARG, -1);
+
+ /* Persistent minor */
+ if (arg_count(cmd, persistent_ARG)) {
+ if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) {
+ if (lp->minor == -1) {
+ log_error("Please specify minor number with "
+ "--minor when using -My");
+ return 0;
+ }
+ if (lp->major == -1) {
+ log_error("Please specify major number with "
+ "--major when using -My");
+ return 0;
+ }
+ } else {
+ if ((lp->minor != -1) || (lp->major != -1)) {
+ log_error("--major and --minor incompatible "
+ "with -Mn");
+ return 0;
+ }
+ }
+ } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) {
+ log_error("--major and --minor require -My");
+ return 0;
+ }
+
+ dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
+ if (!grouped_arg_is_set(current_group->arg_values, addtag_ARG))
+ continue;
+
+ if (!(tag = grouped_arg_str_value(current_group->arg_values, addtag_ARG, NULL))) {
+ log_error("Failed to get tag");
+ return 0;
+ }
+
+ if (!str_list_add(cmd->mem, &lp->tags, tag)) {
+ log_error("Unable to allocate memory for tag %s", tag);
+ return 0;
+ }
+ }
+
+ lcp->pv_count = argc;
+ lcp->pvs = argv;
+
+ return 1;
+}
+
+int lvcreate(struct cmd_context *cmd, int argc, char **argv)
+{
+ int r = ECMD_PROCESSED;
+ struct lvcreate_params lp;
+ struct lvcreate_cmdline_params lcp;
+ struct volume_group *vg;
+
+ memset(&lp, 0, sizeof(lp));
+
+ if (!_lvcreate_params(&lp, &lcp, cmd, argc, argv))
+ return EINVALID_CMD_LINE;
+
+ log_verbose("Finding volume group \"%s\"", lp.vg_name);
+ vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0);
+ if (vg_read_error(vg)) {
+ free_vg(vg);
+ stack;
+ return ECMD_FAILED;
+ }
+
+ if (!_update_extents_params(vg, &lp, &lcp)) {
+ r = ECMD_FAILED;
+ goto_out;
+ }
+
+ if (!lv_create_single(vg, &lp)) {
+ stack;
+ r = ECMD_FAILED;
+ }
+out:
+ unlock_and_free_vg(cmd, vg, lp.vg_name);
+ return r;
+}