diff options
author | Alasdair Kergon <agk@redhat.com> | 2001-11-09 22:01:04 +0000 |
---|---|---|
committer | Alasdair Kergon <agk@redhat.com> | 2001-11-09 22:01:04 +0000 |
commit | 7858f6fb16b9b2373efa92103e81b46fce897799 (patch) | |
tree | 12cc418aac3ba47a42528418eee9f5079086d7c6 | |
parent | 4f0a4a6a7a13e3c24360a54813208397fbb6c218 (diff) | |
download | lvm2-7858f6fb16b9b2373efa92103e81b46fce897799.tar.gz lvm2-7858f6fb16b9b2373efa92103e81b46fce897799.tar.xz lvm2-7858f6fb16b9b2373efa92103e81b46fce897799.zip |
o Added lvextend
o Full signed arguments to lvreduce/lvextend
o Consistent lv_number/pe map use
o Populate pv->pe_allocated
o Fixes for allocation/writing of multiple LVs
-rw-r--r-- | lib/format1/disk-rep.c | 3 | ||||
-rw-r--r-- | lib/format1/disk-rep.h | 2 | ||||
-rw-r--r-- | lib/format1/import-export.c | 6 | ||||
-rw-r--r-- | lib/metadata/lv_manip.c | 40 | ||||
-rw-r--r-- | lib/metadata/metadata.c | 50 | ||||
-rw-r--r-- | tools/Makefile.in | 1 | ||||
-rw-r--r-- | tools/args.h | 4 | ||||
-rw-r--r-- | tools/lvcreate.c | 5 | ||||
-rw-r--r-- | tools/lvextend.c | 188 | ||||
-rw-r--r-- | tools/lvm.c | 92 | ||||
-rw-r--r-- | tools/lvreduce.c | 49 | ||||
-rw-r--r-- | tools/lvremove.c | 1 | ||||
-rw-r--r-- | tools/stub.h | 1 | ||||
-rw-r--r-- | tools/tools.h | 17 |
14 files changed, 366 insertions, 93 deletions
diff --git a/lib/format1/disk-rep.c b/lib/format1/disk-rep.c index 5ff957a4..af9ead96 100644 --- a/lib/format1/disk-rep.c +++ b/lib/format1/disk-rep.c @@ -196,6 +196,7 @@ static int _read_lvs(struct disk_list *data) unsigned long pos; struct lvd_list *ll; + /* FIXME May be gaps - use lv_max */ for(i = 0; i < data->vgd.lv_cur; i++) { pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk)); ll = pool_alloc(data->mem, sizeof(*ll)); @@ -384,9 +385,9 @@ static int _write_lvs(struct disk_list *data) struct list *lvh; unsigned long pos; + pos = data->pvd.lv_on_disk.base; list_iterate(lvh, &data->lvds) { struct lvd_list *ll = list_item(lvh, struct lvd_list); - pos = data->pvd.lv_on_disk.base; if (!_write_lvd(data->dev, pos, &ll->lvd)) fail; diff --git a/lib/format1/disk-rep.h b/lib/format1/disk-rep.h index a7f3041d..20b1678e 100644 --- a/lib/format1/disk-rep.h +++ b/lib/format1/disk-rep.h @@ -144,9 +144,9 @@ struct lvd_list { }; struct disk_list { + struct list list; struct pool *mem; struct device *dev; - struct list list; struct pv_disk pvd; struct vg_disk vgd; diff --git a/lib/format1/import-export.c b/lib/format1/import-export.c index 0d016866..23c3d765 100644 --- a/lib/format1/import-export.c +++ b/lib/format1/import-export.c @@ -493,6 +493,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg, } export_lv(&lvdl->lvd, vg, &ll->lv, prefix); + lvdl->lvd.lv_number = lv_num; if (!export_extents(dl, lv_num++, &ll->lv, pv)) { stack; return 0; @@ -556,11 +557,6 @@ void export_numbers(struct list *pvs, struct volume_group *vg) list_iterate(pvh, pvs) { dl = list_item(pvh, struct disk_list); dl->pvd.pv_number = pv_num++; - - list_iterate(lvh, &dl->lvds) { - ll = list_item(lvh, struct lvd_list); - ll->lvd.lv_number = _get_lv_number(vg, ll->lvd.lv_name); - } } } diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index c03af7c7..c4070ae8 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -64,11 +64,11 @@ static int _alloc_contiguous(struct logical_volume *lv, struct pv_map *pvm; struct pv_area *pva, *biggest; - list_iterate (tmp1, pvms) { + list_iterate(tmp1, pvms) { pvm = list_item(tmp1, struct pv_map); biggest = NULL; - list_iterate (tmp2, &pvm->areas) { + list_iterate(tmp2, &pvm->areas) { pva = list_item(tmp2, struct pv_area); if (!biggest || (pva->count > biggest->count)) @@ -85,7 +85,7 @@ static int _alloc_contiguous(struct logical_volume *lv, if (allocated != lv->le_count) { log_error("Insufficient free extents to " - "allocate logical volume %s: %u required", + "allocate logical volume %s: %u required", lv->name, lv->le_count); return 0; } @@ -104,10 +104,10 @@ static int _alloc_simple(struct logical_volume *lv, struct pv_map *pvm; struct pv_area *pva; - list_iterate (tmp1, pvms) { + list_iterate(tmp1, pvms) { pvm = list_item(tmp1, struct pv_map); - list_iterate (tmp2, &pvm->areas) { + list_iterate(tmp2, &pvm->areas) { pva = list_item(tmp2, struct pv_area); allocated += _alloc_area(lv, allocated, pvm->pv, pva); @@ -115,13 +115,13 @@ static int _alloc_simple(struct logical_volume *lv, break; } - if (allocated == lv->le_count) /* FIXME: yuck, repeated test */ + if (allocated == lv->le_count) /* FIXME: yuck, repeated test */ break; } if (allocated != lv->le_count) { log_error("Insufficient free logical extents to " - "allocate logical volume %s: %u required", + "allocate logical volume %s: %u required", lv->name, lv->le_count); return 0; } @@ -162,11 +162,10 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv, r = _alloc_simple(lv, pvms, allocated); if (r) { - vg->lv_count++; vg->free_count -= lv->le_count - allocated; } - out: + out: pool_destroy(scratch); return r; } @@ -182,6 +181,7 @@ struct logical_volume *lv_create(struct io_space *ios, { struct lv_list *ll = NULL; struct logical_volume *lv; + int i; if (!extents) { log_error("Unable to create logical volume %s with no extents", @@ -217,7 +217,6 @@ struct logical_volume *lv_create(struct io_space *ios, goto bad; } - lv->vg = vg; lv->status = status; lv->read_ahead = 0; lv->stripes = stripes; @@ -234,18 +233,24 @@ struct logical_volume *lv_create(struct io_space *ios, goto bad; } + for (i = 0; i < lv->le_count; i++) { + lv->map[i].pv->pe_allocated++; + } + + vg->lv_count++; list_add(&vg->lvs, &ll->list); + lv->vg = vg; + return lv; - bad: + bad: if (ll) pool_free(ios->mem, ll); return NULL; } -int lv_reduce(struct io_space *ios, - struct logical_volume *lv, uint32_t extents) +int lv_reduce(struct io_space *ios, struct logical_volume *lv, uint32_t extents) { if (extents % lv->stripes) { log_error("For a striped volume you must reduce by a " @@ -270,6 +275,7 @@ int lv_extend(struct io_space *ios, { struct pe_specifier *new_map; struct logical_volume *new_lv; + int i; if (!(new_map = pool_zalloc(ios->mem, sizeof(*new_map) * (extents + lv->le_count)))) { @@ -289,18 +295,22 @@ int lv_extend(struct io_space *ios, new_lv->map = new_map; new_lv->le_count += extents; - if (!_allocate(new_lv->vg, new_lv, acceptable_pvs, new_lv->le_count)) { + if (!_allocate(new_lv->vg, new_lv, acceptable_pvs, lv->le_count)) { stack; goto bad; } + for (i = lv->le_count; i < new_lv->le_count; i++) { + new_lv->map[i].pv->pe_allocated++; + } + memcpy(lv, new_lv, sizeof(*lv)); /* now you see why new_lv had to be allocated last */ pool_free(ios->mem, new_lv); return 1; - bad: + bad: pool_free(ios->mem, new_map); return 0; } diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 8161fabd..24a8eacd 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -19,7 +19,7 @@ int _add_pv_to_vg(struct io_space *ios, struct volume_group *vg, struct physical_volume *pv; log_verbose("Adding physical volume '%s' to volume group '%s'", - pv_name, vg->name); + pv_name, vg->name); if (!(pvl = pool_alloc(ios->mem, sizeof (*pvl)))) { log_error("pv_list allocation for '%s' failed", pv_name); @@ -100,7 +100,7 @@ int _add_pv_to_vg(struct io_space *ios, struct volume_group *vg, } int vg_extend(struct io_space *ios, struct volume_group *vg, int pv_count, - char **pv_names) + char **pv_names) { int i; @@ -133,14 +133,13 @@ struct volume_group *vg_create(struct io_space *ios, const char *vg_name, } if (!id_create(&vg->id)) { - log_err("Couldn't create uuid for volume group '%s'.", - vg_name); + log_err("Couldn't create uuid for volume group '%s'.", vg_name); goto bad; } - /* Strip prefix if present */ - if (!strncmp(vg_name, ios->prefix, strlen(ios->prefix))) - vg_name += strlen(ios->prefix); + /* Strip prefix if present */ + if (!strncmp(vg_name, ios->prefix, strlen(ios->prefix))) + vg_name += strlen(ios->prefix); if (!(vg->name = pool_strdup(ios->mem, vg_name))) { stack; @@ -246,11 +245,11 @@ struct list *find_lv_in_vg(struct volume_group *vg, const char *lv_name) else ptr = lv_name; - list_iterate(lvh, &vg->lvs) - if (!strcmp(list_item(lvh, struct lv_list)->lv.name, ptr)) - return lvh; + list_iterate(lvh, &vg->lvs) + if (!strcmp(list_item(lvh, struct lv_list)->lv.name, ptr)) + return lvh; - return NULL; + return NULL; } struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name) @@ -266,23 +265,30 @@ struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name) struct physical_volume *_find_pv(struct volume_group *vg, struct device *dev) { struct list *pvh; - struct physical_volume *pv; - struct pv_list *pl; - - list_iterate(pvh, &vg->pvs) { - pl = list_item(pvh, struct pv_list); - pv = &pl->pv; - if (dev == pv->dev) - return pv; - } - return NULL; + struct physical_volume *pv; + struct pv_list *pl; + + list_iterate(pvh, &vg->pvs) { + pl = list_item(pvh, struct pv_list); + pv = &pl->pv; + if (dev == pv->dev) + return pv; + } + return NULL; } int lv_remove(struct volume_group *vg, struct list *lvh) { + int i; + struct logical_volume *lv; + + lv = &list_item(lvh, struct lv_list)->lv; + for (i = 0; i < lv->le_count; i++) { + lv->map[i].pv->pe_allocated--; + } + list_del(lvh); vg->lv_count--; return 1; } - diff --git a/tools/Makefile.in b/tools/Makefile.in index 11db65b5..33505854 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -24,6 +24,7 @@ SOURCES=\ lvchange.c \ lvcreate.c \ lvdisplay.c \ + lvextend.c \ lvm.c \ lvmchange.c \ lvreduce.c \ diff --git a/tools/args.h b/tools/args.h index b3a58d06..74f96ea9 100644 --- a/tools/args.h +++ b/tools/args.h @@ -39,11 +39,11 @@ xx(stripes_ARG, 'i', "stripes", int_arg) xx(iop_version_ARG, 'i', "iop_version", NULL) xx(logicalvolume_ARG, 'l', "logicalvolume", int_arg) xx(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg) -xx(extents_ARG, 'l', "extents", int_arg) +xx(extents_ARG, 'l', "extents", int_arg_with_sign) xx(lvmpartition_ARG, 'l', "lvmpartition", NULL) xx(list_ARG, 'l', "list", NULL) xx(size_ARG, 'L', "size", size_arg) -xx(logicalextent_ARG, 'L', "logicalextent", int_arg) +xx(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign) xx(name_ARG, 'n', "name", string_arg) xx(oldpath_ARG, 'n', "oldpath", NULL) xx(nofsck_ARG, 'n', "nofsck", NULL) diff --git a/tools/lvcreate.c b/tools/lvcreate.c index 6004ea12..d93faaaf 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -144,9 +144,12 @@ int lvcreate(int argc, char **argv) return EINVALID_CMD_LINE; } if (list_item(pvl, struct pv_list)->pv.pe_count == - list_item(pvl, struct pv_list)->pv.pe_allocated) + list_item(pvl, struct pv_list)->pv.pe_allocated) { log_error("No free extents on physical volume" " %s", argv[opt]); + continue; + /* FIXME But check not null at end! */ + } list_add(pvh, pvl); } } else { diff --git a/tools/lvextend.c b/tools/lvextend.c new file mode 100644 index 00000000..090d55ff --- /dev/null +++ b/tools/lvextend.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2001 Sistina Software + * + * LVM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LVM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LVM; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "tools.h" + +int lvextend(int argc, char **argv) +{ + struct volume_group *vg; + struct logical_volume *lv; + uint32_t extents = 0; + uint32_t size = 0; + sign_t sign = SIGN_NONE; + char *lv_name, *vg_name; + char *st; + char *dummy; + struct list *lvh, *pvh, *pvl; + int opt = 0; + + if (arg_count(extents_ARG) + arg_count(size_ARG) != 1) { + log_error("Please specify either size or extents (not both)"); + return EINVALID_CMD_LINE; + } + + if (arg_count(extents_ARG)) { + extents = arg_int_value(extents_ARG, 0); + sign = arg_sign_value(extents_ARG, SIGN_NONE); + } + + if (arg_count(size_ARG)) { + size = arg_int_value(size_ARG, 0); + sign = arg_sign_value(extents_ARG, SIGN_NONE); + } + + if (sign == SIGN_MINUS) { + log_error("Negative argument not permitted - use lvreduce"); + return EINVALID_CMD_LINE; + } + + if (!argc) { + log_error("Please provide the logical volume name"); + return EINVALID_CMD_LINE; + } + + lv_name = argv[0]; + argv++; + argc--; + + if (!(vg_name = extract_vgname(ios, lv_name))) { + log_error("Please provide a volume group name"); + return EINVALID_CMD_LINE; + } + + 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; + } + + /* does LV exist? */ + if (!(lvh = find_lv_in_vg(vg, lv_name))) { + log_error("Logical volume %s not found in volume group %s", + lv_name, vg_name); + return ECMD_FAILED; + } + + lv = &list_item(lvh, struct lv_list)->lv; + + if (!(lv->status & ACTIVE)) { + log_error("Logical volume %s must be active before change", + lv_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]); + continue; + /* FIXME Buy check not empty at end! */ + } + list_add(pvh, pvl); + } + } else { + /* Use full list from VG */ + pvh = &vg->pvs; + } + + 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; + } + + if (sign == SIGN_PLUS) + extents += lv->le_count; + + if (extents <= lv->le_count) { + log_error("New size given (%d extents) not larger than " + "existing size (%d extents)", extents, lv->le_count); + return EINVALID_CMD_LINE; + } + + if (!extents) { + log_error("New size of 0 not permitted"); + return EINVALID_CMD_LINE; + } + + log_print("Extending logical volume %s to %s", lv_name, + (dummy = + display_size(extents * vg->extent_size / 2, SIZE_SHORT))); + dbg_free(dummy); + + lv_extend(ios, lv, extents - lv->le_count, pvh); + /* where parm is always *increase* not actual */ + +/********* FIXME Suspend lv ***********/ + + /* store vg on disk(s) */ + if (!ios->vg_write(ios, vg)) + return ECMD_FAILED; + + /* FIXME Ensure it always displays errors? */ + if (!lv_reactivate(lv)) + return ECMD_FAILED; + +/********* FIXME Resume *********/ + +/********* FIXME Backup + if ((ret = do_autobackup(vg_name, vg))) + return ret; +************/ + + log_print("Logical volume %s successfully extended", lv_name); + + return 0; +} diff --git a/tools/lvm.c b/tools/lvm.c index f8e9ca89..90da2f4f 100644 --- a/tools/lvm.c +++ b/tools/lvm.c @@ -157,6 +157,8 @@ void usage(const char *name) int yes_no_arg(struct arg *a) { + a->sign = SIGN_NONE; + if (!strcmp(a->value, "y")) a->i_value = 1; @@ -169,15 +171,44 @@ int yes_no_arg(struct arg *a) return 1; } -int size_arg(struct arg *a) +int _get_int_arg(struct arg *a, char **ptr) { - static char *suffixes = "kmgt"; + char *val; + long v; + + val = a->value; + switch (*val) { + case '+': + a->sign = SIGN_PLUS; + val++; + break; + case '-': + a->sign = SIGN_MINUS; + val++; + break; + default: + a->sign = SIGN_NONE; + } + + if (!isdigit(*val)) + return 0; + + v = strtol(val, ptr, 10); + if (*ptr == val) + return 0; + + a->i_value = (uint32_t) v; + return 1; +} + +int size_arg(struct arg *a) +{ char *ptr; int i; - long v = strtol(a->value, &ptr, 10); + static char *suffixes = "kmgt"; - if (ptr == a->value) + if (!_get_int_arg(a, &ptr)) return 0; if (*ptr) { @@ -189,10 +220,9 @@ int size_arg(struct arg *a) return 0; while (i-- > 0) - v *= 1024; + a->i_value *= 1024; } - a->i_value = (int) v; return 1; } @@ -200,12 +230,20 @@ int size_arg(struct arg *a) int int_arg(struct arg *a) { char *ptr; - long v = strtol(a->value, &ptr, 10); - if (ptr == a->value || *ptr) + if (!_get_int_arg(a, &ptr) || (*ptr) || (a->sign == SIGN_MINUS)) + return 0; + + return 1; +} + +int int_arg_with_sign(struct arg *a) +{ + char *ptr; + + if (!_get_int_arg(a, &ptr) || (*ptr)) return 0; - a->i_value = (int) v; return 1; } @@ -216,6 +254,8 @@ int string_arg(struct arg *a) int permission_arg(struct arg *a) { + a->sign = SIGN_NONE; + if ((!strcmp(a->value, "rw")) || (!strcmp(a->value, "wr"))) a->i_value = LVM_READ | LVM_WRITE; @@ -242,8 +282,7 @@ char yes_no_prompt(const char *prompt, ...) c = tolower(getchar()); } - while (getchar() != '\n') - ; + while (getchar() != '\n') ; return c; } @@ -271,7 +310,7 @@ static void register_command(const char *name, command_fn fn, va_end(ap); /* allocate space for them */ - if (!(args = dbg_malloc(sizeof (*args) * nargs))) { + if (!(args = dbg_malloc(sizeof(*args) * nargs))) { log_fatal("Out of memory."); exit(ECMD_FAILED); } @@ -327,7 +366,7 @@ static void create_new_command(const char *name, command_fn command, static void __alloc(int size) { - if (!(_commands = dbg_realloc(_commands, sizeof (*_commands) * size))) { + if (!(_commands = dbg_realloc(_commands, sizeof(*_commands) * size))) { log_fatal("Couldn't allocate memory."); exit(ECMD_FAILED); } @@ -385,7 +424,7 @@ static int process_command_line(struct command *com, int *argc, char ***argv) add_getopt_arg(com->valid_args[i], &ptr, &o); *ptr = '\0'; - memset(o, 0, sizeof (*o)); + memset(o, 0, sizeof(*o)); /* initialise getopt_long & scan for command line switches */ optarg = 0; @@ -609,7 +648,8 @@ static int dev_cache_setup(void) "device cache"); return 0; } - log_verbose("device/scan not in config file: Defaulting to /dev"); + log_verbose + ("device/scan not in config file: Defaulting to /dev"); return 1; } @@ -619,14 +659,14 @@ static int dev_cache_setup(void) "devices/scan"); return 0; } - + if (!dev_cache_add_dir(cv->v.str)) { - log_error("Failed to add %s to internal device cache", + log_error("Failed to add %s to internal device cache", cv->v.str); return 0; } - } - + } + return 1; } @@ -669,7 +709,7 @@ static struct dev_filter *filter_setup(void) return 0; lvm_cache = find_config_str(_cf->root, "devices/cache", '/', - "/etc/lvm/.cache"); + "/etc/lvm/.cache"); if (!(f4 = persistent_filter_create(f3, lvm_cache))) { log_error("Failed to create persistent device filter"); @@ -679,7 +719,7 @@ static struct dev_filter *filter_setup(void) /* Should we ever dump persistent filter state? */ if (find_config_int(_cf->root, "devices/write_cache_state", '/', 1)) dump_filter = 1; - + if (!stat(lvm_cache, &st) && !persistent_filter_load(f4)) log_verbose("Failed to load existing device cache from %s", lvm_cache); @@ -694,7 +734,7 @@ static int init(void) struct stat info; struct pool *ios_pool; - /* FIXME: Override from config file. (Append trailing slash if reqd)*/ + /* FIXME: Override from config file. (Append trailing slash if reqd) */ char *prefix = "/dev/"; if (!(_cf = create_config_file())) { @@ -781,15 +821,15 @@ static int run_script(int argc, char **argv) if ((script = fopen(argv[0], "r")) == NULL) return ENO_SUCH_CMD; - while (fgets(buffer, sizeof (buffer), script) != NULL) { + while (fgets(buffer, sizeof(buffer), script) != NULL) { if (!magic_number) { if (buffer[0] == '#' && buffer[1] == '!') magic_number = 1; else return ENO_SUCH_CMD; } - if ((strlen(buffer) == sizeof (buffer) - 1) - && (buffer[sizeof (buffer) - 1] - 2 != '\n')) { + if ((strlen(buffer) == sizeof(buffer) - 1) + && (buffer[sizeof(buffer) - 1] - 2 != '\n')) { buffer[50] = '\0'; log_error("Line too long (max 255) beginning: %s", buffer); @@ -901,7 +941,7 @@ static char *list_args(char *text, int state) char c; if (!(c = (the_args + com->valid_args[match_no++])->short_arg)) - continue; + continue; sprintf(s, "-%c", c); if (!strncmp(text, s, len)) diff --git a/tools/lvreduce.c b/tools/lvreduce.c index e9163e5b..48aaf3f2 100644 --- a/tools/lvreduce.c +++ b/tools/lvreduce.c @@ -25,22 +25,32 @@ int lvreduce(int argc, char **argv) struct volume_group *vg; struct logical_volume *lv; struct list *lvh; - int32_t extents = 0; - int32_t size = 0; + uint32_t extents = 0; + uint32_t size = 0; + sign_t sign = SIGN_NONE; char *lv_name, *vg_name; char *st; + int i; if (arg_count(extents_ARG) + arg_count(size_ARG) != 1) { log_error("Please specify either size or extents (not both)"); return EINVALID_CMD_LINE; } - /* FIXME signed use throughout halves the maximum... */ - if (arg_count(extents_ARG)) + if (arg_count(extents_ARG)) { extents = arg_int_value(extents_ARG, 0); + sign = arg_sign_value(extents_ARG, SIGN_NONE); + } - if (arg_count(size_ARG)) + if (arg_count(size_ARG)) { size = arg_int_value(size_ARG, 0); + sign = arg_sign_value(extents_ARG, SIGN_NONE); + } + + if (sign == SIGN_PLUS) { + log_error("Positive sign not permitted - use lvextend"); + return EINVALID_CMD_LINE; + } if (!argc) { log_error("Please provide the logical volume name"); @@ -94,15 +104,18 @@ int lvreduce(int argc, char **argv) if (extents % vg->extent_size) { char *s1; - extents += (signed) vg->extent_size - - (signed) (extents % vg->extent_size); + if (sign == SIGN_NONE) + extents += vg->extent_size - + (extents % vg->extent_size); + else + extents -= extents % vg->extent_size; + log_print("Rounding up size to full physical extent %s", - (s1 = - display_size(abs(extents) / 2, SIZE_SHORT))); + (s1 = display_size(extents / 2, SIZE_SHORT))); dbg_free(s1); } - extents /= (signed) vg->extent_size; + extents /= vg->extent_size; } if (!extents) { @@ -110,14 +123,14 @@ int lvreduce(int argc, char **argv) return EINVALID_CMD_LINE; } - if (extents < 0) { - if (1 - extents > lv->le_count) { + if (sign == SIGN_MINUS) { + if (extents >= lv->le_count) { log_error("Unable to reduce %s below 1 extent", lv_name); return EINVALID_CMD_LINE; } - lv->le_count += extents; + extents = lv->le_count - extents; } else { if (extents >= lv->le_count) { log_error("New size given (%d extents) not less than " @@ -125,7 +138,6 @@ int lvreduce(int argc, char **argv) lv->le_count); return EINVALID_CMD_LINE; } - lv->le_count = extents; } /************ FIXME Stripes @@ -144,7 +156,7 @@ int lvreduce(int argc, char **argv) log_print("WARNING: Reducing active%s logical volume to %s", (lv_open_count(lv) > 0) ? " and open" : "", (dummy = - display_size(lv->le_count * vg->extent_size / 2, + display_size(extents * vg->extent_size / 2, SIZE_SHORT))); log_print("THIS MAY DESTROY YOUR DATA (filesystem etc.)"); dbg_free(dummy); @@ -159,6 +171,12 @@ int lvreduce(int argc, char **argv) } } + for (i = extents; i < lv->le_count; i++) { + lv->map[i].pv->pe_allocated--; + } + + lv->le_count = extents; + /********* FIXME Suspend lv ***********/ /* store vg on disk(s) */ @@ -180,4 +198,3 @@ int lvreduce(int argc, char **argv) return 0; } - diff --git a/tools/lvremove.c b/tools/lvremove.c index cc2d17f3..20caaa2d 100644 --- a/tools/lvremove.c +++ b/tools/lvremove.c @@ -121,4 +121,3 @@ int lvremove_single(char *lv_name) log_print("logical volume %s successfully removed", lv_name); return 0; } - diff --git a/tools/stub.h b/tools/stub.h index a8cfc955..d60eaa74 100644 --- a/tools/stub.h +++ b/tools/stub.h @@ -19,7 +19,6 @@ */ int e2fsadm(int argc, char **argv) {return 1;} -int lvextend(int argc, char **argv) {return 1;} int lvmdiskscan(int argc, char **argv) {return 1;} int lvmsadc(int argc, char **argv) {return 1;} int lvmsar(int argc, char **argv) {return 1;} diff --git a/tools/tools.h b/tools/tools.h index 767100d7..9ac189f5 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -62,6 +62,12 @@ enum { #undef xx }; +typedef enum { + SIGN_NONE = 0, + SIGN_PLUS = 1, + SIGN_MINUS = 2 +} sign_t; + /* a global table of possible arguments */ struct arg { char short_arg; @@ -69,7 +75,8 @@ struct arg { int (*fn)(struct arg *a); int count; char *value; - int i_value; + uint32_t i_value; + sign_t sign; }; extern struct arg the_args[ARG_COUNT + 1]; @@ -80,6 +87,7 @@ void usage(const char *name); int yes_no_arg(struct arg *a); int size_arg(struct arg *a); int int_arg(struct arg *a); +int int_arg_with_sign(struct arg *a); int string_arg(struct arg *a); int permission_arg(struct arg *a); @@ -99,11 +107,16 @@ static inline char *arg_str_value(int a, char *def) return arg_count(a) ? the_args[a].value : def; } -static inline int arg_int_value(int a, int def) +static inline uint32_t arg_int_value(int a, uint32_t def) { return arg_count(a) ? the_args[a].i_value : def; } +static inline sign_t arg_sign_value(int a, sign_t def) +{ + return arg_count(a) ? the_args[a].sign : def; +} + static inline int arg_count_increment(int a) { return the_args[a].count++; |