diff options
author | Alasdair Kergon <agk@redhat.com> | 2002-11-18 14:04:08 +0000 |
---|---|---|
committer | Alasdair Kergon <agk@redhat.com> | 2002-11-18 14:04:08 +0000 |
commit | 5a52dca9c26ade9f233abcf5213300560d7a13a9 (patch) | |
tree | 9afbc621c07148c96a1ba1878a262dbd8aec613a /tools | |
parent | d1d9800ef1c7ec38a5f72b8e2586f927ab68188c (diff) | |
download | lvm2-5a52dca9c26ade9f233abcf5213300560d7a13a9.tar.gz lvm2-5a52dca9c26ade9f233abcf5213300560d7a13a9.tar.xz lvm2-5a52dca9c26ade9f233abcf5213300560d7a13a9.zip |
Some new features.
Diffstat (limited to 'tools')
39 files changed, 1859 insertions, 1700 deletions
diff --git a/tools/Makefile.in b/tools/Makefile.in index 800b43eb..42ae8aef 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -37,6 +37,7 @@ SOURCES=\ pvchange.c \ pvcreate.c \ pvdisplay.c \ + pvremove.c \ pvscan.c \ toollib.c \ vgcfgbackup.c \ @@ -44,6 +45,7 @@ SOURCES=\ vgchange.c \ vgck.c \ vgcreate.c \ + vgconvert.c \ vgdisplay.c \ vgexport.c \ vgextend.c \ diff --git a/tools/archive.c b/tools/archive.c index 15251b51..8fdafc26 100644 --- a/tools/archive.c +++ b/tools/archive.c @@ -4,18 +4,8 @@ * This file is released under the GPL. */ -#include "log.h" -#include "archive.h" -#include "dbg_malloc.h" -#include "format-text.h" -#include "lvm-string.h" -#include "toollib.h" - #include "tools.h" -#include <unistd.h> -#include <limits.h> - static struct { int enabled; char *dir; @@ -97,7 +87,7 @@ int archive(struct volume_group *vg) return 1; if (test_mode()) { - log_print("Test mode: Skipping archiving of volume group."); + log_verbose("Test mode: Skipping archiving of volume group."); return 1; } @@ -113,7 +103,7 @@ int archive(struct volume_group *vg) int archive_display(struct cmd_context *cmd, const char *vg_name) { - return archive_list(cmd, cmd->um, _archive_params.dir, vg_name); + return archive_list(cmd, _archive_params.dir, vg_name); } static struct { @@ -153,11 +143,8 @@ void backup_enable(int flag) static int __backup(struct volume_group *vg) { - int r; - struct format_instance *tf; char name[PATH_MAX]; char *desc; - void *context; if (!(desc = _build_desc(vg->cmd->mem, vg->cmd->cmd_line, 0))) { stack; @@ -173,20 +160,7 @@ static int __backup(struct volume_group *vg) log_verbose("Creating volume group backup \"%s\"", name); - if (!(context = create_text_context(vg->cmd->fmtt, name, desc)) || - !(tf = vg->cmd->fmtt->ops->create_instance(vg->cmd->fmtt, NULL, - context))) { - stack; - return 0; - } - - if (!(r = tf->fmt->ops->vg_write(tf, vg, context)) || - !(r = tf->fmt->ops->vg_commit(tf, vg, context))) - stack; - - tf->fmt->ops->destroy_instance(tf); - - return r; + return backup_to_file(name, desc, vg); } int backup(struct volume_group *vg) @@ -197,7 +171,7 @@ int backup(struct volume_group *vg) } if (test_mode()) { - log_print("Test mode: Skipping volume group backup."); + log_verbose("Test mode: Skipping volume group backup."); return 1; } @@ -227,57 +201,73 @@ int backup_remove(const char *vg_name) return 1; } -static struct volume_group *_read_vg(struct cmd_context *cmd, - const char *vg_name, const char *file) +struct volume_group *backup_read_vg(struct cmd_context *cmd, + const char *vg_name, const char *file) { struct volume_group *vg; struct format_instance *tf; + struct list *mdah; + struct metadata_area *mda; void *context; - if (!(context = create_text_context(cmd->fmtt, file, + if (!(context = create_text_context(cmd, file, cmd->cmd_line)) || - !(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) { + !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL, + context))) { log_error("Couldn't create text format object."); return NULL; } - if (!(vg = tf->fmt->ops->vg_read(tf, vg_name, context))) - stack; + list_iterate(mdah, &tf->metadata_areas) { + mda = list_item(mdah, struct metadata_area); + if (!(vg = mda->ops->vg_read(tf, vg_name, mda))) + stack; + break; + } tf->fmt->ops->destroy_instance(tf); return vg; } -int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name, - const char *file) +/* ORPHAN and VG locks held before calling this */ +int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg) { - struct volume_group *vg; + struct list *pvh; + struct physical_volume *pv; + struct cache_info *info; /* - * Read in the volume group. + * FIXME: Check that the PVs referenced in the backup are + * not members of other existing VGs. */ - if (!(vg = _read_vg(cmd, vg_name, file))) { - stack; + + /* Attempt to write out using currently active format */ + if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg->name, + NULL))) { + log_error("Failed to allocate format instance"); return 0; } - /* - * Check that those pv's referenced in the backup are - * currently orphans or members of the vg.s - */ - /* - * FIXME: waiting for label code. - */ - - /* - * Write the vg. - */ - - /* FIXME How do I find what format to write out the VG in? */ - /* Must store the format type inside the backup? */ - if (!(vg->fid = cmd->fmt1->ops->create_instance(cmd->fmt1, NULL, NULL))) { - log_error("Failed to allocate format1 instance"); - return 0; + /* Add any metadata areas on the PVs */ + list_iterate(pvh, &vg->pvs) { + pv = list_item(pvh, struct pv_list)->pv; + if (!(info = info_from_pvid(pv->dev->pvid))) { + log_error("PV %s missing from cache", + dev_name(pv->dev)); + return 0; + } + if (cmd->fmt != info->fmt) { + log_error("PV %s is a different format (%s)", + dev_name(pv->dev), info->fmt->name); + return 0; + } + if (!vg->fid->fmt->ops-> + pv_setup(vg->fid->fmt, 0, 0, 0, 0, 0, + &vg->fid->metadata_areas, pv, vg)) { + log_error("Format-specific setup for %s failed", + dev_name(pv->dev)); + return 0; + } } if (!vg_write(vg)) { @@ -288,6 +278,23 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name, return 1; } +/* ORPHAN and VG locks held before calling this */ +int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name, + const char *file) +{ + struct volume_group *vg; + + /* + * Read in the volume group from the text file. + */ + if (!(vg = backup_read_vg(cmd, vg_name, file))) { + stack; + return 0; + } + + return backup_restore_vg(cmd, vg); +} + int backup_restore(struct cmd_context *cmd, const char *vg_name) { char path[PATH_MAX]; @@ -300,3 +307,38 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name) return backup_restore_from_file(cmd, vg_name, path); } + +int backup_to_file(const char *file, const char *desc, struct volume_group *vg) +{ + int r; + struct format_instance *tf; + struct list *mdah; + struct metadata_area *mda; + void *context; + struct cmd_context *cmd; + + cmd = vg->cmd; + + if (!(context = create_text_context(cmd, file, desc)) || + !(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL, + context))) { + log_error("Couldn't create backup object."); + return 0; + } + + /* Write and commit the metadata area */ + list_iterate(mdah, &tf->metadata_areas) { + mda = list_item(mdah, struct metadata_area); + if (!(r = mda->ops->vg_write(tf, vg, mda))) { + stack; + continue; + } + if (mda->ops->vg_commit && + !(r = mda->ops->vg_commit(tf, vg, mda))) { + stack; + } + } + + tf->fmt->ops->destroy_instance(tf); + return r; +} diff --git a/tools/archive.h b/tools/archive.h index f0f34eb2..157ae805 100644 --- a/tools/archive.h +++ b/tools/archive.h @@ -42,8 +42,13 @@ void backup_enable(int flag); int backup(struct volume_group *vg); int backup_remove(const char *vg_name); +struct volume_group *backup_read_vg(struct cmd_context *cmd, + const char *vg_name, const char *file); +int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg); int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name, const char *file); int backup_restore(struct cmd_context *cmd, const char *vg_name); +int backup_to_file(const char *file, const char *desc, struct volume_group *vg); + #endif diff --git a/tools/args.h b/tools/args.h index ecfb1d12..15d47349 100644 --- a/tools/args.h +++ b/tools/args.h @@ -12,6 +12,11 @@ arg(version_ARG, '\0', "version", NULL) arg(quiet_ARG, '\0', "quiet", NULL) arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_arg) arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL) +arg(metadatacopies_ARG, '\0', "metadatacopies", int_arg) +arg(metadatasize_ARG, '\0', "metadatasize", size_arg) +arg(restorefile_ARG, '\0', "restorefile", string_arg) +arg(labelsector_ARG, '\0', "labelsector", int_arg) +arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg) /* Allow some variations */ arg(resizable_ARG, '\0', "resizable", yes_no_arg) @@ -77,4 +82,3 @@ arg(zero_ARG, 'Z', "zero", yes_no_arg) /* this should always be last */ arg(ARG_COUNT, '-', "", NULL) - diff --git a/tools/commands.h b/tools/commands.h index 672cb2f2..b2e4868c 100644 --- a/tools/commands.h +++ b/tools/commands.h @@ -18,6 +18,21 @@ * */ +/*********** Replace with script? +xx(e2fsadm, + "Resize logical volume and ext2 filesystem", + "e2fsadm " + "[-d|--debug] " "[-h|--help] " "[-n|--nofsck]" "\n" + "\t{[-l|--extents] [+|-]LogicalExtentsNumber |" "\n" + "\t [-L|--size] [+|-]LogicalVolumeSize[kKmMgGtT]}" "\n" + "\t[-t|--test] " "\n" + "\t[-v|--verbose] " "\n" + "\t[--version] " "\n" + "\tLogicalVolumePath" "\n", + + extents_ARG, size_ARG, nofsck_ARG, test_ARG) +*********/ + xx(help, "Display help for commands", "help <command>" "\n") @@ -40,6 +55,7 @@ xx(lvchange, "\t[-C/--contiguous y/n]\n" "\t[-d/--debug]\n" "\t[-h/-?/--help]\n" + "\t[--ignorelockingfailure]\n" "\t[-M/--persistent y/n] [--minor minor]\n" "\t[-P/--partial] " "\n" "\t[-p/--permission r/rw]\n" @@ -84,14 +100,14 @@ xx(lvdisplay, "lvdisplay\n" "\t[-c/--colon]\n" "\t[-d/--debug]\n" - "\t[-D/--disk]\n" "\t[-h/-?/--help]\n" "\t[-m/--maps]\n" "\t[-P/--partial] " "\n" "\t[-v/--verbose]\n" "\tLogicalVolume[Path] [LogicalVolume[Path]...]\n", - colon_ARG, disk_ARG, maps_ARG, partial_ARG, ignorelockingfailure_ARG) + colon_ARG, disk_ARG, maps_ARG, partial_ARG, + ignorelockingfailure_ARG) xx(lvextend, "Add space to a logical volume", @@ -106,8 +122,8 @@ xx(lvextend, "\t[-v/--verbose]\n" "\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n", - autobackup_ARG, extents_ARG, size_ARG, stripes_ARG, stripesize_ARG, - test_ARG) + autobackup_ARG, extents_ARG, size_ARG, stripes_ARG, + stripesize_ARG, test_ARG) xx(lvmchange, "With the device mapper, this is obsolete and does nothing.", @@ -212,7 +228,6 @@ xx(lvscan, "lvscan " "\n" "\t[-b|--blockdevice] " "\n" "\t[-d|--debug] " "\n" - "\t[-D|--disk]" "\n" "\t[-h|--help] " "\n" "\t[-P|--partial] " "\n" "\t[-v|--verbose] " "\n" @@ -237,18 +252,25 @@ xx(pvchange, xx(pvcreate, "Initialize physical volume(s) for use by LVM", "pvcreate " "\n" + "\t[--restorefile file]\n" "\t[-d|--debug]" "\n" "\t[-f[f]|--force [--force]] " "\n" "\t[-h|--help] " "\n" - "\t[-y|--yes]" "\n" - "\t[-s|--size PhysicalVolumeSize[kKmMgGtT]" "\n" + "\t[--labelsector sector] " "\n" + "\t[-M|--metadatatype 1|2]" "\n" + "\t[--metadatacopies #copies]" "\n" + "\t[--metadatasize MetadataSize[kKmMgGtT]]" "\n" + "\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtT]" "\n" "\t[-t|--test] " "\n" "\t[-u|--uuid uuid] " "\n" "\t[-v|--verbose] " "\n" + "\t[-y|--yes]" "\n" "\t[--version] " "\n" "\tPhysicalVolume [PhysicalVolume...]\n", - force_ARG, test_ARG, physicalvolumesize_ARG, uuidstr_ARG, yes_ARG) + force_ARG, test_ARG, labelsector_ARG, metadatatype_ARG, metadatacopies_ARG, + metadatasize_ARG, physicalvolumesize_ARG, restorefile_ARG, uuidstr_ARG, + yes_ARG) xx(pvdata, "Display the on-disk metadata for physical volume(s)", @@ -297,9 +319,26 @@ xx(pvmove, autobackup_ARG, force_ARG, name_ARG, test_ARG) +xx(pvremove, + "Remove LVM label(s) from physical volume(s)", + "pvremove " "\n" + "\t[-d|--debug]" "\n" + "\t[-f[f]|--force [--force]] " "\n" + "\t[-h|--help] " "\n" + "\t[-y|--yes]" "\n" + "\t[-t|--test] " "\n" + "\t[-v|--verbose] " "\n" + "\t[-y|--yes]" "\n" + "\t[--version] " "\n" + "\tPhysicalVolume [PhysicalVolume...]\n", + + force_ARG, test_ARG, yes_ARG) + xx(pvresize, "Resize a physical volume in use by a volume group", - "pvmove " + "Not implemented. Use pvcreate options.", +/*** + "pvresize " "[-A|--autobackup {y|n}] " "[-d|--debug] " "[-h|--help]\n\t" @@ -307,7 +346,7 @@ xx(pvresize, "[-v|--verbose] " "[--version]\n\t" "\tPhysicalVolumePath [PhysicalVolumePath...]\n", - +***/ autobackup_ARG, physicalvolumesize_ARG) xx(pvscan, @@ -343,6 +382,7 @@ xx(vgcfgrestore, "\t[-d|--debug] " "\n" "\t[-f|--file filename] " "\n" "\t[-l[l]|--list [--list]]" "\n" + "\t[-M|--metadatatype 1|2]" "\n" "\t[-n|--name VolumeGroupName] " "\n" "\t[-h|--help]" "\n" "\t[-t|--test] " "\n" @@ -350,7 +390,7 @@ xx(vgcfgrestore, "\t[--version] " "\n" "\tVolumeGroupName", - file_ARG, list_ARG, name_ARG, test_ARG) + file_ARG, list_ARG, metadatatype_ARG, name_ARG, test_ARG) xx(vgchange, "Change volume group attributes", @@ -379,6 +419,23 @@ xx(vgck, "\t[-v/--verbose]\n" "\t[VolumeGroupName...]\n" ) +xx(vgconvert, + "Change volume group metadata format", + "vgconvert " "\n" + "\t[-d|--debug]" "\n" + "\t[-h|--help] " "\n" + "\t[--labelsector sector] " "\n" + "\t[-M|--metadatatype 1|2]" "\n" + "\t[--metadatacopies #copies]" "\n" + "\t[--metadatasize MetadataSize[kKmMgGtT]]" "\n" + "\t[-t|--test] " "\n" + "\t[-v|--verbose] " "\n" + "\t[--version] " "\n" + "\tVolumeGroupName [VolumeGroupName...]\n", + + force_ARG, test_ARG, labelsector_ARG, metadatatype_ARG, metadatacopies_ARG, + metadatasize_ARG ) + xx(vgcreate, "Create a volume group", "vgcreate" "\n" @@ -386,7 +443,7 @@ xx(vgcreate, "\t[-d|--debug]" "\n" "\t[-h|--help]" "\n" "\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n" - "\t[-M|--metadatatype lvm1/text] " "\n" + "\t[-M|--metadatatype 1|2] " "\n" "\t[-p|--maxphysicalvolumes MaxPhysicalVolumes] " "\n" "\t[-s|--physicalextentsize PhysicalExtentSize[kKmMgGtT]] " "\n" "\t[-t|--test] " "\n" @@ -403,6 +460,7 @@ xx(vgdisplay, "\t[-c|--colon | -s|--short | -v|--verbose]" "\n" "\t[-d|--debug] " "\n" "\t[-h|--help] " "\n" + "\t[--ignorelockingfailure]" "\n" "\t[-P|--partial] " "\n" "\t[-A|--activevolumegroups | [-D|--disk]" "\n" "\t[--version]" "\n" @@ -499,7 +557,6 @@ xx(vgrename, "vgrename\n" "\t[-A/--autobackup y/n]\n" "\t[-d/--debug]\n" - "\t[-f/--force]\n" "\t[-h/-?/--help]\n" "\t[-t/--test]\n" "\t[-v/--verbose]\n" @@ -524,7 +581,7 @@ xx(vgsplit, "\t[-d|--debug] " "\n" "\t[-h|--help] " "\n" "\t[-l|--list]" "\n" - "\t[-M|--metadatatype lvm1/text] " "\n" + "\t[-M|--metadatatype 1|2] " "\n" "\t[-t|--test] " "\n" "\t[-v|--verbose] " "\n" "\t[--version]" "\n" diff --git a/tools/lvchange.c b/tools/lvchange.c index 59d5901c..24cc73d0 100644 --- a/tools/lvchange.c +++ b/tools/lvchange.c @@ -20,120 +20,6 @@ #include "tools.h" -static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv); -static int lvchange_permission(struct cmd_context *cmd, - struct logical_volume *lv); -static int lvchange_availability(struct cmd_context *cmd, - struct logical_volume *lv); -static int lvchange_contiguous(struct cmd_context *cmd, - struct logical_volume *lv); -static int lvchange_readahead(struct cmd_context *cmd, - struct logical_volume *lv); -static int lvchange_persistent(struct cmd_context *cmd, - struct logical_volume *lv); - -int lvchange(struct cmd_context *cmd, int argc, char **argv) -{ - if (!arg_count(cmd, available_ARG) && !arg_count(cmd, contiguous_ARG) - && !arg_count(cmd, permission_ARG) && !arg_count(cmd, readahead_ARG) - && !arg_count(cmd, minor_ARG) && !arg_count(cmd, persistent_ARG)) { - log_error("One or more of -a, -C, -m, -M, -p or -r required"); - return EINVALID_CMD_LINE; - } - - if (arg_count(cmd, ignorelockingfailure_ARG) && - (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) || - arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) { - log_error("Only -a permitted with --ignorelockingfailure"); - return EINVALID_CMD_LINE; - } - - if (!argc) { - log_error("Please give logical volume path(s)"); - return EINVALID_CMD_LINE; - } - - if (arg_count(cmd, minor_ARG) && argc != 1) { - log_error("Only give one logical volume when specifying minor"); - return EINVALID_CMD_LINE; - } - - if (!driver_is_loaded()) - return ECMD_FAILED; - - return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, &lvchange_single); -} - -static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv) -{ - int doit = 0; - int archived = 0; - - if (!(lv->vg->status & LVM_WRITE) && - (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) || - arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) { - log_error("Only -a permitted with read-only volume " - "group \"%s\"", lv->vg->name); - return EINVALID_CMD_LINE; - } - - if (lv_is_origin(lv) && - (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) || - arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) { - log_error("Can't change logical volume \"%s\" under snapshot", - lv->name); - return ECMD_FAILED; - } - - if (lv_is_cow(lv)) { - log_error("Can't change snapshot logical volume \"%s\"", - lv->name); - return ECMD_FAILED; - } - - /* access permission change */ - if (arg_count(cmd, permission_ARG)) { - if (!archive(lv->vg)) - return ECMD_FAILED; - archived = 1; - doit += lvchange_permission(cmd, lv); - } - - /* allocation policy change */ - if (arg_count(cmd, contiguous_ARG)) { - if (!archived && !archive(lv->vg)) - return ECMD_FAILED; - archived = 1; - doit += lvchange_contiguous(cmd, lv); - } - - /* read ahead sector change */ - if (arg_count(cmd, readahead_ARG)) { - if (!archived && !archive(lv->vg)) - return ECMD_FAILED; - archived = 1; - doit += lvchange_readahead(cmd, lv); - } - - /* read ahead sector change */ - if (arg_count(cmd, persistent_ARG)) { - if (!archived && !archive(lv->vg)) - return ECMD_FAILED; - archived = 1; - doit += lvchange_persistent(cmd, lv); - } - - if (doit) - log_print("Logical volume \"%s\" changed", lv->name); - - /* availability change */ - if (arg_count(cmd, available_ARG)) - if (!lvchange_availability(cmd, lv)) - return ECMD_FAILED; - - return 0; -} - static int lvchange_permission(struct cmd_context *cmd, struct logical_volume *lv) { @@ -234,7 +120,7 @@ static int lvchange_contiguous(struct cmd_context *cmd, } /******** FIXME lv_check_contiguous? - if ((lv_allocation & ALLOC_CONTIGUOUS) + if (want_contiguous) && (ret = lv_check_contiguous(vg, lv_index + 1)) == FALSE) { log_error("No contiguous logical volume \"%s\"", lv->name); return 0; @@ -245,8 +131,8 @@ static int lvchange_contiguous(struct cmd_context *cmd, log_verbose("Setting contiguous allocation policy for \"%s\"", lv->name); } else { - lv->alloc = ALLOC_NEXT_FREE; - log_verbose("Removing contiguous allocation policy for \"%s\"", + lv->alloc = ALLOC_DEFAULT; + log_verbose("Reverting to default allocation policy for \"%s\"", lv->name); } @@ -371,3 +257,104 @@ static int lvchange_persistent(struct cmd_context *cmd, return 1; } + +static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv, + void *handle) +{ + int doit = 0; + int archived = 0; + + if (!(lv->vg->status & LVM_WRITE) && + (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) || + arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) { + log_error("Only -a permitted with read-only volume " + "group \"%s\"", lv->vg->name); + return EINVALID_CMD_LINE; + } + + if (lv_is_origin(lv) && + (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) || + arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) { + log_error("Can't change logical volume \"%s\" under snapshot", + lv->name); + return ECMD_FAILED; + } + + if (lv_is_cow(lv)) { + log_error("Can't change snapshot logical volume \"%s\"", + lv->name); + return ECMD_FAILED; + } + + /* access permission change */ + if (arg_count(cmd, permission_ARG)) { + if (!archive(lv->vg)) + return ECMD_FAILED; + archived = 1; + doit += lvchange_permission(cmd, lv); + } + + /* allocation policy change */ + if (arg_count(cmd, contiguous_ARG)) { + if (!archived && !archive(lv->vg)) + return ECMD_FAILED; + archived = 1; + doit += lvchange_contiguous(cmd, lv); + } + + /* read ahead sector change */ + if (arg_count(cmd, readahead_ARG)) { + if (!archived && !archive(lv->vg)) + return ECMD_FAILED; + archived = 1; + doit += lvchange_readahead(cmd, lv); + } + + /* read ahead sector change */ + if (arg_count(cmd, persistent_ARG)) { + if (!archived && !archive(lv->vg)) + return ECMD_FAILED; + archived = 1; + doit += lvchange_persistent(cmd, lv); + } + + if (doit) + log_print("Logical volume \"%s\" changed", lv->name); + + /* availability change */ + if (arg_count(cmd, available_ARG)) + if (!lvchange_availability(cmd, lv)) + return ECMD_FAILED; + + return 0; +} + +int lvchange(struct cmd_context *cmd, int argc, char **argv) +{ + if (!arg_count(cmd, available_ARG) && !arg_count(cmd, contiguous_ARG) + && !arg_count(cmd, permission_ARG) && !arg_count(cmd, readahead_ARG) + && !arg_count(cmd, minor_ARG) && !arg_count(cmd, persistent_ARG)) { + log_error("One or more of -a, -C, -m, -M, -p or -r required"); + return EINVALID_CMD_LINE; + } + + if (arg_count(cmd, ignorelockingfailure_ARG) && + (arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) || + arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG))) { + log_error("Only -a permitted with --ignorelockingfailure"); + return EINVALID_CMD_LINE; + } + + if (!argc) { + log_error("Please give logical volume path(s)"); + return EINVALID_CMD_LINE; + } + + if (arg_count(cmd, minor_ARG) && argc != 1) { + log_error("Only give one logical volume when specifying minor"); + return EINVALID_CMD_LINE; + } + + return process_each_lv(cmd, argc, argv, LCK_VG_WRITE, NULL, + &lvchange_single); +} diff --git a/tools/lvcreate.c b/tools/lvcreate.c index 3065806c..59e9ed0a 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -90,7 +90,7 @@ static int _read_name_params(struct lvcreate_params *lp, if (lp->lv_name && strchr(lp->lv_name, '/')) { if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) - return 0; + return 0; if (strcmp(lp->vg_name, argv[0])) { log_error("Inconsistent volume group " @@ -109,6 +109,13 @@ static int _read_name_params(struct lvcreate_params *lp, if (lp->lv_name && (ptr = strrchr(lp->lv_name, '/'))) lp->lv_name = ptr + 1; + /* FIXME Remove this restriction eventually */ + if (lp->lv_name && !strncmp(lp->lv_name, "snapshot", 8)) { + log_error("Names starting \"snapshot\" are reserved. " + "Please choose a different LV name."); + return 0; + } + return 1; } @@ -312,20 +319,21 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) { uint32_t size_rest; uint32_t status = 0; - alloc_policy_t alloc = ALLOC_NEXT_FREE; + alloc_policy_t alloc = ALLOC_DEFAULT; struct volume_group *vg; struct logical_volume *lv, *org; struct list *pvh; + int consistent = 1; if (lp->contiguous) alloc = ALLOC_CONTIGUOUS; - status |= lp->permission; + status |= lp->permission | VISIBLE_LV; /* does VG exist? */ log_verbose("Finding volume group \"%s\"", lp->vg_name); - if (!(vg = vg_read(cmd, lp->vg_name))) { + if (!(vg = vg_read(cmd, lp->vg_name, &consistent))) { log_error("Volume group \"%s\" doesn't exist", lp->vg_name); return 0; } @@ -391,20 +399,30 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) lp->extents = lp->extents - size_rest + lp->stripes; } - if (lp->snapshot && !(org = find_lv(vg, lp->origin))) { - log_err("Couldn't find origin volume '%s'.", lp->origin); + if (!activation()) { + if (lp->snapshot) + log_error("Can't create snapshot without using " + "device-mapper kernel driver"); return 0; } - /* - * For now all logical volumes are visible. - */ - status |= VISIBLE_LV; - + if (lp->snapshot) { + if (!(org = find_lv(vg, lp->origin))) { + log_err("Couldn't find origin volume '%s'.", + lp->origin); + return 0; + } + if (lv_is_cow(org)) { + log_error("Snapshots of snapshots are not supported " + "yet."); + return 0; + } + } if (!(lv = lv_create(vg->fid, lp->lv_name, status, alloc, lp->stripes, lp->stripe_size, lp->extents, - vg, pvh))) return 0; + vg, pvh))) + return 0; if (lp->read_ahead) { log_verbose("Setting read ahead sectors"); @@ -421,16 +439,28 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) return 0; /* store vg on disk(s) */ - if (!vg_write(vg)) + if (!vg_write(vg)) { return 0; + } - if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE)) + if (!lock_vol(cmd, lv->lvid.s, LCK_LV_ACTIVATE)) { + /* FIXME Remove the failed lv we just added */ + log_error("Aborting. Failed to wipe snapshot " + "exception store. Remove new LV and retry."); return 0; + } - if (lp->zero || lp->snapshot) - _zero_lv(cmd, lv); - else - log_print("WARNING: \"%s\" not zeroed", lv->name); + if ((lp->zero || lp->snapshot) && activation()) { + if (!_zero_lv(cmd, lv) && lp->snapshot) { + /* FIXME Remove the failed lv we just added */ + log_error("Aborting. Failed to wipe snapshot " + "exception store. Remove new LV and retry."); + return 0; + } + } else { + log_error("WARNING: \"%s\" not zeroed", lv->name); + /* FIXME Remove the failed lv we just added */ + } if (lp->snapshot) { if (!lock_vol(cmd, lv->lvid.s, LCK_LV_DEACTIVATE)) { @@ -443,7 +473,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp) return 0; } - if (!vg_add_snapshot(org, lv, 1, lp->chunk_size)) { + if (!vg_add_snapshot(org, lv, 1, NULL, lp->chunk_size)) { log_err("Couldn't create snapshot."); return 0; } @@ -480,9 +510,6 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv) if (!_read_params(&lp, cmd, argc, argv)) return -EINVALID_CMD_LINE; - if (!driver_is_loaded()) - return ECMD_FAILED; - if (!lock_vol(cmd, lp.vg_name, LCK_VG_WRITE)) { log_error("Can't get lock for %s", lp.vg_name); return 0; diff --git a/tools/lvdisplay.c b/tools/lvdisplay.c index d421327c..69971b1b 100644 --- a/tools/lvdisplay.c +++ b/tools/lvdisplay.c @@ -20,12 +20,13 @@ #include "tools.h" -int lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv) +int lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv, + void *handle) { if (arg_count(cmd, colon_ARG)) lvdisplay_colons(lv); else { - lvdisplay_full(cmd, lv); + lvdisplay_full(cmd, lv, handle); if (arg_count(cmd, maps_ARG)) lvdisplay_segments(lv); } @@ -42,8 +43,6 @@ int lvdisplay(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } - if (!driver_is_loaded()) - return ECMD_FAILED; - - return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvdisplay_single); + return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL, + &lvdisplay_single); } diff --git a/tools/lvm.c b/tools/lvm.c index 366b906b..526c1847 100644 --- a/tools/lvm.c +++ b/tools/lvm.c @@ -5,9 +5,7 @@ */ #include "tools.h" -#include "archive.h" #include "defaults.h" -#include "lvm1_label.h" #include "label.h" #include "version.h" @@ -19,10 +17,7 @@ #include <syslog.h> #include <libgen.h> #include <sys/stat.h> -#include <ctype.h> #include <time.h> -#include <stdlib.h> -#include <locale.h> #ifdef READLINE_SUPPORT #include <readline/readline.h> @@ -46,136 +41,10 @@ struct arg the_args[ARG_COUNT + 1] = { static int _array_size; static int _num_commands; static struct command *_commands; -struct cmd_context *cmd; - -/* Whether or not to dump persistent filter state */ -static int _dump_filter; static int _interactive; -static FILE *_log; - -/* lvm1 label handler */ -static struct labeller *_lvm1_label; - -/* - * This structure only contains those options that - * can have a default and per command setting. - */ -struct config_info { - int debug; - int verbose; - int test; - int syslog; - const char *msg_prefix; - int cmd_name; /* Show command name? */ - - int archive; /* should we archive ? */ - int backup; /* should we backup ? */ - - struct format_type *fmt; - - mode_t umask; -}; - -static struct config_info _default_settings; -static struct config_info _current_settings; - -/* - * The lvm_sys_dir contains: - * - * o The lvm configuration (lvm.conf) - * o The persistent filter cache (.cache) - * o Volume group backups (/backup) - * o Archive of old vg configurations (/archive) - */ -static char _sys_dir[PATH_MAX] = "/etc/lvm"; -static char _dev_dir[PATH_MAX]; -static char _proc_dir[PATH_MAX]; - -/* static functions */ -static void register_commands(void); -static struct command *find_command(const char *name); -static void register_command(const char *name, command_fn fn, - const char *desc, const char *usage, ...); -static void create_new_command(const char *name, command_fn command, - const char *desc, const char *usage, - int nargs, int *args); - -static void alloc_command(void); -static void add_getopt_arg(int arg, char **ptr, struct option **o); -static int process_command_line(struct command *com, int *argc, char ***argv); -static struct arg *find_arg(struct command *com, int a); -static int process_common_commands(struct command *com); -static int run_command(int argc, char **argv); -static int init(void); -static void fin(void); -static int run_script(int argc, char **argv); - -#ifdef READLINE_SUPPORT -static int shell(void); -#endif - -static void display_help(void); - -int main(int argc, char **argv) -{ - char *namebase, *base; - int ret, alias = 0; - - if (!init()) - return -1; - - namebase = strdup(argv[0]); - base = basename(namebase); - while (*base == '/') - base++; - if (strcmp(base, "lvm")) - alias = 1; - free(namebase); - - register_commands(); - -#ifdef READLINE_SUPPORT - if (!alias && argc == 1) { - ret = shell(); - goto out; - } -#endif - - if (!alias) { - if (argc < 2) { - log_fatal("Please supply an LVM command."); - display_help(); - ret = EINVALID_CMD_LINE; - goto out; - } - - argc--; - argv++; - } - ret = run_command(argc, argv); - if ((ret == ENO_SUCH_CMD) && (!alias)) - ret = run_script(argc, argv); - if (ret == ENO_SUCH_CMD) - log_error("No such command. Try 'help'."); - - out: - fin(); - return ret; -} - -void usage(const char *name) -{ - struct command *com = find_command(name); - - if (!com) - return; - - log_error("%s: %s\n\n%s", com->name, com->desc, com->usage); -} - -int yes_no_arg(struct arg *a) +int yes_no_arg(struct cmd_context *cmd, struct arg *a) { a->sign = SIGN_NONE; @@ -191,18 +60,26 @@ int yes_no_arg(struct arg *a) return 1; } -int metadatatype_arg(struct arg *a) +int metadatatype_arg(struct cmd_context *cmd, struct arg *a) { - if (!strcasecmp(a->value, cmd->fmtt->name)) - a->ptr = cmd->fmtt; + struct format_type *fmt; + struct list *fmth; - else if (!strcasecmp(a->value, cmd->fmt1->name)) - a->ptr = cmd->fmt1; + char *format; - else - return 0; + format = a->value; - return 1; + list_iterate(fmth, &cmd->formats) { + fmt = list_item(fmth, struct format_type); + if (!strcasecmp(fmt->name, format) || + !strcasecmp(fmt->name + 3, format) || + (fmt->alias && !strcasecmp(fmt->alias, format))) { + a->ptr = fmt; + return 1; + } + } + + return 0; } int _get_int_arg(struct arg *a, char **ptr) @@ -236,7 +113,7 @@ int _get_int_arg(struct arg *a, char **ptr) return 1; } -int size_arg(struct arg *a) +int size_arg(struct cmd_context *cmd, struct arg *a) { char *ptr; int i; @@ -283,7 +160,7 @@ int size_arg(struct arg *a) return 1; } -int int_arg(struct arg *a) +int int_arg(struct cmd_context *cmd, struct arg *a) { char *ptr; @@ -293,7 +170,7 @@ int int_arg(struct arg *a) return 1; } -int int_arg_with_sign(struct arg *a) +int int_arg_with_sign(struct cmd_context *cmd, struct arg *a) { char *ptr; @@ -303,7 +180,7 @@ int int_arg_with_sign(struct arg *a) return 1; } -int minor_arg(struct arg *a) +int minor_arg(struct cmd_context *cmd, struct arg *a) { char *ptr; @@ -318,12 +195,12 @@ int minor_arg(struct arg *a) return 1; } -int string_arg(struct arg *a) +int string_arg(struct cmd_context *cmd, struct arg *a) { return 1; } -int permission_arg(struct arg *a) +int permission_arg(struct cmd_context *cmd, struct arg *a) { a->sign = SIGN_NONE; @@ -358,18 +235,45 @@ char yes_no_prompt(const char *prompt, ...) return c; } -static void register_commands() +static void __alloc(int size) +{ + if (!(_commands = dbg_realloc(_commands, sizeof(*_commands) * size))) { + log_fatal("Couldn't allocate memory."); + exit(ECMD_FAILED); + } + + _array_size = size; +} + +static void _alloc_command(void) { -#define xx(a, b, c...) register_command(# a, a, b, ## c, \ - debug_ARG, help_ARG, \ - version_ARG, verbose_ARG, \ - quiet_ARG, -1); -#include "commands.h" -#undef xx + if (!_array_size) + __alloc(32); + + if (_array_size <= _num_commands) + __alloc(2 * _array_size); } -static void register_command(const char *name, command_fn fn, - const char *desc, const char *usage, ...) +static void _create_new_command(const char *name, command_fn command, + const char *desc, const char *usage, + int nargs, int *args) +{ + struct command *nc; + + _alloc_command(); + + nc = _commands + _num_commands++; + + nc->name = name; + nc->desc = desc; + nc->usage = usage; + nc->fn = command; + nc->num_args = nargs; + nc->valid_args = args; +} + +static void _register_command(const char *name, command_fn fn, + const char *desc, const char *usage, ...) { int nargs = 0, i; int *args; @@ -394,10 +298,21 @@ static void register_command(const char *name, command_fn fn, va_end(ap); /* enter the command in the register */ - create_new_command(name, fn, desc, usage, nargs, args); + _create_new_command(name, fn, desc, usage, nargs, args); +} + +static void _register_commands() +{ +#define xx(a, b, c...) _register_command(# a, a, b, ## c, \ + driverloaded_ARG, \ + debug_ARG, help_ARG, \ + version_ARG, verbose_ARG, \ + quiet_ARG, -1); +#include "commands.h" +#undef xx } -static struct command *find_command(const char *name) +static struct command *_find_command(const char *name) { int i; char *namebase, *base; @@ -418,41 +333,14 @@ static struct command *find_command(const char *name) return _commands + i; } -static void create_new_command(const char *name, command_fn command, - const char *desc, const char *usage, - int nargs, int *args) -{ - struct command *nc; - - alloc_command(); - - nc = _commands + _num_commands++; - - nc->name = name; - nc->desc = desc; - nc->usage = usage; - nc->fn = command; - nc->num_args = nargs; - nc->valid_args = args; -} - -static void __alloc(int size) +void usage(const char *name) { - if (!(_commands = dbg_realloc(_commands, sizeof(*_commands) * size))) { - log_fatal("Couldn't allocate memory."); - exit(ECMD_FAILED); - } - - _array_size = size; -} + struct command *com = _find_command(name); -static void alloc_command(void) -{ - if (!_array_size) - __alloc(32); + if (!com) + return; - if (_array_size <= _num_commands) - __alloc(2 * _array_size); + log_error("%s: %s\n\n%s", com->name, com->desc, com->usage); } /* @@ -464,7 +352,7 @@ static void alloc_command(void) * we have only 1 ATM (--version) I think we can * live with this restriction. */ -static void add_getopt_arg(int arg, char **ptr, struct option **o) +static void _add_getopt_arg(int arg, char **ptr, struct option **o) { struct arg *a = the_args + arg; @@ -484,7 +372,29 @@ static void add_getopt_arg(int arg, char **ptr, struct option **o) } } -static int process_command_line(struct command *com, int *argc, char ***argv) +static struct arg *_find_arg(struct command *com, int opt) +{ + struct arg *a; + int i, arg; + + for (i = 0; i < com->num_args; i++) { + arg = com->valid_args[i]; + a = the_args + arg; + + /* + * opt should equal either the + * short arg, or the index into + * 'the_args'. + */ + if ((a->short_arg && (opt == a->short_arg)) || (opt == arg)) + return a; + } + + return 0; +} + +static int _process_command_line(struct cmd_context *cmd, int *argc, + char ***argv) { int i, opt; char str[((ARG_COUNT + 1) * 2) + 1], *ptr = str; @@ -501,8 +411,8 @@ static int process_command_line(struct command *com, int *argc, char ***argv) } /* fill in the short and long opts */ - for (i = 0; i < com->num_args; i++) - add_getopt_arg(com->valid_args[i], &ptr, &o); + for (i = 0; i < cmd->command->num_args; i++) + _add_getopt_arg(cmd->command->valid_args[i], &ptr, &o); *ptr = '\0'; memset(o, 0, sizeof(*o)); @@ -512,7 +422,7 @@ static int process_command_line(struct command *com, int *argc, char ***argv) optind = 0; while ((opt = getopt_long(*argc, *argv, str, opts, NULL)) >= 0) { - a = find_arg(com, opt); + a = _find_arg(cmd->command, opt); if (!a) { log_fatal("Unrecognised option."); @@ -528,7 +438,7 @@ static int process_command_line(struct command *com, int *argc, char ***argv) a->value = optarg; - if (!a->fn(a)) { + if (!a->fn(cmd, a)) { log_error("Invalid argument %s", optarg); return 0; } @@ -542,28 +452,7 @@ static int process_command_line(struct command *com, int *argc, char ***argv) return 1; } -static struct arg *find_arg(struct command *com, int opt) -{ - struct arg *a; - int i, arg; - - for (i = 0; i < com->num_args; i++) { - arg = com->valid_args[i]; - a = the_args + arg; - - /* - * opt should equal either the - * short arg, or the index into - * 'the_args'. - */ - if ((a->short_arg && (opt == a->short_arg)) || (opt == arg)) - return a; - } - - return 0; -} - -static int merge_synonym(int oldarg, int newarg) +static int _merge_synonym(struct cmd_context *cmd, int oldarg, int newarg) { struct arg *old, *new; @@ -600,37 +489,34 @@ int version(struct cmd_context *cmd, int argc, char **argv) return ECMD_PROCESSED; } -static int process_common_commands(struct command *com) +static int _get_settings(struct cmd_context *cmd) { - _current_settings = _default_settings; + cmd->current_settings = cmd->default_settings; if (arg_count(cmd, debug_ARG)) - _current_settings.debug = _LOG_FATAL + + cmd->current_settings.debug = _LOG_FATAL + (arg_count(cmd, debug_ARG) - 1); if (arg_count(cmd, verbose_ARG)) - _current_settings.verbose = arg_count(cmd, verbose_ARG); + cmd->current_settings.verbose = arg_count(cmd, verbose_ARG); if (arg_count(cmd, quiet_ARG)) { - _current_settings.debug = 0; - _current_settings.verbose = 0; + cmd->current_settings.debug = 0; + cmd->current_settings.verbose = 0; } if (arg_count(cmd, test_ARG)) - _current_settings.test = arg_count(cmd, test_ARG); + cmd->current_settings.test = arg_count(cmd, test_ARG); - if (arg_count(cmd, help_ARG)) { - usage(com->name); - return ECMD_PROCESSED; - } - - if (arg_count(cmd, version_ARG)) { - return version(cmd, 0, (char **) NULL); + if (arg_count(cmd, driverloaded_ARG)) { + cmd->current_settings.activation = + arg_int_value(cmd, driverloaded_ARG, + cmd->default_settings.activation); } if (arg_count(cmd, autobackup_ARG)) { - _current_settings.archive = 1; - _current_settings.backup = 1; + cmd->current_settings.archive = 1; + cmd->current_settings.backup = 1; } if (arg_count(cmd, partial_ARG)) { @@ -646,29 +532,31 @@ static int process_common_commands(struct command *com) init_ignorelockingfailure(0); /* Handle synonyms */ - if (!merge_synonym(resizable_ARG, resizeable_ARG) || - !merge_synonym(allocation_ARG, allocatable_ARG) || - !merge_synonym(allocation_ARG, resizeable_ARG)) - return ECMD_FAILED; + if (!_merge_synonym(cmd, resizable_ARG, resizeable_ARG) || + !_merge_synonym(cmd, allocation_ARG, allocatable_ARG) || + !_merge_synonym(cmd, allocation_ARG, resizeable_ARG)) + return EINVALID_CMD_LINE; - /* Zero indicates it's OK to continue processing this command */ + /* Zero indicates success */ return 0; } -int help(struct cmd_context *cmd, int argc, char **argv) +static int _process_common_commands(struct cmd_context *cmd) { - if (!argc) - display_help(); - else { - int i; - for (i = 0; i < argc; i++) - usage(argv[i]); + if (arg_count(cmd, help_ARG)) { + usage(cmd->command->name); + return ECMD_PROCESSED; } + if (arg_count(cmd, version_ARG)) { + return version(cmd, 0, (char **) NULL); + } + + /* Zero indicates it's OK to continue processing this command */ return 0; } -static void display_help(void) +static void _display_help(void) { int i; @@ -683,22 +571,38 @@ static void display_help(void) } } -static void _use_settings(struct config_info *settings) +int help(struct cmd_context *cmd, int argc, char **argv) +{ + if (!argc) + _display_help(); + else { + int i; + for (i = 0; i < argc; i++) + usage(argv[i]); + } + + return 0; +} + +static void _apply_settings(struct cmd_context *cmd) { - init_debug(settings->debug); - init_verbose(settings->verbose); - init_test(settings->test); + init_debug(cmd->current_settings.debug); + init_verbose(cmd->current_settings.verbose); + init_test(cmd->current_settings.test); + + init_msg_prefix(cmd->default_settings.msg_prefix); + init_cmd_name(cmd->default_settings.cmd_name); - init_msg_prefix(_default_settings.msg_prefix); - init_cmd_name(_default_settings.cmd_name); + archive_enable(cmd->current_settings.archive); + backup_enable(cmd->current_settings.backup); - archive_enable(settings->archive); - backup_enable(settings->backup); + set_activation(cmd->current_settings.activation); - cmd->fmt = arg_ptr_value(cmd, metadatatype_ARG, settings->fmt); + cmd->fmt = arg_ptr_value(cmd, metadatatype_ARG, + cmd->current_settings.fmt); } -static char *_copy_command_line(struct pool *mem, int argc, char **argv) +static char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv) { int i; @@ -720,59 +624,68 @@ static char *_copy_command_line(struct pool *mem, int argc, char **argv) /* * Terminate. */ - if (!pool_grow_object(mem, "\0", 1)) + if (!pool_grow_object(cmd->mem, "\0", 1)) goto bad; - return pool_end_object(mem); + return pool_end_object(cmd->mem); bad: log_err("Couldn't copy command line."); - pool_abandon_object(mem); + pool_abandon_object(cmd->mem); return NULL; } -static int run_command(int argc, char **argv) +static int _run_command(struct cmd_context *cmd, int argc, char **argv) { int ret = 0; int locking_type; - if (!(cmd->cmd_line = _copy_command_line(cmd->mem, argc, argv))) + if (!(cmd->cmd_line = _copy_command_line(cmd, argc, argv))) return ECMD_FAILED; - if (!(cmd->command = find_command(argv[0]))) + if (!(cmd->command = _find_command(argv[0]))) return ENO_SUCH_CMD; - if (!process_command_line(cmd->command, &argc, &argv)) { + if (!_process_command_line(cmd, &argc, &argv)) { log_error("Error during parsing of command line."); return EINVALID_CMD_LINE; } set_cmd_name(cmd->command->name); - if ((ret = process_common_commands(cmd->command))) - return ret; + if (reload_config_file(&cmd->cf)) { + ; + /* FIXME Reinitialise various settings inc. logging, filters */ + } - _use_settings(&_current_settings); + if ((ret = _get_settings(cmd))) + goto out; + _apply_settings(cmd); + + if ((ret = _process_common_commands(cmd))) + goto out; locking_type = find_config_int(cmd->cf->root, "global/locking_type", '/', 1); if (!init_locking(locking_type, cmd->cf)) { log_error("Locking type %d initialisation failed.", locking_type); - return 0; + ret = ECMD_FAILED; + goto out; } ret = cmd->command->fn(cmd, argc, argv); fin_locking(); - /* - * set the debug and verbose levels back - * to the global default. We have to do - * this so the logging levels get set - * correctly for program exit. - */ - _use_settings(&_default_settings); + out: + if (test_mode()) { + log_verbose("Test mode: Wiping internal cache"); + cache_destroy(); + } + + cmd->current_settings = cmd->default_settings; + _apply_settings(cmd); /* * free off any memory the command used. @@ -785,7 +698,7 @@ static int run_command(int argc, char **argv) return ret; } -static int split(char *str, int *argc, char **argv, int max) +static int _split(char *str, int *argc, char **argv, int max) { char *b = str, *e; *argc = 0; @@ -818,62 +731,13 @@ static void _init_rand(void) srand((unsigned int) time(NULL) + (unsigned int) getpid()); } -static void __init_log(struct config_file *cf) -{ - char *open_mode = "a"; - - const char *log_file; - - _default_settings.syslog = - find_config_int(cf->root, "log/syslog", '/', 1); - if (_default_settings.syslog != 1) - fin_syslog(); - - if (_default_settings.syslog > 1) - init_syslog(_default_settings.syslog); - - _default_settings.debug = - find_config_int(cf->root, "log/level", '/', 0); - init_debug(_default_settings.debug); - - _default_settings.verbose = - find_config_int(cf->root, "log/verbose", '/', 0); - init_verbose(_default_settings.verbose); - - init_indent(find_config_int(cf->root, "log/indent", '/', 1)); - - _default_settings.msg_prefix = find_config_str(cf->root, "log/prefix", - '/', DEFAULT_MSG_PREFIX); - init_msg_prefix(_default_settings.msg_prefix); - - _default_settings.cmd_name = find_config_int(cf->root, - "log/command_names", '/', - DEFAULT_CMD_NAME); - init_cmd_name(_default_settings.cmd_name); - - _default_settings.test = find_config_int(cf->root, "global/test", - '/', 0); - if (find_config_int(cf->root, "log/overwrite", '/', 0)) - open_mode = "w"; - - log_file = find_config_str(cf->root, "log/file", '/', 0); - if (log_file) { - /* set up the logging */ - if (!(_log = fopen(log_file, open_mode))) - log_error("Couldn't open log file %s", log_file); - else - init_log(_log); - } - -} - -static int _init_backup(struct config_file *cf) +static int _init_backup(struct cmd_context *cmd, struct config_tree *cf) { int days, min; char default_dir[PATH_MAX]; const char *dir; - if (!_sys_dir) { + if (!cmd->sys_dir) { log_warn("WARNING: Metadata changes will NOT be backed up"); backup_init(""); archive_init("", 0, 0); @@ -881,7 +745,7 @@ static int _init_backup(struct config_file *cf) } /* set up archiving */ - _default_settings.archive = + cmd->default_settings.archive = find_config_bool(cmd->cf->root, "backup/archive", '/', DEFAULT_ARCHIVE_ENABLED); @@ -891,10 +755,11 @@ static int _init_backup(struct config_file *cf) min = find_config_int(cmd->cf->root, "backup/retain_min", '/', DEFAULT_ARCHIVE_NUMBER); - if (lvm_snprintf(default_dir, sizeof(default_dir), "%s/%s", _sys_dir, - DEFAULT_ARCHIVE_SUBDIR) == -1) { + if (lvm_snprintf + (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir, + DEFAULT_ARCHIVE_SUBDIR) == -1) { log_err("Couldn't create default archive path '%s/%s'.", - _sys_dir, DEFAULT_ARCHIVE_SUBDIR); + cmd->sys_dir, DEFAULT_ARCHIVE_SUBDIR); return 0; } @@ -907,14 +772,15 @@ static int _init_backup(struct config_file *cf) } /* set up the backup */ - _default_settings.backup = + cmd->default_settings.backup = find_config_bool(cmd->cf->root, "backup/backup", '/', DEFAULT_BACKUP_ENABLED); - if (lvm_snprintf(default_dir, sizeof(default_dir), "%s/%s", _sys_dir, - DEFAULT_BACKUP_SUBDIR) == -1) { + if (lvm_snprintf + (default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir, + DEFAULT_BACKUP_SUBDIR) == -1) { log_err("Couldn't create default backup path '%s/%s'.", - _sys_dir, DEFAULT_BACKUP_SUBDIR); + cmd->sys_dir, DEFAULT_BACKUP_SUBDIR); return 0; } @@ -929,269 +795,26 @@ static int _init_backup(struct config_file *cf) return 1; } -static int dev_cache_setup(struct config_file *cf) -{ - struct config_node *cn; - struct config_value *cv; - - if (!dev_cache_init()) { - stack; - return 0; - } - - if (!(cn = find_config_node(cf->root, "devices/scan", '/'))) { - if (!dev_cache_add_dir("/dev")) { - log_error("Failed to add /dev to internal " - "device cache"); - return 0; - } - log_verbose - ("device/scan not in config file: Defaulting to /dev"); - return 1; - } - - for (cv = cn->v; cv; cv = cv->next) { - if (cv->type != CFG_STRING) { - log_error("Invalid string in config file: " - "devices/scan"); - return 0; - } - - if (!dev_cache_add_dir(cv->v.str)) { - log_error("Failed to add %s to internal device cache", - cv->v.str); - return 0; - } - } - - return 1; -} - -static struct dev_filter *filter_components_setup(struct config_file *cf) -{ - struct config_node *cn; - struct dev_filter *f1, *f2, *f3; - - if (!(f2 = lvm_type_filter_create(_proc_dir))) - return 0; - - if (!(cn = find_config_node(cf->root, "devices/filter", '/'))) { - log_debug("devices/filter not found in config file: no regex " - "filter installed"); - return f2; - } - - if (!(f1 = regex_filter_create(cn->v))) { - log_error("Failed to create regex device filter"); - return f2; - } - - if (!(f3 = composite_filter_create(2, f1, f2))) { - log_error("Failed to create composite device filter"); - return f2; - } - - return f3; -} - -static struct dev_filter *filter_setup(struct config_file *cf) -{ - const char *lvm_cache; - struct dev_filter *f3, *f4; - struct stat st; - char cache_file[PATH_MAX]; - - _dump_filter = 0; - - if (!(f3 = filter_components_setup(cmd->cf))) - return 0; - - if (lvm_snprintf(cache_file, sizeof(cache_file), - "%s/.cache", _sys_dir) < 0) { - log_error("Persistent cache filename too long ('%s/.cache').", - _sys_dir); - return 0; - } - - lvm_cache = find_config_str(cf->root, "devices/cache", '/', cache_file); - - if (!(f4 = persistent_filter_create(f3, lvm_cache))) { - log_error("Failed to create persistent device filter"); - return 0; - } - - /* Should we ever dump persistent filter state? */ - if (find_config_int(cf->root, "devices/write_cache_state", '/', 1)) - _dump_filter = 1; - - if (!*_sys_dir) - _dump_filter = 0; - - if (!stat(lvm_cache, &st) && !persistent_filter_load(f4)) - log_verbose("Failed to load existing device cache from %s", - lvm_cache); - - return f4; -} - -static struct uuid_map *_init_uuid_map(struct dev_filter *filter) -{ - label_init(); - - /* add in the lvm1 labeller */ - if (!(_lvm1_label = lvm1_labeller_create())) { - log_err("Couldn't create lvm1 label handler."); - return 0; - } - - if (!(label_register_handler("lvm1", _lvm1_label))) { - log_err("Couldn't register lvm1 label handler."); - return 0; - } - - return uuid_map_create(filter); -} - -static void _exit_uuid_map(void) -{ - uuid_map_destroy(cmd->um); - label_exit(); - _lvm1_label->ops->destroy(_lvm1_label); - _lvm1_label = NULL; -} - -static int _get_env_vars(void) -{ - const char *e; - - /* Set to "" to avoid using any system directory */ - if ((e = getenv("LVM_SYSTEM_DIR"))) { - if (lvm_snprintf(_sys_dir, sizeof(_sys_dir), "%s", e) < 0) { - log_error("LVM_SYSTEM_DIR environment variable " - "is too long."); - return 0; - } - } - - return 1; -} - -static int init(void) +static struct cmd_context *_init(void) { - struct stat info; - char config_file[PATH_MAX] = ""; - const char *format; - mode_t old_umask; - - if (!setlocale(LC_ALL, "")) - log_error("setlocale failed"); - - if (!_get_env_vars()) - return 0; + struct cmd_context *cmd; - /* Create system directory if it doesn't already exist */ - if (!create_dir(_sys_dir)) - return 0; - - if (!(cmd = dbg_malloc(sizeof(*cmd)))) { - log_error("Failed to allocate command context"); - return 0; - } - - cmd->args = &the_args[0]; - - if (!(cmd->cf = create_config_file())) { + if (!(cmd = create_toolcontext(&the_args[0]))) { stack; - return 0; + return NULL; } - /* Use LOG_USER for syslog messages by default */ - init_syslog(LOG_USER); - _init_rand(); - if (*_sys_dir && lvm_snprintf(config_file, sizeof(config_file), - "%s/lvm.conf", _sys_dir) < 0) { - log_error("lvm_sys_dir was too long"); - return 0; - } - - if (stat(config_file, &info) != -1 && - !read_config(cmd->cf, config_file)) { - log_error("Failed to load config file %s", config_file); - return 0; - } - - __init_log(cmd->cf); - - _default_settings.umask = find_config_int(cmd->cf->root, - "global/umask", '/', - DEFAULT_UMASK); - - if ((old_umask = umask((mode_t) _default_settings.umask)) != - (mode_t) _default_settings.umask) - log_verbose("Set umask to %04o", _default_settings.umask); - - if (lvm_snprintf(_dev_dir, sizeof(_dev_dir), "%s/", - find_config_str(cmd->cf->root, "devices/dir", - '/', DEFAULT_DEV_DIR)) < 0) { - log_error("Device directory given in config file too long"); - return 0; - } - - cmd->dev_dir = _dev_dir; - dm_set_dev_dir(cmd->dev_dir); - - dm_log_init(print_log); - - if (lvm_snprintf(_proc_dir, sizeof(_proc_dir), "%s", - find_config_str(cmd->cf->root, "global/proc", - '/', DEFAULT_PROC_DIR)) < 0) { - log_error("Device directory given in config file too long"); - return 0; - } + if (!_init_backup(cmd, cmd->cf)) + return NULL; - if (!_init_backup(cmd->cf)) - return 0; + _apply_settings(cmd); - if (!dev_cache_setup(cmd->cf)) - return 0; - - if (!(cmd->filter = filter_setup(cmd->cf))) { - log_error("Failed to set up internal device filters"); - return 0; - } - - /* the uuid map uses the filter */ - if (!(cmd->um = _init_uuid_map(cmd->filter))) { - log_err("Failed to set up the uuid map."); - return 0; - } - - if (!(cmd->mem = pool_create(4 * 1024))) { - log_error("Command pool creation failed"); - return 0; - } - - /* FIXME Replace with list, dynamic libs etc. */ - if (!(cmd->fmt1 = create_lvm1_format(cmd))) - return 0; - - if (!(cmd->fmtt = create_text_format(cmd))) - return 0; - - format = find_config_str(cmd->cf->root, "global/format", '/', - DEFAULT_FORMAT); - if (!strcasecmp(format, "text")) - _default_settings.fmt = cmd->fmtt; - else /* "lvm1" */ - _default_settings.fmt = cmd->fmt1; - - _use_settings(&_default_settings); - return 1; + return cmd; } -static void __fin_commands(void) +static void _fin_commands(struct cmd_context *cmd) { int i; @@ -1201,33 +824,16 @@ static void __fin_commands(void) dbg_free(_commands); } -static void fin(void) +static void _fin(struct cmd_context *cmd) { - if (_dump_filter) - persistent_filter_dump(cmd->filter); - - cmd->fmt1->ops->destroy(cmd->fmt1); - cmd->fmtt->ops->destroy(cmd->fmtt); - cmd->filter->destroy(cmd->filter); - pool_destroy(cmd->mem); - vgcache_destroy(); - dev_cache_exit(); - destroy_config_file(cmd->cf); archive_exit(); backup_exit(); - _exit_uuid_map(); - dbg_free(cmd); - __fin_commands(); + _fin_commands(cmd); - dump_memory(); - fin_log(); - fin_syslog(); - - if (_log) - fclose(_log); + destroy_toolcontext(cmd); } -static int run_script(int argc, char **argv) +static int _run_script(struct cmd_context *cmd, int argc, char **argv) { FILE *script; @@ -1253,7 +859,7 @@ static int run_script(int argc, char **argv) ret = EINVALID_CMD_LINE; break; } - if (split(buffer, &argc, argv, MAX_ARGS) == MAX_ARGS) { + if (_split(buffer, &argc, argv, MAX_ARGS) == MAX_ARGS) { buffer[50] = '\0'; log_error("Too many arguments: %s", buffer); ret = EINVALID_CMD_LINE; @@ -1263,7 +869,7 @@ static int run_script(int argc, char **argv) continue; if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) break; - run_command(argc, argv); + _run_command(cmd, argc, argv); } fclose(script); @@ -1337,7 +943,7 @@ static char *_list_args(const 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)) @@ -1394,7 +1000,7 @@ static int _hist_file(char *buffer, size_t size) return 1; } -static void _read_history(void) +static void _read_history(struct cmd_context *cmd) { char hist_file[PATH_MAX]; @@ -1420,7 +1026,7 @@ static void _write_history(void) log_very_verbose("Couldn't write history to %s.", hist_file); } -static int shell(void) +static int _shell(struct cmd_context *cmd) { int argc, ret; char *input = NULL, *args[MAX_ARGS], **argv; @@ -1428,7 +1034,7 @@ static int shell(void) rl_readline_name = "lvm"; rl_attempted_completion_function = (CPPFunction *) _completion; - _read_history(); + _read_history(cmd); _interactive = 1; while (1) { @@ -1449,7 +1055,7 @@ static int shell(void) argv = args; - if (split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) { + if (_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) { log_error("Too many arguments, sorry."); continue; } @@ -1468,14 +1074,65 @@ static int shell(void) break; } - ret = run_command(argc, argv); + ret = _run_command(cmd, argc, argv); if (ret == ENO_SUCH_CMD) log_error("No such command '%s'. Try 'help'.", argv[0]); + + _write_history(); } - _write_history(); free(input); return 0; } + #endif + +int main(int argc, char **argv) +{ + char *namebase, *base; + int ret, alias = 0; + struct cmd_context *cmd; + + if (!(cmd = _init())) + return -1; + + namebase = strdup(argv[0]); + base = basename(namebase); + while (*base == '/') + base++; + if (strcmp(base, "lvm")) + alias = 1; + free(namebase); + + _register_commands(); + +#ifdef READLINE_SUPPORT + if (!alias && argc == 1) { + ret = _shell(cmd); + goto out; + } +#endif + + if (!alias) { + if (argc < 2) { + log_fatal("Please supply an LVM command."); + _display_help(); + ret = EINVALID_CMD_LINE; + goto out; + } + + argc--; + argv++; + } + + ret = _run_command(cmd, argc, argv); + if ((ret == ENO_SUCH_CMD) && (!alias)) + ret = _run_script(cmd, argc, argv); + if (ret == ENO_SUCH_CMD) + log_error("No such command. Try 'help'."); + + out: + _fin(cmd); + return ret; +} diff --git a/tools/lvmdiskscan.c b/tools/lvmdiskscan.c index c573517a..e65f80af 100644 --- a/tools/lvmdiskscan.c +++ b/tools/lvmdiskscan.c @@ -29,7 +29,7 @@ int lvmdiskscan(struct cmd_context *cmd, int argc, char **argv) uint64_t size; struct dev_iter *iter; struct device *dev; - struct physical_volume *pv; + struct label *label; if (arg_count(cmd, lvmpartition_ARG)) log_print("WARNING: only considering LVM devices"); @@ -44,7 +44,7 @@ int lvmdiskscan(struct cmd_context *cmd, int argc, char **argv) /* Do scan */ for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) { /* Try if it is a PV first */ - if ((pv = pv_read(cmd, dev_name(dev)))) { + if ((label_read(dev, &label))) { if (!dev_get_size(dev, &size)) { log_error("Couldn't get size of \"%s\"", dev_name(dev)); diff --git a/tools/lvremove.c b/tools/lvremove.c index 0e93866e..a41c1e59 100644 --- a/tools/lvremove.c +++ b/tools/lvremove.c @@ -20,22 +20,8 @@ #include "tools.h" -static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv); - -int lvremove(struct cmd_context *cmd, int argc, char **argv) -{ - if (!argc) { - log_error("Please enter one or more logical volume paths"); - return EINVALID_CMD_LINE; - } - - if (!driver_is_loaded()) - return ECMD_FAILED; - - return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvremove_single); -} - -static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv) +static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv, + void *handle) { struct volume_group *vg; struct dm_info info; @@ -95,7 +81,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv) } /* store it on disks */ - if (vg_write(vg)) + if (!vg_write(vg)) return ECMD_FAILED; backup(vg); @@ -103,3 +89,14 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv) log_print("Logical volume \"%s\" successfully removed", lv->name); return 0; } + +int lvremove(struct cmd_context *cmd, int argc, char **argv) +{ + if (!argc) { + log_error("Please enter one or more logical volume paths"); + return EINVALID_CMD_LINE; + } + + return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL, + &lvremove_single); +} diff --git a/tools/lvrename.c b/tools/lvrename.c index e84e3c91..b061abd8 100644 --- a/tools/lvrename.c +++ b/tools/lvrename.c @@ -26,6 +26,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv) char *lv_name_old, *lv_name_new; char *vg_name, *vg_name_new, *vg_name_old; char *st; + int consistent = 1; struct volume_group *vg; struct logical_volume *lv; @@ -53,7 +54,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } - if (!is_valid_chars(vg_name)) { + if (!validate_vgname(vg_name)) { log_error("Please provide a valid volume group name"); return EINVALID_CMD_LINE; } @@ -86,7 +87,14 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!is_valid_chars(lv_name_new)) { + /* FIXME Remove this restriction eventually */ + if (!strncmp(lv_name_new, "snapshot", 8)) { + log_error("Names starting \"snapshot\" are reserved. " + "Please choose a different LV name."); + return ECMD_FAILED; + } + + if (!validate_vgname(lv_name_new)) { log_error ("New logical volume name \"%s\" has invalid characters", lv_name_new); @@ -98,9 +106,6 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } - if (!driver_is_loaded()) - return ECMD_FAILED; - log_verbose("Checking for existing volume group \"%s\"", vg_name); if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { @@ -108,7 +113,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!(vg = vg_read(cmd, vg_name))) { + if (!(vg = vg_read(cmd, vg_name, &consistent))) { log_error("Volume group \"%s\" doesn't exist", vg_name); goto error; } diff --git a/tools/lvresize.c b/tools/lvresize.c index 974c29b8..b058d8f5 100644 --- a/tools/lvresize.c +++ b/tools/lvresize.c @@ -39,6 +39,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) struct list *pvh, *segh; struct lv_list *lvl; int opt = 0; + int consistent = 1; enum { LV_ANY = 0, @@ -94,9 +95,6 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) if ((st = strrchr(lv_name, '/'))) lv_name = st + 1; - if (!driver_is_loaded()) - return ECMD_FAILED; - /* does VG exist? */ log_verbose("Finding volume group %s", vg_name); if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { @@ -104,7 +102,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!(vg = vg_read(cmd, vg_name))) { + if (!(vg = vg_read(cmd, vg_name, &consistent))) { log_error("Volume group %s doesn't exist", vg_name); goto error; } @@ -193,10 +191,10 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) if (extents > lv->le_count && !(stripes == 1 || (stripes > 1 && stripesize))) { list_iterate(segh, &lv->segments) { - struct stripe_segment *seg; + struct lv_segment *seg; uint32_t sz, str; - seg = list_item(segh, struct stripe_segment); + seg = list_item(segh, struct lv_segment); sz = seg->stripe_size; str = seg->stripes; @@ -237,10 +235,10 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) "when reducing"); list_iterate(segh, &lv->segments) { - struct stripe_segment *seg; + struct lv_segment *seg; uint32_t seg_extents; - seg = list_item(segh, struct stripe_segment); + seg = list_item(segh, struct lv_segment); seg_extents = seg->len; seg_stripesize = seg->stripe_size; @@ -261,7 +259,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv) log_error("Stripesize for striped segment should not be 0!"); goto error_cmdline; } - + if ((stripes > 1)) { if (!(stripesize_extents = stripesize / vg->extent_size)) stripesize_extents = 1; diff --git a/tools/lvscan.c b/tools/lvscan.c index 044e2e6b..d0449288 100644 --- a/tools/lvscan.c +++ b/tools/lvscan.c @@ -20,41 +20,8 @@ #include "tools.h" -static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv); - -int lvscan(struct cmd_context *cmd, int argc, char **argv) -{ - if (argc) { - log_error("No additional command line arguments allowed"); - return EINVALID_CMD_LINE; - } - - return process_each_lv(cmd, argc, argv, LCK_VG_READ, &lvscan_single); - -/*********** FIXME Count! Add private struct to process_each* -* if (!lv_total) -* log_print("no logical volumes found"); -* else { -* log_print -* ("%d logical volumes with %s total in %d volume group%s", -* lv_total, (dummy = -* display_size(lv_capacity_total / 2, SIZE_SHORT)), -* vg_total, vg_total == 1 ? "" : "s"); -* dbg_free(dummy); -* dummy = NULL; -* if (lv_active > 0) -* printf("%d active", lv_active); -* if (lv_active > 0 && lv_total - lv_active > 0) -* printf(" / "); -* if (lv_total - lv_active > 0) -* printf("%d inactive", lv_total - lv_active); -* printf(" logical volumes\n"); -* } -*************/ - -} - -static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv) +static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv, + void *handle) { struct dm_info info; int lv_total = 0; @@ -63,7 +30,6 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv) char *dummy; const char *active_str, *snapshot_str; -/* FIXME Add -D arg to skip this! */ if (lv_info(lv, &info) && info.exists) active_str = "ACTIVE "; else @@ -76,48 +42,28 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv) else snapshot_str = " "; -/********** FIXME Snapshot - if (lv->status & SNAPSHOT) - dummy = - display_size(lv->lv_remap_end * - lv->lv_chunk_size / 2, - SIZE_SHORT); - else -***********/ dummy = display_size(lv->size / 2, SIZE_SHORT); - log_print("%s%s '%s%s/%s' [%s]%s", active_str, snapshot_str, + log_print("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str, cmd->dev_dir, lv->vg->name, lv->name, dummy, get_alloc_string(lv->alloc)); dbg_free(dummy); - /* FIXME sprintf? */ - -/*********** FIXME Handle segments? - if (lv->segments[0]->stripes > 1 && !(lv->status & SNAPSHOT)) - log_print(" striped[%u]", lv->segments[0]->stripes); -****************/ - -/******** FIXME Device number display & Snapshot - if (arg_count(cmd,blockdevice_ARG)) - printf(" %d:%d", - MAJOR(lv->lv_dev), - MINOR(lv->lv_dev)); - else - if (lv->status & SNAPSHOT) - printf(" of %s", lv->lv_snapshot_org->name); -*****************/ - lv_total++; -/******** FIXME Snapshot - if (lv->status & SNAPSHOT) - lv_capacity_total += - lv->lv_remap_end * lv->lv_chunk_size - else -********/ lv_capacity_total += lv->size; return 0; } + +int lvscan(struct cmd_context *cmd, int argc, char **argv) +{ + if (argc) { + log_error("No additional command line arguments allowed"); + return EINVALID_CMD_LINE; + } + + return process_each_lv(cmd, argc, argv, LCK_VG_READ, NULL, + &lvscan_single); +} diff --git a/tools/pvchange.c b/tools/pvchange.c index b509f007..189c94d3 100644 --- a/tools/pvchange.c +++ b/tools/pvchange.c @@ -20,76 +20,19 @@ #include "tools.h" -int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv); +/* FIXME Locking. PVs in VG. */ -int pvchange(struct cmd_context *cmd, int argc, char **argv) -{ - int opt = 0; - int done = 0; - int total = 0; - - struct physical_volume *pv; - char *pv_name; - - struct list *pvh, *pvs; - - if (arg_count(cmd, allocatable_ARG) == 0) { - log_error("Please give the x option"); - return EINVALID_CMD_LINE; - } - - if (!(arg_count(cmd, all_ARG)) && !argc) { - log_error("Please give a physical volume path"); - return EINVALID_CMD_LINE; - } - - if (arg_count(cmd, all_ARG) && argc) { - log_error("Option a and PhysicalVolumePath are exclusive"); - return EINVALID_CMD_LINE; - } - - if (argc) { - log_verbose("Using physical volume(s) on command line"); - for (; opt < argc; opt++) { - pv_name = argv[opt]; - if (!(pv = pv_read(cmd, pv_name))) { - log_error - ("Failed to read physical volume \"%s\"", - pv_name); - continue; - } - total++; - done += pvchange_single(cmd, pv); - } - } else { - log_verbose("Scanning for physical volume names"); - if (!(pvs = get_pvs(cmd))) { - return ECMD_FAILED; - } - - list_iterate(pvh, pvs) { - total++; - done += pvchange_single(cmd, - list_item(pvh, - struct pv_list)->pv); - } - } - - log_print("%d physical volume%s changed / %d physical volume%s " - "not changed", - done, done > 1 ? "s" : "", - total - done, total - done > 1 ? "s" : ""); - - return 0; -} - -int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv) +int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv, + void *handle) { struct volume_group *vg = NULL; struct pv_list *pvl; + struct list mdas; + uint64_t sector; const char *pv_name = dev_name(pv->dev); + int consistent = 1; int allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"), "y"); @@ -103,7 +46,7 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv) return ECMD_FAILED; } - if (!(vg = vg_read(cmd, pv->vg_name))) { + if (!(vg = vg_read(cmd, pv->vg_name, &consistent))) { unlock_vg(cmd, pv->vg_name); log_error("Unable to find volume group of \"%s\"", pv_name); @@ -132,6 +75,18 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv) pv = pvl->pv; if (!archive(vg)) return 0; + } else { + if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) { + log_error("Can't get lock for orphans"); + return ECMD_FAILED; + } + + if (!(pv = pv_read(cmd, pv_name, &mdas, §or))) { + unlock_vg(cmd, ORPHAN); + log_error("Unable to read PV \"%s\"", pv_name); + return 0; + } + } /* change allocatability for a PV */ @@ -140,6 +95,8 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv) pv_name); if (*pv->vg_name) unlock_vg(cmd, pv->vg_name); + else + unlock_vg(cmd, ORPHAN); return 0; } @@ -148,6 +105,8 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv) pv_name); if (*pv->vg_name) unlock_vg(cmd, pv->vg_name); + else + unlock_vg(cmd, ORPHAN); return 0; } @@ -172,14 +131,82 @@ int pvchange_single(struct cmd_context *cmd, struct physical_volume *pv) backup(vg); unlock_vg(cmd, pv->vg_name); } else { - if (!(pv_write(cmd, pv))) { + if (!(pv_write(cmd, pv, &mdas, sector))) { + unlock_vg(cmd, ORPHAN); log_error("Failed to store physical volume \"%s\"", pv_name); return 0; } + unlock_vg(cmd, ORPHAN); } log_print("Physical volume \"%s\" changed", pv_name); return 1; } + +int pvchange(struct cmd_context *cmd, int argc, char **argv) +{ + int opt = 0; + int done = 0; + int total = 0; + + struct physical_volume *pv; + char *pv_name; + + struct list *pvh, *pvs; + struct list mdas; + + list_init(&mdas); + + if (arg_count(cmd, allocatable_ARG) == 0) { + log_error("Please give the x option"); + return EINVALID_CMD_LINE; + } + + if (!(arg_count(cmd, all_ARG)) && !argc) { + log_error("Please give a physical volume path"); + return EINVALID_CMD_LINE; + } + + if (arg_count(cmd, all_ARG) && argc) { + log_error("Option a and PhysicalVolumePath are exclusive"); + return EINVALID_CMD_LINE; + } + + if (argc) { + log_verbose("Using physical volume(s) on command line"); + for (; opt < argc; opt++) { + pv_name = argv[opt]; + /* FIXME Read VG instead - pv_read will fail */ + if (!(pv = pv_read(cmd, pv_name, &mdas, NULL))) { + log_error + ("Failed to read physical volume \"%s\"", + pv_name); + continue; + } + total++; + done += pvchange_single(cmd, pv, NULL); + } + } else { + log_verbose("Scanning for physical volume names"); + if (!(pvs = get_pvs(cmd))) { + return ECMD_FAILED; + } + + list_iterate(pvh, pvs) { + total++; + done += pvchange_single(cmd, + list_item(pvh, + struct pv_list)->pv, + NULL); + } + } + + log_print("%d physical volume%s changed / %d physical volume%s " + "not changed", + done, done > 1 ? "s" : "", + total - done, total - done > 1 ? "s" : ""); + + return 0; +} diff --git a/tools/pvcreate.c b/tools/pvcreate.c index 0cc1d95f..7ca11ede 100644 --- a/tools/pvcreate.c +++ b/tools/pvcreate.c @@ -19,6 +19,7 @@ */ #include "tools.h" +#include "defaults.h" const char _really_init[] = "Really INITIALIZE physical volume \"%s\" of volume group \"%s\" [y/n]? "; @@ -39,7 +40,7 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name) } /* is there a pv here already */ - if (!(pv = pv_read(cmd, name))) + if (!(pv = pv_read(cmd, name, NULL, NULL))) return 1; /* orphan ? */ @@ -72,20 +73,28 @@ static int pvcreate_check(struct cmd_context *cmd, const char *name) return 1; } -static void pvcreate_single(struct cmd_context *cmd, const char *pv_name) +static void pvcreate_single(struct cmd_context *cmd, const char *pv_name, + void *handle) { - struct physical_volume *pv; - struct format_instance *fid; + struct physical_volume *pv, *existing_pv; struct id id, *idp = NULL; char *uuid; uint64_t size = 0; struct device *dev; + struct list mdas; + int pvmetadatacopies; + uint64_t pvmetadatasize; + struct volume_group *vg; + char *restorefile; + uint64_t pe_start = 0; + uint32_t extent_count = 0, extent_size = 0; if (arg_count(cmd, uuidstr_ARG)) { uuid = arg_str_value(cmd, uuidstr_ARG, ""); if (!id_read_format(&id, uuid)) return; - if ((dev = uuid_map_lookup(cmd->um, &id))) { + if ((dev = device_from_pvid(cmd, &id)) && + (dev != dev_cache_get(pv_name, cmd->filter))) { log_error("uuid %s already in use on \"%s\"", uuid, dev_name(dev)); return; @@ -93,32 +102,84 @@ static void pvcreate_single(struct cmd_context *cmd, const char *pv_name) idp = &id; } - if (!pvcreate_check(cmd, pv_name)) + if (arg_count(cmd, restorefile_ARG)) { + restorefile = arg_str_value(cmd, restorefile_ARG, ""); + /* The uuid won't already exist */ + init_partial(1); + if (!(vg = backup_read_vg(cmd, NULL, restorefile))) { + log_error("Unable to read volume group from %s", + restorefile); + return; + } + init_partial(0); + if (!(existing_pv = find_pv_in_vg_by_uuid(vg, idp))) { + log_error("Can't find uuid %s in backup file %s", + uuid, restorefile); + return; + } + pe_start = existing_pv->pe_start; + extent_size = existing_pv->pe_size; + extent_count = existing_pv->pe_count; + } + + if (!lock_vol(cmd, "", LCK_VG_WRITE)) { + log_error("Can't get lock for orphan PVs"); return; + } + + if (!pvcreate_check(cmd, pv_name)) + goto error; size = arg_int64_value(cmd, physicalvolumesize_ARG, 0) * 2; - /* FIXME Use config file/cmd line to specify format */ - if (!(fid = cmd->fmt1->ops->create_instance(cmd->fmt1, NULL, NULL))) { - log_error("Failed to create format1 instance"); - return; + pvmetadatasize = arg_int64_value(cmd, metadatasize_ARG, 0) * 2; + if (!pvmetadatasize) + pvmetadatasize = find_config_int(cmd->cf->root, + "metadata/pvmetadatasize", + '/', DEFAULT_PVMETADATASIZE); + + pvmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, -1); + if (pvmetadatacopies < 0) + pvmetadatacopies = find_config_int(cmd->cf->root, + "metadata/pvmetadatacopies", + '/', + DEFAULT_PVMETADATACOPIES); + + if (!(dev = dev_cache_get(pv_name, cmd->filter))) { + log_error("%s: Couldn't find device.", pv_name); + goto error; } - if (!(pv = pv_create(fid, pv_name, idp, size))) { + + list_init(&mdas); + if (!(pv = pv_create(cmd->fmt, dev, idp, size, pe_start, + extent_count, extent_size, + pvmetadatacopies, pvmetadatasize, &mdas))) { log_error("Failed to setup physical volume \"%s\"", pv_name); - return; + goto error; } log_verbose("Set up physical volume for \"%s\" with %" PRIu64 - " sectors", pv_name, pv->size); + " available sectors", pv_name, pv->size); + + /* Wipe existing label first */ + if (!label_remove(pv->dev)) { + log_error("Failed to wipe existing label on %s", pv_name); + goto error; + } log_very_verbose("Writing physical volume data to disk \"%s\"", pv_name); - if (!(pv_write(cmd, pv))) { + if (!(pv_write(cmd, pv, &mdas, arg_int_value(cmd, labelsector_ARG, + DEFAULT_LABELSECTOR)))) { log_error("Failed to write physical volume \"%s\"", pv_name); - return; + goto error; } log_print("Physical volume \"%s\" successfully created", pv_name); + + error: + unlock_vg(cmd, ""); + return; } int pvcreate(struct cmd_context *cmd, int argc, char **argv) @@ -130,6 +191,11 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } + if (arg_count(cmd, restorefile_ARG) && !arg_count(cmd, uuidstr_ARG)) { + log_error("--uuid is required with --restorefile"); + return EINVALID_CMD_LINE; + } + if (arg_count(cmd, uuidstr_ARG) && argc != 1) { log_error("Can only set uuid on one volume at once"); return EINVALID_CMD_LINE; @@ -140,8 +206,27 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } + if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) { + log_error("labelsector must be less than %lu", + LABEL_SCAN_SECTORS); + return EINVALID_CMD_LINE; + } + + if (!(cmd->fmt->features & FMT_MDAS) && + (arg_count(cmd, metadatacopies_ARG) || + arg_count(cmd, metadatasize_ARG))) { + log_error("Metadata parameters only apply to text format"); + return EINVALID_CMD_LINE; + } + + if (arg_count(cmd, metadatacopies_ARG) && + arg_int_value(cmd, metadatacopies_ARG, -1) > 2) { + log_error("Metadatacopies may only be 0, 1 or 2"); + return EINVALID_CMD_LINE; + } + for (i = 0; i < argc; i++) { - pvcreate_single(cmd, argv[i]); + pvcreate_single(cmd, argv[i], NULL); pool_empty(cmd->mem); } diff --git a/tools/pvdisplay.c b/tools/pvdisplay.c index b526cc9b..ff4d121a 100644 --- a/tools/pvdisplay.c +++ b/tools/pvdisplay.c @@ -20,44 +20,8 @@ #include "tools.h" -void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv); - -int pvdisplay(struct cmd_context *cmd, int argc, char **argv) -{ - int opt = 0; - - struct list *pvh, *pvs; - struct physical_volume *pv; - - if (arg_count(cmd, colon_ARG) && arg_count(cmd, maps_ARG)) { - log_error("Option -v not allowed with option -c"); - return EINVALID_CMD_LINE; - } - - if (argc) { - log_very_verbose("Using physical volume(s) on command line"); - - for (; opt < argc; opt++) { - if (!(pv = pv_read(cmd, argv[opt]))) { - log_error("Failed to read physical " - "volume \"%s\"", argv[opt]); - continue; - } - pvdisplay_single(cmd, pv); - } - } else { - log_verbose("Scanning for physical volume names"); - if (!(pvs = get_pvs(cmd))) - return ECMD_FAILED; - - list_iterate(pvh, pvs) - pvdisplay_single(cmd, list_item(pvh, struct pv_list)->pv); - } - - return 0; -} - -void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv) +void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv, + void *handle) { char *sz; uint64_t size; @@ -80,50 +44,57 @@ void pvdisplay_single(struct cmd_context *cmd, struct physical_volume *pv) log_print("Physical volume \"%s\" of volume group \"%s\" " "is exported", pv_name, pv->vg_name); -/********* FIXME - log_error("no physical volume identifier on \"%s\"" , pv_name); -*********/ - if (!pv->vg_name) { log_print("\"%s\" is a new physical volume of \"%s\"", pv_name, (sz = display_size(size / 2, SIZE_SHORT))); dbg_free(sz); } -/* FIXME: Check active - no point? - log_very_verbose("checking physical volume activity" ); - pv_check_active ( pv->vg_name, pv->pv_name) - pv_status ( pv->vg_name, pv->pv_name, &pv) -*/ - -/* FIXME: Check consistency - do this when reading metadata BUT trigger mesgs - log_very_verbose("checking physical volume consistency" ); - ret = pv_check_consistency (pv) -*/ - if (arg_count(cmd, colon_ARG)) { pvdisplay_colons(pv); return; } - pvdisplay_full(pv); + pvdisplay_full(pv, handle); if (!arg_count(cmd, maps_ARG)) return; -/******* FIXME - if (pv->pe_alloc_count) { - if (!(pv->pe = pv_read_pe(pv_name, pv))) - goto pvdisplay_device_out; - if (!(lvs = pv_read_lvs(pv))) { - log_error("Failed to read LVs on \"%s\"", pv->pv_name); - goto pvdisplay_device_out; + return; +} + +int pvdisplay(struct cmd_context *cmd, int argc, char **argv) +{ + int opt = 0; + + struct list *pvh, *pvs; + struct physical_volume *pv; + + if (arg_count(cmd, colon_ARG) && arg_count(cmd, maps_ARG)) { + log_error("Option -v not allowed with option -c"); + return EINVALID_CMD_LINE; + } + + if (argc) { + log_very_verbose("Using physical volume(s) on command line"); + + for (; opt < argc; opt++) { + if (!(pv = pv_read(cmd, argv[opt], NULL, NULL))) { + log_error("Failed to read physical " + "volume \"%s\"", argv[opt]); + continue; + } + pvdisplay_single(cmd, pv, NULL); } - pv_display_pe_text(pv, pv->pe, lvs); - } else - log_print("no logical volume on physical volume \"%s\"", - pv_name); -**********/ + } else { + log_verbose("Scanning for physical volume names"); + if (!(pvs = get_pvs(cmd))) + return ECMD_FAILED; - return; + list_iterate(pvh, pvs) + pvdisplay_single(cmd, list_item(pvh, struct pv_list)->pv, + NULL); + } + + return 0; } diff --git a/tools/pvremove.c b/tools/pvremove.c new file mode 100644 index 00000000..3410378f --- /dev/null +++ b/tools/pvremove.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2002 Sistina Software + * + * pvcreate 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. + * + * pvcreate 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" +#include "defaults.h" + +const char _really_wipe[] = + "Really WIPE LABELS from physical volume \"%s\" of volume group \"%s\" [y/n]? "; + +/* + * Decide whether it is "safe" to wipe the labels on this device. + * 0 indicates we may not. + */ +static int pvremove_check(struct cmd_context *cmd, const char *name) +{ + struct physical_volume *pv; + + /* is the partition type set correctly ? */ + if ((arg_count(cmd, force_ARG) < 1) && !is_lvm_partition(name)) { + log_error("%s: Not LVM partition type: use -f to override", + name); + return 0; + } + + /* is there a pv here already */ + if (!(pv = pv_read(cmd, name, NULL, NULL))) + return 1; + + /* orphan ? */ + if (!pv->vg_name[0]) + return 1; + + /* Allow partial & exported VGs to be destroyed. */ + /* we must have -ff to overwrite a non orphan */ + if (arg_count(cmd, force_ARG) < 2) { + log_error("Can't pvremove physical volume \"%s\" of " + "volume group \"%s\" without -ff", name, pv->vg_name); + return 0; + } + + /* prompt */ + if (!arg_count(cmd, yes_ARG) && + yes_no_prompt(_really_wipe, name, pv->vg_name) == 'n') { + log_print("%s: physical volume label not removed", name); + return 0; + } + + if (arg_count(cmd, force_ARG)) { + log_print("WARNING: Wiping physical volume label from " + "%s%s%s%s", name, + pv->vg_name[0] ? " of volume group \"" : "", + pv->vg_name[0] ? pv->vg_name : "", + pv->vg_name[0] ? "\"" : ""); + } + + return 1; +} + +static void pvremove_single(struct cmd_context *cmd, const char *pv_name, + void *handle) +{ + struct device *dev; + + if (!lock_vol(cmd, "", LCK_VG_WRITE)) { + log_error("Can't get lock for orphan PVs"); + return; + } + + if (!pvremove_check(cmd, pv_name)) + goto error; + + if (!(dev = dev_cache_get(pv_name, cmd->filter))) { + log_error("%s: Couldn't find device.", pv_name); + goto error; + } + + /* Wipe existing label(s) */ + if (!label_remove(dev)) { + log_error("Failed to wipe existing label(s) on %s", pv_name); + goto error; + } + + log_print("Labels on physical volume \"%s\" successfully wiped", + pv_name); + + error: + unlock_vg(cmd, ""); + return; +} + +int pvremove(struct cmd_context *cmd, int argc, char **argv) +{ + int i; + + if (!argc) { + log_error("Please enter a physical volume path"); + return EINVALID_CMD_LINE; + } + + if (arg_count(cmd, yes_ARG) && !arg_count(cmd, force_ARG)) { + log_error("Option y can only be given with option f"); + return EINVALID_CMD_LINE; + } + + for (i = 0; i < argc; i++) { + pvremove_single(cmd, argv[i], NULL); + pool_empty(cmd->mem); + } + + return 0; +} diff --git a/tools/pvscan.c b/tools/pvscan.c index 868dea47..3f3b2f1b 100644 --- a/tools/pvscan.c +++ b/tools/pvscan.c @@ -20,11 +20,95 @@ #include "tools.h" -void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv); - int pv_max_name_len = 0; int vg_max_name_len = 0; +void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv, + void *handle) +{ + char uuid[64]; + int vg_name_len = 0; + + char *s1, *s2; + + char pv_tmp_name[NAME_LEN] = { 0, }; + char vg_tmp_name[NAME_LEN] = { 0, }; + char vg_name_this[NAME_LEN] = { 0, }; + + /* short listing? */ + if (arg_count(cmd, short_ARG) > 0) { + log_print("%s", dev_name(pv->dev)); + return; + } + + if (arg_count(cmd, verbose_ARG) > 1) { + /* FIXME As per pv_display! Drop through for now. */ + /* pv_show(pv); */ + + /* FIXME - Moved to Volume Group structure */ + /* log_print("System Id %s", pv->vg->system_id); */ + + /* log_print(" "); */ + /* return; */ + } + + memset(pv_tmp_name, 0, sizeof(pv_tmp_name)); + + vg_name_len = strlen(pv->vg_name) + 1; + + if (arg_count(cmd, uuid_ARG)) { + if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { + stack; + return; + } + + sprintf(pv_tmp_name, "%-*s with UUID %s", + pv_max_name_len - 2, dev_name(pv->dev), uuid); + } else { + sprintf(pv_tmp_name, "%s", dev_name(pv->dev)); + } + + if (!*pv->vg_name) { + log_print("PV %-*s %-*s %s [%s]", + pv_max_name_len, pv_tmp_name, + vg_max_name_len, " ", + pv->fmt ? pv->fmt->name : " ", + (s1 = display_size(pv->size / 2, SIZE_SHORT))); + dbg_free(s1); + return; + } + + if (pv->status & EXPORTED_VG) { + strncpy(vg_name_this, pv->vg_name, vg_name_len); + log_print("PV %-*s is in exported VG %s " + "[%s / %s free]", + pv_max_name_len, pv_tmp_name, + vg_name_this, (s1 = + display_size(pv->pe_count * + pv->pe_size / 2, + SIZE_SHORT)), + (s2 = display_size((pv->pe_count - pv->pe_alloc_count) + * pv->pe_size / 2, SIZE_SHORT))); + dbg_free(s1); + dbg_free(s2); + return; + } + + sprintf(vg_tmp_name, "%s", pv->vg_name); + log_print + ("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len, + pv_tmp_name, vg_max_name_len, vg_tmp_name, + pv->fmt ? pv->fmt->name : " ", + (s1 = display_size(pv->pe_count * pv->pe_size / 2, SIZE_SHORT)), + (s2 = + display_size((pv->pe_count - pv->pe_alloc_count) * pv->pe_size / + 2, SIZE_SHORT))); + dbg_free(s1); + dbg_free(s2); + + return; +} + int pvscan(struct cmd_context *cmd, int argc, char **argv) { int new_pvs_found = 0; @@ -56,6 +140,9 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv) log_verbose("Wiping cache of LVM-capable devices"); persistent_filter_wipe(cmd->filter); + log_verbose("Wiping internal cache"); + cache_destroy(); + log_verbose("Walking through all physical volumes"); if (!(pvs = get_pvs(cmd))) return ECMD_FAILED; @@ -108,7 +195,8 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv) vg_max_name_len += 2; list_iterate(pvh, pvs) - pvscan_display_single(cmd, list_item(pvh, struct pv_list)->pv); + pvscan_display_single(cmd, list_item(pvh, struct pv_list)->pv, + NULL); if (!pvs_found) { log_print("No matching physical volumes found"); @@ -128,87 +216,3 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv) return 0; } - -void pvscan_display_single(struct cmd_context *cmd, struct physical_volume *pv) -{ - char uuid[64]; - int vg_name_len = 0; - - char *s1, *s2; - - char pv_tmp_name[NAME_LEN] = { 0, }; - char vg_tmp_name[NAME_LEN] = { 0, }; - char vg_name_this[NAME_LEN] = { 0, }; - - /* short listing? */ - if (arg_count(cmd, short_ARG) > 0) { - log_print("%s", dev_name(pv->dev)); - return; - } - - if (arg_count(cmd, verbose_ARG) > 1) { - /* FIXME As per pv_display! Drop through for now. */ - /* pv_show(pv); */ - - /* FIXME - Moved to Volume Group structure */ - /* log_print("System Id %s", pv->vg->system_id); */ - - /* log_print(" "); */ - /* return; */ - } - - memset(pv_tmp_name, 0, sizeof(pv_tmp_name)); - - vg_name_len = strlen(pv->vg_name) + 1; - - if (arg_count(cmd, uuid_ARG)) { - if (!id_write_format(&pv->id, uuid, sizeof(uuid))) { - stack; - return; - } - - sprintf(pv_tmp_name, "%-*s with UUID %s", - pv_max_name_len - 2, dev_name(pv->dev), uuid); - } else { - sprintf(pv_tmp_name, "%s", dev_name(pv->dev)); - } - - if (!*pv->vg_name) { - log_print("PV %-*s %-*s [%s]", - pv_max_name_len, pv_tmp_name, - vg_max_name_len, " ", - (s1 = display_size(pv->size / 2, SIZE_SHORT))); - dbg_free(s1); - return; - } - - if (pv->status & EXPORTED_VG) { - strncpy(vg_name_this, pv->vg_name, vg_name_len); - log_print("PV %-*s is in exported VG %s " - "[%s / %s free]", - pv_max_name_len, pv_tmp_name, - vg_name_this, (s1 = - display_size(pv->pe_count * - pv->pe_size / 2, - SIZE_SHORT)), - (s2 = display_size((pv->pe_count - pv->pe_alloc_count) - * pv->pe_size / 2, SIZE_SHORT))); - dbg_free(s1); - dbg_free(s2); - return; - } - - sprintf(vg_tmp_name, "%s", pv->vg_name); - log_print - ("PV %-*s VG %-*s %s [%s / %s free]", pv_max_name_len, - pv_tmp_name, vg_max_name_len, vg_tmp_name, - pv->fid ? pv->fid->fmt->name : " ", - (s1 = display_size(pv->pe_count * pv->pe_size / 2, SIZE_SHORT)), - (s2 = - display_size((pv->pe_count - pv->pe_alloc_count) * pv->pe_size / - 2, SIZE_SHORT))); - dbg_free(s1); - dbg_free(s2); - - return; -} diff --git a/tools/stub.h b/tools/stub.h index 185535c0..8ffefe13 100644 --- a/tools/stub.h +++ b/tools/stub.h @@ -6,10 +6,10 @@ #define unimplemented \ { log_error("Command not implemented yet."); return ECMD_FAILED;} +/*int e2fsadm(struct cmd_context *cmd, int argc, char **argv) unimplemented*/ int lvmsadc(struct cmd_context *cmd, int argc, char **argv) unimplemented int lvmsar(struct cmd_context *cmd, int argc, char **argv) unimplemented int pvdata(struct cmd_context *cmd, int argc, char **argv) unimplemented int pvmove(struct cmd_context *cmd, int argc, char **argv) unimplemented int pvresize(struct cmd_context *cmd, int argc, char **argv) unimplemented int vgmknodes(struct cmd_context *cmd, int argc, char **argv) unimplemented - diff --git a/tools/toollib.c b/tools/toollib.c index 9b628ab0..917b4ff0 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -9,8 +9,10 @@ #include <sys/stat.h> int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, + void *handle, int (*process_single) (struct cmd_context * cmd, - struct logical_volume * lv)) + struct logical_volume * lv, + void *handle)) { int ret_max = 0; int ret = 0; @@ -25,7 +27,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, list_iterate(lvh, &vg->lvs) { lv = list_item(lvh, struct lv_list)->lv; - ret = process_single(cmd, lv); + ret = process_single(cmd, lv, handle); if (ret > ret_max) ret_max = ret; } @@ -34,94 +36,163 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, } +struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname, + int lock_type) +{ + int consistent = 1; + + lock_type &= ~LCK_TYPE_MASK; + lock_type |= LCK_WRITE; + + if (!lock_vol(cmd, vgname, lock_type)) { + log_error("Can't lock %s for metadata recovery: skipping", + vgname); + return NULL; + } + + return vg_read(cmd, vgname, &consistent); +} + int process_each_lv(struct cmd_context *cmd, int argc, char **argv, - int lock_type, + int lock_type, void *handle, int (*process_single) (struct cmd_context * cmd, - struct logical_volume * lv)) + struct logical_volume * lv, + void *handle)) { int opt = 0; int ret_max = 0; int ret = 0; int vg_count = 0; + int consistent; - struct list *vgh, *vgs; + struct list *slh, *vgnames; struct volume_group *vg; struct logical_volume *lv; struct lv_list *lvl; - char *vg_name; + char *vgname; if (argc) { log_verbose("Using logical volume(s) on command line"); for (; opt < argc; opt++) { char *lv_name = argv[opt]; - - /* does VG exist? */ - if (!(vg_name = extract_vgname(cmd, lv_name))) { - if (ret_max < ECMD_FAILED) - ret_max = ECMD_FAILED; - continue; + int vgname_provided = 1; + + /* Do we have a vgname or lvname? */ + vgname = lv_name; + if (!strncmp(vgname, cmd->dev_dir, + strlen(cmd->dev_dir))) + vgname += strlen(cmd->dev_dir); + if (strchr(vgname, '/')) { + /* Must be an LV */ + vgname_provided = 0; + if (!(vgname = extract_vgname(cmd, lv_name))) { + if (ret_max < ECMD_FAILED) + ret_max = ECMD_FAILED; + continue; + } } - log_verbose("Finding volume group \"%s\"", vg_name); - if (!lock_vol(cmd, vg_name, lock_type)) { - log_error("Can't lock %s: skipping", vg_name); + log_verbose("Finding volume group \"%s\"", vgname); + if (!lock_vol(cmd, vgname, lock_type)) { + log_error("Can't lock %s: skipping", vgname); continue; } - if (!(vg = vg_read(cmd, vg_name))) { - log_error("Volume group \"%s\" doesn't exist", - vg_name); - if (ret_max < ECMD_FAILED) - ret_max = ECMD_FAILED; - unlock_vg(cmd, vg_name); - continue; + if (lock_type & LCK_WRITE) + consistent = 1; + else + consistent = 0; + if (!(vg = vg_read(cmd, vgname, &consistent)) || + !consistent) { + unlock_vg(cmd, vgname); + if (!vg) + log_error("Volume group \"%s\" " + "not found", vgname); + else + log_error("Volume group \"%s\" " + "inconsistent", vgname); + if (!vg || !(vg = + recover_vg(cmd, vgname, + lock_type))) { + unlock_vg(cmd, vgname); + if (ret_max < ECMD_FAILED) + ret_max = ECMD_FAILED; + continue; + } } if (vg->status & EXPORTED_VG) { log_error("Volume group \"%s\" is exported", vg->name); - unlock_vg(cmd, vg_name); + unlock_vg(cmd, vgname); return ECMD_FAILED; } + if (vgname_provided) { + if ((ret = + process_each_lv_in_vg(cmd, vg, handle, + process_single)) > + ret_max) + ret_max = ret; + unlock_vg(cmd, vgname); + continue; + } + if (!(lvl = find_lv_in_vg(vg, lv_name))) { log_error("Can't find logical volume \"%s\" " "in volume group \"%s\"", - lv_name, vg_name); + lv_name, vgname); if (ret_max < ECMD_FAILED) ret_max = ECMD_FAILED; - unlock_vg(cmd, vg_name); + unlock_vg(cmd, vgname); continue; } lv = lvl->lv; - if ((ret = process_single(cmd, lv)) > ret_max) + if ((ret = process_single(cmd, lv, handle)) > ret_max) ret_max = ret; - unlock_vg(cmd, vg_name); + unlock_vg(cmd, vgname); } } else { log_verbose("Finding all logical volumes"); - if (!(vgs = get_vgs(cmd))) { + if (!(vgnames = get_vgs(cmd, 0))) { log_error("No volume groups found"); return ECMD_FAILED; } - list_iterate(vgh, vgs) { - vg_name = list_item(vgh, struct name_list)->name; - if (!lock_vol(cmd, vg_name, lock_type)) { - log_error("Can't lock %s: skipping", vg_name); + list_iterate(slh, vgnames) { + vgname = list_item(slh, struct str_list)->str; + if (!vgname || !*vgname) + continue; /* FIXME Unnecessary? */ + if (!lock_vol(cmd, vgname, lock_type)) { + log_error("Can't lock %s: skipping", vgname); continue; } - if (!(vg = vg_read(cmd, vg_name))) { - log_error("Volume group \"%s\" not found", - vg_name); - if (ret_max < ECMD_FAILED) - ret_max = ECMD_FAILED; - unlock_vg(cmd, vg_name); - continue; + if (lock_type & LCK_WRITE) + consistent = 1; + else + consistent = 0; + if (!(vg = vg_read(cmd, vgname, &consistent)) || + !consistent) { + unlock_vg(cmd, vgname); + if (!vg) + log_error("Volume group \"%s\" " + "not found", vgname); + else + log_error("Volume group \"%s\" " + "inconsistent", vgname); + if (!vg || !(vg = + recover_vg(cmd, vgname, + lock_type))) { + unlock_vg(cmd, vgname); + if (ret_max < ECMD_FAILED) + ret_max = ECMD_FAILED; + continue; + } } - ret = process_each_lv_in_vg(cmd, vg, process_single); - unlock_vg(cmd, vg_name); + ret = process_each_lv_in_vg(cmd, vg, handle, + process_single); + unlock_vg(cmd, vgname); if (ret > ret_max) ret_max = ret; vg_count++; @@ -132,16 +203,18 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv, } int process_each_vg(struct cmd_context *cmd, int argc, char **argv, - int lock_type, + int lock_type, int consistent, void *handle, int (*process_single) (struct cmd_context * cmd, - const char *vg_name)) + const char *vg_name, + struct volume_group * vg, + int consistent, void *handle)) { int opt = 0; int ret_max = 0; int ret = 0; - struct list *vgh; - struct list *vgs; + struct list *slh, *vgnames; + struct volume_group *vg; char *vg_name; char *dev_dir = cmd->dev_dir; @@ -161,24 +234,32 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv, log_error("Can't lock %s: skipping", vg_name); continue; } - if ((ret = process_single(cmd, vg_name)) > ret_max) + log_verbose("Finding volume group \"%s\"", vg_name); + vg = vg_read(cmd, vg_name, &consistent); + if ((ret = process_single(cmd, vg_name, vg, consistent, + handle)) + > ret_max) ret_max = ret; unlock_vg(cmd, vg_name); } } else { log_verbose("Finding all volume groups"); - if (!(vgs = get_vgs(cmd))) { + if (!(vgnames = get_vgs(cmd, 0)) || list_empty(vgnames)) { log_error("No volume groups found"); return ECMD_FAILED; } - list_iterate(vgh, vgs) { - vg_name = list_item(vgh, struct name_list)->name; + list_iterate(slh, vgnames) { + vg_name = list_item(slh, struct str_list)->str; + if (!vg_name || !*vg_name) + continue; /* FIXME Unnecessary? */ if (!lock_vol(cmd, vg_name, lock_type)) { log_error("Can't lock %s: skipping", vg_name); continue; } - ret = process_single(cmd, vg_name); - + log_verbose("Finding volume group \"%s\"", vg_name); + vg = vg_read(cmd, vg_name, &consistent); + ret = process_single(cmd, vg_name, vg, consistent, + handle); if (ret > ret_max) ret_max = ret; unlock_vg(cmd, vg_name); @@ -189,9 +270,11 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv, } int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, + void *handle, int (*process_single) (struct cmd_context * cmd, struct volume_group * vg, - struct physical_volume * pv)) + struct physical_volume * pv, + void *handle)) { int ret_max = 0; int ret = 0; @@ -201,7 +284,7 @@ int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, list_iterate(pvh, &vg->pvs) { pv = list_item(pvh, struct pv_list)->pv; - if ((ret = process_single(cmd, vg, pv)) > ret_max) + if ((ret = process_single(cmd, vg, pv, handle)) > ret_max) ret_max = ret; } @@ -209,10 +292,11 @@ int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, } int process_each_pv(struct cmd_context *cmd, int argc, char **argv, - struct volume_group *vg, + struct volume_group *vg, void *handle, int (*process_single) (struct cmd_context * cmd, struct volume_group * vg, - struct physical_volume * pv)) + struct physical_volume * pv, + void *handle)) { int opt = 0; int ret_max = 0; @@ -229,32 +313,18 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv, vg->name); continue; } - ret = process_single(cmd, vg, pvl->pv); + ret = process_single(cmd, vg, pvl->pv, handle); if (ret > ret_max) ret_max = ret; } } else { log_verbose("Using all physical volume(s) in volume group"); - process_each_pv_in_vg(cmd, vg, process_single); + process_each_pv_in_vg(cmd, vg, handle, process_single); } return ret_max; } -int is_valid_chars(char *n) -{ - register char c; - - /* Hyphen used as VG-LV separator - ambiguity if LV starts with it */ - if (*n == '-') - return 0; - - while ((c = *n++)) - if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+') - return 0; - return 1; -} - char *extract_vgname(struct cmd_context *cmd, char *lv_name) { char *vg_name = lv_name; diff --git a/tools/toollib.h b/tools/toollib.h index 49f06fbe..8b5ef7ed 100644 --- a/tools/toollib.h +++ b/tools/toollib.h @@ -29,30 +29,42 @@ int autobackup_init(const char *backup_dir, int keep_days, int keep_number, int autobackup); int autobackup(struct volume_group *vg); +struct volume_group *recover_vg(struct cmd_context *cmd, const char *vgname, + int lock_type); + int process_each_vg(struct cmd_context *cmd, int argc, char **argv, - int lock_type, + int lock_type, int consistent, void *handle, int (*process_single) (struct cmd_context * cmd, - const char *vg_name)); + const char *vg_name, + struct volume_group *vg, + int consistent, + void *handle)); int process_each_pv(struct cmd_context *cmd, int argc, char **argv, - struct volume_group *vg, + struct volume_group *vg, void *handle, int (*process_single) (struct cmd_context * cmd, struct volume_group * vg, - struct physical_volume * pv)); + struct physical_volume * pv, + void *handle)); + int process_each_lv(struct cmd_context *cmd, int argc, char **argv, - int lock_type, + int lock_type, void *handle, int (*process_single) (struct cmd_context * cmd, - struct logical_volume * lv)); + struct logical_volume * lv, + void *handle)); int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg, + void *handle, int (*process_single) (struct cmd_context * cmd, struct volume_group * vg, - struct physical_volume * pv)); + struct physical_volume * pv, + void *handle)); + int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg, + void *handle, int (*process_single) (struct cmd_context * cmd, - struct logical_volume * lv)); - -int is_valid_chars(char *n); + struct logical_volume * lv, + void *handle)); char *default_vgname(struct cmd_context *cmd); char *extract_vgname(struct cmd_context *cmd, char *lv_name); diff --git a/tools/tools.h b/tools/tools.h index cd148967..2f253204 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -7,39 +7,40 @@ #ifndef _LVM_TOOLS_H #define _LVM_TOOLS_H -#include "pool.h" -#include "dbg_malloc.h" -#include "list.h" -#include "log.h" -#include "lvm-string.h" -#include "lvm-file.h" -#include "metadata.h" +#define _GNU_SOURCE + +#include "activate.h" +#include "archive.h" +#include "cache.h" #include "config.h" +#include "dbg_malloc.h" #include "dev-cache.h" #include "device.h" -#include "vgcache.h" #include "display.h" #include "errors.h" #include "filter.h" -#include "filter-persistent.h" #include "filter-composite.h" +#include "filter-persistent.h" #include "filter-regex.h" -#include "format1.h" #include "format-text.h" -#include "toollib.h" -#include "activate.h" -#include "archive.h" +#include "metadata.h" +#include "list.h" #include "locking.h" +#include "log.h" +#include "lvm-file.h" +#include "lvm-string.h" +#include "pool.h" #include "toolcontext.h" +#include "toollib.h" -#include <stdio.h> +#include <ctype.h> +#include <limits.h> #include <stdarg.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <sys/types.h> -#include <ctype.h> -#include <string.h> -#include <limits.h> #define CMD_LEN 256 #define MAX_ARGS 64 @@ -68,7 +69,7 @@ typedef enum { struct arg { char short_arg; char *long_arg; - int (*fn) (struct arg * a); + int (*fn) (struct cmd_context * cmd, struct arg * a); int count; char *value; @@ -92,14 +93,14 @@ struct command { void usage(const char *name); /* the argument verify/normalise functions */ -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 minor_arg(struct arg *a); -int string_arg(struct arg *a); -int permission_arg(struct arg *a); -int metadatatype_arg(struct arg *a); +int yes_no_arg(struct cmd_context *cmd, struct arg *a); +int size_arg(struct cmd_context *cmd, struct arg *a); +int int_arg(struct cmd_context *cmd, struct arg *a); +int int_arg_with_sign(struct cmd_context *cmd, struct arg *a); +int minor_arg(struct cmd_context *cmd, struct arg *a); +int string_arg(struct cmd_context *cmd, struct arg *a); +int permission_arg(struct cmd_context *cmd, struct arg *a); +int metadatatype_arg(struct cmd_context *cmd, struct arg *a); char yes_no_prompt(const char *prompt, ...); @@ -151,13 +152,4 @@ static inline const char *command_name(struct cmd_context *cmd) return cmd->command->name; } -static inline int driver_is_loaded(void) -{ - int i = driver_version(NULL, 0); - - if (!i) - log_error("device-mapper driver/module not loaded?"); - return i; -} - #endif diff --git a/tools/vgcfgbackup.c b/tools/vgcfgbackup.c index a7801589..46f90ec6 100644 --- a/tools/vgcfgbackup.c +++ b/tools/vgcfgbackup.c @@ -6,44 +6,29 @@ #include "tools.h" -#include <stdio.h> - -static int _backup_to_file(const char *file, struct volume_group *vg) -{ - int r; - struct format_instance *tf; - void *context; - - if (!(context = create_text_context(vg->cmd->fmtt, file, - vg->cmd->cmd_line)) || - !(tf = vg->cmd->fmtt->ops->create_instance(vg->cmd->fmtt, NULL, - context))) { - log_error("Couldn't create backup object."); - return 0; - } - - if (!(r = tf->fmt->ops->vg_write(tf, vg, context)) || - !(r = tf->fmt->ops->vg_commit(tf, vg, context))) - stack; - - tf->fmt->ops->destroy_instance(tf); - return r; -} - -static int vg_backup_single(struct cmd_context *cmd, const char *vg_name) +static int vg_backup_single(struct cmd_context *cmd, const char *vg_name, + struct volume_group *vg, int consistent, + void *handle) { - struct volume_group *vg; - - log_verbose("Checking for volume group \"%s\"", vg_name); - if (!(vg = vg_read(cmd, vg_name))) { + if (!vg) { log_error("Volume group \"%s\" not found", vg_name); return ECMD_FAILED; } + if (!consistent) + log_error("Warning: Volume group \"%s\" inconsistent", vg_name); + if (arg_count(cmd, file_ARG)) { - _backup_to_file(arg_value(cmd, file_ARG), vg); + backup_to_file(arg_value(cmd, file_ARG), vg->cmd->cmd_line, vg); } else { + if (!consistent) { + log_error("No backup taken: specify filename with -f " + "to backup an inconsistent VG"); + stack; + return ECMD_FAILED; + } + /* just use the normal backup code */ backup_enable(1); /* force a backup */ if (!backup(vg)) { @@ -58,8 +43,6 @@ static int vg_backup_single(struct cmd_context *cmd, const char *vg_name) int vgcfgbackup(struct cmd_context *cmd, int argc, char **argv) { - if (!driver_is_loaded()) - return ECMD_FAILED; - - return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vg_backup_single); + return process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, NULL, + &vg_backup_single); } diff --git a/tools/vgcfgrestore.c b/tools/vgcfgrestore.c index fe497816..2c38ed64 100644 --- a/tools/vgcfgrestore.c +++ b/tools/vgcfgrestore.c @@ -13,9 +13,6 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!driver_is_loaded()) - return ECMD_FAILED; - /* * FIXME: overloading the -l arg for now to display a * list of archive files for a particular vg @@ -27,13 +24,28 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv) return 0; } + if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) { + log_error("Unable to lock orphans"); + return ECMD_FAILED; + } + + if (!lock_vol(cmd, argv[0], LCK_VG_WRITE | LCK_NONBLOCK)) { + log_error("Unable to lock volume group %s", argv[0]); + unlock_vg(cmd, ORPHAN); + return ECMD_FAILED; + } + if (!(arg_count(cmd, file_ARG) ? backup_restore_from_file(cmd, argv[0], arg_str_value(cmd, file_ARG, "")) : backup_restore(cmd, argv[0]))) { + unlock_vg(cmd, argv[0]); + unlock_vg(cmd, ORPHAN); log_err("Restore failed."); return ECMD_FAILED; } + unlock_vg(cmd, argv[0]); + unlock_vg(cmd, ORPHAN); return 0; } diff --git a/tools/vgchange.c b/tools/vgchange.c index 3165ba88..9579bef3 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -20,11 +20,6 @@ #include "tools.h" -static int vgchange_single(struct cmd_context *cmd, const char *vg_name); -void vgchange_available(struct cmd_context *cmd, struct volume_group *vg); -void vgchange_resizeable(struct cmd_context *cmd, struct volume_group *vg); -void vgchange_logicalvolume(struct cmd_context *cmd, struct volume_group *vg); - static int _activate_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg, int lock) { @@ -48,72 +43,6 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd, return count; } -int vgchange(struct cmd_context *cmd, int argc, char **argv) -{ - if (! - (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) + - arg_count(cmd, resizeable_ARG))) { - log_error("One of -a, -l or -x options required"); - return EINVALID_CMD_LINE; - } - - if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) + - arg_count(cmd, resizeable_ARG) > 1) { - log_error("Only one of -a, -l or -x options allowed"); - return EINVALID_CMD_LINE; - } - - if (arg_count(cmd, ignorelockingfailure_ARG) && - !arg_count(cmd, available_ARG)) { - log_error("--ignorelockingfailure only available with -a"); - return EINVALID_CMD_LINE; - } - - if (arg_count(cmd, available_ARG) == 1 - && arg_count(cmd, autobackup_ARG)) { - log_error("-A option not necessary with -a option"); - return EINVALID_CMD_LINE; - } - - if (!driver_is_loaded()) - return ECMD_FAILED; - - return process_each_vg(cmd, argc, argv, - (arg_count(cmd, available_ARG)) ? - LCK_VG_READ : LCK_VG_WRITE, &vgchange_single); -} - -static int vgchange_single(struct cmd_context *cmd, const char *vg_name) -{ - struct volume_group *vg; - - if (!(vg = vg_read(cmd, vg_name))) { - log_error("Unable to find volume group \"%s\"", vg_name); - return ECMD_FAILED; - } - - if (!(vg->status & LVM_WRITE) && !arg_count(cmd, available_ARG)) { - log_error("Volume group \"%s\" is read-only", vg->name); - return ECMD_FAILED; - } - - if (vg->status & EXPORTED_VG) { - log_error("Volume group \"%s\" is exported", vg_name); - return ECMD_FAILED; - } - - if (arg_count(cmd, available_ARG)) - vgchange_available(cmd, vg); - - if (arg_count(cmd, resizeable_ARG)) - vgchange_resizeable(cmd, vg); - - if (arg_count(cmd, logicalvolume_ARG)) - vgchange_logicalvolume(cmd, vg); - - return 0; -} - void vgchange_available(struct cmd_context *cmd, struct volume_group *vg) { int lv_open, active; @@ -208,3 +137,74 @@ void vgchange_logicalvolume(struct cmd_context *cmd, struct volume_group *vg) return; } + +static int vgchange_single(struct cmd_context *cmd, const char *vg_name, + struct volume_group *vg, int consistent, + void *handle) +{ + if (!vg) { + log_error("Unable to find volume group \"%s\"", vg_name); + return ECMD_FAILED; + } + + if (!consistent) { + unlock_vg(cmd, vg_name); + log_error("Volume group \"%s\" inconsistent", vg_name); + if (!(vg = recover_vg(cmd, vg_name, LCK_VG_WRITE))) + return ECMD_FAILED; + } + + if (!(vg->status & LVM_WRITE) && !arg_count(cmd, available_ARG)) { + log_error("Volume group \"%s\" is read-only", vg->name); + return ECMD_FAILED; + } + + if (vg->status & EXPORTED_VG) { + log_error("Volume group \"%s\" is exported", vg_name); + return ECMD_FAILED; + } + + if (arg_count(cmd, available_ARG)) + vgchange_available(cmd, vg); + + if (arg_count(cmd, resizeable_ARG)) + vgchange_resizeable(cmd, vg); + + if (arg_count(cmd, logicalvolume_ARG)) + vgchange_logicalvolume(cmd, vg); + + return 0; +} + +int vgchange(struct cmd_context *cmd, int argc, char **argv) +{ + if (! + (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) + + arg_count(cmd, resizeable_ARG))) { + log_error("One of -a, -l or -x options required"); + return EINVALID_CMD_LINE; + } + + if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) + + arg_count(cmd, resizeable_ARG) > 1) { + log_error("Only one of -a, -l or -x options allowed"); + return EINVALID_CMD_LINE; + } + + if (arg_count(cmd, ignorelockingfailure_ARG) && + !arg_count(cmd, available_ARG)) { + log_error("--ignorelockingfailure only available with -a"); + return EINVALID_CMD_LINE; + } + + if (arg_count(cmd, available_ARG) == 1 + && arg_count(cmd, autobackup_ARG)) { + log_error("-A option not necessary with -a option"); + return EINVALID_CMD_LINE; + } + + return process_each_vg(cmd, argc, argv, + (arg_count(cmd, available_ARG)) ? + LCK_VG_READ : LCK_VG_WRITE, 0, NULL, + &vgchange_single); +} diff --git a/tools/vgck.c b/tools/vgck.c index e90f5317..6a6eb1ec 100644 --- a/tools/vgck.c +++ b/tools/vgck.c @@ -20,20 +20,15 @@ #include "tools.h" -static int vgck_single(struct cmd_context *cmd, const char *vg_name); - -int vgck(struct cmd_context *cmd, int argc, char **argv) +static int vgck_single(struct cmd_context *cmd, const char *vg_name, + struct volume_group *vg, int consistent, void *handle) { - return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgck_single); -} - -static int vgck_single(struct cmd_context *cmd, const char *vg_name) -{ - struct volume_group *vg; - - log_verbose("Checking volume group \"%s\"", vg_name); + if (!consistent) { + log_error("Volume group \"%s\" inconsistent", vg_name); + return ECMD_FAILED; + } - if (!(vg = vg_read(cmd, vg_name))) { + if (!vg) { log_error("Volume group \"%s\" not found", vg_name); return ECMD_FAILED; } @@ -43,12 +38,12 @@ static int vgck_single(struct cmd_context *cmd, const char *vg_name) return ECMD_FAILED; } -/******* FIXME Must be caught and logged by vg_read - log_error("not all physical volumes of volume group \"%s\" online", - log_error("volume group \"%s\" has physical volumes with ", - "invalid version", -********/ - /* FIXME: free */ return 0; } + +int vgck(struct cmd_context *cmd, int argc, char **argv) +{ + return process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, NULL, + &vgck_single); +} diff --git a/tools/vgconvert.c b/tools/vgconvert.c new file mode 100644 index 00000000..91bd8886 --- /dev/null +++ b/tools/vgconvert.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2001 Sistina Software + * + * pvcreate 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. + * + * pvcreate 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" +#include "defaults.h" + +static int vgconvert_single(struct cmd_context *cmd, const char *vg_name, + struct volume_group *vg, int consistent, + void *handle) +{ + struct physical_volume *pv, *existing_pv; + uint64_t size = 0; + struct list mdas; + int pvmetadatacopies = 0; + uint64_t pvmetadatasize = 0; + uint64_t pe_end = 0, pe_start = 0; + struct list *pvh; + + if (!vg) { + log_error("Unable to find volume group \"%s\"", vg_name); + return ECMD_FAILED; + } + + if (!consistent) { + unlock_vg(cmd, vg_name); + log_error("Volume group \"%s\" inconsistent", vg_name); + if (!(vg = recover_vg(cmd, vg_name, LCK_VG_WRITE))) + return ECMD_FAILED; + } + + if (!(vg->status & LVM_WRITE)) { + log_error("Volume group \"%s\" is read-only", vg->name); + return ECMD_FAILED; + } + + if (vg->status & EXPORTED_VG) { + log_error("Volume group \"%s\" is exported", vg_name); + return ECMD_FAILED; + } + + if (vg->fid->fmt == cmd->fmt) { + log_error("Volume group \"%s\" already uses format %s", + vg_name, cmd->fmt->name); + return ECMD_FAILED; + } + + if (cmd->fmt->features & FMT_MDAS) { + pvmetadatasize = arg_int64_value(cmd, metadatasize_ARG, 0) * 2; + if (!pvmetadatasize) + pvmetadatasize = + find_config_int(cmd->cf->root, + "metadata/pvmetadatasize", + '/', DEFAULT_PVMETADATASIZE); + + pvmetadatacopies = arg_int_value(cmd, metadatacopies_ARG, -1); + if (pvmetadatacopies < 0) + pvmetadatacopies = + find_config_int(cmd->cf->root, + "metadata/pvmetadatacopies", + '/', DEFAULT_PVMETADATACOPIES); + } + + if (!archive(vg)) { + log_error("Archive of \"%s\" metadata failed.", vg_name); + return ECMD_FAILED; + } + + list_iterate(pvh, &vg->pvs) { + existing_pv = list_item(pvh, struct pv_list)->pv; + + pe_start = existing_pv->pe_start; + pe_end = existing_pv->pe_count * existing_pv->pe_size + + pe_start - 1; + + list_init(&mdas); + if (!(pv = pv_create(cmd->fmt, existing_pv->dev, + &existing_pv->id, size, + pe_start, existing_pv->pe_count, + existing_pv->pe_size, pvmetadatacopies, + pvmetadatasize, &mdas))) { + log_error("Failed to setup physical volume \"%s\"", + dev_name(existing_pv->dev)); + log_error("Use pvcreate and vgcfgrestore to repair " + "from archived metadata."); + return ECMD_FAILED; + } + + log_verbose("Set up physical volume for \"%s\" with %" PRIu64 + " available sectors", dev_name(pv->dev), pv->size); + + /* Wipe existing label first */ + if (!label_remove(pv->dev)) { + log_error("Failed to wipe existing label on %s", + dev_name(pv->dev)); + log_error("Use pvcreate and vgcfgrestore to repair " + "from archived metadata."); + return ECMD_FAILED; + } + + log_very_verbose("Writing physical volume data to disk \"%s\"", + dev_name(pv->dev)); + if (!(pv_write(cmd, pv, &mdas, + arg_int_value(cmd, labelsector_ARG, + DEFAULT_LABELSECTOR)))) { + log_error("Failed to write physical volume \"%s\"", + dev_name(pv->dev)); + log_error("Use pvcreate and vgcfgrestore to repair " + "from archived metadata."); + return ECMD_FAILED; + } + log_verbose("Physical volume \"%s\" successfully created", + dev_name(pv->dev)); + + } + + log_verbose("Deleting existing metadata for VG %s", vg_name); + if (!vg_remove(vg)) { + log_error("Removal of existing metadata for %s failed.", + vg_name); + log_error("Use pvcreate and vgcfgrestore to repair " + "from archived metadata."); + return ECMD_FAILED; + } + + log_verbose("Writing metadata for VG %s using format %s", vg_name, + cmd->fmt->name); + if (!backup_restore_vg(cmd, vg)) { + log_error("Conversion failed for volume group %s.", vg_name); + log_error("Use pvcreate and vgcfgrestore to repair from " + "archived metadata."); + return ECMD_FAILED; + } + log_print("Volume group %s successfully converted", vg_name); + + backup(vg); + + return 0; +} + +int vgconvert(struct cmd_context *cmd, int argc, char **argv) +{ + if (!argc) { + log_error("Please enter volume group(s)"); + return EINVALID_CMD_LINE; + } + + if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) { + log_error("labelsector must be less than %lu", + LABEL_SCAN_SECTORS); + return EINVALID_CMD_LINE; + } + + if (!(cmd->fmt->features & FMT_MDAS) && + (arg_count(cmd, metadatacopies_ARG) || + arg_count(cmd, metadatasize_ARG))) { + log_error("Metadata parameters only apply to text format"); + return EINVALID_CMD_LINE; + } + + if (arg_count(cmd, metadatacopies_ARG) && + arg_int_value(cmd, metadatacopies_ARG, -1) > 2) { + log_error("Metadatacopies may only be 0, 1 or 2"); + return EINVALID_CMD_LINE; + } + + return process_each_vg(cmd, argc, argv, LCK_VG_WRITE, 0, NULL, + &vgconvert_single); +} diff --git a/tools/vgcreate.c b/tools/vgcreate.c index 7c092e0b..23a8389c 100644 --- a/tools/vgcreate.c +++ b/tools/vgcreate.c @@ -73,15 +73,12 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!is_valid_chars(vg_name)) { + if (!validate_vgname(vg_name)) { log_error("New volume group name \"%s\" has invalid characters", vg_name); return ECMD_FAILED; } - if (!driver_is_loaded()) - return ECMD_FAILED; - /* Create the new VG */ if (!(vg = vg_create(cmd, vg_name, extent_size, max_pv, max_lv, argc - 1, argv + 1))) diff --git a/tools/vgdisplay.c b/tools/vgdisplay.c index 13f30112..72bc3b38 100644 --- a/tools/vgdisplay.c +++ b/tools/vgdisplay.c @@ -20,7 +20,45 @@ #include "tools.h" -static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name); +static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name, + struct volume_group *vg, int consistent, + void *handle) +{ + /* FIXME Do the active check here if activevolumegroups_ARG ? */ + if (!vg) { + log_error("Volume group \"%s\" doesn't exist", vg_name); + return ECMD_FAILED; + } + + if (!consistent) + log_error("WARNING: Volume group \"%s\" inconsistent", vg_name); + + if (vg->status & EXPORTED_VG) + log_print("WARNING: volume group \"%s\" is exported", vg_name); + + if (arg_count(cmd, colon_ARG)) { + vgdisplay_colons(vg); + return 0; + } + + if (arg_count(cmd, short_ARG)) { + vgdisplay_short(vg); + return 0; + } + + vgdisplay_full(vg); /* was vg_show */ + + if (arg_count(cmd, verbose_ARG)) { + vgdisplay_extents(vg); + + process_each_lv_in_vg(cmd, vg, NULL, &lvdisplay_full); + + log_print("--- Physical volumes ---"); + process_each_pv_in_vg(cmd, vg, NULL, &pvdisplay_short); + } + + return 0; +} int vgdisplay(struct cmd_context *cmd, int argc, char **argv) { @@ -34,11 +72,6 @@ int vgdisplay(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } - if (!driver_is_loaded()) - return ECMD_FAILED; - - /* FIXME -D disk_ARG is now redundant */ - /********* FIXME: Do without this - or else 2(+) passes! Figure out longest volume group name for (c = opt; opt < argc; opt++) { @@ -48,7 +81,8 @@ int vgdisplay(struct cmd_context *cmd, int argc, char **argv) } **********/ - process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgdisplay_single); + process_each_vg(cmd, argc, argv, LCK_VG_READ, 0, NULL, + &vgdisplay_single); /******** FIXME Need to count number processed Add this to process_each_vg if arg_count(cmd,activevolumegroups_ARG) ? @@ -64,43 +98,3 @@ int vgdisplay(struct cmd_context *cmd, int argc, char **argv) return 0; } - -static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name) -{ - - struct volume_group *vg; - - /* FIXME Do the active check here if activevolumegroups_ARG ? */ - - log_very_verbose("Finding volume group \"%s\"", vg_name); - if (!(vg = vg_read(cmd, vg_name))) { - log_error("Volume group \"%s\" doesn't exist", vg_name); - return ECMD_FAILED; - } - - if (vg->status & EXPORTED_VG) - log_print("WARNING: volume group \"%s\" is exported", vg_name); - - if (arg_count(cmd, colon_ARG)) { - vgdisplay_colons(vg); - return 0; - } - - if (arg_count(cmd, short_ARG)) { - vgdisplay_short(vg); - return 0; - } - - vgdisplay_full(vg); /* was vg_show */ - - if (arg_count(cmd, verbose_ARG)) { - vgdisplay_extents(vg); - - process_each_lv_in_vg(cmd, vg, &lvdisplay_full); - - log_print("--- Physical volumes ---"); - process_each_pv_in_vg(cmd, vg, &pvdisplay_short); - } - - return 0; -} diff --git a/tools/vgexport.c b/tools/vgexport.c index 50fe605f..5e521f01 100644 --- a/tools/vgexport.c +++ b/tools/vgexport.c @@ -20,32 +20,17 @@ #include "tools.h" -static int vgexport_single(struct cmd_context *cmd, const char *vg_name); - -int vgexport(struct cmd_context *cmd, int argc, char **argv) +static int vgexport_single(struct cmd_context *cmd, const char *vg_name, + struct volume_group *vg, int consistent, + void *handle) { - if (!argc && !arg_count(cmd, all_ARG)) { - log_error("Please supply volume groups or use -a for all."); - return ECMD_FAILED; - } - - if (argc && arg_count(cmd, all_ARG)) { - log_error("No arguments permitted when using -a for all."); - return ECMD_FAILED; + if (!vg) { + log_error("Unable to find volume group \"%s\"", vg_name); + goto error; } - if (!driver_is_loaded()) - return ECMD_FAILED; - - return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgexport_single); -} - -static int vgexport_single(struct cmd_context *cmd, const char *vg_name) -{ - struct volume_group *vg; - - if (!(vg = vg_read(cmd, vg_name))) { - log_error("Unable to find volume group \"%s\"", vg_name); + if (!consistent) { + log_error("Volume group %s inconsistent", vg_name); goto error; } @@ -82,3 +67,19 @@ static int vgexport_single(struct cmd_context *cmd, const char *vg_name) error: return ECMD_FAILED; } + +int vgexport(struct cmd_context *cmd, int argc, char **argv) +{ + if (!argc && !arg_count(cmd, all_ARG)) { + log_error("Please supply volume groups or use -a for all."); + return ECMD_FAILED; + } + + if (argc && arg_count(cmd, all_ARG)) { + log_error("No arguments permitted when using -a for all."); + return ECMD_FAILED; + } + + return process_each_vg(cmd, argc, argv, LCK_VG_WRITE, 1, NULL, + &vgexport_single); +} diff --git a/tools/vgextend.c b/tools/vgextend.c index 6b5adb9a..0cb9f073 100644 --- a/tools/vgextend.c +++ b/tools/vgextend.c @@ -24,6 +24,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv) { char *vg_name; struct volume_group *vg = NULL; + int consistent = 1; if (!argc) { log_error("Please enter volume group name and " @@ -36,9 +37,6 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } - if (!driver_is_loaded()) - return ECMD_FAILED; - vg_name = argv[0]; argc--; argv++; @@ -55,7 +53,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv) goto error; } - if (!(vg = vg_read(cmd, vg_name))) { + if (!(vg = vg_read(cmd, vg_name, &consistent)) || !consistent) { log_error("Volume group \"%s\" not found.", vg_name); goto error; } diff --git a/tools/vgimport.c b/tools/vgimport.c index bb72d7a7..d515caad 100644 --- a/tools/vgimport.c +++ b/tools/vgimport.c @@ -20,31 +20,11 @@ #include "tools.h" -static int vgimport_single(struct cmd_context *cmd, const char *vg_name); - -int vgimport(struct cmd_context *cmd, int argc, char **argv) -{ - if (!argc && !arg_count(cmd, all_ARG)) { - log_error("Please supply volume groups or use -a for all."); - return ECMD_FAILED; - } - - if (argc && arg_count(cmd, all_ARG)) { - log_error("No arguments permitted when using -a for all."); - return ECMD_FAILED; - } - - if (!driver_is_loaded()) - return ECMD_FAILED; - - return process_each_vg(cmd, argc, argv, LCK_VG_WRITE, &vgimport_single); -} - -static int vgimport_single(struct cmd_context *cmd, const char *vg_name) +static int vgimport_single(struct cmd_context *cmd, const char *vg_name, + struct volume_group *vg, int consistent, + void *handle) { - struct volume_group *vg; - - if (!(vg = vg_read(cmd, vg_name))) { + if (!vg || !consistent) { log_error("Unable to find exported volume group \"%s\"", vg_name); goto error; @@ -77,3 +57,19 @@ static int vgimport_single(struct cmd_context *cmd, const char *vg_name) error: return ECMD_FAILED; } + +int vgimport(struct cmd_context *cmd, int argc, char **argv) +{ + if (!argc && !arg_count(cmd, all_ARG)) { + log_error("Please supply volume groups or use -a for all."); + return ECMD_FAILED; + } + + if (argc && arg_count(cmd, all_ARG)) { + log_error("No arguments permitted when using -a for all."); + return ECMD_FAILED; + } + + return process_each_vg(cmd, argc, argv, LCK_VG_WRITE, 1, NULL, + &vgimport_single); +} diff --git a/tools/vgmerge.c b/tools/vgmerge.c index 8d6e7b44..6a705658 100644 --- a/tools/vgmerge.c +++ b/tools/vgmerge.c @@ -21,41 +21,12 @@ #include "tools.h" int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, - const char *vg_name_from); - -int vgmerge(struct cmd_context *cmd, int argc, char **argv) -{ - char *vg_name_to; - int opt = 0; - int ret = 0, ret_max = 0; - - if (argc < 2) { - log_error("Please enter 2 or more volume groups to merge"); - return EINVALID_CMD_LINE; - } - - if (!driver_is_loaded()) - return ECMD_FAILED; - - vg_name_to = argv[0]; - argc--; - argv++; - - for (; opt < argc; opt++) { - ret = vgmerge_single(cmd, vg_name_to, argv[opt]); - if (ret > ret_max) - ret_max = ret; - } - - return ret_max; -} - -int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, const char *vg_name_from) { struct volume_group *vg_to, *vg_from; struct list *lvh1, *lvh2; int active; + int consistent = 1; if (!strcmp(vg_name_to, vg_name_from)) { log_error("Duplicate volume group name \"%s\"", vg_name_from); @@ -68,7 +39,7 @@ int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, return ECMD_FAILED; } - if (!(vg_to = vg_read(cmd, vg_name_to))) { + if (!(vg_to = vg_read(cmd, vg_name_to, &consistent)) || !consistent) { log_error("Volume group \"%s\" doesn't exist", vg_name_to); unlock_vg(cmd, vg_name_to); return ECMD_FAILED; @@ -93,7 +64,8 @@ int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, return ECMD_FAILED; } - if (!(vg_from = vg_read(cmd, vg_name_from))) { + consistent = 1; + if (!(vg_from = vg_read(cmd, vg_name_from, &consistent)) || !consistent) { log_error("Volume group \"%s\" doesn't exist", vg_name_from); goto error; } @@ -178,6 +150,14 @@ int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, list_del(lvh); list_add(&vg_to->lvs, lvh); } + + while (!list_empty(&vg_from->fid->metadata_areas)) { + struct list *mdah = vg_from->fid->metadata_areas.n; + + list_del(mdah); + list_add(&vg_to->fid->metadata_areas, mdah); + } + vg_to->lv_count += vg_from->lv_count; vg_to->extent_count += vg_from->extent_count; @@ -205,3 +185,27 @@ int vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, unlock_vg(cmd, vg_name_to); return ECMD_FAILED; } + +int vgmerge(struct cmd_context *cmd, int argc, char **argv) +{ + char *vg_name_to; + int opt = 0; + int ret = 0, ret_max = 0; + + if (argc < 2) { + log_error("Please enter 2 or more volume groups to merge"); + return EINVALID_CMD_LINE; + } + + vg_name_to = argv[0]; + argc--; + argv++; + + for (; opt < argc; opt++) { + ret = vgmerge_single(cmd, vg_name_to, argv[opt]); + if (ret > ret_max) + ret_max = ret; + } + + return ret_max; +} diff --git a/tools/vgreduce.c b/tools/vgreduce.c index b2bd476b..a0855731 100644 --- a/tools/vgreduce.c +++ b/tools/vgreduce.c @@ -20,14 +20,64 @@ #include "tools.h" +/* Or take pv_name instead? */ static int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg, - struct physical_volume *pv); + struct physical_volume *pv, void *handle) +{ + struct pv_list *pvl; + const char *name = dev_name(pv->dev); + + if (pv->pe_alloc_count) { + log_error("Physical volume \"%s\" still in use", name); + return ECMD_FAILED; + } + + if (vg->pv_count == 1) { + log_error("Can't remove final physical volume \"%s\" from " + "volume group \"%s\"", name, vg->name); + return ECMD_FAILED; + } + + pvl = find_pv_in_vg(vg, name); + + if (!archive(vg)) + return ECMD_FAILED; + log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name); + + if (pvl) + list_del(&pvl->list); + + *pv->vg_name = '\0'; + vg->pv_count--; + vg->free_count -= pv->pe_count - pv->pe_alloc_count; + vg->extent_count -= pv->pe_count; + + if (!vg_write(vg)) { + log_error("Removal of physical volume \"%s\" from " + "\"%s\" failed", name, vg->name); + return ECMD_FAILED; + } + + if (!pv_write(cmd, pv, NULL, -1)) { + log_error("Failed to clear metadata from physical " + "volume \"%s\" " + "after removal from \"%s\"", name, vg->name); + return ECMD_FAILED; + } + + backup(vg); + + log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name); + + return 0; +} int vgreduce(struct cmd_context *cmd, int argc, char **argv) { struct volume_group *vg; char *vg_name; int ret; + int consistent = 1; if (!argc) { log_error("Please give volume group name and " @@ -46,9 +96,6 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } - if (!driver_is_loaded()) - return ECMD_FAILED; - vg_name = argv[0]; argv++; argc--; @@ -59,7 +106,7 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!(vg = vg_read(cmd, vg_name))) { + if (!(vg = vg_read(cmd, vg_name, &consistent)) || !consistent) { log_error("Volume group \"%s\" doesn't exist", vg_name); unlock_vg(cmd, vg_name); return ECMD_FAILED; @@ -85,7 +132,7 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv) /* FIXME: Pass private structure through to all these functions */ /* and update in batch here? */ - ret = process_each_pv(cmd, argc, argv, vg, vgreduce_single); + ret = process_each_pv(cmd, argc, argv, vg, NULL, vgreduce_single); unlock_vg(cmd, vg_name); @@ -107,62 +154,3 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv) ********/ } - -/* Or take pv_name instead? */ -static int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg, - struct physical_volume *pv) -{ - struct pv_list *pvl; - const char *name = dev_name(pv->dev); - - if (pv->pe_alloc_count) { - log_error("Physical volume \"%s\" still in use", name); - return ECMD_FAILED; - } - -/********* FIXME: Is this unnecessary after checking pe_alloc_count? - 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\"", name, vg->name); - return ECMD_FAILED; - } - - pvl = find_pv_in_vg(vg, name); - - if (!archive(vg)) - return ECMD_FAILED; - - log_verbose("Removing \"%s\" from volume group \"%s\"", name, vg->name); - - if (pvl) - list_del(&pvl->list); - - *pv->vg_name = '\0'; - vg->pv_count--; - vg->free_count -= pv->pe_count - pv->pe_alloc_count; - vg->extent_count -= pv->pe_count; - - if (!vg_write(vg)) { - log_error("Removal of physical volume \"%s\" from " - "\"%s\" failed", name, vg->name); - return ECMD_FAILED; - } - - if (!pv_write(cmd, pv)) { - log_error("Failed to clear metadata from physical " - "volume \"%s\" " - "after removal from \"%s\"", name, vg->name); - return ECMD_FAILED; - } - - backup(vg); - - log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name); - - return 0; -} diff --git a/tools/vgremove.c b/tools/vgremove.c index 018976f7..14a0fcf3 100644 --- a/tools/vgremove.c +++ b/tools/vgremove.c @@ -20,38 +20,15 @@ #include "tools.h" -static int vgremove_single(struct cmd_context *cmd, const char *vg_name); - -int vgremove(struct cmd_context *cmd, int argc, char **argv) -{ - int ret; - - if (!driver_is_loaded()) - return ECMD_FAILED; - - if (!lock_vol(cmd, "", LCK_VG_WRITE)) { - log_error("Can't get lock for orphan PVs"); - return ECMD_FAILED; - } - - ret = process_each_vg(cmd, argc, argv, - LCK_VG | LCK_WRITE | LCK_NONBLOCK, - &vgremove_single); - - unlock_vg(cmd, ""); - - return ret; -} - -static int vgremove_single(struct cmd_context *cmd, const char *vg_name) +static int vgremove_single(struct cmd_context *cmd, const char *vg_name, + struct volume_group *vg, int consistent, + void *handle) { - struct volume_group *vg; struct physical_volume *pv; struct list *pvh; int ret = 0; - log_verbose("Checking for volume group \"%s\"", vg_name); - if (!(vg = vg_read(cmd, vg_name))) { + if (!vg || !consistent) { log_error("Volume group \"%s\" doesn't exist", vg_name); return ECMD_FAILED; } @@ -87,7 +64,8 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name) log_verbose("Removing physical volume \"%s\" from " "volume group \"%s\"", dev_name(pv->dev), vg_name); *pv->vg_name = '\0'; - if (!pv_write(cmd, pv)) { + /* FIXME Write to same sector label was read from */ + if (!pv_write(cmd, pv, NULL, -1)) { log_error("Failed to remove physical volume \"%s\"" " from volume group \"%s\"", dev_name(pv->dev), vg_name); @@ -104,3 +82,21 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name) return ret; } + +int vgremove(struct cmd_context *cmd, int argc, char **argv) +{ + int ret; + + if (!lock_vol(cmd, "", LCK_VG_WRITE)) { + log_error("Can't get lock for orphan PVs"); + return ECMD_FAILED; + } + + ret = process_each_vg(cmd, argc, argv, + LCK_VG | LCK_WRITE | LCK_NONBLOCK, 1, NULL, + &vgremove_single); + + unlock_vg(cmd, ""); + + return ret; +} diff --git a/tools/vgrename.c b/tools/vgrename.c index 4ec3d985..50c04512 100644 --- a/tools/vgrename.c +++ b/tools/vgrename.c @@ -24,6 +24,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) { char *dev_dir; int length; + int consistent = 1; char *vg_name_old, *vg_name_new; @@ -56,7 +57,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!is_valid_chars(vg_name_new)) { + if (!validate_vgname(vg_name_new)) { log_error("New volume group name \"%s\" has invalid characters", vg_name_new); return ECMD_FAILED; @@ -67,9 +68,6 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!driver_is_loaded()) - return ECMD_FAILED; - log_verbose("Checking for existing volume group \"%s\"", vg_name_old); if (!lock_vol(cmd, vg_name_old, LCK_VG_WRITE)) { @@ -77,7 +75,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!(vg_old = vg_read(cmd, vg_name_old))) { + if (!(vg_old = vg_read(cmd, vg_name_old, &consistent)) || !consistent) { log_error("Volume group \"%s\" doesn't exist", vg_name_old); unlock_vg(cmd, vg_name_old); return ECMD_FAILED; @@ -115,7 +113,8 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if ((vg_new = vg_read(cmd, vg_name_new))) { + consistent = 0; + if ((vg_new = vg_read(cmd, vg_name_new, &consistent))) { log_error("New volume group \"%s\" already exists", vg_name_new); goto error; @@ -133,18 +132,14 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) vg_name_new); } -/********** FIXME: Check within vg_write now - log_error("A new logical volume path exceeds " - "maximum of %d!", NAME_LEN - 2); - goto error; -*************/ - sprintf(old_path, "%s%s", dev_dir, vg_name_old); sprintf(new_path, "%s%s", dev_dir, vg_name_new); if (dir_exists(old_path)) { log_verbose("Renaming \"%s\" to \"%s\"", old_path, new_path); - if (rename(old_path, new_path)) { + if (test_mode()) + log_verbose("Test mode: Skipping rename."); + else if (rename(old_path, new_path)) { log_error("Renaming \"%s\" to \"%s\" failed: %s", old_path, new_path, strerror(errno)); goto error; @@ -175,19 +170,3 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } -/* FIXME: Moved into vg_write now */ -/******************* -char *lv_change_vgname(char *vg_name, char *lv_name) -{ - char *lv_name_ptr = NULL; - static char lv_name_buf[NAME_LEN] = { 0, }; - - ** check if lv_name includes a path - if ((lv_name_ptr = strrchr(lv_name, '/'))) { - lv_name_ptr++; - sprintf(lv_name_buf, "%s%s/%s%c", cmd->dev_dir, vg_name, - lv_name_ptr, 0);} - else - strncpy(lv_name_buf, lv_name, NAME_LEN - 1); return lv_name_buf;} - -**********************/ diff --git a/tools/vgscan.c b/tools/vgscan.c index 504f5347..0af067d7 100644 --- a/tools/vgscan.c +++ b/tools/vgscan.c @@ -20,7 +20,28 @@ #include "tools.h" -static int vgscan_single(struct cmd_context *cmd, const char *vg_name); +static int vgscan_single(struct cmd_context *cmd, const char *vg_name, + struct volume_group *vg, int consistent, void *handle) +{ + if (!vg) { + log_error("Volume group \"%s\" not found", vg_name); + return ECMD_FAILED; + } + + if (!consistent) { + unlock_vg(cmd, vg_name); + log_error("Volume group \"%s\" inconsistent", vg_name); + /* Don't allow partial switch to this program */ + if (!(vg = recover_vg(cmd, vg_name, LCK_VG_WRITE))) + return ECMD_FAILED; + } + + log_print("Found %svolume group \"%s\" using metadata type %s", + (vg->status & EXPORTED_VG) ? "exported " : "", vg_name, + vg->fid->fmt->name); + + return 0; +} int vgscan(struct cmd_context *cmd, int argc, char **argv) { @@ -32,28 +53,11 @@ int vgscan(struct cmd_context *cmd, int argc, char **argv) log_verbose("Wiping cache of LVM-capable devices"); persistent_filter_wipe(cmd->filter); - log_verbose("Wiping internal cache of PVs in VGs"); - vgcache_destroy(); + log_verbose("Wiping internal cache"); + cache_destroy(); log_print("Reading all physical volumes. This may take a while..."); - return process_each_vg(cmd, argc, argv, LCK_VG_READ, &vgscan_single); -} - -static int vgscan_single(struct cmd_context *cmd, const char *vg_name) -{ - struct volume_group *vg; - - log_verbose("Checking for volume group \"%s\"", vg_name); - - if (!(vg = vg_read(cmd, vg_name))) { - log_error("Volume group \"%s\" not found", vg_name); - return ECMD_FAILED; - } - - log_print("Found %svolume group \"%s\" using metadata type %s", - (vg->status & EXPORTED_VG) ? "exported " : "", vg_name, - vg->fid->fmt->name); - - return 0; + return process_each_vg(cmd, argc, argv, LCK_VG_READ, 1, NULL, + &vgscan_single); } diff --git a/tools/vgsplit.c b/tools/vgsplit.c index baa7d2e5..00a77ff1 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -65,7 +65,7 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) { struct list *lvh, *lvht, *segh; struct logical_volume *lv; - struct stripe_segment *seg; + struct lv_segment *seg; struct physical_volume *pv; struct volume_group *vg_with; int s; @@ -77,7 +77,7 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to) /* VG as each other */ vg_with = NULL; list_iterate(segh, &lv->segments) { - seg = list_item(segh, struct stripe_segment); + seg = list_item(segh, struct lv_segment); for (s = 0; s < seg->stripes; s++) { pv = seg->area[s].pv; if (vg_with) { @@ -164,6 +164,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) struct volume_group *vg_to, *vg_from; int opt; int active; + int consistent = 1; if (argc < 3) { log_error("Existing VG, new VG and physical volumes required."); @@ -180,16 +181,13 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if (!driver_is_loaded()) - return ECMD_FAILED; - log_verbose("Checking for volume group \"%s\"", vg_name_from); if (!lock_vol(cmd, vg_name_from, LCK_VG_WRITE)) { log_error("Can't get lock for %s", vg_name_from); return ECMD_FAILED; } - if (!(vg_from = vg_read(cmd, vg_name_from))) { + if (!(vg_from = vg_read(cmd, vg_name_from, &consistent)) || !consistent) { log_error("Volume group \"%s\" doesn't exist", vg_name_from); unlock_vg(cmd, vg_name_from); return ECMD_FAILED; @@ -214,7 +212,8 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } - if ((vg_to = vg_read(cmd, vg_name_to))) { + consistent = 0; + if ((vg_to = vg_read(cmd, vg_name_to, &consistent))) { /* FIXME Remove this restriction */ log_error("Volume group \"%s\" already exists", vg_name_to); goto error; @@ -250,6 +249,12 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) if (!(_move_snapshots(vg_from, vg_to))) goto error; + /* FIXME Split mdas properly somehow too! */ + /* Currently we cheat by sharing the format instance and relying on + * vg_write to ignore mdas outside the VG! Done this way, with text + * format, vg_from disappears for a short time. */ + vg_to->fid = vg_from->fid; + /* store it on disks */ log_verbose("Writing out updated volume groups"); @@ -271,6 +276,13 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) backup(vg_from); /* Remove EXPORTED flag from new VG */ + consistent = 1; + if (!(vg_to = vg_read(cmd, vg_name_to, &consistent)) || !consistent) { + log_error("Volume group \"%s\" became inconsistent: please " + "fix manually", vg_name_to); + goto error; + } + vg_to->status &= ~EXPORTED_VG; if (!vg_write(vg_to)) |