diff options
author | Anas Nashif <anas.nashif@intel.com> | 2013-03-05 01:43:20 -0800 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2013-03-05 01:43:20 -0800 |
commit | 8bd28eea831fd5215c12e6fcecc8e9a772398ed9 (patch) | |
tree | 2579ba0d9921953cadfc17006c47ff419382898a /tools/lvcreate.c | |
download | device-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.c | 566 |
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; +} |