From 642c2e964bb1f4719a9330c3ae967805b8ebf12f Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Tue, 6 Nov 2001 19:02:26 +0000 Subject: [PATCH] lvcreate --- lib/activate/activate.c | 2 + lib/metadata/lv_manip.c | 39 +++--- lib/metadata/metadata.c | 4 +- lib/metadata/metadata.h | 17 ++- lib/metadata/pv_map.c | 10 +- tools/Makefile.in | 1 + tools/lvcreate.c | 266 ++++++++++++++++++++++++++++++++++++++++ tools/stub.h | 1 - tools/toollib.c | 26 ++-- tools/toollib.h | 1 + tools/vgcreate.c | 3 +- 11 files changed, 329 insertions(+), 41 deletions(-) create mode 100644 tools/lvcreate.c diff --git a/lib/activate/activate.c b/lib/activate/activate.c index 253d1e7f5..da2079232 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -54,6 +54,8 @@ static int _emit_target(struct dm_task *dmt, struct logical_volume *lv, return 1; } +/* FIXME: Always display error msg */ +/* FIXME: Create dev entry if required */ int lv_activate(struct logical_volume *lv) { int r = 0; diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 45fbb019e..267f1cee2 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -48,7 +48,7 @@ static int _alloc_striped(struct logical_volume *lv, struct list *pvms, uint32_t allocated) { /* FIXME: finish */ - log_err("striped allocation not implemented yet."); + log_error("Striped allocation not implemented yet in LVM2."); return 0; } @@ -84,8 +84,9 @@ static int _alloc_contiguous(struct logical_volume *lv, } if (allocated != lv->le_count) { - log_err("insufficient free extents to " - "allocate logical volume"); + log_error("Insufficient free extents to " + "allocate logical volume %s: %u required", + lv->name, lv->le_count); return 0; } @@ -119,8 +120,9 @@ static int _alloc_simple(struct logical_volume *lv, } if (allocated != lv->le_count) { - log_err("insufficient free extents to " - "allocate logical volume"); + log_error("Insufficient free logical extents to " + "allocate logical volume %s: %u required", + lv->name, lv->le_count); return 0; } @@ -147,7 +149,6 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv, * the pv's. */ if (!(pvms = create_pv_maps(scratch, vg, acceptable_pvs))) { - log_err("couldn't create extent mappings"); goto out; } @@ -183,19 +184,21 @@ struct logical_volume *lv_create(struct io_space *ios, struct logical_volume *lv; if (!extents) { - log_err("Attempt to create an lv with zero extents"); + log_error("Unable to create logical volume %s with no extents", + name); return NULL; } if (vg->free_count < extents) { - log_err("Insufficient free extents in volume group"); - goto bad; + log_error("Insufficient free extents (%u) in volume group %s: " + "%u required", vg->free_count, vg->name, extents); + return NULL; } if (vg->max_lv == vg->lv_count) { - log_err("Maximum logical volumes already reached " - "for this volume group."); - goto bad; + log_error("Maximum number of logical volumes (%u) reached " + "in volume group %s", vg->max_lv, vg->name); + return NULL; } if (!(ll = pool_zalloc(ios->mem, sizeof(*ll)))) { @@ -203,6 +206,8 @@ struct logical_volume *lv_create(struct io_space *ios, return NULL; } + list_init(&ll->list); + lv = &ll->lv; strcpy(lv->id.uuid, ""); @@ -229,7 +234,7 @@ struct logical_volume *lv_create(struct io_space *ios, goto bad; } - list_add(&ll->list, &vg->lvs); + list_add(&vg->lvs, &ll->list); return lv; bad: @@ -243,14 +248,14 @@ int lv_reduce(struct io_space *ios, struct logical_volume *lv, uint32_t extents) { if (extents % lv->stripes) { - log_err("For a striped volume you must reduce by a " - "multiple of the number of stripes"); + log_error("For a striped volume you must reduce by a " + "multiple of the number of stripes"); return 0; } if (lv->le_count <= extents) { - log_err("Attempt to reduce by too many extents, " - "there would be nothing left of the logical volume."); + log_error("Attempt to reduce by so many extents there would " + "be nothing left of the logical volume."); return 0; } diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 7c2968d1a..25044be53 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -93,6 +93,8 @@ int _add_pv_to_vg(struct io_space *ios, struct volume_group *vg, list_add(&vg->pvs, &pvl->list); vg->pv_count++; + vg->extent_count += pv->pe_count; + vg->free_count += pv->pe_count; return 1; } @@ -114,7 +116,7 @@ int vg_extend(struct io_space *ios, struct volume_group *vg, int pv_count, } struct volume_group *vg_create(struct io_space *ios, const char *vg_name, - uint64_t extent_size, int max_pv, int max_lv, + uint32_t extent_size, int max_pv, int max_lv, int pv_count, char **pv_names) { struct volume_group *vg; diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h index 37d81d0b4..1d4d9e362 100644 --- a/lib/metadata/metadata.h +++ b/lib/metadata/metadata.h @@ -33,7 +33,7 @@ #define CLUSTERED 0x00000400 /* VG */ #define SHARED 0x00000800 /* VG */ -#define ALLOC_STRICT 0x00001000 /* LV */ +#define ALLOC_STRICT 0x00001000 /* LV */ #define ALLOC_CONTIGUOUS 0x00002000 /* LV */ #define SNAPSHOT 0x00004000 /* LV */ #define SNAPSHOT_ORG 0x00008000 /* LV */ @@ -70,7 +70,7 @@ struct volume_group { uint32_t status; - uint64_t extent_size; + uint32_t extent_size; uint32_t extent_count; uint32_t free_count; @@ -204,13 +204,13 @@ struct io_space { * Utility functions */ struct volume_group *vg_create(struct io_space *ios, const char *name, - uint64_t extent_size, int max_pv, int max_lv, + uint32_t extent_size, int max_pv, int max_lv, int pv_count, char **pv_names); struct physical_volume *pv_create(struct io_space *ios, const char *name); /* - * This will insert the new lv into the - * volume_group. + * Create a new LV within a given volume group. + * */ struct logical_volume *lv_create(struct io_space *ios, const char *name, @@ -228,8 +228,9 @@ int lv_reduce(struct io_space *ios, int lv_extend(struct io_space *ios, struct logical_volume *lv, uint32_t extents, struct list *allocatable_pvs); + int vg_extend(struct io_space *ios, struct volume_group *vg, int pv_count, - char **pv_names); + char **pv_names); @@ -250,10 +251,6 @@ int pv_remove(struct volume_group *vg, struct physical_volume *pv); struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name); -/* Add an LV to a given VG */ -int lv_add(struct io_space *ios, struct volume_group *vg, - struct logical_volume *lv); - /* Remove an LV from a given VG */ int lv_remove(struct volume_group *vg, struct list *lvh); diff --git a/lib/metadata/pv_map.c b/lib/metadata/pv_map.c index 2b4e09311..7e3702e4e 100644 --- a/lib/metadata/pv_map.c +++ b/lib/metadata/pv_map.c @@ -97,6 +97,7 @@ static int _create_single_area(struct pool *mem, struct pv_map *pvm, return 0; } + list_init(&pvm->areas); pva->start = b; pva->count = e - b; list_add(&pvm->areas, &pva->list); @@ -148,17 +149,19 @@ struct list *create_pv_maps(struct pool *mem, struct volume_group *vg, list_init(maps); if (!_create_maps(mem, pvs, maps)) { - log_err("couldn't create pv maps."); + log_error("Couldn't create physical volume maps in %s", + vg->name); goto bad; } if (!_fill_bitsets(vg, maps)) { - log_err("couldn't fill extent allocation bitmaps."); + log_error("Couldn't fill extent allocation bitmaps in %s", + vg->name); goto bad; } if (!_create_all_areas(mem, maps)) { - log_err("couldn't create area maps."); + log_error("Couldn't create area maps in %s", vg->name); goto bad; } @@ -168,3 +171,4 @@ struct list *create_pv_maps(struct pool *mem, struct volume_group *vg, pool_free(mem, maps); return NULL; } + diff --git a/tools/Makefile.in b/tools/Makefile.in index 72f9dae23..77a761752 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -22,6 +22,7 @@ VPATH = @srcdir@ SOURCES=\ lvchange.c \ + lvcreate.c \ lvm.c \ lvmchange.c \ lvremove.c \ diff --git a/tools/lvcreate.c b/tools/lvcreate.c new file mode 100644 index 000000000..b6436a0bd --- /dev/null +++ b/tools/lvcreate.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2001 Sistina Software + * + * This file is released under the GPL. + * + */ + +#include "tools.h" + +int lvcreate(int argc, char **argv) +{ + int zero; + int size_rest = 0; + uint32_t read_ahead = 0; + int stripes = 1; + int stripesize = 0; + + int opt = 0; + uint32_t status = 0; + uint32_t size = 0; + uint32_t extents = 0; + struct volume_group *vg; + struct logical_volume *lv; + struct list *lvh, *pvh, *pvl; + 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; + + zero = strcmp(arg_str_value(zero_ARG, "y"), "n"); + + if (arg_count(stripes_ARG)) { + log_print("Stripes not yet implemented in LVM2. Ignoring."); + stripes = arg_int_value(stripes_ARG, 1); + if (stripes == 1) + log_print("Redundant stripes argument: default is 1"); + } + + if (arg_count(stripesize_ARG)) + stripesize = arg_int_value(stripesize_ARG, 0); + + if (stripes == 1 && stripesize) { + log_print("Ignoring stripesize argument with single stripe"); + stripesize = 0; + } + + if (arg_count(permission_ARG)) + status |= arg_int_value(permission_ARG, 0); + + 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); + else { + log_error("LVM2 currently requires you to give a name " + "using -n"); + return EINVALID_CMD_LINE; + } + + /* If VG not on command line, try -n arg and then environment */ + if (!argc) { + if (!(vg_name = extract_vgname(ios, lv_name))) { + log_error("Please provide a volume group name"); + return EINVALID_CMD_LINE; + } + } else { + /* Ensure lv_name doesn't contain a different VG! */ + if (strchr(lv_name, '/')) { + if (!(vg_name = extract_vgname(ios, lv_name))) + return EINVALID_CMD_LINE; + if (strcmp(vg_name, argv[0])) { + log_error("Inconsistent volume group names " + "given: %s and %s", vg_name, argv[0]); + return EINVALID_CMD_LINE; + } + } + vg_name = argv[0]; + argv++; + argc--; + } + + if ((st = strrchr(lv_name, '/'))) + lv_name = st + 1; + + /* does VG exist? */ + log_verbose("Finding volume group %s", vg_name); + if (!(vg = ios->vg_read(ios, vg_name))) { + log_error("Volume group %s doesn't exist", vg_name); + return ECMD_FAILED; + } + + if (!(vg->status & ACTIVE)) { + log_error("Volume group %s must be active before changing a " + "logical volume", vg_name); + return ECMD_FAILED; + } + + if (lv_name && (lvh = find_lv_in_vg(vg, lv_name))) { + log_error("Logical volume %s already exists in volume group %s", + lv_name, vg_name); + return ECMD_FAILED; + } + + if (argc) { + /* Build up list of PVs */ + if (!(pvh = pool_alloc(ios->mem, sizeof (struct list)))) { + log_error("pvh list allocation failed"); + return ECMD_FAILED; + } + list_init(pvh); + for (; opt < argc; opt++) { + if (!(pvl = find_pv_in_vg(vg, argv[opt]))) { + log_error("Physical Volume %s not found in " + "Volume Group %s", argv[opt], + vg->name); + return EINVALID_CMD_LINE; + } + if (list_item(pvl, struct pv_list)->pv.pe_count == + list_item(pvl, struct pv_list)->pv.pe_allocated) + log_error("No free extents on physical volume" + " %s", argv[opt]); + list_add(pvh, pvl); + } + } else { + /* Use full list from VG */ + pvh = &vg->pvs; + } + +/********* FIXME Move default choice (0) into format1 + log_print("Using default stripe size of %lu KB", + LVM_DEFAULT_STRIPE_SIZE); +***********/ + + if (argc && argc != stripes) { + log_error("Incorrect number of physical volumes on " + "command line for %d-way striping", stripes); + return EINVALID_CMD_LINE; + } + +/******** FIXME Inside lv_create stripes + log_verbose("checking stripe count"); + if (stripes < 1 || stripes > LVM_MAX_STRIPES) { + log_error("Invalid number of stripes: %d", stripes); + log_error("must be between %d and %d", 1, LVM_MAX_STRIPES); + return EINVALID_CMD_LINE; + } + + log_verbose("checking stripe size"); + if (stripesize > 0 && lv_check_stripesize(stripesize) < 0) { + log_error("invalid stripe size %d", stripesize); + return EINVALID_CMD_LINE; + } +*********/ + + stripesize *= 2; + +/******** FIXME Stripes + log_verbose + ("checking stripe size against volume group physical extent size"); + if (stripesize > vg_core->pe_size) { + log_error + ("setting stripe size %d KB to physical extent size %u KB", + stripesize / 2, vg_core->pe_size / 2); + stripesize = vg_core->pe_size; + } +**********/ + + 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))); + dbg_free(s1); + } + + extents /= vg->extent_size; + } + +/******* FIXME Stripes + size_rest = size % (stripes * vg_core->pe_size); + if (size_rest != 0) { + log_print("rounding %d KB to stripe boundary size ", + size / 2); + size = size - size_rest + stripes * vg_core->pe_size; + printf("%d KB / %u PE\n", size / 2, + size / vg_core->pe_size); + } +*************/ + + log_verbose("Creating logical volume %s", lv_name); + + if (!(lv = lv_create(ios, lv_name, status, stripes, stripesize, + extents, vg, pvh))) + return ECMD_FAILED; + + if (arg_count(readahead_ARG)) { + log_verbose("Setting read ahead sectors"); + lv->read_ahead = read_ahead; + } + + /* store vg on disk(s) */ + if (!ios->vg_write(ios, vg)) + return ECMD_FAILED; + + if (!lv_activate(lv)) + return ECMD_FAILED; + + if (zero) { + struct device *dev; + /* FIXME 2 blocks */ + char buf[4096]; + + memset(buf, 0, sizeof (buf)); + + log_verbose("Zeroing start of logical volume %s", lv_name); + + /* FIXME get dev = dev_cache_get(lv_name, ios->filter); */ + /* FIXME Add fsync! */ + if (!(dev_write(dev, 0, sizeof (buf), &buf) == sizeof (buf))) { + log_error("Initialisation of %s failed", dev_name(dev)); + return ECMD_FAILED; + } + } else + log_print("WARNING: %s not zeroed", lv_name); + +/******** FIXME backup + if ((ret = do_autobackup(vg_name, vg))) + return ret; +***********/ + + log_print("Logical volume %s created", lv_name); + + return 0; +} diff --git a/tools/stub.h b/tools/stub.h index b269c8e92..94ccc4f4e 100644 --- a/tools/stub.h +++ b/tools/stub.h @@ -19,7 +19,6 @@ */ int e2fsadm(int argc, char **argv) {return 1;} -int lvcreate(int argc, char **argv) {return 1;} int lvdisplay(int argc, char **argv) {return 1;} int lvextend(int argc, char **argv) {return 1;} int lvmdiskscan(int argc, char **argv) {return 1;} diff --git a/tools/toollib.c b/tools/toollib.c index 79b945f43..f84e0cc39 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -168,10 +168,10 @@ int is_valid_chars(char *n) char *extract_vgname(struct io_space *ios, char *lv_name) { char *vg_name = lv_name; - char *vg_path, *st; + char *st; /* Path supplied? */ - if (strchr(vg_name, '/')) { + if (vg_name && strchr(vg_name, '/')) { /* Strip prefix (optional) */ if (!strncmp(vg_name, ios->prefix, strlen(ios->prefix))) vg_name += strlen(ios->prefix); @@ -192,13 +192,24 @@ char *extract_vgname(struct io_space *ios, char *lv_name) *strchr(vg_name, '/') = '\0'; return vg_name; } - - /* Take default VG from environment? */ - vg_path = getenv("LVM_VG_NAME"); - if (!vg_path) { - log_error("Path required for Logical Volume %s", lv_name); + + if (!(vg_name = default_vgname(ios))) { + if (lv_name) + log_error("Path required for Logical Volume %s", lv_name); return 0; } + + return vg_name; +} + +char *default_vgname(struct io_space *ios) +{ + char *vg_path; + + /* Take default VG from environment? */ + vg_path = getenv("LVM_VG_NAME"); + if (!vg_path) + return 0; /* Strip prefix (optional) */ if (!strncmp(vg_path, ios->prefix, strlen(ios->prefix))) @@ -211,6 +222,5 @@ char *extract_vgname(struct io_space *ios, char *lv_name) } return pool_strdup(ios->mem, vg_path); - } diff --git a/tools/toollib.h b/tools/toollib.h index 260706550..cb6dba9cf 100644 --- a/tools/toollib.h +++ b/tools/toollib.h @@ -34,6 +34,7 @@ int process_each_pv(int argc, char **argv, struct volume_group *vg, int is_valid_chars(char *n); +char *default_vgname(struct io_space *ios); char *extract_vgname(struct io_space *ios, char *lv_name); #endif diff --git a/tools/vgcreate.c b/tools/vgcreate.c index 3f57e4204..bd26ee35d 100644 --- a/tools/vgcreate.c +++ b/tools/vgcreate.c @@ -14,7 +14,8 @@ int vgcreate(int argc, char **argv) { - int max_lv, max_pv, extent_size; + int max_lv, max_pv; + uint32_t extent_size; char *vg_name; struct volume_group *vg;