1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-22 17:35:59 +03:00
lvm2/tools/lvcreate.c

259 lines
6.1 KiB
C
Raw Normal View History

2001-11-06 22:02:26 +03:00
/*
* Copyright (C) 2001 Sistina Software
2001-11-06 22:02:26 +03:00
*
* This file is released under the GPL.
2001-11-06 22:02:26 +03:00
*
*/
#include "tools.h"
2001-11-16 18:38:52 +03:00
#include <fcntl.h>
2001-11-06 22:02:26 +03:00
int lvcreate(int argc, char **argv)
{
int zero;
uint32_t read_ahead = 0;
int stripes = 1;
int stripesize = 0;
int opt = 0;
uint32_t status = 0;
uint32_t size = 0;
2001-12-03 19:27:16 +03:00
uint32_t size_rest;
2001-11-06 22:02:26 +03:00
uint32_t extents = 0;
struct volume_group *vg;
struct logical_volume *lv;
struct list *pvh;
2001-11-06 22:02:26 +03:00
char *lv_name = NULL;
char *vg_name;
char *st;
if (arg_count(snapshot_ARG) || arg_count(chunksize_ARG)) {
log_error("Snapshots are not yet supported in LVM2.");
return EINVALID_CMD_LINE;
}
/* mutually exclusive */
if ((arg_count(zero_ARG) && arg_count(snapshot_ARG)) ||
(arg_count(extents_ARG) && arg_count(size_ARG))) {
log_error("Invalid combination of arguments");
return EINVALID_CMD_LINE;
}
if (arg_count(size_ARG) + arg_count(extents_ARG) == 0) {
log_error("Please indicate size using option -l or -L");
return EINVALID_CMD_LINE;
}
if (strcmp(arg_str_value(contiguous_ARG, "n"), "n"))
status |= ALLOC_CONTIGUOUS;
2001-11-12 22:28:50 +03:00
else
status |= ALLOC_SIMPLE;
2001-11-06 22:02:26 +03:00
zero = strcmp(arg_str_value(zero_ARG, "y"), "n");
if (arg_count(stripes_ARG)) {
stripes = arg_int_value(stripes_ARG, 1);
if (stripes == 1)
log_print("Redundant stripes argument: default is 1");
}
if (arg_count(stripesize_ARG))
2001-12-03 19:27:16 +03:00
stripesize = 2 * arg_int_value(stripesize_ARG, 0);
2001-11-06 22:02:26 +03:00
if (stripes == 1 && stripesize) {
log_print("Ignoring stripesize argument with single stripe");
stripesize = 0;
}
2001-12-03 19:27:16 +03:00
if (stripes > 1 && !stripesize) {
stripesize = 2 * STRIPE_SIZE_DEFAULT;
log_print("Using default stripesize %dKB", stripesize / 2);
}
2001-11-06 22:02:26 +03:00
if (arg_count(permission_ARG))
status |= arg_int_value(permission_ARG, 0);
else
status |= LVM_READ | LVM_WRITE;
2001-11-06 22:02:26 +03:00
if (arg_count(readahead_ARG))
read_ahead = arg_int_value(readahead_ARG, 0);
if (arg_count(extents_ARG))
extents = arg_int_value(extents_ARG, 0);
/* Size returned in kilobyte units; held in sectors */
if (arg_count(size_ARG))
size = arg_int_value(size_ARG, 0);
if (arg_count(name_ARG))
lv_name = arg_value(name_ARG);
2001-11-12 22:28:50 +03:00
2001-11-06 22:02:26 +03:00
/* If VG not on command line, try -n arg and then environment */
if (!argc) {
2001-11-14 16:52:38 +03:00
if (!(vg_name = extract_vgname(fid, lv_name))) {
2001-11-06 22:02:26 +03:00
log_error("Please provide a volume group name");
return EINVALID_CMD_LINE;
}
2001-11-06 22:02:26 +03:00
} else {
/* Ensure lv_name doesn't contain a different VG! */
if (lv_name && strchr(lv_name, '/')) {
2001-11-12 18:10:01 +03:00
if (!(vg_name = extract_vgname(fid, lv_name)))
2001-11-06 22:02:26 +03:00
return EINVALID_CMD_LINE;
if (strcmp(vg_name, argv[0])) {
log_error("Inconsistent volume group names "
2002-01-30 18:04:48 +03:00
"given: \"%s\" and \"%s\"",
vg_name, argv[0]);
2001-11-06 22:02:26 +03:00
return EINVALID_CMD_LINE;
}
}
vg_name = argv[0];
argv++;
argc--;
}
if (lv_name && (st = strrchr(lv_name, '/')))
2001-11-06 22:02:26 +03:00
lv_name = st + 1;
/* does VG exist? */
2002-01-30 18:04:48 +03:00
log_verbose("Finding volume group \"%s\"", vg_name);
2001-11-12 18:10:01 +03:00
if (!(vg = fid->ops->vg_read(fid, vg_name))) {
2002-01-30 18:04:48 +03:00
log_error("Volume group \"%s\" doesn't exist", vg_name);
2001-11-06 22:02:26 +03:00
return ECMD_FAILED;
}
if (vg->status & EXPORTED_VG) {
2002-01-30 18:04:48 +03:00
log_error("Volume group \"%s\" is exported", vg_name);
return ECMD_FAILED;
}
if (!(vg->status & LVM_WRITE)) {
2002-01-30 18:04:48 +03:00
log_error("Volume group \"%s\" is read-only", vg_name);
return ECMD_FAILED;
}
if (lv_name && find_lv_in_vg(vg, lv_name)) {
2002-01-30 18:04:48 +03:00
log_error("Logical volume \"%s\" already exists in "
"volume group \"%s\"", lv_name, vg_name);
2001-11-06 22:02:26 +03:00
return ECMD_FAILED;
}
if (!argc)
2001-11-06 22:02:26 +03:00
/* Use full list from VG */
pvh = &vg->pvs;
else {
if (!(pvh = create_pv_list(fid->cmd->mem, vg,
argc - opt, argv + opt))) {
stack;
return ECMD_FAILED;
}
2001-11-06 22:02:26 +03:00
}
2001-12-03 19:27:16 +03:00
if (argc && argc < stripes ) {
log_error("Too few physical volumes on "
2001-11-06 22:02:26 +03:00
"command line for %d-way striping", stripes);
return EINVALID_CMD_LINE;
}
2001-12-03 19:27:16 +03:00
if (stripes < 1 || stripes > MAX_STRIPES) {
log_error("Number of stripes (%d) must be between %d and %d",
2001-12-03 19:27:16 +03:00
stripes, 1, MAX_STRIPES);
2001-11-06 22:02:26 +03:00
return EINVALID_CMD_LINE;
}
2001-12-03 19:27:16 +03:00
if (stripes > 1 && (stripesize < STRIPE_SIZE_MIN ||
stripesize > STRIPE_SIZE_MAX ||
stripesize & (stripesize - 1))) {
log_error("Invalid stripe size %d", stripesize);
2001-11-06 22:02:26 +03:00
return EINVALID_CMD_LINE;
}
2001-12-03 19:27:16 +03:00
if (stripesize > vg->extent_size) {
log_error("Setting stripe size %d KB to physical extent "
"size %u KB",
stripesize / 2, vg->extent_size / 2);
stripesize = vg->extent_size;
2001-11-06 22:02:26 +03:00
}
if (size) {
/* No of 512-byte sectors */
extents = size * 2;
if (extents % vg->extent_size) {
char *s1;
extents += vg->extent_size - extents % vg->extent_size;
log_print("Rounding up size to full physical extent %s",
(s1 = display_size(extents / 2, SIZE_SHORT)));
2001-11-06 22:02:26 +03:00
dbg_free(s1);
}
extents /= vg->extent_size;
}
2001-12-03 19:27:16 +03:00
if ((size_rest = extents % stripes)) {
log_print("Rounding size (%d extents) up to stripe boundary "
"size (%d extents)", extents,
extents - size_rest + stripes);
extents = extents - size_rest + stripes;
}
2001-11-06 22:02:26 +03:00
2002-01-09 16:17:14 +03:00
if (!archive(vg))
return ECMD_FAILED;
2002-01-24 20:15:24 +03:00
if (!(lv = lv_create(fid, lv_name, status,
stripes, stripesize, extents,
vg, pvh)))
return ECMD_FAILED;
2001-11-06 22:02:26 +03:00
if (arg_count(readahead_ARG)) {
log_verbose("Setting read ahead sectors");
lv->read_ahead = read_ahead;
}
/* store vg on disk(s) */
2001-11-12 18:10:01 +03:00
if (!fid->ops->vg_write(fid, vg))
2001-11-06 22:02:26 +03:00
return ECMD_FAILED;
2002-01-07 14:12:11 +03:00
backup(vg);
2002-01-30 18:04:48 +03:00
log_print("Logical volume \"%s\" created", lv->name);
2001-11-14 17:12:01 +03:00
2001-11-06 22:02:26 +03:00
if (!lv_activate(lv))
return ECMD_FAILED;
2001-11-14 16:52:38 +03:00
if (zero) {
2001-11-06 22:02:26 +03:00
struct device *dev;
2001-11-16 18:38:52 +03:00
char *name;
2001-11-06 22:02:26 +03:00
if (!(name = pool_alloc(fid->cmd->mem, PATH_MAX))) {
2001-11-16 18:38:52 +03:00
log_error("Name allocation failed - device not zeroed");
return ECMD_FAILED;
}
2001-11-06 22:02:26 +03:00
if (lvm_snprintf(name, PATH_MAX, "%s%s/%s", fid->cmd->dev_dir,
lv->vg->name, lv->name) < 0) {
log_error("Name too long - device not zeroed (%s)",
lv->name);
return ECMD_FAILED;
}
2001-11-06 22:02:26 +03:00
2002-01-30 18:04:48 +03:00
log_verbose("Zeroing start of logical volume \"%s\"", name);
2001-11-16 18:38:52 +03:00
if (!(dev = dev_cache_get(name, NULL))) {
2002-01-30 18:04:48 +03:00
log_error("\"%s\" not found: device not zeroed", name);
2001-11-06 22:02:26 +03:00
return ECMD_FAILED;
}
2001-11-16 18:38:52 +03:00
if (!(dev_open(dev, O_WRONLY)))
return ECMD_FAILED;
dev_zero(dev, 0, 4096);
dev_close(dev);
2001-11-06 22:02:26 +03:00
} else
2002-01-30 18:04:48 +03:00
log_print("WARNING: \"%s\" not zeroed", lv->name);
2001-11-06 22:02:26 +03:00
return 0;
}