From 6e91eeef1353ead8a0327b1905a4bcf093de91aa Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Thu, 11 Oct 2001 21:35:55 +0000 Subject: [PATCH] vgreduce, vgremove, vgrename & vgscan --- lib/format1/format1.c | 12 +++- tools/Makefile.in | 4 +- tools/args.h | 2 +- tools/stub.h | 2 - tools/toollib.c | 51 +++++++++++++++- tools/toollib.h | 6 ++ tools/vgreduce.c | 132 ++++++++++++++++++++++++++++++++++++++++++ tools/vgremove.c | 30 +++++----- tools/vgrename.c | 5 +- tools/vgscan.c | 66 +++++++++++++++++++++ 10 files changed, 285 insertions(+), 25 deletions(-) create mode 100644 tools/vgreduce.c create mode 100644 tools/vgscan.c diff --git a/lib/format1/format1.c b/lib/format1/format1.c index b5940018e..858e3c70d 100644 --- a/lib/format1/format1.c +++ b/lib/format1/format1.c @@ -91,6 +91,10 @@ static struct volume_group *_vg_read(struct io_space *is, const char *vg_name) return NULL; } + /* Strip prefix if present */ + if (!strncmp(vg_name, is->prefix, strlen(is->prefix))) + vg_name += strlen(is->prefix); + if (!read_pvs_in_vg(vg_name, is->filter, mem, &pvs)) { stack; return NULL; @@ -295,7 +299,8 @@ static struct list_head *_get_vgs(struct io_space *is) list_for_each(tmp, pvs) { struct pv_list *pvl = list_entry(tmp, struct pv_list, list); - if (_find_vg_name(names, pvl->pv.vg_name)) + if (!(*pvl->pv.vg_name) || + _find_vg_name(names, pvl->pv.vg_name)) continue; if (!(nl = pool_alloc(is->mem, sizeof(*nl)))) { @@ -358,8 +363,9 @@ static int _pv_write(struct io_space *is, struct physical_volume *pv) INIT_LIST_HEAD(&pvs); - if (pv->vg_name) { - log_info("pv_write should only be called for an orphan pv"); + if (*pv->vg_name) { + log_error("Assertion failed: can't _pv_write non-orphan PV " + "(in VG %s)", pv->vg_name); return 0; } diff --git a/tools/Makefile.in b/tools/Makefile.in index 4203c6f2b..1c75460d6 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -25,8 +25,10 @@ SOURCES=\ lvmchange.c\ toollib.c\ vgck.c\ + vgreduce.c\ vgrename.c\ - vgremove.c + vgremove.c\ + vgscan.c TARGETS=\ lvm diff --git a/tools/args.h b/tools/args.h index f1f2ee651..b3a58d067 100644 --- a/tools/args.h +++ b/tools/args.h @@ -19,7 +19,7 @@ */ xx(available_ARG, 'a', "available", yes_no_arg) -xx(all_ARG, 'a', "all", yes_no_arg) +xx(all_ARG, 'a', "all", NULL) xx(autobackup_ARG, 'A', "autobackup", yes_no_arg) xx(activevolumegroups_ARG, 'A', "activevolumegroups", NULL) xx(blockdevice_ARG, 'b', "blockdevice", NULL) diff --git a/tools/stub.h b/tools/stub.h index eab698dc4..933281221 100644 --- a/tools/stub.h +++ b/tools/stub.h @@ -45,7 +45,5 @@ int vgextend(int argc, char **argv) {return 1;} int vgimport(int argc, char **argv) {return 1;} int vgmerge(int argc, char **argv) {return 1;} int vgmknodes(int argc, char **argv) {return 1;} -int vgreduce(int argc, char **argv) {return 1;} -int vgscan(int argc, char **argv) {return 1;} int vgsplit(int argc, char **argv) {return 1;} diff --git a/tools/toollib.c b/tools/toollib.c index c091bb244..b96a64c11 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -120,13 +120,60 @@ int process_each_vg(int argc, char **argv, return ret_max; } +int process_each_pv(int argc, char **argv, struct volume_group *vg, + int (*process_single) (struct volume_group * vg, + struct physical_volume * pv)) +{ + int opt = 0; + int ret_max = 0; + int ret = 0; + + struct list_head *pvh; + + if (argc) { + log_verbose("Using physical volume(s) on command line"); + for (; opt < argc; opt++) { + if (!(pvh = find_pv_in_vg(vg, argv[opt]))) { + log_error("Physical Volume %s not found in " + "Volume Group %s", argv[opt], + vg->name); + continue; + } + ret = process_single(vg, &list_entry + (pvh, struct pv_list, list)->pv); + if (ret > ret_max) + ret_max = ret; + } + } else { + log_verbose("Using all physical volume(s) in volume group"); + list_for_each(pvh, &vg->pvs) { + ret = process_single(vg, &list_entry + (pvh, struct pv_list, list)->pv); + if (ret > ret_max) + ret_max = ret; + } + } + + return ret_max; +} + int is_valid_chars(char *n) { register char c; while ((c = *n++)) - if (!isalnum(c) && c != '.' && c != '_' && c != '-' && - c != '+') + if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+') return 0; return 1; } +struct list_head *find_pv_in_vg(struct volume_group *vg, const char *pv_name) +{ + struct list_head *pvh; + list_for_each(pvh, &vg->pvs) { + if (!strcmp(list_entry(pvh, struct pv_list, list)->pv.dev->name, + pv_name)) return pvh; + } + + return NULL; + +} diff --git a/tools/toollib.h b/tools/toollib.h index ed5421d3b..b3aeca4ab 100644 --- a/tools/toollib.h +++ b/tools/toollib.h @@ -28,6 +28,12 @@ int do_autobackup(struct volume_group *vg); int process_each_vg(int argc, char **argv, int (*process_single) (const char *vg_name)); +int process_each_pv(int argc, char **argv, struct volume_group *vg, + int (*process_single) (struct volume_group * vg, + struct physical_volume * pv)); + int is_valid_chars(char *n); +struct list_head *find_pv_in_vg(struct volume_group *vg, const char *pv_name); + #endif diff --git a/tools/vgreduce.c b/tools/vgreduce.c new file mode 100644 index 000000000..83581ee58 --- /dev/null +++ b/tools/vgreduce.c @@ -0,0 +1,132 @@ +/* + * 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" + +static int vgreduce_single(struct volume_group *vg, struct physical_volume *pv); + +int vgreduce(int argc, char **argv) +{ + struct volume_group *vg; + char *vg_name; + + if (!argc) { + log_error("Please give volume group name and " + "physical volume paths"); + return EINVALID_CMD_LINE; + } + + if (argc == 1 && !arg_count(all_ARG)) { + log_error("Please enter physical volume paths or option -a"); + return EINVALID_CMD_LINE; + } + + if (argc > 1 && arg_count(all_ARG)) { + log_error("Option -a and physical volume paths mutually " + "exclusive"); + return EINVALID_CMD_LINE; + } + + vg_name = argv[0]; + argv++; + argc--; + + 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 is not active", vg_name); + return ECMD_FAILED; + } + + if (!(vg->status & EXTENDABLE_VG)) { + log_error("Volume group %s is not reducable", vg_name); + return ECMD_FAILED; + } + + /* FIXME: Pass private structure through to all these functions */ + /* and update in batch here? */ + return process_each_pv(argc, argv, vg, vgreduce_single); + +/******* FIXME + log_error ("no empty physical volumes found in volume group \"%s\"", vg_name); + + log_verbose + ("volume group \"%s\" will be reduced by %d physical volume%s", + vg_name, np, np > 1 ? "s" : ""); + log_verbose ("reducing volume group \"%s\" by physical volume \"%s\"", vg_name, pv_names[p]); + + log_print + ("volume group \"%s\" %ssuccessfully reduced by physical volume%s:", + vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : ""); + log_print("%s", pv_this[p]->pv_name); +********/ + +} + +/* Or take pv_name instead? */ +static int vgreduce_single(struct volume_group *vg, struct physical_volume *pv) +{ + struct list_head *pvh; + + if (pv->pe_allocated) { + log_error("Physical volume %s still in use", pv->dev->name); + return ECMD_FAILED; + } + +/********* FIXME: Is this unnecessary after checking pe_allocated? + if (pv->lv_cur > 0) { + log_error ("can't reduce volume group \"%s\" by used physical volume \"%s\"", vg_name, error_pv_name); + } +*********/ + + if (vg->pv_count == 1) { + log_error("Can't remove final physical volume %s from " + "volume group %s", pv->dev->name, vg->name); + return ECMD_FAILED; + } + + pvh = find_pv_in_vg(vg, pv->dev->name); + + log_verbose("Removing %s from volume group %s", pv->dev->name, + vg->name); + list_del(pvh); + *pv->vg_name = '\0'; + vg->pv_count--; + + if (!(ios->vg_write(ios, vg))) { + log_error("Removal of physical volume %s from %s failed", + pv->dev->name, vg->name); + return ECMD_FAILED; + } + + if (!ios->pv_write(ios, pv)) { + log_error("Failed to clear metadata from physical volume %s " + "after removal from %s", pv->dev->name, vg->name); + return ECMD_FAILED; + } + + log_print("Removed %s from volume group %s", pv->dev->name, vg->name); + + return 0; +} diff --git a/tools/vgremove.c b/tools/vgremove.c index ad1aaf4e9..da1bf299f 100644 --- a/tools/vgremove.c +++ b/tools/vgremove.c @@ -32,13 +32,13 @@ static int vgremove_single(const char *vg_name) struct volume_group *vg; struct physical_volume *pv; struct list_head *pvh; + int ret = 0; - log_verbose("Checking for 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; - } - + log_verbose("Checking for 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 is still active", vg_name); @@ -47,7 +47,7 @@ static int vgremove_single(const char *vg_name) if (vg->lv_count) { log_error("Volume group %s still contains %d logical volume(s)", - vg_name, vg->lv_count); + vg_name, vg->lv_count); return ECMD_FAILED; } @@ -58,19 +58,23 @@ static int vgremove_single(const char *vg_name) } *************/ - /* init physical volumes */ list_for_each(pvh, &vg->pvs) { pv = &list_entry(pvh, struct pv_list, list)->pv; log_verbose("Removing physical volume %s from volume group %s", pv->dev->name, vg_name); - pv->vg_name = '\0'; - if (!(ios->pv_write(ios, pv))) + *pv->vg_name = '\0'; + if (!(ios->pv_write(ios, pv))) { log_error("Failed to remove physical volume %s from " - "volume group %s", pv->dev->name, vg_name); + "volume group %s", pv->dev->name, vg_name); + ret = ECMD_FAILED; + } } - log_print("Volume group %s successfully removed", vg_name); + if (!ret) + log_print("Volume group %s successfully removed", vg_name); + else + log_error("Volume group %s not properly removed", vg_name); - return 0; + return ret; } diff --git a/tools/vgrename.c b/tools/vgrename.c index ac2027453..571185028 100644 --- a/tools/vgrename.c +++ b/tools/vgrename.c @@ -92,8 +92,8 @@ int vgrename(int argc, char **argv) /* FIXME Should vg_write fix these implicitly? It has to check them. */ list_for_each(pvh, &vg_old->pvs) { - strcpy(list_entry(pvh, struct pv_list, list)->pv.vg_name, - vg_name_new); + strcpy(list_entry(pvh, struct pv_list, list)->pv.vg_name, + vg_name_new); } /********** FIXME: Check within vg_write now @@ -147,4 +147,3 @@ char *lv_change_vgname(char *vg_name, char *lv_name) strncpy(lv_name_buf, lv_name, NAME_LEN - 1); return lv_name_buf;} **********************/ - diff --git a/tools/vgscan.c b/tools/vgscan.c new file mode 100644 index 000000000..799d50b3e --- /dev/null +++ b/tools/vgscan.c @@ -0,0 +1,66 @@ +/* + * 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" + +static int vgscan_single(const char *vg_name); + +int vgscan(int argc, char **argv) +{ + if (argc) { + log_error("Too many parameters on command line"); + return EINVALID_CMD_LINE; + } + + log_print("Reading all physical volumes (this may take a while...)"); + + return process_each_vg(argc, argv, &vgscan_single); +} + +static int vgscan_single(const char *vg_name) +{ + struct volume_group *vg; + + log_verbose("Checking for volume group %s", vg_name); + if (!(vg = ios->vg_read(ios, vg_name))) { + log_error("Volume group %s not found", vg_name); + return ECMD_FAILED; + } + + log_print("Found %sactive volume group %s", + (vg->status & ACTIVE) ? "" : "in", vg_name); + + /* FIXME: Now try to activate any inactive logical volumes */ + /* activate_lvs(vg) ? */ + + if (!(vg->status & ACTIVE)) { + vg->status |= ACTIVE; + if (!(ios->vg_write(ios, vg))) { + log_error("Failed to activate volume group %s", + vg_name); + return ECMD_FAILED; + } + + /* FIXME: Create /dev/vg entries? */ + log_print("Volume Group %s activated", vg_name); + } + + return 0; +}