summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2013-03-05 01:47:43 -0800
committerAnas Nashif <anas.nashif@intel.com>2013-03-05 01:47:43 -0800
commit44a3c2255bc480c82f34db156553a595606d8a0b (patch)
tree5e6df96a6c6e40207cb3a711860e16b543918c0d /tools
parent8bd28eea831fd5215c12e6fcecc8e9a772398ed9 (diff)
downloaddevice-mapper-44a3c2255bc480c82f34db156553a595606d8a0b.tar.gz
device-mapper-44a3c2255bc480c82f34db156553a595606d8a0b.tar.bz2
device-mapper-44a3c2255bc480c82f34db156553a595606d8a0b.zip
Imported Upstream version 2.02.98upstream/2.02.98upstream/1.02.77
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile.in6
-rw-r--r--tools/args.h19
-rw-r--r--tools/commands.h89
-rw-r--r--tools/dmsetup.c1002
-rw-r--r--tools/dumpconfig.c2
-rw-r--r--tools/lvchange.c446
-rw-r--r--tools/lvconvert.c968
-rw-r--r--tools/lvcreate.c870
-rw-r--r--tools/lvm.c4
-rw-r--r--tools/lvm2cmd.h6
-rw-r--r--tools/lvmcmdlib.c7
-rw-r--r--tools/lvmcmdline.c319
-rw-r--r--tools/lvmdiskscan.c11
-rw-r--r--tools/lvremove.c2
-rw-r--r--tools/lvrename.c23
-rw-r--r--tools/lvresize.c318
-rw-r--r--tools/lvscan.c16
-rw-r--r--tools/polldaemon.c68
-rw-r--r--tools/polldaemon.h6
-rw-r--r--tools/pvchange.c120
-rw-r--r--tools/pvck.c2
-rw-r--r--tools/pvcreate.c10
-rw-r--r--tools/pvdisplay.c6
-rw-r--r--tools/pvmove.c240
-rw-r--r--tools/pvremove.c51
-rw-r--r--tools/pvresize.c89
-rw-r--r--tools/pvscan.c223
-rw-r--r--tools/reporter.c18
-rw-r--r--tools/toollib.c214
-rw-r--r--tools/toollib.h8
-rw-r--r--tools/tools.h23
-rw-r--r--tools/vgcfgbackup.c4
-rw-r--r--tools/vgcfgrestore.c6
-rw-r--r--tools/vgchange.c171
-rw-r--r--tools/vgconvert.c25
-rw-r--r--tools/vgcreate.c14
-rw-r--r--tools/vgexport.c2
-rw-r--r--tools/vgextend.c21
-rw-r--r--tools/vgimport.c2
-rw-r--r--tools/vgmerge.c29
-rw-r--r--tools/vgreduce.c341
-rw-r--r--tools/vgremove.c2
-rw-r--r--tools/vgrename.c36
-rw-r--r--tools/vgscan.c23
-rw-r--r--tools/vgsplit.c55
45 files changed, 4011 insertions, 1906 deletions
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 70a1b61..15843f0 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -1,6 +1,6 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
-# Copyright (C) 2004-2010 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -132,7 +132,7 @@ dmsetup.static: dmsetup.o $(interfacebuilddir)/libdevmapper.a
all: device-mapper
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) lvm.o \
+ $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
$(LVMLIBS) $(READLINE_LIBS) $(LIBS) -rdynamic
lvm.static: $(OBJECTS) lvm-static.o $(top_builddir)/lib/liblvm-internal.a $(interfacebuilddir)/libdevmapper.a
@@ -203,5 +203,3 @@ install_device-mapper: $(INSTALL_DMSETUP_TARGETS)
install_lvm2: $(INSTALL_LVM_TARGETS)
install: install_lvm2 install_device-mapper
-
-DISTCLEAN_TARGETS += .exported_symbols_generated
diff --git a/tools/args.h b/tools/args.h
index ff7514b..0d9605a 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -18,7 +18,6 @@
*/
/* *INDENT-OFF* */
arg(version_ARG, '\0', "version", NULL, 0)
-arg(quiet_ARG, '\0', "quiet", NULL, 0)
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_mb_arg, 0)
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL, 0)
arg(nolocking_ARG, '\0', "nolocking", NULL, 0)
@@ -44,7 +43,7 @@ arg(addtag_ARG, '\0', "addtag", tag_arg, ARG_GROUPABLE)
arg(deltag_ARG, '\0', "deltag", tag_arg, ARG_GROUPABLE)
arg(refresh_ARG, '\0', "refresh", NULL, 0)
arg(mknodes_ARG, '\0', "mknodes", NULL, 0)
-arg(minor_ARG, '\0', "minor", minor_arg, 0)
+arg(minor_ARG, '\0', "minor", int_arg, ARG_GROUPABLE)
arg(type_ARG, '\0', "type", segtype_arg, 0)
arg(alloc_ARG, '\0', "alloc", alloc_arg, 0)
arg(separator_ARG, '\0', "separator", string_arg, 0)
@@ -54,11 +53,14 @@ arg(resync_ARG, '\0', "resync", NULL, 0)
arg(corelog_ARG, '\0', "corelog", NULL, 0)
arg(mirrorlog_ARG, '\0', "mirrorlog", string_arg, 0)
arg(splitmirrors_ARG, '\0', "splitmirrors", int_arg, 0)
+arg(trackchanges_ARG, '\0', "trackchanges", NULL, 0)
+arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE)
arg(repair_ARG, '\0', "repair", NULL, 0)
arg(use_policies_ARG, '\0', "use-policies", NULL, 0)
arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0)
arg(config_ARG, '\0', "config", string_arg, 0)
arg(trustcache_ARG, '\0', "trustcache", NULL, 0)
+arg(cache_ARG, '\0', "cache", NULL, 0)
arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0)
arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0)
arg(unquoted_ARG, '\0', "unquoted", NULL, 0)
@@ -66,20 +68,24 @@ arg(rows_ARG, '\0', "rows", NULL, 0)
arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0)
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0)
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0)
-arg(virtualsize_ARG, '\0', "virtualsize", size_mb_arg, 0)
arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0)
arg(poll_ARG, '\0', "poll", yes_no_arg, 0)
+arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0)
+arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0)
+arg(discards_ARG, '\0', "discards", discards_arg, 0)
arg(stripes_long_ARG, '\0', "stripes", int_arg, 0)
arg(sysinit_ARG, '\0', "sysinit", NULL, 0)
+arg(thinpool_ARG, '\0', "thinpool", string_arg, 0)
/* Allow some variations */
arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0)
arg(allocation_ARG, '\0', "allocation", yes_no_arg, 0)
+arg(available_ARG, '\0', "available", activation_arg, 0)
/*
* ... and now the short args.
*/
-arg(available_ARG, 'a', "available", yes_no_excl_arg, 0)
+arg(activate_ARG, 'a', "activate", activation_arg, 0)
arg(all_ARG, 'a', "all", NULL, 0)
arg(autobackup_ARG, 'A', "autobackup", yes_no_arg, 0)
arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL, 0)
@@ -111,7 +117,7 @@ arg(size_ARG, 'L', "size", size_mb_arg, 0)
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign, 0)
arg(persistent_ARG, 'M', "persistent", yes_no_arg, 0)
arg(merge_ARG, '\0', "merge", NULL, 0)
-arg(major_ARG, 'j', "major", major_arg, 0)
+arg(major_ARG, 'j', "major", int_arg, ARG_GROUPABLE)
arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0)
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0)
arg(maps_ARG, 'm', "maps", NULL, 0)
@@ -125,6 +131,7 @@ arg(permission_ARG, 'p', "permission", permission_arg, 0)
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg, 0)
arg(partial_ARG, 'P', "partial", NULL, 0)
arg(physicalvolume_ARG, 'P', "physicalvolume", NULL, 0)
+arg(quiet_ARG, 'q', "quiet", NULL, ARG_COUNTABLE)
arg(readahead_ARG, 'r', "readahead", readahead_arg, 0)
arg(resizefs_ARG, 'r', "resizefs", NULL, 0)
arg(reset_ARG, 'R', "reset", NULL, 0)
@@ -133,12 +140,14 @@ arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0)
arg(stdin_ARG, 's', "stdin", NULL, 0)
arg(snapshot_ARG, 's', "snapshot", NULL, 0)
arg(short_ARG, 's', "short", NULL, 0)
+arg(thin_ARG, 'T', "thin", NULL, 0)
arg(test_ARG, 't', "test", NULL, 0)
arg(uuid_ARG, 'u', "uuid", NULL, 0)
arg(uuidstr_ARG, 'u', "uuid", string_arg, 0)
arg(uuidlist_ARG, 'U', "uuidlist", NULL, 0)
arg(verbose_ARG, 'v', "verbose", NULL, ARG_COUNTABLE)
arg(volumegroup_ARG, 'V', "volumegroup", NULL, 0)
+arg(virtualsize_ARG, 'V', "virtualsize", size_mb_arg, 0)
arg(allocatable_ARG, 'x', "allocatable", yes_no_arg, 0)
arg(resizeable_ARG, 'x', "resizeable", yes_no_arg, 0)
arg(yes_ARG, 'y', "yes", NULL, 0)
diff --git a/tools/commands.h b/tools/commands.h
index fa177cd..6415d34 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -61,7 +61,7 @@ xx(lvchange,
CACHE_VGMETADATA | PERMITTED_READ_ONLY,
"lvchange\n"
"\t[-A|--autobackup y|n]\n"
- "\t[-a|--available [e|l]y|n]\n"
+ "\t[-a|--activate [a|e|l]{y|n}]\n"
"\t[--addtag Tag]\n"
"\t[--alloc AllocationPolicy]\n"
"\t[-C|--contiguous y|n]\n"
@@ -69,6 +69,7 @@ xx(lvchange,
"\t[--deltag Tag]\n"
"\t[-f|--force]\n"
"\t[-h|--help]\n"
+ "\t[--discards {ignore|nopassdown|passdown}]\n"
"\t[--ignorelockingfailure]\n"
"\t[--ignoremonitoring]\n"
"\t[--monitor {y|n}]\n"
@@ -84,21 +85,25 @@ xx(lvchange,
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
"\t[-y|--yes]\n"
- "\t[--version]" "\n"
+ "\t[--version]\n"
+ "\t[-Z|--zero {y|n}]\n"
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
- alloc_ARG, autobackup_ARG, available_ARG, contiguous_ARG, force_ARG,
- ignorelockingfailure_ARG, ignoremonitoring_ARG, major_ARG, minor_ARG,
- monitor_ARG, noudevsync_ARG, partial_ARG, permission_ARG, persistent_ARG,
- poll_ARG, readahead_ARG, resync_ARG, refresh_ARG, addtag_ARG, deltag_ARG,
- sysinit_ARG, test_ARG, yes_ARG)
+ alloc_ARG, autobackup_ARG, activate_ARG, available_ARG, contiguous_ARG,
+ discards_ARG, force_ARG, ignorelockingfailure_ARG, ignoremonitoring_ARG,
+ major_ARG, minor_ARG, monitor_ARG, noudevsync_ARG, partial_ARG,
+ permission_ARG, persistent_ARG, poll_ARG, readahead_ARG, resync_ARG,
+ refresh_ARG, addtag_ARG, deltag_ARG, sysinit_ARG, test_ARG, yes_ARG,
+ zero_ARG)
xx(lvconvert,
"Change logical volume layout",
0,
"lvconvert "
"[-m|--mirrors Mirrors [{--mirrorlog {disk|core|mirrored}|--corelog}]]\n"
+ "\t[--type SegmentType]\n"
"\t[--repair [--use-policies]]\n"
+ "\t[--replace PhysicalVolume]\n"
"\t[-R|--regionsize MirrorLogRegionSize]\n"
"\t[--alloc AllocationPolicy]\n"
"\t[-b|--background]\n"
@@ -114,6 +119,7 @@ xx(lvconvert,
"\tLogicalVolume[Path] [PhysicalVolume[Path]...]\n\n"
"lvconvert "
+ "[--splitmirrors Images --trackchanges]\n"
"[--splitmirrors Images --name SplitLogicalVolumeName]\n"
"\tLogicalVolume[Path] [SplittablePhysicalVolume[Path]...]\n\n"
@@ -135,12 +141,21 @@ xx(lvconvert,
"\t[-d|--debug]\n"
"\t[-h|-?|--help]\n"
"\t[-v|--verbose]\n"
- "\tSnapshotLogicalVolume[Path]\n",
+ "\tLogicalVolume[Path]\n\n"
+
+ "lvconvert "
+ "--thinpool ThinPoolLogicalVolume[Path]\n"
+ "\t[--chunksize size]\n"
+ "\t[--discards {ignore|nopassdown|passdown}]\n"
+ "\t[[--poolmetadatasize size] | --poolmetadata ThinMetadataLogicalVolume[Path]]\n"
+ "\t[-Z|--zero {y|n}]\n"
+ "\t[-d|--debug] [-h|-?|--help] [-v|--verbose]\n",
alloc_ARG, background_ARG, chunksize_ARG, corelog_ARG, interval_ARG,
merge_ARG, mirrorlog_ARG, mirrors_ARG, name_ARG, noudevsync_ARG,
- regionsize_ARG, repair_ARG, snapshot_ARG, splitmirrors_ARG,
- stripes_long_ARG, stripesize_ARG, test_ARG,
+ regionsize_ARG, repair_ARG, replace_ARG, snapshot_ARG, splitmirrors_ARG,
+ trackchanges_ARG, type_ARG, stripes_long_ARG, stripesize_ARG, test_ARG,
+ chunksize_ARG, discards_ARG, poolmetadata_ARG, poolmetadatasize_ARG, thinpool_ARG,
use_policies_ARG, yes_ARG, force_ARG, zero_ARG)
xx(lvcreate,
@@ -148,6 +163,7 @@ xx(lvcreate,
0,
"lvcreate " "\n"
"\t[-A|--autobackup {y|n}]\n"
+ "\t[-a|--activate [a|e|l]{y|n}]\n"
"\t[--addtag Tag]\n"
"\t[--alloc AllocationPolicy]\n"
"\t[-C|--contiguous {y|n}]\n"
@@ -165,6 +181,10 @@ xx(lvcreate,
"\t[-p|--permission {r|rw}]\n"
"\t[-r|--readahead ReadAheadSectors|auto|none]\n"
"\t[-R|--regionsize MirrorLogRegionSize]\n"
+ "\t[-T|--thin [-c|--chunksize ChunkSize]\n"
+ "\t [--discards {ignore|nopassdown|passdown}]\n"
+ "\t [--poolmetadatasize MetadataSize[bBsSkKmMgG]]]\n"
+ "\t[--thinpool ThinPoolLogicalVolume{Name|Path}]\n"
"\t[-t|--test]\n"
"\t[--type VolumeType]\n"
"\t[-v|--verbose]\n"
@@ -174,36 +194,42 @@ xx(lvcreate,
"lvcreate \n"
"\t{ {-s|--snapshot} OriginalLogicalVolume[Path] |\n"
- "\t [-s|--snapshot] VolumeGroupName[Path] --virtualsize VirtualSize}\n"
+ "\t [-s|--snapshot] VolumeGroupName[Path] -V|--virtualsize VirtualSize}\n"
+ "\t {-T|--thin} VolumeGroupName[Path][/PoolLogicalVolume] \n"
+ "\t -V|--virtualsize VirtualSize}\n"
"\t[-c|--chunksize]\n"
"\t[-A|--autobackup {y|n}]\n"
"\t[--addtag Tag]\n"
"\t[--alloc AllocationPolicy]\n"
"\t[-C|--contiguous {y|n}]\n"
"\t[-d|--debug]\n"
+ "\t[--discards {ignore|nopassdown|passdown}]\n"
"\t[-h|-?|--help]\n"
"\t[--ignoremonitoring]\n"
"\t[--monitor {y|n}]\n"
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents LogicalExtentsNumber[%{VG|FREE|ORIGIN}] |\n"
"\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n"
+ "\t[--poolmetadatasize Size[bBsSkKmMgG]]\n"
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
"\t[-n|--name LogicalVolumeName]\n"
"\t[--noudevsync]\n"
"\t[-p|--permission {r|rw}]\n"
"\t[-r|--readahead ReadAheadSectors|auto|none]\n"
"\t[-t|--test]\n"
+ "\t[--thinpool ThinPoolLogicalVolume[Path]]\n"
"\t[-v|--verbose]\n"
"\t[--version]\n"
"\t[PhysicalVolumePath...]\n\n",
- addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, contiguous_ARG,
- corelog_ARG, extents_ARG, ignoremonitoring_ARG, major_ARG, minor_ARG,
- mirrorlog_ARG, mirrors_ARG, monitor_ARG, name_ARG, nosync_ARG, noudevsync_ARG,
- permission_ARG, persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG,
- snapshot_ARG, stripes_ARG, stripesize_ARG, test_ARG, type_ARG,
- virtualoriginsize_ARG, virtualsize_ARG, zero_ARG)
+ addtag_ARG, alloc_ARG, autobackup_ARG, activate_ARG, available_ARG,
+ chunksize_ARG, contiguous_ARG, corelog_ARG, discards_ARG, extents_ARG,
+ ignoremonitoring_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG,
+ monitor_ARG, name_ARG, nosync_ARG, noudevsync_ARG, permission_ARG,
+ persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG,
+ stripes_ARG, stripesize_ARG, test_ARG, thin_ARG, thinpool_ARG, type_ARG,
+ virtualoriginsize_ARG, poolmetadatasize_ARG, virtualsize_ARG, zero_ARG)
xx(lvdisplay,
"Display information about a logical volume",
@@ -259,6 +285,7 @@ xx(lvextend,
"\t{-l|--extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |\n"
"\t -L|--size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n"
"\t[-m|--mirrors Mirrors]\n"
+ "\t[--nosync]\n"
"\t[--use-policies]\n"
"\t[-n|--nofsck]\n"
"\t[--noudevsync]\n"
@@ -270,7 +297,7 @@ xx(lvextend,
"\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
alloc_ARG, autobackup_ARG, extents_ARG, force_ARG, mirrors_ARG,
- nofsck_ARG, noudevsync_ARG, resizefs_ARG, size_ARG, stripes_ARG,
+ nofsck_ARG, nosync_ARG, noudevsync_ARG, resizefs_ARG, size_ARG, stripes_ARG,
stripesize_ARG, test_ARG, type_ARG, use_policies_ARG)
xx(lvmchange,
@@ -361,7 +388,7 @@ xx(lvremove,
xx(lvrename,
"Rename a logical volume",
0,
- "lvrename "
+ "lvrename\n"
"\t[-A|--autobackup {y|n}] " "\n"
"\t[-d|--debug] " "\n"
"\t[-h|-?|--help] " "\n"
@@ -653,6 +680,8 @@ xx(pvscan,
"List all physical volumes",
PERMITTED_READ_ONLY,
"pvscan " "\n"
+ "\t[-a|--activate ay]\n"
+ "\t[--cache [ DevicePath | --major major --minor minor]...]\n"
"\t[-d|--debug] " "\n"
"\t{-e|--exported | -n|--novolumegroup} " "\n"
"\t[-h|-?|--help]" "\n"
@@ -663,8 +692,9 @@ xx(pvscan,
"\t[-v|--verbose] " "\n"
"\t[--version]\n",
- exported_ARG, ignorelockingfailure_ARG, novolumegroup_ARG, partial_ARG,
- short_ARG, uuid_ARG)
+ activate_ARG, available_ARG, cache_ARG, exported_ARG,
+ ignorelockingfailure_ARG, major_ARG, minor_ARG,
+ novolumegroup_ARG, partial_ARG, short_ARG, uuid_ARG)
xx(segtypes,
"List available segment types",
@@ -723,7 +753,7 @@ xx(vgchange,
"\t[-u|--uuid] " "\n"
"\t[-v|--verbose] " "\n"
"\t[--version]" "\n"
- "\t{-a|--available [e|l]{y|n} |" "\n"
+ "\t{-a|--activate [a|e|l]{y|n} |" "\n"
"\t -c|--clustered {y|n} |" "\n"
"\t -x|--resizeable {y|n} |" "\n"
"\t -l|--logicalvolume MaxLogicalVolumes |" "\n"
@@ -733,11 +763,11 @@ xx(vgchange,
"\t --deltag Tag}\n"
"\t[VolumeGroupName...]\n",
- addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, available_ARG,
- clustered_ARG, deltag_ARG, ignorelockingfailure_ARG, ignoremonitoring_ARG,
- logicalvolume_ARG, maxphysicalvolumes_ARG, monitor_ARG, noudevsync_ARG,
- metadatacopies_ARG, vgmetadatacopies_ARG, partial_ARG,
- physicalextentsize_ARG, poll_ARG, refresh_ARG, resizeable_ARG,
+ addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, activate_ARG,
+ available_ARG, clustered_ARG, deltag_ARG, ignorelockingfailure_ARG,
+ ignoremonitoring_ARG, logicalvolume_ARG, maxphysicalvolumes_ARG,
+ monitor_ARG, noudevsync_ARG, metadatacopies_ARG, vgmetadatacopies_ARG,
+ partial_ARG, physicalextentsize_ARG, poll_ARG, refresh_ARG, resizeable_ARG,
resizable_ARG, sysinit_ARG, test_ARG, uuid_ARG)
xx(vgck,
@@ -993,6 +1023,7 @@ xx(vgscan,
"Search for all volume groups",
PERMITTED_READ_ONLY,
"vgscan "
+ "\t[--cache]\n"
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[--ignorelockingfailure]\n"
@@ -1001,7 +1032,7 @@ xx(vgscan,
"\t[-v|--verbose]\n"
"\t[--version]" "\n",
- ignorelockingfailure_ARG, mknodes_ARG, partial_ARG)
+ cache_ARG, ignorelockingfailure_ARG, mknodes_ARG, partial_ARG)
xx(vgsplit,
"Move physical volumes into a new or existing volume group",
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 2eeee7f..196c170 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
* Copyright (C) 2005-2007 NEC Corporation
*
* This file is part of the device-mapper userspace tools.
@@ -30,7 +30,6 @@
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
-#include <libgen.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/param.h>
@@ -45,7 +44,6 @@
# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/sem.h>
-# define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
# include <libudev.h>
#endif
@@ -118,12 +116,16 @@ extern char *optarg;
*/
enum {
READ_ONLY = 0,
+ ADD_NODE_ON_CREATE_ARG,
+ ADD_NODE_ON_RESUME_ARG,
+ CHECKS_ARG,
COLS_ARG,
EXEC_ARG,
FORCE_ARG,
GID_ARG,
HELP_ARG,
INACTIVE_ARG,
+ MANGLENAME_ARG,
MAJOR_ARG,
MINOR_ARG,
MODE_ARG,
@@ -138,6 +140,7 @@ enum {
NOUDEVSYNC_ARG,
OPTIONS_ARG,
READAHEAD_ARG,
+ RETRY_ARG,
ROWS_ARG,
SEPARATOR_ARG,
SETUUID_ARG,
@@ -151,6 +154,7 @@ enum {
UNQUOTED_ARG,
UUID_ARG,
VERBOSE_ARG,
+ VERIFYUDEV_ARG,
VERSION_ARG,
YES_ARG,
NUM_SWITCHES
@@ -164,6 +168,12 @@ typedef enum {
DR_NAME = 16
} report_type_t;
+typedef enum {
+ DN_DEVNO, /* Major and minor number pair */
+ DN_BLK, /* Block device name (e.g. dm-0) */
+ DN_MAP /* Map name (for dm devices only, equal to DN_BLK otherwise) */
+} dev_name_t;
+
static int _switches[NUM_SWITCHES];
static int _int_args[NUM_SWITCHES];
static char *_string_args[NUM_SWITCHES];
@@ -178,18 +188,22 @@ static int _udev_only;
static struct dm_tree *_dtree;
static struct dm_report *_report;
static report_type_t _report_type;
+static dev_name_t _dev_name_type;
/*
* Commands
*/
-typedef int (*command_fn) (int argc, char **argv, void *data);
+struct command;
+#define CMD_ARGS const struct command *cmd, int argc, char **argv, struct dm_names *names, int multiple_devices
+typedef int (*command_fn) (CMD_ARGS);
struct command {
const char *name;
const char *help;
int min_args;
int max_args;
+ int repeatable_cmd; /* Repeat to process device list? */
command_fn fn;
};
@@ -312,6 +326,9 @@ static struct dm_task *_get_deps_task(int major, int minor)
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto err;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto err;
+
if (!dm_task_run(dmt))
goto err;
@@ -362,7 +379,11 @@ static struct dm_split_name *_get_split_name(const char *uuid, const char *name,
return NULL;
}
- split_name->subsystem = _extract_uuid_prefix(uuid, separator);
+ if (!(split_name->subsystem = _extract_uuid_prefix(uuid, separator))) {
+ dm_free(split_name);
+ return_NULL;
+ }
+
split_name->vg_name = split_name->lv_name =
split_name->lv_layer = (char *) "";
@@ -405,16 +426,24 @@ static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
obj.split_name = NULL;
if (_report_type & DR_TREE)
- obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor);
+ if (!(obj.tree_node = dm_tree_find_node(_dtree, info->major, info->minor))) {
+ log_error("Cannot find node %d:%d.", info->major, info->minor);
+ goto out;
+ }
if (_report_type & DR_DEPS)
- obj.deps_task = _get_deps_task(info->major, info->minor);
+ if (!(obj.deps_task = _get_deps_task(info->major, info->minor))) {
+ log_error("Cannot get deps for %d:%d.", info->major, info->minor);
+ goto out;
+ }
if (_report_type & DR_NAME)
- obj.split_name = _get_split_name(dm_task_get_uuid(dmt), dm_task_get_name(dmt), '-');
+ if (!(obj.split_name = _get_split_name(dm_task_get_uuid(dmt),
+ dm_task_get_name(dmt), '-')))
+ goto_out;
if (!dm_report_object(_report, &obj))
- goto out;
+ goto_out;
r = 1;
@@ -505,7 +534,23 @@ static int _set_task_device(struct dm_task *dmt, const char *name, int optional)
return 1;
}
-static int _load(int argc, char **argv, void *data __attribute__((unused)))
+static int _set_task_add_node(struct dm_task *dmt)
+{
+ if (!dm_task_set_add_node(dmt, DEFAULT_DM_ADD_NODE))
+ return 0;
+
+ if (_switches[ADD_NODE_ON_RESUME_ARG] &&
+ !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_RESUME))
+ return 0;
+
+ if (_switches[ADD_NODE_ON_CREATE_ARG] &&
+ !dm_task_set_add_node(dmt, DM_ADD_NODE_ON_CREATE))
+ return 0;
+
+ return 1;
+}
+
+static int _load(CMD_ARGS)
{
int r = 0;
struct dm_task *dmt;
@@ -551,6 +596,9 @@ static int _load(int argc, char **argv, void *data __attribute__((unused)))
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto out;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
if (!dm_task_run(dmt))
goto out;
@@ -565,7 +613,7 @@ static int _load(int argc, char **argv, void *data __attribute__((unused)))
return r;
}
-static int _create(int argc, char **argv, void *data __attribute__((unused)))
+static int _create(CMD_ARGS)
{
int r = 0;
struct dm_task *dmt;
@@ -624,11 +672,17 @@ static int _create(int argc, char **argv, void *data __attribute__((unused)))
udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
- if (_udev_cookie) {
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
+ if (!_set_task_add_node(dmt))
+ goto out;
+
+ if (_udev_cookie)
cookie = _udev_cookie;
- if (_udev_only)
- udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
- }
+
+ if (_udev_only)
+ udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
!dm_task_run(dmt))
@@ -636,26 +690,19 @@ static int _create(int argc, char **argv, void *data __attribute__((unused)))
r = 1;
+ out:
if (!_udev_cookie)
(void) dm_udev_wait(cookie);
- if (_switches[VERBOSE_ARG])
+ if (r && _switches[VERBOSE_ARG])
r = _display_info(dmt);
dm_task_destroy(dmt);
return r;
-
- out:
- if (!_udev_cookie)
- (void) dm_udev_wait(cookie);
- dm_task_destroy(dmt);
-
- return r;
}
-static int _rename(int argc, char **argv, void *data __attribute__((unused)))
-{
+static int _do_rename(const char *name, const char *new_name, const char *new_uuid) {
int r = 0;
struct dm_task *dmt;
uint32_t cookie = 0;
@@ -665,13 +712,13 @@ static int _rename(int argc, char **argv, void *data __attribute__((unused)))
return 0;
/* FIXME Kernel doesn't support uuid or device number here yet */
- if (!_set_task_device(dmt, (argc == 3) ? argv[1] : NULL, 0))
+ if (!_set_task_device(dmt, name, 0))
goto out;
- if (_switches[SETUUID_ARG]) {
- if (!dm_task_set_newuuid(dmt, argv[argc - 1]))
+ if (new_uuid) {
+ if (!dm_task_set_newuuid(dmt, new_uuid))
goto out;
- } else if (!dm_task_set_newname(dmt, argv[argc - 1]))
+ } else if (!new_name || !dm_task_set_newname(dmt, new_name))
goto out;
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
@@ -680,15 +727,18 @@ static int _rename(int argc, char **argv, void *data __attribute__((unused)))
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto out;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
if (_switches[NOUDEVRULES_ARG])
udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
- if (_udev_cookie) {
+ if (_udev_cookie)
cookie = _udev_cookie;
- if (_udev_only)
- udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
- }
+
+ if (_udev_only)
+ udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
!dm_task_run(dmt))
@@ -699,12 +749,22 @@ static int _rename(int argc, char **argv, void *data __attribute__((unused)))
out:
if (!_udev_cookie)
(void) dm_udev_wait(cookie);
+
dm_task_destroy(dmt);
return r;
}
-static int _message(int argc, char **argv, void *data __attribute__((unused)))
+static int _rename(CMD_ARGS)
+{
+ const char *name = (argc == 3) ? argv[1] : NULL;
+
+ return _switches[SETUUID_ARG] ? _do_rename(name, NULL, argv[argc - 1]) :
+ _do_rename(name, argv[argc - 1], NULL);
+
+}
+
+static int _message(CMD_ARGS)
{
int r = 0, i;
size_t sz = 1;
@@ -747,17 +807,22 @@ static int _message(int argc, char **argv, void *data __attribute__((unused)))
strcat(str, argv[i]);
}
- if (!dm_task_set_message(dmt, str))
- goto out;
+ i = dm_task_set_message(dmt, str);
dm_free(str);
+ if (!i)
+ goto out;
+
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
goto out;
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto out;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
if (!dm_task_run(dmt))
goto out;
@@ -769,7 +834,7 @@ static int _message(int argc, char **argv, void *data __attribute__((unused)))
return r;
}
-static int _setgeometry(int argc, char **argv, void *data __attribute__((unused)))
+static int _setgeometry(CMD_ARGS)
{
int r = 0;
struct dm_task *dmt;
@@ -796,6 +861,9 @@ static int _setgeometry(int argc, char **argv, void *data __attribute__((unused)
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto out;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
/* run the task */
if (!dm_task_run(dmt))
goto out;
@@ -808,7 +876,7 @@ static int _setgeometry(int argc, char **argv, void *data __attribute__((unused)
return r;
}
-static int _splitname(int argc, char **argv, void *data __attribute__((unused)))
+static int _splitname(CMD_ARGS)
{
struct dmsetup_report_obj obj;
int r = 1;
@@ -817,8 +885,9 @@ static int _splitname(int argc, char **argv, void *data __attribute__((unused)))
obj.info = NULL;
obj.deps_task = NULL;
obj.tree_node = NULL;
- obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM",
- argv[1], '\0');
+ if (!(obj.split_name = _get_split_name((argc == 3) ? argv[2] : "LVM",
+ argv[1], '\0')))
+ return_0;
r = dm_report_object(_report, &obj);
_destroy_split_name(obj.split_name);
@@ -842,7 +911,7 @@ static uint32_t _get_cookie_value(const char *str_value)
return (uint32_t) value;
}
-static int _udevflags(int args, char **argv, void *data __attribute__((unused)))
+static int _udevflags(CMD_ARGS)
{
uint32_t cookie;
uint16_t flags;
@@ -884,7 +953,7 @@ static int _udevflags(int args, char **argv, void *data __attribute__((unused)))
return 1;
}
-static int _udevcomplete(int argc, char **argv, void *data __attribute__((unused)))
+static int _udevcomplete(CMD_ARGS)
{
uint32_t cookie;
@@ -907,32 +976,30 @@ static int _udevcomplete(int argc, char **argv, void *data __attribute__((unused
}
#ifndef UDEV_SYNC_SUPPORT
-static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev-sync\" to enable.";
+static const char _cmd_not_supported[] = "Command not supported. Recompile with \"--enable-udev_sync\" to enable.";
-static int _udevcreatecookie(int argc, char **argv,
- void *data __attribute__((unused)))
+static int _udevcreatecookie(CMD_ARGS)
{
log_error(_cmd_not_supported);
return 0;
}
-static int _udevreleasecookie(int argc, char **argv,
- void *data __attribute__((unused)))
+static int _udevreleasecookie(CMD_ARGS)
{
log_error(_cmd_not_supported);
return 0;
}
-static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _udevcomplete_all(CMD_ARGS)
{
log_error(_cmd_not_supported);
return 0;
}
-static int _udevcookies(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _udevcookies(CMD_ARGS)
{
log_error(_cmd_not_supported);
@@ -942,11 +1009,9 @@ static int _udevcookies(int argc __attribute__((unused)), char **argv __attribut
#else /* UDEV_SYNC_SUPPORT */
static int _set_up_udev_support(const char *dev_dir)
{
- struct udev *udev;
- const char *udev_dev_dir;
- size_t udev_dev_dir_len;
int dirs_diff;
const char *env;
+ size_t len = strlen(dev_dir), udev_dir_len = strlen(DM_UDEV_DEV_DIR);
if (_switches[NOUDEVSYNC_ARG])
dm_udev_set_sync_support(0);
@@ -964,14 +1029,6 @@ static int _set_up_udev_support(const char *dev_dir)
" defined by --udevcookie option.",
_udev_cookie);
- if (!(udev = udev_new()) ||
- !(udev_dev_dir = udev_get_dev_path(udev)) ||
- !*udev_dev_dir) {
- log_error("Could not get udev dev path.");
- return 0;
- }
- udev_dev_dir_len = strlen(udev_dev_dir);
-
/*
* Normally, there's always a fallback action by libdevmapper if udev
* has not done its job correctly, e.g. the nodes were not created.
@@ -983,13 +1040,18 @@ static int _set_up_udev_support(const char *dev_dir)
* is the same as "dev path" used by libdevmapper.
*/
- /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */
- if (udev_dev_dir[udev_dev_dir_len - 1] != '/')
- dirs_diff = strncmp(dev_dir, udev_dev_dir, udev_dev_dir_len);
- else
- dirs_diff = strcmp(dev_dir, udev_dev_dir);
- _udev_only = _udev_cookie && !dirs_diff;
+ /*
+ * DM_UDEV_DEV_DIR always has '/' at its end.
+ * If the dev_dir does not have it, be sure
+ * to make the right comparison without the '/' char!
+ */
+ if (dev_dir[len - 1] != '/')
+ udev_dir_len--;
+
+ dirs_diff = udev_dir_len != len ||
+ strncmp(DM_UDEV_DEV_DIR, dev_dir, len);
+ _udev_only = !dirs_diff && (_udev_cookie || !_switches[VERIFYUDEV_ARG]);
if (dirs_diff) {
log_debug("The path %s used for creating device nodes that is "
@@ -998,16 +1060,14 @@ static int _set_up_udev_support(const char *dev_dir)
"about udev not working correctly while processing "
"particular nodes will be suppressed. These nodes "
"and symlinks will be managed in each directory "
- "separately.", dev_dir, udev_dev_dir);
+ "separately.", dev_dir, DM_UDEV_DEV_DIR);
dm_udev_set_checking(0);
}
- udev_unref(udev);
return 1;
}
-static int _udevcreatecookie(int argc, char **argv,
- void *data __attribute__((unused)))
+static int _udevcreatecookie(CMD_ARGS)
{
uint32_t cookie;
@@ -1020,8 +1080,7 @@ static int _udevcreatecookie(int argc, char **argv,
return 1;
}
-static int _udevreleasecookie(int argc, char **argv,
- void *data __attribute__((unused)))
+static int _udevreleasecookie(CMD_ARGS)
{
if (argv[1] && !(_udev_cookie = _get_cookie_value(argv[1])))
return 0;
@@ -1034,6 +1093,7 @@ static int _udevreleasecookie(int argc, char **argv,
return dm_udev_wait(_udev_cookie);
}
+__attribute__((format(printf, 1, 2)))
static char _yes_no_prompt(const char *prompt, ...)
{
int c = 0, ret = 0;
@@ -1062,16 +1122,25 @@ static char _yes_no_prompt(const char *prompt, ...)
return ret;
}
-static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _udevcomplete_all(CMD_ARGS)
{
int max_id, id, sid;
struct seminfo sinfo;
struct semid_ds sdata;
int counter = 0;
+ int skipped = 0;
+ unsigned age = 0;
+ time_t t;
+
+ if (argc == 2 && (sscanf(argv[1], "%i", &age) != 1)) {
+ log_error("Failed to read age_in_minutes parameter.");
+ return 0;
+ }
if (!_switches[YES_ARG]) {
- log_warn("This operation will destroy all semaphores with keys "
+ log_warn("This operation will destroy all semaphores %s%.0d%swith keys "
"that have a prefix %" PRIu16 " (0x%" PRIx16 ").",
+ age ? "older than " : "", age, age ? " minutes " : "",
DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
if (_yes_no_prompt("Do you really want to continue? [y/n]: ") == 'n') {
@@ -1092,6 +1161,13 @@ static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __att
continue;
if (sdata.sem_perm.__key >> 16 == DM_COOKIE_MAGIC) {
+ t = time(NULL);
+
+ if (sdata.sem_ctime + age * 60 > t ||
+ sdata.sem_otime + age * 60 > t) {
+ skipped++;
+ continue;
+ }
if (semctl(sid, 0, IPC_RMID, 0) < 0) {
log_error("Could not cleanup notification semaphore "
"with semid %d and cookie value "
@@ -1105,26 +1181,27 @@ static int _udevcomplete_all(int argc __attribute__((unused)), char **argv __att
}
log_print("%d semaphores with keys prefixed by "
- "%" PRIu16 " (0x%" PRIx16 ") destroyed.",
- counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC);
+ "%" PRIu16 " (0x%" PRIx16 ") destroyed. %d skipped.",
+ counter, DM_COOKIE_MAGIC, DM_COOKIE_MAGIC, skipped);
return 1;
}
-static int _udevcookies(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _udevcookies(CMD_ARGS)
{
int max_id, id, sid;
struct seminfo sinfo;
struct semid_ds sdata;
int val;
- char *time_str;
+ char otime_str[26], ctime_str[26];
+ char *otimes, *ctimes;
if ((max_id = semctl(0, 0, SEM_INFO, &sinfo)) < 0) {
log_sys_error("sem_ctl", "SEM_INFO");
return 0;
}
- printf("cookie semid value last_semop_time\n");
+ printf("Cookie Semid Value Last semop time Last change time\n");
for (id = 0; id <= max_id; id++) {
if ((sid = semctl(id, 0, SEM_STAT, &sdata)) < 0)
@@ -1139,10 +1216,14 @@ static int _udevcookies(int argc __attribute__((unused)), char **argv __attribut
continue;
}
- time_str = ctime((const time_t *) &sdata.sem_otime);
+ if ((otimes = ctime_r((const time_t *) &sdata.sem_otime, (char *)&otime_str)))
+ otime_str[strlen(otimes)-1] = '\0';
+ if ((ctimes = ctime_r((const time_t *) &sdata.sem_ctime, (char *)&ctime_str)))
+ ctime_str[strlen(ctimes)-1] = '\0';
- printf("0x%-10x %-10d %-10d %s", sdata.sem_perm.__key,
- sid, val, time_str ? time_str : "unknown\n");
+ printf("0x%-10x %-10d %-10d %s %s\n", sdata.sem_perm.__key,
+ sid, val, otimes ? : "unknown",
+ ctimes? : "unknown");
}
}
@@ -1150,7 +1231,7 @@ static int _udevcookies(int argc __attribute__((unused)), char **argv __attribut
}
#endif /* UDEV_SYNC_SUPPORT */
-static int _version(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _version(CMD_ARGS)
{
char version[80];
@@ -1196,6 +1277,13 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display)
if (_switches[NOLOCKFS_ARG] && !dm_task_skip_lockfs(dmt))
goto out;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
+ /* FIXME: needs to coperate with udev */
+ if (!_set_task_add_node(dmt))
+ goto out;
+
if (_switches[READAHEAD_ARG] &&
!dm_task_set_read_ahead(dmt, _int_args[READAHEAD_ARG],
_read_ahead_flags))
@@ -1205,44 +1293,48 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display)
udev_flags |= DM_UDEV_DISABLE_DM_RULES_FLAG |
DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG;
- if (_udev_cookie) {
+ if (_udev_cookie)
cookie = _udev_cookie;
- if (_udev_only)
- udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
- }
+
+ if (_udev_only)
+ udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags))
goto out;
- r = dm_task_run(dmt);
+ if (_switches[RETRY_ARG] && task == DM_DEVICE_REMOVE)
+ dm_task_retry_remove(dmt);
- if (r && display && _switches[VERBOSE_ARG])
- r = _display_info(dmt);
+ r = dm_task_run(dmt);
out:
if (!_udev_cookie && udev_wait_flag)
(void) dm_udev_wait(cookie);
+ if (r && display && _switches[VERBOSE_ARG])
+ r = _display_info(dmt);
+
dm_task_destroy(dmt);
+
return r;
}
-static int _suspend(int argc, char **argv, void *data __attribute__((unused)))
+static int _suspend(CMD_ARGS)
{
return _simple(DM_DEVICE_SUSPEND, argc > 1 ? argv[1] : NULL, 0, 1);
}
-static int _resume(int argc, char **argv, void *data __attribute__((unused)))
+static int _resume(CMD_ARGS)
{
return _simple(DM_DEVICE_RESUME, argc > 1 ? argv[1] : NULL, 0, 1);
}
-static int _clear(int argc, char **argv, void *data __attribute__((unused)))
+static int _clear(CMD_ARGS)
{
return _simple(DM_DEVICE_CLEAR, argc > 1 ? argv[1] : NULL, 0, 1);
}
-static int _wait(int argc, char **argv, void *data __attribute__((unused)))
+static int _wait(CMD_ARGS)
{
const char *name = NULL;
@@ -1259,8 +1351,8 @@ static int _wait(int argc, char **argv, void *data __attribute__((unused)))
(argc > 1) ? (uint32_t) atoi(argv[argc - 1]) : 0, 1);
}
-static int _process_all(int argc, char **argv, int silent,
- int (*fn) (int argc, char **argv, void *data))
+static int _process_all(const struct command *cmd, int argc, char **argv, int silent,
+ int (*fn) (CMD_ARGS))
{
int r = 1;
struct dm_names *names;
@@ -1271,6 +1363,9 @@ static int _process_all(int argc, char **argv, int silent,
if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
return 0;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
if (!dm_task_run(dmt)) {
r = 0;
goto out;
@@ -1289,7 +1384,7 @@ static int _process_all(int argc, char **argv, int silent,
do {
names = (struct dm_names *)((char *) names + next);
- if (!fn(argc, argv, names))
+ if (!fn(cmd, argc, argv, names, 1))
r = 0;
next = names->next;
} while (next);
@@ -1319,6 +1414,9 @@ static uint64_t _get_device_size(const char *name)
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto out;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
if (!dm_task_run(dmt))
goto out;
@@ -1336,18 +1434,14 @@ static uint64_t _get_device_size(const char *name)
return size;
}
-static int _error_device(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data)
+static int _error_device(CMD_ARGS)
{
- struct dm_names *names = (struct dm_names *) data;
struct dm_task *dmt;
const char *name;
uint64_t size;
int r = 0;
- if (data)
- name = names->name;
- else
- name = argv[1];
+ name = names ? names->name : argv[1];
size = _get_device_size(name);
@@ -1369,6 +1463,9 @@ static int _error_device(int argc __attribute__((unused)), char **argv __attribu
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto error;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto error;
+
if (!dm_task_run(dmt))
goto error;
@@ -1384,22 +1481,22 @@ error:
return r;
}
-static int _remove(int argc, char **argv, void *data __attribute__((unused)))
+static int _remove(CMD_ARGS)
{
if (_switches[FORCE_ARG] && argc > 1)
- (void) _error_device(argc, argv, NULL);
+ (void) _error_device(cmd, argc, argv, NULL, 0);
return _simple(DM_DEVICE_REMOVE, argc > 1 ? argv[1] : NULL, 0, 0);
}
-static int _count_devices(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _count_devices(CMD_ARGS)
{
_num_devices++;
return 1;
}
-static int _remove_all(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _remove_all(CMD_ARGS)
{
int r;
@@ -1410,17 +1507,17 @@ static int _remove_all(int argc __attribute__((unused)), char **argv __attribute
return r;
_num_devices = 0;
- r |= _process_all(argc, argv, 1, _count_devices);
+ r |= _process_all(cmd, argc, argv, 1, _count_devices);
/* No devices left? */
if (!_num_devices)
return r;
- r |= _process_all(argc, argv, 1, _error_device);
+ r |= _process_all(cmd, argc, argv, 1, _error_device);
r |= _simple(DM_DEVICE_REMOVE_ALL, "", 0, 0) | dm_mknodes(NULL);
_num_devices = 0;
- r |= _process_all(argc, argv, 1, _count_devices);
+ r |= _process_all(cmd, argc, argv, 1, _count_devices);
if (!_num_devices)
return r;
@@ -1437,7 +1534,7 @@ static void _display_dev(struct dm_task *dmt, const char *name)
printf("%s\t(%u, %u)\n", name, info.major, info.minor);
}
-static int _mknodes(int argc, char **argv, void *data __attribute__((unused)))
+static int _mknodes(CMD_ARGS)
{
return dm_mknodes(argc > 1 ? argv[1] : NULL);
}
@@ -1501,7 +1598,7 @@ static int _exec_command(const char *name)
return 1;
}
-static int _status(int argc, char **argv, void *data)
+static int _status(CMD_ARGS)
{
int r = 0;
struct dm_task *dmt;
@@ -1509,31 +1606,29 @@ static int _status(int argc, char **argv, void *data)
uint64_t start, length;
char *target_type = NULL;
char *params, *c;
- int cmd;
- struct dm_names *names = (struct dm_names *) data;
+ int cmdno;
const char *name = NULL;
int matched = 0;
int ls_only = 0;
struct dm_info info;
- if (data)
+ if (names)
name = names->name;
else {
if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
- return _process_all(argc, argv, 0, _status);
- if (argc == 2)
- name = argv[1];
+ return _process_all(cmd, argc, argv, 0, _status);
+ name = argv[1];
}
- if (!strcmp(argv[0], "table"))
- cmd = DM_DEVICE_TABLE;
+ if (!strcmp(cmd->name, "table"))
+ cmdno = DM_DEVICE_TABLE;
else
- cmd = DM_DEVICE_STATUS;
+ cmdno = DM_DEVICE_STATUS;
- if (!strcmp(argv[0], "ls"))
+ if (!strcmp(cmd->name, "ls"))
ls_only = 1;
- if (!(dmt = dm_task_create(cmd)))
+ if (!(dmt = dm_task_create(cmdno)))
return 0;
if (!_set_task_device(dmt, name, 0))
@@ -1545,6 +1640,12 @@ static int _status(int argc, char **argv, void *data)
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto out;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
+ if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
+ goto out;
+
if (!dm_task_run(dmt))
goto out;
@@ -1571,12 +1672,12 @@ static int _status(int argc, char **argv, void *data)
_switches[VERBOSE_ARG]) {
if (!matched && _switches[VERBOSE_ARG])
_display_info(dmt);
- if (data && !_switches[VERBOSE_ARG])
+ if (multiple_devices && !_switches[VERBOSE_ARG])
printf("%s: ", name);
if (target_type) {
/* Suppress encryption key */
if (!_switches[SHOWKEYS_ARG] &&
- cmd == DM_DEVICE_TABLE &&
+ cmdno == DM_DEVICE_TABLE &&
!strcmp(target_type, "crypt")) {
c = params;
while (*c && *c != ' ')
@@ -1594,7 +1695,7 @@ static int _status(int argc, char **argv, void *data)
matched = 1;
} while (next);
- if (data && _switches[VERBOSE_ARG] && matched && !ls_only)
+ if (multiple_devices && _switches[VERBOSE_ARG] && matched && !ls_only)
printf("\n");
if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name))
@@ -1608,7 +1709,7 @@ static int _status(int argc, char **argv, void *data)
}
/* Show target names and their version numbers */
-static int _targets(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data __attribute__((unused)))
+static int _targets(CMD_ARGS)
{
int r = 0;
struct dm_task *dmt;
@@ -1618,6 +1719,9 @@ static int _targets(int argc __attribute__((unused)), char **argv __attribute__(
if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
return 0;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
if (!dm_task_run(dmt))
goto out;
@@ -1640,21 +1744,19 @@ static int _targets(int argc __attribute__((unused)), char **argv __attribute__(
return r;
}
-static int _info(int argc, char **argv, void *data)
+static int _info(CMD_ARGS)
{
int r = 0;
struct dm_task *dmt;
- struct dm_names *names = (struct dm_names *) data;
char *name = NULL;
- if (data)
+ if (names)
name = names->name;
else {
if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
- return _process_all(argc, argv, 0, _info);
- if (argc == 2)
- name = argv[1];
+ return _process_all(cmd, argc, argv, 0, _info);
+ name = argv[1];
}
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
@@ -1669,6 +1771,9 @@ static int _info(int argc, char **argv, void *data)
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto out;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
if (!dm_task_run(dmt))
goto out;
@@ -1679,23 +1784,23 @@ static int _info(int argc, char **argv, void *data)
return r;
}
-static int _deps(int argc, char **argv, void *data)
+static int _deps(CMD_ARGS)
{
int r = 0;
uint32_t i;
struct dm_deps *deps;
struct dm_task *dmt;
struct dm_info info;
- struct dm_names *names = (struct dm_names *) data;
char *name = NULL;
+ char dev_name[PATH_MAX];
+ int major, minor;
- if (data)
+ if (names)
name = names->name;
else {
if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
- return _process_all(argc, argv, 0, _deps);
- if (argc == 2)
- name = argv[1];
+ return _process_all(cmd, argc, argv, 0, _deps);
+ name = argv[1];
}
if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
@@ -1710,6 +1815,9 @@ static int _deps(int argc, char **argv, void *data)
if (_switches[INACTIVE_ARG] && !dm_task_query_inactive_table(dmt))
goto out;
+ if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
if (!dm_task_run(dmt))
goto out;
@@ -1728,17 +1836,24 @@ static int _deps(int argc, char **argv, void *data)
if (_switches[VERBOSE_ARG])
_display_info(dmt);
- if (data && !_switches[VERBOSE_ARG])
+ if (multiple_devices && !_switches[VERBOSE_ARG])
printf("%s: ", name);
printf("%d dependencies\t:", deps->count);
- for (i = 0; i < deps->count; i++)
- printf(" (%d, %d)",
- (int) MAJOR(deps->device[i]),
- (int) MINOR(deps->device[i]));
+ for (i = 0; i < deps->count; i++) {
+ major = (int) MAJOR(deps->device[i]);
+ minor = (int) MINOR(deps->device[i]);
+
+ if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) &&
+ dm_device_get_name(major, minor, _dev_name_type == DN_BLK,
+ dev_name, PATH_MAX))
+ printf(" (%s)", dev_name);
+ else
+ printf(" (%d, %d)", major, minor);
+ }
printf("\n");
- if (data && _switches[VERBOSE_ARG])
+ if (multiple_devices && _switches[VERBOSE_ARG])
printf("\n");
r = 1;
@@ -1748,12 +1863,21 @@ static int _deps(int argc, char **argv, void *data)
return r;
}
-static int _display_name(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data)
+static int _display_name(CMD_ARGS)
{
- struct dm_names *names = (struct dm_names *) data;
+ char dev_name[PATH_MAX];
+
+ if (!names)
+ return 1;
- printf("%s\t(%d, %d)\n", names->name,
- (int) MAJOR(names->dev), (int) MINOR(names->dev));
+ if ((_dev_name_type == DN_BLK || _dev_name_type == DN_MAP) &&
+ dm_device_get_name((int) MAJOR(names->dev), (int) MINOR(names->dev),
+ _dev_name_type == DN_BLK, dev_name, PATH_MAX))
+ printf("%s\t(%s)\n", names->name, dev_name);
+ else
+ printf("%s\t(%d:%d)\n", names->name,
+ (int) MAJOR(names->dev),
+ (int) MINOR(names->dev));
return 1;
}
@@ -1764,6 +1888,7 @@ static int _display_name(int argc __attribute__((unused)), char **argv __attribu
enum {
TR_DEVICE=0, /* display device major:minor number */
+ TR_BLKDEVNAME, /* display device kernel name */
TR_TABLE,
TR_STATUS,
TR_ACTIVE,
@@ -1970,6 +2095,11 @@ static void _display_tree_attributes(struct dm_tree_node *node)
_out_char(']');
}
+/* FIXME Display table or status line. (Disallow both?) */
+static void _display_tree_targets(struct dm_tree_node *node, unsigned depth)
+{
+}
+
static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
unsigned first_child __attribute__((unused)),
unsigned last_child, unsigned has_children)
@@ -1978,6 +2108,7 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
const char *name;
const struct dm_info *info;
int first_on_line = 0;
+ char dev_name[PATH_MAX];
/* Sub-tree for targets has 2 more depth */
if (depth + 2 > MAX_DEPTH)
@@ -1985,7 +2116,8 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
name = dm_tree_node_get_name(node);
- if ((!name || !*name) && !_tree_switches[TR_DEVICE])
+ if ((!name || !*name) &&
+ (!_tree_switches[TR_DEVICE] && !_tree_switches[TR_BLKDEVNAME]))
return;
/* Indicate whether there are more nodes at this depth */
@@ -2010,6 +2142,13 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
info = dm_tree_node_get_info(node);
+ if (_tree_switches[TR_BLKDEVNAME] &&
+ dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) {
+ _out_string(name ? " <" : "<");
+ _out_string(dev_name);
+ _out_char('>');
+ }
+
if (_tree_switches[TR_DEVICE]) {
_out_string(name ? " (" : "(");
(void) _out_int(info->major);
@@ -2030,7 +2169,7 @@ static void _display_tree_node(struct dm_tree_node *node, unsigned depth,
if (TR_PRINT_TARGETS) {
_tree_more[depth + 1] = has_children;
- // FIXME _display_tree_targets(name, depth + 2);
+ _display_tree_targets(node, depth + 2);
}
}
@@ -2063,11 +2202,10 @@ static void _display_tree_walk_children(struct dm_tree_node *node,
}
}
-static int _add_dep(int argc __attribute__((unused)), char **argv __attribute__((unused)), void *data)
+static int _add_dep(CMD_ARGS)
{
- struct dm_names *names = (struct dm_names *) data;
-
- if (!dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev)))
+ if (names &&
+ !dm_tree_add_dev(_dtree, (unsigned) MAJOR(names->dev), (unsigned) MINOR(names->dev)))
return 0;
return 1;
@@ -2076,7 +2214,7 @@ static int _add_dep(int argc __attribute__((unused)), char **argv __attribute__(
/*
* Create and walk dependency tree
*/
-static int _build_whole_deptree(void)
+static int _build_whole_deptree(const struct command *cmd)
{
if (_dtree)
return 1;
@@ -2084,17 +2222,15 @@ static int _build_whole_deptree(void)
if (!(_dtree = dm_tree_create()))
return 0;
- if (!_process_all(0, NULL, 0, _add_dep))
+ if (!_process_all(cmd, 0, NULL, 0, _add_dep))
return 0;
return 1;
}
-static int _display_tree(int argc __attribute__((unused)),
- char **argv __attribute__((unused)),
- void *data __attribute__((unused)))
+static int _display_tree(CMD_ARGS)
{
- if (!_build_whole_deptree())
+ if (!_build_whole_deptree(cmd))
return 0;
_display_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
@@ -2138,6 +2274,38 @@ static int _dm_name_disp(struct dm_report *rh,
return dm_report_field_string(rh, field, &name);
}
+static int _dm_mangled_name_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute__((unused)),
+ struct dm_report_field *field, const void *data,
+ void *private __attribute__((unused)))
+{
+ char *name;
+ int r = 0;
+
+ if ((name = dm_task_get_name_mangled((const struct dm_task *) data))) {
+ r = dm_report_field_string(rh, field, (const char * const *) &name);
+ dm_free(name);
+ }
+
+ return r;
+}
+
+static int _dm_unmangled_name_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute__((unused)),
+ struct dm_report_field *field, const void *data,
+ void *private __attribute__((unused)))
+{
+ char *name;
+ int r = 0;
+
+ if ((name = dm_task_get_name_unmangled((const struct dm_task *) data))) {
+ r = dm_report_field_string(rh, field, (const char * const *) &name);
+ dm_free(name);
+ }
+
+ return r;
+}
+
static int _dm_uuid_disp(struct dm_report *rh,
struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field,
@@ -2151,6 +2319,38 @@ static int _dm_uuid_disp(struct dm_report *rh,
return dm_report_field_string(rh, field, &uuid);
}
+static int _dm_mangled_uuid_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute__((unused)),
+ struct dm_report_field *field,
+ const void *data, void *private __attribute__((unused)))
+{
+ char *uuid;
+ int r = 0;
+
+ if ((uuid = dm_task_get_uuid_mangled((const struct dm_task *) data))) {
+ r = dm_report_field_string(rh, field, (const char * const *) &uuid);
+ dm_free(uuid);
+ }
+
+ return r;
+}
+
+static int _dm_unmangled_uuid_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute__((unused)),
+ struct dm_report_field *field,
+ const void *data, void *private __attribute__((unused)))
+{
+ char *uuid;
+ int r = 0;
+
+ if ((uuid = dm_task_get_uuid_unmangled((const struct dm_task *) data))) {
+ r = dm_report_field_string(rh, field, (const char * const *) &uuid);
+ dm_free(uuid);
+ }
+
+ return r;
+}
+
static int _dm_read_ahead_disp(struct dm_report *rh,
struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field, const void *data,
@@ -2164,6 +2364,24 @@ static int _dm_read_ahead_disp(struct dm_report *rh,
return dm_report_field_uint32(rh, field, &value);
}
+static int _dm_blk_name_disp(struct dm_report *rh,
+ struct dm_pool *mem __attribute__((unused)),
+ struct dm_report_field *field, const void *data,
+ void *private __attribute__((unused)))
+{
+ char dev_name[PATH_MAX];
+ const char *s = dev_name;
+ const struct dm_info *info = data;
+
+ if (!dm_device_get_name(info->major, info->minor, 1, dev_name, PATH_MAX)) {
+ log_error("Could not resolve block device name for %d:%d.",
+ info->major, info->minor);
+ return 0;
+ }
+
+ return dm_report_field_string(rh, field, &s);
+}
+
static int _dm_info_status_disp(struct dm_report *rh,
struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field, const void *data,
@@ -2243,7 +2461,7 @@ static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field, const void *data,
void *private)
{
- char buf[DM_MAX_TYPE_NAME], *repstr;
+ char buf[PATH_MAX], *repstr;
const struct dm_info *info = data;
if (!dm_pool_begin_object(mem, 8)) {
@@ -2251,10 +2469,17 @@ static int _dm_info_devno_disp(struct dm_report *rh, struct dm_pool *mem,
return 0;
}
- if (dm_snprintf(buf, sizeof(buf), "%d:%d",
- info->major, info->minor) < 0) {
- log_error("dm_pool_alloc failed");
- goto out_abandon;
+ if (private) {
+ if (!dm_device_get_name(info->major, info->minor,
+ 1, buf, PATH_MAX))
+ goto out_abandon;
+ }
+ else {
+ if (dm_snprintf(buf, sizeof(buf), "%d:%d",
+ info->major, info->minor) < 0) {
+ log_error("dm_pool_alloc failed");
+ goto out_abandon;
+ }
}
if (!dm_pool_grow_object(mem, buf, strlen(buf) + 1)) {
@@ -2395,13 +2620,14 @@ static int _dm_tree_parents_count_disp(struct dm_report *rh,
return dm_report_field_int(rh, field, &num_parent);
}
-static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
- struct dm_report_field *field, const void *data,
- void *private)
+static int _dm_deps_disp_common(struct dm_report *rh, struct dm_pool*mem,
+ struct dm_report_field *field, const void *data,
+ void *private, int disp_blk_dev_names)
{
const struct dm_deps *deps = data;
- int i;
- char buf[DM_MAX_TYPE_NAME], *repstr;
+ char buf[PATH_MAX], *repstr;
+ int major, minor;
+ unsigned i;
if (!dm_pool_begin_object(mem, 16)) {
log_error("dm_pool_begin_object failed");
@@ -2409,16 +2635,27 @@ static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
}
for (i = 0; i < deps->count; i++) {
- if (dm_snprintf(buf, sizeof(buf), "%d:%d",
- (int) MAJOR(deps->device[i]),
- (int) MINOR(deps->device[i])) < 0) {
+ major = (int) MAJOR(deps->device[i]);
+ minor = (int) MINOR(deps->device[i]);
+
+ if (disp_blk_dev_names) {
+ if (!dm_device_get_name(major, minor, 1, buf, PATH_MAX)) {
+ log_error("Could not resolve block device "
+ "name for %d:%d.", major, minor);
+ goto out_abandon;
+ }
+ }
+ else if (dm_snprintf(buf, sizeof(buf), "%d:%d",
+ major, minor) < 0) {
log_error("dm_snprintf failed");
goto out_abandon;
}
+
if (!dm_pool_grow_object(mem, buf, 0)) {
log_error("dm_pool_grow_object failed");
goto out_abandon;
}
+
if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
log_error("dm_pool_grow_object failed");
goto out_abandon;
@@ -2439,12 +2676,26 @@ static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
return 0;
}
+static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field, const void *data,
+ void *private)
+{
+ return _dm_deps_disp_common(rh, mem, field, data, private, 0);
+}
+
+static int _dm_deps_blk_names_disp(struct dm_report *rh, struct dm_pool *mem,
+ struct dm_report_field *field,
+ const void *data, void *private)
+{
+ return _dm_deps_disp_common(rh, mem, field, data, private, 1);
+}
+
static int _dm_subsystem_disp(struct dm_report *rh,
struct dm_pool *mem __attribute__((unused)),
struct dm_report_field *field, const void *data,
void *private __attribute__((unused)))
{
- return dm_report_field_string(rh, field, (const char **) data);
+ return dm_report_field_string(rh, field, (const char *const *) data);
}
static int _dm_vg_name_disp(struct dm_report *rh,
@@ -2453,7 +2704,7 @@ static int _dm_vg_name_disp(struct dm_report *rh,
void *private __attribute__((unused)))
{
- return dm_report_field_string(rh, field, (const char **) data);
+ return dm_report_field_string(rh, field, (const char *const *) data);
}
static int _dm_lv_name_disp(struct dm_report *rh,
@@ -2462,7 +2713,7 @@ static int _dm_lv_name_disp(struct dm_report *rh,
void *private __attribute__((unused)))
{
- return dm_report_field_string(rh, field, (const char **) data);
+ return dm_report_field_string(rh, field, (const char *const *) data);
}
static int _dm_lv_layer_name_disp(struct dm_report *rh,
@@ -2471,7 +2722,7 @@ static int _dm_lv_layer_name_disp(struct dm_report *rh,
void *private __attribute__((unused)))
{
- return dm_report_field_string(rh, field, (const char **) data);
+ return dm_report_field_string(rh, field, (const char *const *) data);
}
static void *_task_get_obj(void *obj)
@@ -2518,11 +2769,16 @@ static const struct dm_report_object_type _report_types[] = {
static const struct dm_report_field_type _report_fields[] = {
/* *INDENT-OFF* */
FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
+FIELD_F(TASK, STR, "MangledName", 16, dm_mangled_name, "mangled_name", "Mangled name of mapped device.")
+FIELD_F(TASK, STR, "UnmangledName", 16, dm_unmangled_name, "unmangled_name", "Unmangled name of mapped device.")
FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
+FIELD_F(TASK, STR, "MangledUUID", 32, dm_mangled_uuid, "mangled_uuid", "Mangled unique (optional) identifier for mapped device.")
+FIELD_F(TASK, STR, "UnmangledUUID", 32, dm_unmangled_uuid, "unmangled_uuid", "Unmangled unique (optional) identifier for mapped device.")
/* FIXME Next one should be INFO */
FIELD_F(TASK, NUM, "RAhead", 6, dm_read_ahead, "read_ahead", "Read ahead in sectors.")
+FIELD_F(INFO, STR, "BlkDevName", 16, dm_blk_name, "blkdevname", "Name of block device.")
FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
FIELD_F(INFO, STR, "Tables", 6, dm_info_table_loaded, "tables_loaded", "Which of the live and inactive table slots are filled.")
FIELD_F(INFO, STR, "Suspended", 9, dm_info_suspended, "suspended", "Whether the device is suspended.")
@@ -2535,8 +2791,9 @@ FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number
FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
FIELD_O(DEPS, dm_deps, NUM, "#Devs", count, 5, int32, "device_count", "Number of devices used by this one.")
-FIELD_F(TREE, STR, "DevNames", 8, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")
-FIELD_F(DEPS, STR, "DevNos", 6, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")
+FIELD_F(TREE, STR, "DevNamesUsed", 16, dm_deps_names, "devs_used", "List of names of mapped devices used by this one.")
+FIELD_F(DEPS, STR, "DevNosUsed", 16, dm_deps, "devnos_used", "List of device numbers of devices used by this one.")
+FIELD_F(DEPS, STR, "BlkDevNamesUsed", 16, dm_deps_blk_names, "blkdevs_used", "List of names of block devices used by this one.")
FIELD_F(TREE, NUM, "#Refs", 5, dm_tree_parents_count, "device_ref_count", "Number of mapped devices referencing this one.")
FIELD_F(TREE, STR, "RefNames", 8, dm_tree_parents_names, "names_using_dev", "List of names of mapped devices using this one.")
@@ -2559,7 +2816,7 @@ FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_
static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";
static const char *splitname_report_options = "vg_name,lv_name,lv_layer";
-static int _report_init(struct command *c)
+static int _report_init(const struct command *cmd)
{
char *options = (char *) default_report_options;
const char *keys = "";
@@ -2570,7 +2827,7 @@ static int _report_init(struct command *c)
size_t len = 0;
int r = 0;
- if (c && !strcmp(c->name, "splitname"))
+ if (cmd && !strcmp(cmd->name, "splitname"))
options = (char *) splitname_report_options;
/* emulate old dmsetup behaviour */
@@ -2616,7 +2873,7 @@ static int _report_init(struct command *c)
if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
keys = _string_args[SORT_ARG];
buffered = 1;
- if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) {
+ if (cmd && (!strcmp(cmd->name, "status") || !strcmp(cmd->name, "table"))) {
err("--sort is not yet supported with status and table");
goto out;
}
@@ -2650,7 +2907,7 @@ static int _report_init(struct command *c)
options, separator, flags, keys, NULL)))
goto out;
- if ((_report_type & DR_TREE) && !_build_whole_deptree()) {
+ if ((_report_type & DR_TREE) && !_build_whole_deptree(cmd)) {
err("Internal device dependency tree creation failed.");
goto out;
}
@@ -2673,56 +2930,149 @@ out:
/*
* List devices
*/
-static int _ls(int argc, char **argv, void *data)
+static int _ls(CMD_ARGS)
{
if ((_switches[TARGET_ARG] && _target) ||
(_switches[EXEC_ARG] && _command))
- return _status(argc, argv, data);
+ return _status(cmd, argc, argv, NULL, 0);
else if ((_switches[TREE_ARG]))
- return _display_tree(argc, argv, data);
+ return _display_tree(cmd, 0, NULL, NULL, 0);
else
- return _process_all(argc, argv, 0, _display_name);
+ return _process_all(cmd, argc, argv, 0, _display_name);
}
-static int _help(int argc, char **argv, void *data);
+static int _mangle(CMD_ARGS)
+{
+ const char *name, *uuid;
+ char *new_name = NULL, *new_uuid = NULL;
+ struct dm_task *dmt;
+ struct dm_info info;
+ int r = 0;
+ int target_format;
+
+ if (names)
+ name = names->name;
+ else {
+ if (argc == 1 && !_switches[UUID_ARG] && !_switches[MAJOR_ARG])
+ return _process_all(cmd, argc, argv, 0, _mangle);
+ name = argv[1];
+ }
+
+ if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
+ return 0;
+
+ if (!(_set_task_device(dmt, name, 0)))
+ goto out;
+
+ if (!_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
+ goto out;
+
+ if (!dm_task_run(dmt))
+ goto out;
+
+ if (!dm_task_get_info(dmt, &info) || !info.exists)
+ goto out;
+
+ uuid = dm_task_get_uuid(dmt);
+
+ target_format = _switches[MANGLENAME_ARG] ? _int_args[MANGLENAME_ARG]
+ : DEFAULT_DM_NAME_MANGLING;
+
+ if (target_format == DM_STRING_MANGLING_AUTO) {
+ if (strstr(name, "\\x5cx")) {
+ log_error("The name \"%s\" seems to be mangled more than once. "
+ "Manual intervention required to rename the device.", name);
+ goto out;
+ }
+ if (strstr(uuid, "\\x5cx")) {
+ log_error("The UUID \"%s\" seems to be mangled more than once. "
+ "Manual intervention required to correct the device UUID.", uuid);
+ goto out;
+ }
+ }
+
+ if (target_format == DM_STRING_MANGLING_NONE) {
+ if (!(new_name = dm_task_get_name_unmangled(dmt)))
+ goto out;
+ if (!(new_uuid = dm_task_get_uuid_unmangled(dmt)))
+ goto out;
+ }
+ else {
+ if (!(new_name = dm_task_get_name_mangled(dmt)))
+ goto out;
+ if (!(new_uuid = dm_task_get_uuid_mangled(dmt)))
+ goto out;
+ }
+
+ /* We can't rename the UUID, the device must be reactivated manually. */
+ if (strcmp(uuid, new_uuid)) {
+ log_error("%s: %s: UUID in incorrect form. ", name, uuid);
+ log_error("Unable to change device UUID. The device must be deactivated first.");
+ r = 0;
+ goto out;
+ }
+
+ /* Nothing to do if the name is in correct form already. */
+ if (!strcmp(name, new_name)) {
+ log_print("%s: %s: name %salready in correct form", name,
+ *uuid ? uuid : "[no UUID]", *uuid ? "and UUID " : "");
+ r = 1;
+ goto out;
+ }
+ else
+ log_print("%s: renaming to %s", name, new_name);
+
+ /* Rename to correct form of the name. */
+ r = _do_rename(name, new_name, NULL);
+
+out:
+ dm_free(new_name);
+ dm_free(new_uuid);
+ dm_task_destroy(dmt);
+ return r;
+}
+
+static int _help(CMD_ARGS);
/*
* Dispatch table
*/
static struct command _commands[] = {
- {"help", "[-c|-C|--columns]", 0, 0, _help},
+ {"help", "[-c|-C|--columns]", 0, 0, 0, _help},
{"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
"\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
- "\t [-u|uuid <uuid>]\n"
+ "\t [-u|uuid <uuid>] [{--addnodeonresume|--addnodeoncreate}]\n"
"\t [--notable | --table <table> | <table_file>]",
- 1, 2, _create},
- {"remove", "[-f|--force] <device>", 0, 1, _remove},
- {"remove_all", "[-f|--force]", 0, 0, _remove_all},
- {"suspend", "[--noflush] <device>", 0, 1, _suspend},
- {"resume", "<device>", 0, 1, _resume},
- {"load", "<device> [<table_file>]", 0, 2, _load},
- {"clear", "<device>", 0, 1, _clear},
- {"reload", "<device> [<table_file>]", 0, 2, _load},
- {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, _rename},
- {"message", "<device> <sector> <message>", 2, -1, _message},
- {"ls", "[--target <target_type>] [--exec <command>] [--tree [-o options]]", 0, 0, _ls},
- {"info", "[<device>]", 0, 1, _info},
- {"deps", "[<device>]", 0, 1, _deps},
- {"status", "[<device>] [--target <target_type>]", 0, 1, _status},
- {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status},
- {"wait", "<device> [<event_nr>]", 0, 2, _wait},
- {"mknodes", "[<device>]", 0, 1, _mknodes},
- {"udevcreatecookie", "", 0, 0, _udevcreatecookie},
- {"udevreleasecookie", "[<cookie>]", 0, 1, _udevreleasecookie},
- {"udevflags", "<cookie>", 1, 1, _udevflags},
- {"udevcomplete", "<cookie>", 1, 1, _udevcomplete},
- {"udevcomplete_all", "", 0, 0, _udevcomplete_all},
- {"udevcookies", "", 0, 0, _udevcookies},
- {"targets", "", 0, 0, _targets},
- {"version", "", 0, 0, _version},
- {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, _setgeometry},
- {"splitname", "<device> [<subsystem>]", 1, 2, _splitname},
- {NULL, NULL, 0, 0, NULL}
+ 1, 2,0, _create},
+ {"remove", "[-f|--force] <device>", 0, -1, 1, _remove},
+ {"remove_all", "[-f|--force]", 0, 0, 0, _remove_all},
+ {"suspend", "[--noflush] <device>", 0, -1, 1, _suspend},
+ {"resume", "<device> [{--addnodeonresume|--addnodeoncreate}]", 0, -1, 1, _resume},
+ {"load", "<device> [<table_file>]", 0, 2, 0, _load},
+ {"clear", "<device>", 0, -1, 1, _clear},
+ {"reload", "<device> [<table_file>]", 0, 2, 0, _load},
+ {"wipe_table", "<device>", 0, -1, 1, _error_device},
+ {"rename", "<device> [--setuuid] <new_name_or_uuid>", 1, 2, 0, _rename},
+ {"message", "<device> <sector> <message>", 2, -1, 0, _message},
+ {"ls", "[--target <target_type>] [--exec <command>] [-o options] [--tree]", 0, 0, 0, _ls},
+ {"info", "[<device>]", 0, -1, 1, _info},
+ {"deps", "[-o options] [<device>]", 0, -1, 1, _deps},
+ {"status", "[<device>] [--noflush] [--target <target_type>]", 0, -1, 1, _status},
+ {"table", "[<device>] [--target <target_type>] [--showkeys]", 0, -1, 1, _status},
+ {"wait", "<device> [<event_nr>] [--noflush]", 0, 2, 0, _wait},
+ {"mknodes", "[<device>]", 0, -1, 1, _mknodes},
+ {"mangle", "[<device>]", 0, -1, 1, _mangle},
+ {"udevcreatecookie", "", 0, 0, 0, _udevcreatecookie},
+ {"udevreleasecookie", "[<cookie>]", 0, 1, 0, _udevreleasecookie},
+ {"udevflags", "<cookie>", 1, 1, 0, _udevflags},
+ {"udevcomplete", "<cookie>", 1, 1, 0, _udevcomplete},
+ {"udevcomplete_all", "<age_in_minutes>", 0, 1, 0, _udevcomplete_all},
+ {"udevcookies", "", 0, 0, 0, _udevcookies},
+ {"targets", "", 0, 0, 0, _targets},
+ {"version", "", 0, 0, 0, _version},
+ {"setgeometry", "<device> <cyl> <head> <sect> <start>", 5, 5, 0, _setgeometry},
+ {"splitname", "<device> [<subsystem>]", 1, 2, 0, _splitname},
+ {NULL, NULL, 0, 0, 0, NULL}
};
static void _usage(FILE *out)
@@ -2731,20 +3081,22 @@ static void _usage(FILE *out)
fprintf(out, "Usage:\n\n");
fprintf(out, "dmsetup [--version] [-h|--help [-c|-C|--columns]]\n"
- " [-v|--verbose [-v|--verbose ...]]\n"
+ " [--checks] [--manglename <mangling_mode>] [-v|--verbose [-v|--verbose ...]]\n"
" [-r|--readonly] [--noopencount] [--nolockfs] [--inactive]\n"
- " [--udevcookie] [--noudevrules] [--noudevsync] [-y|--yes]\n"
- " [--readahead [+]<sectors>|auto|none]\n"
+ " [--udevcookie [cookie]] [--noudevrules] [--noudevsync] [--verifyudev]\n"
+ " [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
" [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
" [--nameprefixes] [--noheadings] [--separator <separator>]\n\n");
for (i = 0; _commands[i].name; i++)
fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
fprintf(out, "\n<device> may be device name or -u <uuid> or "
"-j <major> -m <minor>\n");
+ fprintf(out, "<mangling_mode> is one of 'none', 'auto' and 'hex'.\n");
fprintf(out, "<fields> are comma-separated. Use 'help -c' for list.\n");
fprintf(out, "Table_file contents may be supplied on stdin.\n");
- fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
- " [no]device, active, open, rw and uuid.\n");
+ fprintf(out, "Options are: devno, devname, blkdevname.\n");
+ fprintf(out, "Tree specific options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
+ " blkdevname, [no]device, active, open, rw and uuid.\n");
fprintf(out, "\n");
}
@@ -2755,9 +3107,7 @@ static void _losetup_usage(FILE *out)
"[-o offset] [-f|loop_device] [file]\n\n");
}
-static int _help(int argc __attribute__((unused)),
- char **argv __attribute__((unused)),
- void *data __attribute__((unused)))
+static int _help(CMD_ARGS)
{
_usage(stderr);
@@ -2770,7 +3120,7 @@ static int _help(int argc __attribute__((unused)),
dm_report_free(_report);
_report = NULL;
}
- (void) _report_init(NULL);
+ (void) _report_init(cmd);
}
return 1;
@@ -2810,6 +3160,8 @@ static int _process_tree_options(const char *options)
;
if (!strncmp(s, "device", len))
_tree_switches[TR_DEVICE] = 1;
+ else if (!strncmp(s, "blkdevname", len))
+ _tree_switches[TR_BLKDEVNAME] = 1;
else if (!strncmp(s, "nodevice", len))
_tree_switches[TR_DEVICE] = 0;
else if (!strncmp(s, "status", len))
@@ -2865,6 +3217,8 @@ static char *_get_abspath(const char *path)
_path = canonicalize_file_name(path);
#else
/* FIXME Provide alternative */
+ log_error(INTERNAL_ERROR "Unimplemented _get_abspath.");
+ _path = NULL;
#endif
return _path;
}
@@ -2872,7 +3226,7 @@ static char *_get_abspath(const char *path)
static char *parse_loop_device_name(const char *dev, const char *dev_dir)
{
char *buf;
- char *device;
+ char *device = NULL;
if (!(buf = dm_malloc(PATH_MAX)))
return NULL;
@@ -2890,7 +3244,8 @@ static char *parse_loop_device_name(const char *dev, const char *dev_dir)
device[strlen(dev_dir)] != '/')
goto error;
- strncpy(buf, strrchr(device, '/') + 1, (size_t) PATH_MAX);
+ strncpy(buf, strrchr(device, '/') + 1, PATH_MAX - 1);
+ buf[PATH_MAX - 1] = '\0';
dm_free(device);
} else {
@@ -2904,7 +3259,9 @@ static char *parse_loop_device_name(const char *dev, const char *dev_dir)
return buf;
error:
+ dm_free(device);
dm_free(buf);
+
return NULL;
}
@@ -2952,7 +3309,8 @@ static int _loop_table(char *table, size_t tlen, char *file,
blksize = fsbuf.f_frsize;
#endif
- close(fd);
+ if (close(fd))
+ log_sys_error("close", file);
if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
(long long unsigned)sectors, file, (long long unsigned)off) < 0)
@@ -2964,15 +3322,15 @@ static int _loop_table(char *table, size_t tlen, char *file,
return 1;
error:
- if (fd > -1)
- close(fd);
+ if (fd > -1 && close(fd))
+ log_sys_error("close", file);
+
return 0;
}
static int _process_losetup_switches(const char *base, int *argc, char ***argv,
const char *dev_dir)
{
- static int ind;
int c;
int encrypt_loop = 0, delete = 0, find = 0, show_all = 0;
char *device_name = NULL;
@@ -2987,8 +3345,8 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv,
optarg = 0;
optind = OPTIND_INIT;
- while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
- long_options, NULL)) != -1 ) {
+ while ((c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
+ long_options, NULL)) != -1 ) {
if (c == ':' || c == '?')
return 0;
if (c == 'a')
@@ -3065,9 +3423,9 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv,
return 0;
}
- /* FIXME Missing free */
_table = dm_malloc(LOOP_TABLE_SIZE);
- if (!_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
+ if (!_table ||
+ !_loop_table(_table, (size_t) LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
dm_free(device_name);
return 0;
@@ -3080,21 +3438,68 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv,
return 1;
}
+static int _process_options(const char *options)
+{
+ const char *s, *end;
+ size_t len;
+
+ /* Tree options are processed separately. */
+ if (_switches[TREE_ARG])
+ return _process_tree_options(_string_args[OPTIONS_ARG]);
+
+ /* Column options are processed separately by _report_init (called later). */
+ if (_switches[COLS_ARG])
+ return 1;
+
+ /* No options specified. */
+ if (!_switches[OPTIONS_ARG])
+ return 1;
+
+ /* Set defaults. */
+ _dev_name_type = DN_DEVNO;
+
+ /* Parse. */
+ for (s = options; s && *s; s++) {
+ len = 0;
+ for (end = s; *end && *end != ','; end++, len++)
+ ;
+ if (!strncmp(s, "devno", len))
+ _dev_name_type = DN_DEVNO;
+ else if (!strncmp(s, "blkdevname", len))
+ _dev_name_type = DN_BLK;
+ else if (!strncmp(s, "devname", len))
+ _dev_name_type = DN_MAP;
+ else {
+ fprintf(stderr, "Option not recognised: %s\n", s);
+ return 0;
+ }
+
+ if (!*end)
+ break;
+ s = end;
+ }
+
+ return 1;
+}
+
static int _process_switches(int *argc, char ***argv, const char *dev_dir)
{
- char *base, *namebase, *s;
+ const char *base;
+ char *namebase, *s;
static int ind;
int c, r;
#ifdef HAVE_GETOPTLONG
static struct option long_options[] = {
{"readonly", 0, &ind, READ_ONLY},
+ {"checks", 0, &ind, CHECKS_ARG},
{"columns", 0, &ind, COLS_ARG},
{"exec", 1, &ind, EXEC_ARG},
{"force", 0, &ind, FORCE_ARG},
{"gid", 1, &ind, GID_ARG},
{"help", 0, &ind, HELP_ARG},
{"inactive", 0, &ind, INACTIVE_ARG},
+ {"manglename", 1, &ind, MANGLENAME_ARG},
{"major", 1, &ind, MAJOR_ARG},
{"minor", 1, &ind, MINOR_ARG},
{"mode", 1, &ind, MODE_ARG},
@@ -3109,6 +3514,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
{"noudevsync", 0, &ind, NOUDEVSYNC_ARG},
{"options", 1, &ind, OPTIONS_ARG},
{"readahead", 1, &ind, READAHEAD_ARG},
+ {"retry", 0, &ind, RETRY_ARG},
{"rows", 0, &ind, ROWS_ARG},
{"separator", 1, &ind, SEPARATOR_ARG},
{"setuuid", 0, &ind, SETUUID_ARG},
@@ -3122,8 +3528,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
{"unbuffered", 0, &ind, UNBUFFERED_ARG},
{"unquoted", 0, &ind, UNQUOTED_ARG},
{"verbose", 1, &ind, VERBOSE_ARG},
+ {"verifyudev", 0, &ind, VERIFYUDEV_ARG},
{"version", 0, &ind, VERSION_ARG},
{"yes", 0, &ind, YES_ARG},
+ {"addnodeonresume", 0, &ind, ADD_NODE_ON_RESUME_ARG},
+ {"addnodeoncreate", 0, &ind, ADD_NODE_ON_CREATE_ARG},
{0, 0, 0, 0}
};
#else
@@ -3137,8 +3546,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
memset(&_int_args, 0, sizeof(_int_args));
_read_ahead_flags = 0;
- namebase = strdup((*argv)[0]);
- base = basename(namebase);
+ if (!(namebase = strdup((*argv)[0]))) {
+ fprintf(stderr, "Failed to duplicate name.\n");
+ return 0;
+ }
+ base = dm_basename(namebase);
if (!strcmp(base, "devmap_name")) {
free(namebase);
@@ -3221,6 +3633,12 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
}
if (c == 'y' || ind == YES_ARG)
_switches[YES_ARG]++;
+ if (ind == ADD_NODE_ON_RESUME_ARG)
+ _switches[ADD_NODE_ON_RESUME_ARG]++;
+ if (ind == ADD_NODE_ON_CREATE_ARG)
+ _switches[ADD_NODE_ON_CREATE_ARG]++;
+ if (ind == CHECKS_ARG)
+ _switches[CHECKS_ARG]++;
if (ind == UDEVCOOKIE_ARG) {
_switches[UDEVCOOKIE_ARG]++;
_udev_cookie = _get_cookie_value(optarg);
@@ -3229,6 +3647,8 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
_switches[NOUDEVRULES_ARG]++;
if (ind == NOUDEVSYNC_ARG)
_switches[NOUDEVSYNC_ARG]++;
+ if (ind == VERIFYUDEV_ARG)
+ _switches[VERIFYUDEV_ARG]++;
if (c == 'G' || ind == GID_ARG) {
_switches[GID_ARG]++;
_int_args[GID_ARG] = atoi(optarg);
@@ -3242,32 +3662,46 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
/* FIXME Accept modes as per chmod */
_int_args[MODE_ARG] = (int) strtol(optarg, NULL, 8);
}
- if ((ind == EXEC_ARG)) {
+ if (ind == EXEC_ARG) {
_switches[EXEC_ARG]++;
_command = optarg;
}
- if ((ind == TARGET_ARG)) {
+ if (ind == TARGET_ARG) {
_switches[TARGET_ARG]++;
_target = optarg;
}
- if ((ind == INACTIVE_ARG))
- _switches[INACTIVE_ARG]++;
- if ((ind == NAMEPREFIXES_ARG))
+ if (ind == INACTIVE_ARG)
+ _switches[INACTIVE_ARG]++;
+ if ((ind == MANGLENAME_ARG)) {
+ _switches[MANGLENAME_ARG]++;
+ if (!strcasecmp(optarg, "none"))
+ _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_NONE;
+ else if (!strcasecmp(optarg, "auto"))
+ _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_AUTO;
+ else if (!strcasecmp(optarg, "hex"))
+ _int_args[MANGLENAME_ARG] = DM_STRING_MANGLING_HEX;
+ else {
+ log_error("Unknown name mangling mode");
+ return 0;
+ }
+ dm_set_name_mangling_mode((dm_string_mangling_t) _int_args[MANGLENAME_ARG]);
+ }
+ if (ind == NAMEPREFIXES_ARG)
_switches[NAMEPREFIXES_ARG]++;
- if ((ind == NOFLUSH_ARG))
+ if (ind == NOFLUSH_ARG)
_switches[NOFLUSH_ARG]++;
- if ((ind == NOHEADINGS_ARG))
+ if (ind == NOHEADINGS_ARG)
_switches[NOHEADINGS_ARG]++;
- if ((ind == NOLOCKFS_ARG))
+ if (ind == NOLOCKFS_ARG)
_switches[NOLOCKFS_ARG]++;
- if ((ind == NOOPENCOUNT_ARG))
+ if (ind == NOOPENCOUNT_ARG)
_switches[NOOPENCOUNT_ARG]++;
- if ((ind == READAHEAD_ARG)) {
+ if (ind == READAHEAD_ARG) {
_switches[READAHEAD_ARG]++;
if (!strcasecmp(optarg, "auto"))
_int_args[READAHEAD_ARG] = DM_READ_AHEAD_AUTO;
else if (!strcasecmp(optarg, "none"))
- _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE;
+ _int_args[READAHEAD_ARG] = DM_READ_AHEAD_NONE;
else {
for (s = optarg; isspace(*s); s++)
;
@@ -3282,21 +3716,26 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
}
}
}
- if ((ind == ROWS_ARG))
+ if (ind == RETRY_ARG)
+ _switches[RETRY_ARG]++;
+ if (ind == ROWS_ARG)
_switches[ROWS_ARG]++;
- if ((ind == SETUUID_ARG))
+ if (ind == SETUUID_ARG)
_switches[SETUUID_ARG]++;
- if ((ind == SHOWKEYS_ARG))
+ if (ind == SHOWKEYS_ARG)
_switches[SHOWKEYS_ARG]++;
- if ((ind == TABLE_ARG)) {
+ if (ind == TABLE_ARG) {
_switches[TABLE_ARG]++;
- _table = optarg;
+ if (!(_table = dm_strdup(optarg))) {
+ log_error("Could not allocate memory for table string.");
+ return 0;
+ }
}
- if ((ind == TREE_ARG))
+ if (ind == TREE_ARG)
_switches[TREE_ARG]++;
- if ((ind == UNQUOTED_ARG))
+ if (ind == UNQUOTED_ARG)
_switches[UNQUOTED_ARG]++;
- if ((ind == VERSION_ARG))
+ if (ind == VERSION_ARG)
_switches[VERSION_ARG]++;
}
@@ -3310,7 +3749,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
return 0;
}
- if (_switches[TREE_ARG] && !_process_tree_options(_string_args[OPTIONS_ARG]))
+ if (!_process_options(_string_args[OPTIONS_ARG]))
return 0;
if (_switches[TABLE_ARG] && _switches[NOTABLE_ARG]) {
@@ -3318,6 +3757,11 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
return 0;
}
+ if (_switches[ADD_NODE_ON_RESUME_ARG] && _switches[ADD_NODE_ON_CREATE_ARG]) {
+ fprintf(stderr, "--addnodeonresume and --addnodeoncreate are incompatible.\n");
+ return 0;
+ }
+
*argv += optind;
*argc -= optind;
return 1;
@@ -3325,9 +3769,10 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
int main(int argc, char **argv)
{
- struct command *c;
int r = 1;
const char *dev_dir;
+ const struct command *cmd;
+ int multiple_devices;
(void) setlocale(LC_ALL, "");
@@ -3346,12 +3791,12 @@ int main(int argc, char **argv)
}
if (_switches[HELP_ARG]) {
- c = _find_command("help");
+ cmd = _find_command("help");
goto doit;
}
if (_switches[VERSION_ARG]) {
- c = _find_command("version");
+ cmd = _find_command("version");
goto doit;
}
@@ -3360,27 +3805,30 @@ int main(int argc, char **argv)
goto out;
}
- if (!(c = _find_command(argv[0]))) {
+ if (!(cmd = _find_command(argv[0]))) {
fprintf(stderr, "Unknown command\n");
_usage(stderr);
goto out;
}
- if (argc < c->min_args + 1 ||
- (c->max_args >= 0 && argc > c->max_args + 1)) {
+ if (argc < cmd->min_args + 1 ||
+ (cmd->max_args >= 0 && argc > cmd->max_args + 1)) {
fprintf(stderr, "Incorrect number of arguments\n");
_usage(stderr);
goto out;
}
- if (!_switches[COLS_ARG] && !strcmp(c->name, "splitname"))
+ if (!_switches[COLS_ARG] && !strcmp(cmd->name, "splitname"))
_switches[COLS_ARG]++;
+ if (!strcmp(cmd->name, "mangle"))
+ dm_set_name_mangling_mode(DM_STRING_MANGLING_NONE);
+
if (_switches[COLS_ARG]) {
- if (!_report_init(c))
+ if (!_report_init(cmd))
goto out;
if (!_report) {
- if (!strcmp(c->name, "info"))
+ if (!strcmp(cmd->name, "info"))
r = 0; /* info -c -o help */
goto out;
}
@@ -3392,10 +3840,14 @@ int main(int argc, char **argv)
#endif
doit:
- if (!c->fn(argc, argv, NULL)) {
- fprintf(stderr, "Command failed\n");
- goto out;
- }
+ multiple_devices = (cmd->repeatable_cmd && argc != 2 &&
+ (argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
+ do {
+ if (!cmd->fn(cmd, argc--, argv++, NULL, multiple_devices)) {
+ fprintf(stderr, "Command failed\n");
+ goto out;
+ }
+ } while (cmd->repeatable_cmd && argc > 1);
r = 0;
@@ -3408,5 +3860,7 @@ out:
if (_dtree)
dm_tree_free(_dtree);
+ dm_free(_table);
+
return r;
}
diff --git a/tools/dumpconfig.c b/tools/dumpconfig.c
index 981147c..c5f5226 100644
--- a/tools/dumpconfig.c
+++ b/tools/dumpconfig.c
@@ -19,7 +19,7 @@ int dumpconfig(struct cmd_context *cmd, int argc, char **argv)
{
const char *file = arg_str_value(cmd, file_ARG, NULL);
- if (!write_config_file(cmd->cft, file, argc, argv)) {
+ if (!config_write(cmd->cft, file, argc, argv)) {
stack;
return ECMD_FAILED;
}
diff --git a/tools/lvchange.c b/tools/lvchange.c
index 8161d22..04facdd 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -43,6 +43,20 @@ static int lvchange_permission(struct cmd_context *cmd,
return 0;
}
+ /* Not allowed to change permissions on RAID sub-LVs directly */
+ if ((lv->status & RAID_META) || (lv->status & RAID_IMAGE)) {
+ log_error("Cannot change permissions of RAID %s \"%s\"",
+ (lv->status & RAID_IMAGE) ? "image" :
+ "metadata area", lv->name);
+ return 0;
+ }
+
+ if (!(lv_access & LVM_WRITE) && lv_is_thin_pool(lv)) {
+ log_error("Change permissions of thin pool \"%s\" not "
+ "yes supported.", lv->name);
+ return 0;
+ }
+
if (lv_access & LVM_WRITE) {
lv->status |= LVM_WRITE;
log_verbose("Setting logical volume \"%s\" read/write",
@@ -81,12 +95,90 @@ out:
return r;
}
+static int lvchange_pool_update(struct cmd_context *cmd,
+ struct logical_volume *lv)
+{
+ int r = 0;
+ int update = 0;
+ unsigned val;
+ thin_discards_t discards;
+
+ if (!lv_is_thin_pool(lv)) {
+ log_error("Logical volume \"%s\" is not a thin pool.", lv->name);
+ return 0;
+ }
+
+ if (arg_count(cmd, discards_ARG)) {
+ discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_IGNORE);
+ if (discards != first_seg(lv)->discards) {
+ if ((discards != THIN_DISCARDS_IGNORE) &&
+ (first_seg(lv)->chunk_size &
+ (first_seg(lv)->chunk_size - 1)))
+ log_error("Cannot change discards state for "
+ "logical volume \"%s\" "
+ "with non power of 2 chunk size.", lv->name);
+ else if (((discards == THIN_DISCARDS_IGNORE) ||
+ (first_seg(lv)->discards == THIN_DISCARDS_IGNORE)) &&
+ lv_is_active(lv))
+ log_error("Cannot change discards state for active "
+ "logical volume \"%s\".", lv->name);
+ else {
+ first_seg(lv)->discards = discards;
+ update++;
+ }
+ } else
+ log_error("Logical volume \"%s\" already uses --discards %s.",
+ lv->name, get_pool_discards_name(discards));
+ }
+
+ if (arg_count(cmd, zero_ARG)) {
+ val = arg_uint_value(cmd, zero_ARG, 1);
+ if (val != first_seg(lv)->zero_new_blocks) {
+ first_seg(lv)->zero_new_blocks = val;
+ update++;
+ } else
+ log_error("Logical volume \"%s\" already %szero new blocks.",
+ lv->name, val ? "" : "does not ");
+ }
+
+ if (!update)
+ return 0;
+
+ log_very_verbose("Updating logical volume \"%s\" on disk(s).", lv->name);
+ if (!vg_write(lv->vg))
+ return_0;
+
+ if (!suspend_lv_origin(cmd, lv)) {
+ log_error("Failed to update active %s/%s (deactivation is needed).",
+ lv->vg->name, lv->name);
+ vg_revert(lv->vg);
+ goto out;
+ }
+
+ if (!vg_commit(lv->vg)) {
+ if (!resume_lv_origin(cmd, lv))
+ stack;
+ goto_out;
+ }
+
+ if (!resume_lv_origin(cmd, lv)) {
+ log_error("Problem reactivating %s.", lv->name);
+ goto out;
+ }
+
+ r = 1;
+out:
+ backup(lv->vg);
+ return r;
+}
+
static int lvchange_monitoring(struct cmd_context *cmd,
struct logical_volume *lv)
{
struct lvinfo info;
- if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists) {
+ if (!lv_info(cmd, lv, lv_is_thin_pool(lv) ? 1 : 0,
+ &info, 0, 0) || !info.exists) {
log_error("Logical volume, %s, is not active", lv->name);
return 0;
}
@@ -118,12 +210,20 @@ static int lvchange_background_polling(struct cmd_context *cmd,
return 1;
}
-static int lvchange_availability(struct cmd_context *cmd,
- struct logical_volume *lv)
+static int _lvchange_activate(struct cmd_context *cmd, struct logical_volume *lv)
{
int activate;
- activate = arg_uint_value(cmd, available_ARG, 0);
+ activate = arg_uint_value(cmd, activate_ARG, 0);
+
+ if (lv_is_cow(lv) && !lv_is_virtual_origin(origin_from_cow(lv)))
+ lv = origin_from_cow(lv);
+
+ if (activate == CHANGE_AAY) {
+ if (!lv_passes_auto_activation_filter(cmd, lv))
+ return 1;
+ activate = CHANGE_ALY;
+ }
if (activate == CHANGE_ALN) {
log_verbose("Deactivating logical volume \"%s\" locally",
@@ -135,7 +235,9 @@ static int lvchange_availability(struct cmd_context *cmd,
if (!deactivate_lv(cmd, lv))
return_0;
} else {
- if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
+ if ((activate == CHANGE_AE) ||
+ lv_is_origin(lv) ||
+ lv_is_thin_type(lv)) {
log_verbose("Activating logical volume \"%s\" "
"exclusively", lv->name);
if (!activate_lv_excl(cmd, lv))
@@ -166,18 +268,82 @@ static int lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv)
return lv_refresh(cmd, lv);
}
+static int detach_metadata_devices(struct lv_segment *seg, struct dm_list *list)
+{
+ uint32_t s;
+ uint32_t num_meta_lvs;
+ struct cmd_context *cmd = seg->lv->vg->cmd;
+ struct lv_list *lvl;
+
+ num_meta_lvs = seg_is_raid(seg) ? seg->area_count : !!seg->log_lv;
+
+ if (!num_meta_lvs)
+ return_0;
+
+ if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl) * num_meta_lvs)))
+ return_0;
+
+ if (seg_is_raid(seg)) {
+ for (s = 0; s < seg->area_count; s++) {
+ if (!seg_metalv(seg, s))
+ return_0; /* Trap this future possibility */
+
+ lvl[s].lv = seg_metalv(seg, s);
+ lv_set_visible(lvl[s].lv);
+
+ dm_list_add(list, &lvl[s].list);
+ }
+ return 1;
+ }
+
+ lvl[0].lv = detach_mirror_log(seg);
+ dm_list_add(list, &lvl[0].list);
+
+ return 1;
+}
+
+static int attach_metadata_devices(struct lv_segment *seg, struct dm_list *list)
+{
+ struct cmd_context *cmd = seg->lv->vg->cmd;
+ struct lv_list *lvl, *tmp;
+
+ if (seg_is_raid(seg)) {
+ dm_list_iterate_items_safe(lvl, tmp, list) {
+ lv_set_hidden(lvl->lv);
+ dm_pool_free(cmd->mem, lvl);
+ }
+ return 1;
+ }
+
+ dm_list_iterate_items(lvl, list)
+ break; /* get first item */
+
+ if (!attach_mirror_log(seg, lvl->lv)) {
+ dm_pool_free(cmd->mem, lvl);
+ return_0;
+ }
+
+ dm_pool_free(cmd->mem, lvl);
+
+ return 1;
+}
+
static int lvchange_resync(struct cmd_context *cmd,
struct logical_volume *lv)
{
int active = 0;
int monitored;
struct lvinfo info;
- struct logical_volume *log_lv;
+ struct lv_segment *seg = first_seg(lv);
+ struct dm_list device_list;
+ struct lv_list *lvl;
- if (!(lv->status & MIRRORED)) {
- log_error("Unable to resync %s because it is not mirrored.",
+ dm_list_init(&device_list);
+
+ if (!(lv->status & MIRRORED) && !seg_is_raid(seg)) {
+ log_error("Unable to resync %s. It is not RAID or mirrored.",
lv->name);
- return 1;
+ return 0;
}
if (lv->status & PVMOVE) {
@@ -216,7 +382,8 @@ static int lvchange_resync(struct cmd_context *cmd,
/* Activate exclusively to ensure no nodes still have LV active */
monitored = dmeventd_monitor_mode();
- init_dmeventd_monitor(0);
+ if (monitored != DMEVENTD_MONITOR_IGNORE)
+ init_dmeventd_monitor(0);
if (!deactivate_lv(cmd, lv)) {
log_error("Unable to deactivate %s for resync", lv->name);
@@ -229,81 +396,109 @@ static int lvchange_resync(struct cmd_context *cmd,
return 0;
}
- init_dmeventd_monitor(monitored);
-
- log_lv = first_seg(lv)->log_lv;
+ if (monitored != DMEVENTD_MONITOR_IGNORE)
+ init_dmeventd_monitor(monitored);
+ init_mirror_in_sync(0);
- log_very_verbose("Starting resync of %s%s%s mirror \"%s\"",
+ log_very_verbose("Starting resync of %s%s%s%s \"%s\"",
(active) ? "active " : "",
vg_is_clustered(lv->vg) ? "clustered " : "",
- (log_lv) ? "disk-logged" : "core-logged",
- lv->name);
+ (seg->log_lv) ? "disk-logged " :
+ seg_is_raid(seg) ? "" : "core-logged ",
+ seg->segtype->ops->name(seg), lv->name);
/*
- * If this mirror has a core log (i.e. !log_lv),
+ * If this mirror has a core log (i.e. !seg->log_lv),
* then simply deactivating/activating will cause
* it to reset the sync status. We only need to
* worry about persistent logs.
*/
- if (!log_lv && !(lv->status & MIRROR_NOTSYNCED)) {
+ if (!seg_is_raid(seg) && !seg->log_lv) {
+ if (lv->status & LV_NOTSYNCED) {
+ lv->status &= ~LV_NOTSYNCED;
+ log_very_verbose("Updating logical volume \"%s\""
+ " on disk(s)", lv->name);
+ if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
+ log_error("Failed to update metadata on disk.");
+ return 0;
+ }
+ }
+
if (active && !activate_lv(cmd, lv)) {
log_error("Failed to reactivate %s to resynchronize "
"mirror", lv->name);
return 0;
}
+
return 1;
}
- lv->status &= ~MIRROR_NOTSYNCED;
+ /*
+ * Now we handle mirrors with log devices
+ */
+ lv->status &= ~LV_NOTSYNCED;
- if (log_lv) {
- /* Separate mirror log so we can clear it */
- detach_mirror_log(first_seg(lv));
+ /* Separate mirror log or metadata devices so we can clear them */
+ if (!detach_metadata_devices(seg, &device_list)) {
+ log_error("Failed to clear %s %s for %s",
+ seg->segtype->name, seg_is_raid(seg) ?
+ "metadata area" : "mirror log", lv->name);
+ return 0;
+ }
- if (!vg_write(lv->vg)) {
- log_error("Failed to write intermediate VG metadata.");
- if (!attach_mirror_log(first_seg(lv), log_lv))
- stack;
- if (active && !activate_lv(cmd, lv))
- stack;
- return 0;
- }
+ if (!vg_write(lv->vg)) {
+ log_error("Failed to write intermediate VG metadata.");
+ if (!attach_metadata_devices(seg, &device_list))
+ stack;
+ if (active && !activate_lv(cmd, lv))
+ stack;
+ return 0;
+ }
- if (!vg_commit(lv->vg)) {
- log_error("Failed to commit intermediate VG metadata.");
- if (!attach_mirror_log(first_seg(lv), log_lv))
- stack;
- if (active && !activate_lv(cmd, lv))
- stack;
- return 0;
- }
+ if (!vg_commit(lv->vg)) {
+ log_error("Failed to commit intermediate VG metadata.");
+ if (!attach_metadata_devices(seg, &device_list))
+ stack;
+ if (active && !activate_lv(cmd, lv))
+ stack;
+ return 0;
+ }
- backup(lv->vg);
+ backup(lv->vg);
- if (!activate_lv(cmd, log_lv)) {
+ dm_list_iterate_items(lvl, &device_list) {
+ if (!activate_lv(cmd, lvl->lv)) {
log_error("Unable to activate %s for mirror log resync",
- log_lv->name);
+ lvl->lv->name);
return 0;
}
- log_very_verbose("Clearing log device %s", log_lv->name);
- if (!set_lv(cmd, log_lv, log_lv->size, 0)) {
- log_error("Unable to reset sync status for %s", lv->name);
- if (!deactivate_lv(cmd, log_lv))
+ log_very_verbose("Clearing %s device %s",
+ (seg_is_raid(seg)) ? "metadata" : "log",
+ lvl->lv->name);
+ if (!set_lv(cmd, lvl->lv, lvl->lv->size, 0)) {
+ log_error("Unable to reset sync status for %s",
+ lv->name);
+ if (!deactivate_lv(cmd, lvl->lv))
log_error("Failed to deactivate log LV after "
"wiping failed");
return 0;
}
- if (!deactivate_lv(cmd, log_lv)) {
- log_error("Unable to deactivate log LV %s after wiping "
- "for resync", log_lv->name);
+ if (!deactivate_lv(cmd, lvl->lv)) {
+ log_error("Unable to deactivate %s LV %s "
+ "after wiping for resync",
+ (seg_is_raid(seg)) ? "metadata" : "log",
+ lvl->lv->name);
return 0;
}
+ }
- /* Put mirror log back in place */
- if (!attach_mirror_log(first_seg(lv), log_lv))
- stack;
+ /* Put metadata sub-LVs back in place */
+ if (!attach_metadata_devices(seg, &device_list)) {
+ log_error("Failed to reattach %s device after clearing",
+ (seg_is_raid(seg)) ? "metadata" : "log");
+ return 0;
}
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
@@ -327,7 +522,7 @@ static int lvchange_alloc(struct cmd_context *cmd, struct logical_volume *lv)
want_contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
alloc = want_contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
- alloc = arg_uint_value(cmd, alloc_ARG, alloc);
+ alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, alloc);
if (alloc == lv->alloc) {
log_error("Allocation policy of logical volume \"%s\" is "
@@ -426,6 +621,7 @@ static int lvchange_persistent(struct cmd_context *cmd,
{
struct lvinfo info;
int active = 0;
+ int32_t major, minor;
if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "n")) {
if (!(lv->status & FIXED_MINOR)) {
@@ -443,12 +639,26 @@ static int lvchange_persistent(struct cmd_context *cmd,
log_error("Minor number must be specified with -My");
return 0;
}
+ if (arg_count(cmd, major_ARG) > 1) {
+ log_error("Option -j/--major may not be repeated.");
+ return 0;
+ }
+ if (arg_count(cmd, minor_ARG) > 1) {
+ log_error("Option --minor may not be repeated.");
+ return 0;
+ }
if (!arg_count(cmd, major_ARG) && lv->major < 0) {
log_error("Major number must be specified with -My");
return 0;
}
if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists)
active = 1;
+
+ major = arg_int_value(cmd, major_ARG, lv->major);
+ minor = arg_int_value(cmd, minor_ARG, lv->minor);
+ if (!major_minor_valid(cmd, lv->vg->fid->fmt, major, minor))
+ return 0;
+
if (active && !arg_count(cmd, force_ARG) &&
yes_no_prompt("Logical volume %s will be "
"deactivated temporarily. "
@@ -467,8 +677,8 @@ static int lvchange_persistent(struct cmd_context *cmd,
return 0;
}
lv->status |= FIXED_MINOR;
- lv->minor = arg_int_value(cmd, minor_ARG, lv->minor);
- lv->major = arg_int_value(cmd, major_ARG, lv->major);
+ lv->minor = minor;
+ lv->major = major;
log_verbose("Setting persistent device number to (%d, %d) "
"for \"%s\"", lv->major, lv->minor, lv->name);
@@ -491,24 +701,10 @@ static int lvchange_persistent(struct cmd_context *cmd,
return 1;
}
-static int lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv,
- int arg)
+static int lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv, int arg)
{
- const char *tag;
- struct arg_value_group_list *current_group;
-
- dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
- if (!grouped_arg_is_set(current_group->arg_values, arg))
- continue;
-
- if (!(tag = grouped_arg_str_value(current_group->arg_values, arg, NULL))) {
- log_error("Failed to get tag");
- return 0;
- }
-
- if (!lv_change_tag(lv, tag, arg == addtag_ARG))
- return_0;
- }
+ if (!change_tag(cmd, NULL, lv, NULL, arg))
+ return_0;
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
@@ -525,19 +721,22 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle __attribute__((unused)))
{
int doit = 0, docmds = 0;
- int dmeventd_mode, archived = 0;
+ int archived = 0;
struct logical_volume *origin;
+ char snaps_msg[128];
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) ||
+ arg_count(cmd, discards_ARG) ||
+ arg_count(cmd, zero_ARG) ||
arg_count(cmd, alloc_ARG))) {
log_error("Only -a permitted with read-only volume "
"group \"%s\"", lv->vg->name);
return EINVALID_CMD_LINE;
}
- if (lv_is_origin(lv) &&
+ if (lv_is_origin(lv) && !lv_is_thin_volume(lv) &&
(arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
arg_count(cmd, alloc_ARG))) {
@@ -546,16 +745,29 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
return ECMD_FAILED;
}
- if (lv_is_cow(lv) && !lv_is_virtual_origin(origin_from_cow(lv)) &&
- arg_count(cmd, available_ARG)) {
- log_error("Can't change snapshot logical volume \"%s\"",
- lv->name);
- return ECMD_FAILED;
+ if (lv_is_cow(lv) && !lv_is_virtual_origin(origin = origin_from_cow(lv)) &&
+ arg_count(cmd, activate_ARG)) {
+ if (origin->origin_count < 2)
+ snaps_msg[0] = '\0';
+ else if (dm_snprintf(snaps_msg, sizeof(snaps_msg),
+ " and %u other snapshot(s)",
+ origin->origin_count - 1) < 0) {
+ log_error("Failed to prepare message.");
+ return ECMD_FAILED;
+ }
+
+ if (!arg_count(cmd, yes_ARG) &&
+ (yes_no_prompt("Change of snapshot %s will also change its"
+ " origin %s%s. Proceed? [y/n]: ", lv->name,
+ origin->name, snaps_msg) == 'n')) {
+ log_error("Logical volume %s not changed.", lv->name);
+ return ECMD_FAILED;
+ }
}
if (lv->status & PVMOVE) {
log_error("Unable to change pvmove LV %s", lv->name);
- if (arg_count(cmd, available_ARG))
+ if (arg_count(cmd, activate_ARG))
log_error("Use 'pvmove --abort' to abandon a pvmove");
return ECMD_FAILED;
}
@@ -572,7 +784,7 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
}
/* If LV is sparse, activate origin instead */
- if (arg_count(cmd, available_ARG) && lv_is_cow(lv) &&
+ if (arg_count(cmd, activate_ARG) && lv_is_cow(lv) &&
lv_is_virtual_origin(origin = origin_from_cow(lv)))
lv = origin;
@@ -582,11 +794,6 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
return ECMD_FAILED;
}
- if (!get_activation_monitoring_mode(cmd, lv->vg, &dmeventd_mode))
- return ECMD_FAILED;
-
- init_dmeventd_monitor(dmeventd_mode);
-
/*
* FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified".
* If --poll is explicitly provided use it; otherwise polling
@@ -648,6 +855,17 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
}
}
+ if (arg_count(cmd, discards_ARG) ||
+ arg_count(cmd, zero_ARG)) {
+ if (!archived && !archive(lv->vg)) {
+ stack;
+ return ECMD_FAILED;
+ }
+ archived = 1;
+ doit += lvchange_pool_update(cmd, lv);
+ docmds++;
+ }
+
/* add tag */
if (arg_count(cmd, addtag_ARG)) {
if (!archived && !archive(lv->vg)) {
@@ -671,7 +889,7 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
}
if (doit)
- log_print("Logical volume \"%s\" changed", lv->name);
+ log_print_unless_silent("Logical volume \"%s\" changed", lv->name);
if (arg_count(cmd, resync_ARG))
if (!lvchange_resync(cmd, lv)) {
@@ -679,9 +897,9 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
return ECMD_FAILED;
}
- /* availability change */
- if (arg_count(cmd, available_ARG)) {
- if (!lvchange_availability(cmd, lv)) {
+ /* activation change */
+ if (arg_count(cmd, activate_ARG)) {
+ if (!_lvchange_activate(cmd, lv)) {
stack;
return ECMD_FAILED;
}
@@ -693,7 +911,7 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
return ECMD_FAILED;
}
- if (!arg_count(cmd, available_ARG) &&
+ if (!arg_count(cmd, activate_ARG) &&
!arg_count(cmd, refresh_ARG) &&
arg_count(cmd, monitor_ARG)) {
if (!lvchange_monitoring(cmd, lv)) {
@@ -702,7 +920,7 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
}
}
- if (!arg_count(cmd, available_ARG) &&
+ if (!arg_count(cmd, activate_ARG) &&
!arg_count(cmd, refresh_ARG) &&
arg_count(cmd, poll_ARG)) {
if (!lvchange_background_polling(cmd, lv)) {
@@ -721,24 +939,35 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
int lvchange(struct cmd_context *cmd, int argc, char **argv)
{
- int update = /* options other than -a, --refresh, --monitor or --poll */
- arg_count(cmd, contiguous_ARG) || arg_count(cmd, permission_ARG) ||
- arg_count(cmd, readahead_ARG) || arg_count(cmd, persistent_ARG) ||
- arg_count(cmd, addtag_ARG) || arg_count(cmd, deltag_ARG) ||
- arg_count(cmd, resync_ARG) || arg_count(cmd, alloc_ARG);
+ /*
+ * Options that update metadata should be listed in one of
+ * the two lists below (i.e. options other than -a, --refresh,
+ * --monitor or --poll).
+ */
+ int update_partial_safe = /* options safe to update if partial */
+ arg_count(cmd, contiguous_ARG) ||
+ arg_count(cmd, permission_ARG) ||
+ arg_count(cmd, readahead_ARG) ||
+ arg_count(cmd, persistent_ARG) ||
+ arg_count(cmd, addtag_ARG) ||
+ arg_count(cmd, deltag_ARG);
+ int update_partial_unsafe =
+ arg_count(cmd, resync_ARG) ||
+ arg_count(cmd, alloc_ARG) ||
+ arg_count(cmd, discards_ARG) ||
+ arg_count(cmd, zero_ARG);
+ int update = update_partial_safe || update_partial_unsafe;
if (!update &&
- !arg_count(cmd, available_ARG) && !arg_count(cmd, refresh_ARG) &&
- !arg_count(cmd, monitor_ARG) && !arg_count(cmd, poll_ARG) &&
- /* for persistent_ARG */
- !arg_count(cmd, minor_ARG) && !arg_count(cmd, major_ARG)) {
- log_error("Need 1 or more of -a, -C, -j, -m, -M, -p, -r, "
+ !arg_count(cmd, activate_ARG) && !arg_count(cmd, refresh_ARG) &&
+ !arg_count(cmd, monitor_ARG) && !arg_count(cmd, poll_ARG)) {
+ log_error("Need 1 or more of -a, -C, -M, -p, -r, -Z, "
"--resync, --refresh, --alloc, --addtag, --deltag, "
- "--monitor or --poll");
+ "--monitor, --poll or --discards");
return EINVALID_CMD_LINE;
}
- if (arg_count(cmd, available_ARG) && arg_count(cmd, refresh_ARG)) {
+ if (arg_count(cmd, activate_ARG) && arg_count(cmd, refresh_ARG)) {
log_error("Only one of -a and --refresh permitted.");
return EINVALID_CMD_LINE;
}
@@ -749,7 +978,7 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
- if (!update)
+ if (!update || !update_partial_unsafe)
cmd->handles_missing_pvs = 1;
if (!argc) {
@@ -778,6 +1007,13 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
+ if (arg_count(cmd, sysinit_ARG) && lvmetad_active() &&
+ arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY) {
+ log_warn("lvmetad is active while using --sysinit -a ay, "
+ "skipping manual activation");
+ return ECMD_PROCESSED;
+ }
+
return process_each_lv(cmd, argc, argv,
update ? READ_FOR_UPDATE : 0, NULL,
&lvchange_single);
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 7c7826b..132a69d 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -20,6 +20,7 @@
struct lvconvert_params {
int snapshot;
int merge;
+ int merge_mirror;
int zero;
const char *origin;
@@ -39,16 +40,24 @@ struct lvconvert_params {
uint32_t stripes;
uint32_t stripe_size;
- struct segment_type *segtype;
+ const struct segment_type *segtype;
alloc_policy_t alloc;
int pv_count;
char **pvs;
struct dm_list *pvh;
- struct dm_list *failed_pvs;
+
+ int replace_pv_count;
+ char **replace_pvs;
+ struct dm_list *replace_pvh;
struct logical_volume *lv_to_poll;
+
+ uint64_t poolmetadata_size;
+ const char *pool_data_lv_name;
+ const char *pool_metadata_lv_name;
+ thin_discards_t discards;
};
static int _lvconvert_name_params(struct lvconvert_params *lp,
@@ -81,6 +90,15 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
lp->origin = ptr + 1;
}
+ if (!*pargc && lp->pool_data_lv_name) {
+ if (!lp->vg_name || !validate_name(lp->vg_name)) {
+ log_error("Please provide a valid volume group name.");
+ return 0;
+ }
+ lp->lv_name = lp->pool_data_lv_name;
+ return 1; /* Create metadata LV on it's own */
+ }
+
if (!*pargc) {
log_error("Please provide logical volume path");
return 0;
@@ -108,7 +126,10 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
if ((ptr = strrchr(lp->lv_name_full, '/')))
lp->lv_name = ptr + 1;
- if (!apply_lvname_restrictions(lp->lv_name))
+ if (!lp->merge_mirror &&
+ !strstr(lp->lv_name, "_tdata") &&
+ !strstr(lp->lv_name, "_tmeta") &&
+ !apply_lvname_restrictions(lp->lv_name))
return_0;
if (*pargc && lp->snapshot) {
@@ -116,12 +137,20 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
return 0;
}
+ if (lp->pool_data_lv_name && lp->lv_name && lp->poolmetadata_size) {
+ log_error("Please specify either metadata logical volume or its size.");
+ return 0;
+ }
+
return 1;
}
static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
int argc, char **argv)
{
+ int i;
+ const char *tmp_str;
+ struct arg_value_group_list *group;
int region_size;
int pagesize = lvm_getpagesize();
@@ -131,7 +160,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
(arg_count(cmd, mirrorlog_ARG) || arg_count(cmd, mirrors_ARG) ||
arg_count(cmd, repair_ARG))) {
log_error("--snapshot or --merge argument cannot be mixed "
- "with --mirrors, --repair or --log");
+ "with --mirrors, --repair or --mirrorlog");
return 0;
}
@@ -152,6 +181,33 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
return 0;
}
+ if (arg_count(cmd, thinpool_ARG)) {
+ if (arg_count(cmd, merge_ARG)) {
+ log_error("--thinpool and --merge are mutually exlusive.");
+ return 0;
+ }
+ if (arg_count(cmd, mirrors_ARG)) {
+ log_error("--thinpool and --mirrors are mutually exlusive.");
+ return 0;
+ }
+ if (arg_count(cmd, repair_ARG)) {
+ log_error("--thinpool and --repair are mutually exlusive.");
+ return 0;
+ }
+ if (arg_count(cmd, snapshot_ARG)) {
+ log_error("--thinpool and --snapshot are mutually exlusive.");
+ return 0;
+ }
+ if (arg_count(cmd, splitmirrors_ARG)) {
+ log_error("--thinpool and --splitmirrors are mutually exlusive.");
+ return 0;
+ }
+ lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN);
+ } else if (arg_count(cmd, discards_ARG)) {
+ log_error("--discards is only valid with --thinpool.");
+ return 0;
+ }
+
/*
* The '--splitmirrors n' argument is equivalent to '--mirrors -n'
* (note the minus sign), except that it signifies the additional
@@ -159,21 +215,28 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
* discarding it.
*/
if (arg_count(cmd, splitmirrors_ARG)) {
- if (!arg_count(cmd, name_ARG)) {
+ if (!arg_count(cmd, name_ARG) &&
+ !arg_count(cmd, trackchanges_ARG)) {
log_error("Please name the new logical volume using '--name'");
return 0;
}
lp->lv_split_name = arg_value(cmd, name_ARG);
- if (!apply_lvname_restrictions(lp->lv_split_name))
- return_0;
+ if (lp->lv_split_name) {
+ if (strchr(lp->lv_split_name, '/')) {
+ if (!(lp->vg_name = extract_vgname(cmd, lp->lv_split_name)))
+ return_0;
+
+ /* Strip VG from lv_split_name */
+ if ((tmp_str = strrchr(lp->lv_split_name, '/')))
+ lp->lv_split_name = tmp_str + 1;
+ }
- lp->keep_mimages = 1;
- if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
- log_error("Argument to --splitmirrors"
- " cannot be negative");
- return 0;
+ if (!apply_lvname_restrictions(lp->lv_split_name))
+ return_0;
}
+
+ lp->keep_mimages = 1;
lp->mirrors = arg_uint_value(cmd, splitmirrors_ARG, 0);
lp->mirrors_sign = SIGN_MINUS;
} else if (arg_count(cmd, name_ARG)) {
@@ -182,8 +245,12 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
return 0;
}
- if (arg_count(cmd, merge_ARG))
- lp->merge = 1;
+ if (arg_count(cmd, merge_ARG)) {
+ if ((argc == 1) && strstr(argv[0], "_rimage_"))
+ lp->merge_mirror = 1;
+ else
+ lp->merge = 1;
+ }
if (arg_count(cmd, mirrors_ARG)) {
/*
@@ -192,10 +259,10 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
* versus an additional qualifying argument being added here.
*/
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0);
- lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, 0);
+ lp->mirrors_sign = arg_sign_value(cmd, mirrors_ARG, SIGN_NONE);
}
- lp->alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
+ lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
/* There are three types of lvconvert. */
if (lp->merge) { /* Snapshot merge */
@@ -221,7 +288,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
return 0;
}
- if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Negative chunk size is invalid");
return 0;
}
@@ -242,15 +309,99 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
SEG_CANNOT_BE_ZEROED) ?
"n" : "y"), "n");
- } else { /* Mirrors */
+ } else if (arg_count(cmd, replace_ARG)) { /* RAID device replacement */
+ lp->replace_pv_count = arg_count(cmd, replace_ARG);
+ lp->replace_pvs = dm_pool_alloc(cmd->mem, sizeof(char *) * lp->replace_pv_count);
+ if (!lp->replace_pvs)
+ return_0;
+
+ i = 0;
+ dm_list_iterate_items(group, &cmd->arg_value_groups) {
+ if (!grouped_arg_is_set(group->arg_values, replace_ARG))
+ continue;
+ if (!(tmp_str = grouped_arg_str_value(group->arg_values,
+ replace_ARG,
+ NULL))) {
+ log_error("Failed to get '--replace' argument");
+ return 0;
+ }
+ if (!(lp->replace_pvs[i++] = dm_pool_strdup(cmd->mem,
+ tmp_str)))
+ return_0;
+ }
+ } else if (arg_count(cmd, thinpool_ARG)) {
+ if (!(lp->pool_data_lv_name = arg_str_value(cmd, thinpool_ARG, NULL))) {
+ log_error("Missing pool logical volume name.");
+ return 0;
+ }
+
+ if (arg_count(cmd, poolmetadata_ARG)) {
+ lp->pool_metadata_lv_name = arg_str_value(cmd, poolmetadata_ARG, "");
+ } else if (arg_count(cmd, poolmetadatasize_ARG)) {
+ if (arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE) == SIGN_MINUS) {
+ log_error("Negative pool metadata size is invalid.");
+ return 0;
+ }
+ lp->poolmetadata_size = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0));
+
+ if (lp->poolmetadata_size > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) {
+ if (arg_count(cmd, poolmetadatasize_ARG))
+ log_warn("WARNING: Maximum supported pool metadata size is 16GB.");
+ lp->poolmetadata_size = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE;
+ } else if (lp->poolmetadata_size < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) {
+ if (arg_count(cmd, poolmetadatasize_ARG))
+ log_warn("WARNING: Minimum supported pool metadata size is 2M.");
+ lp->poolmetadata_size = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE;
+ }
+
+ log_verbose("Setting pool metadata size to %" PRIu64 " sectors.",
+ lp->poolmetadata_size);
+ }
+
+ if (arg_count(cmd, chunksize_ARG)) {
+ if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) {
+ log_error("Negative chunk size is invalid.");
+ return 0;
+ }
+ lp->chunk_size = arg_uint_value(cmd, chunksize_ARG,
+ DM_THIN_MIN_DATA_BLOCK_SIZE);
+
+ if ((lp->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) ||
+ (lp->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE)) {
+ log_error("Chunk size must be in the range %uK to %uK.",
+ (DM_THIN_MIN_DATA_BLOCK_SIZE / 2),
+ (DM_THIN_MAX_DATA_BLOCK_SIZE / 2));
+ return 0;
+ }
+ } else
+ lp->chunk_size = DM_THIN_MIN_DATA_BLOCK_SIZE;
+
+ log_verbose("Setting pool metadata chunk size to %u sectors.",
+ lp->chunk_size);
+
+ if (arg_count(cmd, zero_ARG))
+ lp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n");
+
+ /* If --thinpool contains VG name, extract it. */
+ if ((tmp_str = strchr(lp->pool_data_lv_name, (int) '/'))) {
+ if (!(lp->vg_name = extract_vgname(cmd, lp->pool_data_lv_name)))
+ return 0;
+ /* Strip VG from pool */
+ lp->pool_data_lv_name = tmp_str + 1;
+ }
+
+ lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "thin-pool"));
+ if (!lp->segtype)
+ return_0;
+ } else { /* Mirrors (and some RAID functions) */
if (arg_count(cmd, chunksize_ARG)) {
log_error("--chunksize is only available with "
- "snapshots");
+ "snapshots or thin pools.");
return 0;
}
if (arg_count(cmd, zero_ARG)) {
- log_error("--zero is only available with snapshots");
+ log_error("--zero is only available with snapshots or thin pools.");
return 0;
}
@@ -260,7 +411,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
*/
if (arg_count(cmd, regionsize_ARG)) {
- if (arg_sign_value(cmd, regionsize_ARG, 0) ==
+ if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) ==
SIGN_MINUS) {
log_error("Negative regionsize is invalid");
return 0;
@@ -303,11 +454,12 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
return 0;
}
- if (!(lp->segtype = get_segtype_from_string(cmd, "mirror")))
+ lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "mirror"));
+ if (!lp->segtype)
return_0;
}
- if (activation() && lp->segtype->ops->target_present &&
+ if (activation() && lp->segtype && lp->segtype->ops->target_present &&
!lp->segtype->ops->target_present(cmd, NULL, NULL)) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel", lp->segtype->name);
@@ -319,7 +471,6 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
lp->pv_count = argc;
lp->pvs = argv;
- lp->failed_pvs = NULL;
return 1;
}
@@ -342,7 +493,7 @@ static struct logical_volume *_get_lvconvert_lv(struct cmd_context *cmd __attrib
struct volume_group *vg,
const char *name,
const char *uuid,
- uint32_t lv_type __attribute__((unused)))
+ uint64_t lv_type __attribute__((unused)))
{
struct logical_volume *lv = find_lv(vg, name);
@@ -352,23 +503,12 @@ static struct logical_volume *_get_lvconvert_lv(struct cmd_context *cmd __attrib
return lv;
}
-static int _finish_lvconvert_mirror(struct cmd_context *cmd,
- struct volume_group *vg,
- struct logical_volume *lv,
- struct dm_list *lvs_changed __attribute__((unused)))
+static int _reload_lv(struct cmd_context *cmd,
+ struct volume_group *vg,
+ struct logical_volume *lv)
{
int r = 0;
- if (!(lv->status & CONVERTING))
- return 1;
-
- if (!collapse_mirrored_lv(lv)) {
- log_error("Failed to remove temporary sync layer.");
- return 0;
- }
-
- lv->status &= ~CONVERTING;
-
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
if (!vg_write(vg))
@@ -381,7 +521,8 @@ static int _finish_lvconvert_mirror(struct cmd_context *cmd,
}
if (!vg_commit(vg)) {
- resume_lv(cmd, lv);
+ if (!resume_lv(cmd, lv))
+ stack;
goto_out;
}
@@ -393,12 +534,36 @@ static int _finish_lvconvert_mirror(struct cmd_context *cmd,
}
r = 1;
- log_print("Logical volume %s converted.", lv->name);
out:
backup(vg);
return r;
}
+static int _finish_lvconvert_mirror(struct cmd_context *cmd,
+ struct volume_group *vg,
+ struct logical_volume *lv,
+ struct dm_list *lvs_changed __attribute__((unused)))
+{
+ if (!(lv->status & CONVERTING))
+ return 1;
+
+ if (!collapse_mirrored_lv(lv)) {
+ log_error("Failed to remove temporary sync layer.");
+ return 0;
+ }
+
+ lv->status &= ~CONVERTING;
+
+ log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
+
+ if (!(_reload_lv(cmd, vg, lv)))
+ return_0;
+
+ log_print_unless_silent("Logical volume %s converted.", lv->name);
+
+ return 1;
+}
+
static int _finish_lvconvert_merge(struct cmd_context *cmd,
struct volume_group *vg,
struct logical_volume *lv,
@@ -410,7 +575,7 @@ static int _finish_lvconvert_merge(struct cmd_context *cmd,
return 0;
}
- log_print("Merge of snapshot into logical volume %s has finished.", lv->name);
+ log_print_unless_silent("Merge of snapshot into logical volume %s has finished.", lv->name);
if (!lv_remove_single(cmd, snap_seg->cow, DONT_PROMPT)) {
log_error("Could not remove snapshot %s merged into %s.",
snap_seg->cow->name, lv->name);
@@ -433,14 +598,17 @@ static progress_t _poll_merge_progress(struct cmd_context *cmd,
} else if (percent == PERCENT_INVALID) {
log_error("%s: Merging snapshot invalidated. Aborting merge.", lv->name);
return PROGRESS_CHECK_FAILED;
+ } else if (percent == PERCENT_MERGE_FAILED) {
+ log_error("%s: Merge failed. Retry merge or inspect manually.", lv->name);
+ return PROGRESS_CHECK_FAILED;
}
if (parms->progress_display)
- log_print("%s: %s: %.1f%%", lv->name, parms->progress_title,
- percent_to_float(percent));
+ log_print_unless_silent("%s: %s: %.1f%%", lv->name, parms->progress_title,
+ 100.0 - percent_to_float(percent));
else
log_verbose("%s: %s: %.1f%%", lv->name, parms->progress_title,
- percent_to_float(percent));
+ 100.0 - percent_to_float(percent));
if (percent == PERCENT_0)
return PROGRESS_FINISHED_ALL;
@@ -481,7 +649,7 @@ int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv,
if (!uuid || !lv_full_name)
return_0;
- if (!dm_snprintf(lv_full_name, len, "%s/%s", lv->vg->name, lv->name))
+ if (dm_snprintf(lv_full_name, len, "%s/%s", lv->vg->name, lv->name) < 0)
return_0;
memcpy(uuid, &lv->lvid, sizeof(lv->lvid));
@@ -538,36 +706,51 @@ static int _insert_lvconvert_layer(struct cmd_context *cmd,
return 1;
}
-static int _area_missing(struct lv_segment *lvseg, int s)
-{
- if (seg_type(lvseg, s) == AREA_LV) {
- if (seg_lv(lvseg, s)->status & PARTIAL_LV)
- return 1;
- } else if ((seg_type(lvseg, s) == AREA_PV) &&
- (is_missing_pv(seg_pv(lvseg, s))))
- return 1;
-
- return 0;
-}
-
-/* FIXME we want to handle mirror stacks here... */
static int _failed_mirrors_count(struct logical_volume *lv)
{
struct lv_segment *lvseg;
int ret = 0;
- int s;
+ unsigned s;
dm_list_iterate_items(lvseg, &lv->segments) {
if (!seg_is_mirrored(lvseg))
return -1;
- for (s = 0; s < lvseg->area_count; s++)
- if (_area_missing(lvseg, s))
- ret++;
+ for (s = 0; s < lvseg->area_count; s++) {
+ if (seg_type(lvseg, s) == AREA_LV) {
+ if (is_temporary_mirror_layer(seg_lv(lvseg, s)))
+ ret += _failed_mirrors_count(seg_lv(lvseg, s));
+ else if (seg_lv(lvseg, s)->status & PARTIAL_LV)
+ ++ ret;
+ else if (seg_type(lvseg, s) == AREA_PV &&
+ is_missing_pv(seg_pv(lvseg, s)))
+ ++ret;
+ }
+ }
}
return ret;
}
+static int _failed_logs_count(struct logical_volume *lv)
+{
+ int ret = 0;
+ unsigned s;
+ struct logical_volume *log_lv = first_seg(lv)->log_lv;
+ if (log_lv && (log_lv->status & PARTIAL_LV)) {
+ if (log_lv->status & MIRRORED)
+ ret += _failed_mirrors_count(log_lv);
+ else
+ ret += 1;
+ }
+ for (s = 0; s < first_seg(lv)->area_count; s++) {
+ if (seg_type(first_seg(lv), s) == AREA_LV &&
+ is_temporary_mirror_layer(seg_lv(first_seg(lv), s)))
+ ret += _failed_logs_count(seg_lv(first_seg(lv), s));
+ }
+ return ret;
+}
+
+
static struct dm_list *_failed_pv_list(struct volume_group *vg)
{
struct dm_list *failed_pvs;
@@ -684,10 +867,10 @@ static int _get_log_count(struct logical_volume *lv)
struct logical_volume *log_lv;
log_lv = first_seg(_original_lv(lv))->log_lv;
- if (!log_lv)
- return 0;
+ if (log_lv)
+ return lv_mirror_count(log_lv);
- return lv_mirror_count(log_lv);
+ return 0;
}
static int _lv_update_mirrored_log(struct logical_volume *lv,
@@ -724,8 +907,10 @@ static int _lv_update_log_type(struct cmd_context *cmd,
struct dm_list *operable_pvs,
int log_count)
{
- uint32_t region_size;
int old_log_count;
+ uint32_t region_size = (lp) ? lp->region_size :
+ first_seg(lv)->region_size;
+ alloc_policy_t alloc = (lp) ? lp->alloc : lv->alloc;
struct logical_volume *original_lv;
struct logical_volume *log_lv;
@@ -734,18 +919,6 @@ static int _lv_update_log_type(struct cmd_context *cmd,
return 1;
original_lv = _original_lv(lv);
- region_size = adjusted_mirror_region_size(lv->vg->extent_size,
- lv->le_count,
- lp->region_size);
-
- /* Add a log where there is none */
- if (!old_log_count) {
- if (!add_mirror_log(cmd, original_lv, log_count,
- region_size, operable_pvs, lp->alloc))
- return_0;
- return 1;
- }
-
/* Remove an existing log completely */
if (!log_count) {
if (!remove_mirror_log(cmd, original_lv, operable_pvs,
@@ -759,13 +932,28 @@ static int _lv_update_log_type(struct cmd_context *cmd,
/* Adding redundancy to the log */
if (old_log_count < log_count) {
- log_error("Adding log redundancy not supported yet.");
- log_error("Try converting the log to 'core' first.");
- return_0;
+ region_size = adjusted_mirror_region_size(lv->vg->extent_size,
+ lv->le_count,
+ region_size);
+
+ if (!add_mirror_log(cmd, original_lv, log_count,
+ region_size, operable_pvs, alloc))
+ return_0;
+ /*
+ * FIXME: This simple approach won't work in cluster mirrors,
+ * but it doesn't matter because we don't support
+ * mirrored logs in cluster mirrors.
+ */
+ if (old_log_count &&
+ !_reload_lv(cmd, log_lv->vg, log_lv))
+ return_0;
+
+ return 1;
}
/* Reducing redundancy of the log */
- return remove_mirror_images(log_lv, log_count, is_mirror_image_removable, operable_pvs, 1U);
+ return remove_mirror_images(log_lv, log_count,
+ is_mirror_image_removable, operable_pvs, 1U);
}
/*
@@ -790,6 +978,7 @@ static void _remove_missing_empty_pv(struct volume_group *vg, struct dm_list *re
vg->free_count -= pvl_vg->pv->pe_count;
vg->extent_count -= pvl_vg->pv->pe_count;
del_pvl_from_vgs(vg, pvl_vg);
+ free_pv_fid(pvl_vg->pv);
removed++;
}
@@ -960,33 +1149,6 @@ static int _lvconvert_mirrors_parse_params(struct cmd_context *cmd,
return 1;
}
-static int _reload_lv(struct cmd_context *cmd, struct logical_volume *lv)
-{
- log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
-
- if (!vg_write(lv->vg))
- return_0;
-
- if (!suspend_lv(cmd, lv)) {
- log_error("Failed to lock %s", lv->name);
- vg_revert(lv->vg);
- return 0;
- }
-
- if (!vg_commit(lv->vg)) {
- if (!resume_lv(cmd, lv))
- stack;
- return_0;
- }
-
- log_very_verbose("Updating \"%s\" in kernel", lv->name);
-
- if (!resume_lv(cmd, lv)) {
- log_error("Problem reactivating %s", lv->name);
- return 0;
- }
- return 1;
-}
/*
* _lvconvert_mirrors_aux
@@ -1036,10 +1198,9 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
*/
if (!lv_add_mirrors(cmd, lv, new_mimage_count - 1, lp->stripes,
lp->stripe_size, region_size, new_log_count, operable_pvs,
- lp->alloc, MIRROR_BY_LV)) {
- stack;
- return 0;
- }
+ lp->alloc, MIRROR_BY_LV))
+ return_0;
+
if (lp->wait_completion)
lp->need_polling = 1;
@@ -1050,7 +1211,7 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
* Up-convert m-way mirror to n-way mirror
*/
if (new_mimage_count > old_mimage_count) {
- if (lv->status & MIRROR_NOTSYNCED) {
+ if (lv->status & LV_NOTSYNCED) {
log_error("Can't add mirror to out-of-sync mirrored "
"LV: use lvchange --resync first.");
return 0;
@@ -1080,16 +1241,6 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
}
/*
- * Is there already a convert in progress? We do not
- * currently allow more than one.
- */
- if (find_temporary_mirror(lv) || (lv->status & CONVERTING)) {
- log_error("%s is already being converted. Unable to start another conversion.",
- lv->name);
- return 0;
- }
-
- /*
* Log addition/removal should be done before the layer
* insertion to make the end result consistent with
* linear-to-mirror conversion.
@@ -1109,7 +1260,8 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
/* FIXME: can't have multiple mlogs. force corelog. */
if (!lv_add_mirrors(cmd, lv,
- new_mimage_count - old_mimage_count, lp->stripes, lp->stripe_size,
+ new_mimage_count - old_mimage_count,
+ lp->stripes, lp->stripe_size,
region_size, 0U, operable_pvs, lp->alloc,
MIRROR_BY_LV)) {
layer_lv = seg_lv(first_seg(lv), 0);
@@ -1145,6 +1297,11 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
/* Reduce number of mirrors */
if (lp->keep_mimages) {
+ if (arg_count(cmd, trackchanges_ARG)) {
+ log_error("--trackchanges is not available "
+ "to 'mirror' segment type");
+ return 0;
+ }
if (!lv_split_mirror_images(lv, lp->lv_split_name,
nmc, operable_pvs))
return 0;
@@ -1169,9 +1326,50 @@ out:
out_skip_log_convert:
- if (!_reload_lv(cmd, lv))
+ if (!_reload_lv(cmd, lv->vg, lv))
+ return_0;
+
+ return 1;
+}
+
+int mirror_remove_missing(struct cmd_context *cmd,
+ struct logical_volume *lv, int force)
+{
+ struct dm_list *failed_pvs;
+ int log_count = _get_log_count(lv) - _failed_logs_count(lv);
+
+ if (!(failed_pvs = _failed_pv_list(lv->vg)))
+ return_0;
+
+ /* No point in keeping a log if the result is not a mirror */
+ if (_failed_mirrors_count(lv) + 1 >= lv_mirror_count(lv))
+ log_count = 0;
+
+ if (force && _failed_mirrors_count(lv) == lv_mirror_count(lv)) {
+ log_error("No usable images left in %s.", lv->name);
+ return lv_remove_with_dependencies(cmd, lv, DONT_PROMPT, 0);
+ }
+
+ /*
+ * We must adjust the log first, or the entire mirror
+ * will get stuck during a suspend.
+ */
+ if (!_lv_update_mirrored_log(lv, failed_pvs, log_count))
+ return 0;
+
+ if (_failed_mirrors_count(lv) > 0 &&
+ !lv_remove_mirrors(cmd, lv, _failed_mirrors_count(lv),
+ log_count ? 0U : 1U,
+ _is_partial_lv, NULL, 0))
+ return 0;
+
+ if (!_lv_update_log_type(cmd, NULL, lv, failed_pvs,
+ log_count))
return 0;
+ if (!_reload_lv(cmd, lv->vg, lv))
+ return_0;
+
return 1;
}
@@ -1187,16 +1385,16 @@ out_skip_log_convert:
*/
static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
struct logical_volume *lv,
- struct lvconvert_params *lp,
- uint32_t old_mimage_count,
- uint32_t old_log_count)
+ struct lvconvert_params *lp)
{
- int failed_log = 0;
- int failed_mirrors = 0;
- int replace_log = 0;
- int replace_mirrors = 0;
- uint32_t new_log_count, log_count;
- struct logical_volume *log_lv;
+ int failed_logs = 0;
+ int failed_mimages = 0;
+ int replace_logs = 0;
+ int replace_mimages = 0;
+ uint32_t log_count;
+
+ uint32_t original_mimages = lv_mirror_count(lv);
+ uint32_t original_logs = _get_log_count(lv);
cmd->handles_missing_pvs = 1;
cmd->partial_activation = 1;
@@ -1209,93 +1407,43 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
return 1;
}
- /*
- * Count the failed mimages - negative if 'lv' is not a mirror
- */
- if ((failed_mirrors = _failed_mirrors_count(lv)) < 0)
- return_0;
+ failed_mimages = _failed_mirrors_count(lv);
+ failed_logs = _failed_logs_count(lv);
- lp->mirrors = old_mimage_count - failed_mirrors;
+ mirror_remove_missing(cmd, lv, 0);
- if (lp->mirrors != old_mimage_count)
+ if (failed_mimages)
log_error("Mirror status: %d of %d images failed.",
- failed_mirrors, old_mimage_count);
+ failed_mimages, original_mimages);
/*
* Count the failed log devices
*/
- new_log_count = old_log_count;
- log_lv = first_seg(lv)->log_lv;
- if (log_lv) {
- new_log_count = lv_mirror_count(log_lv);
- if (log_lv->status & PARTIAL_LV) {
- failed_log = 1;
- if (log_lv->status & MIRRORED)
- new_log_count -= _failed_mirrors_count(log_lv);
- else
- new_log_count = 0;
- }
- }
- if (old_log_count != new_log_count)
- log_error("Mirror log status: %d of %d images failed%s",
- old_log_count - new_log_count, old_log_count,
- (!new_log_count) ? " - switching to core" : "");
+ if (failed_logs)
+ log_error("Mirror log status: %d of %d images failed.",
+ failed_logs, original_logs);
/*
* Find out our policies
*/
- _lvconvert_mirrors_repair_ask(cmd, failed_log, failed_mirrors,
- &replace_log, &replace_mirrors);
-
- /*
- * First phase - remove faulty devices
- */
- if (!(lp->failed_pvs = _failed_pv_list(lv->vg)))
- return_0;
-
- log_count = new_log_count;
-
- /*
- * We must adjust the log first, or the entire mirror
- * will get stuck during a suspend.
- */
- if (!_lv_update_mirrored_log(lv, lp->failed_pvs, log_count))
- return 0;
-
- if (lp->mirrors == 1)
- log_count = 0;
-
- if (failed_mirrors) {
- if (!lv_remove_mirrors(cmd, lv, failed_mirrors,
- log_count ? 0U : 1U,
- _is_partial_lv, NULL, 0))
- return 0;
- }
-
- if (!_lv_update_log_type(cmd, lp, lv, lp->failed_pvs,
- log_count))
- return 0;
-
- if (!_reload_lv(cmd, lv))
- return 0;
+ _lvconvert_mirrors_repair_ask(cmd, failed_logs, failed_mimages,
+ &replace_logs, &replace_mimages);
/*
* Second phase - replace faulty devices
*/
-
- if (replace_mirrors)
- lp->mirrors = old_mimage_count;
+ lp->mirrors = replace_mimages ? original_mimages : (original_mimages - failed_mimages);
/*
* It does not make sense to replace the log if the volume is no longer
* a mirror.
*/
- if (!replace_mirrors && lp->mirrors == 1)
- replace_log = 0;
+ if (lp->mirrors == 1)
+ replace_logs = 0;
- log_count = replace_log ? old_log_count : new_log_count;
+ log_count = replace_logs ? original_logs : (original_logs - failed_logs);
- while (replace_mirrors || replace_log) {
+ while (replace_mimages || replace_logs) {
log_warn("Trying to up-convert to %d images, %d logs.", lp->mirrors, log_count);
if (_lvconvert_mirrors_aux(cmd, lv, lp, NULL,
lp->mirrors, log_count))
@@ -1310,12 +1458,12 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
}
}
- if (replace_mirrors && lp->mirrors != old_mimage_count)
+ if (replace_mimages && lv_mirror_count(lv) != original_mimages)
log_warn("WARNING: Failed to replace %d of %d images in volume %s",
- old_mimage_count - lp->mirrors, old_mimage_count, lv->name);
- if (replace_log && log_count != old_log_count)
+ original_mimages - lv_mirror_count(lv), original_mimages, lv->name);
+ if (replace_logs && _get_log_count(lv) != original_logs)
log_warn("WARNING: Failed to replace %d of %d logs in volume %s",
- old_log_count - log_count, old_log_count, lv->name);
+ original_logs - _get_log_count(lv), original_logs, lv->name);
/* if (!arg_count(cmd, use_policies_ARG) && (lp->mirrors != old_mimage_count
|| log_count != old_log_count))
@@ -1340,6 +1488,19 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
uint32_t new_mimage_count;
uint32_t new_log_count;
+ if (lp->merge_mirror) {
+ log_error("Unable to merge mirror images"
+ "of segment type 'mirror'");
+ return 0;
+ }
+
+ /* TODO: decide what should be done here */
+ if (lv_is_thin_type(lv)) {
+ log_error("Converting segment type for %s/%s to mirror is not yet supported.",
+ lv->vg->name, lv->name);
+ return 0;
+ }
+
/* Adjust mimage and/or log count */
if (!_lvconvert_mirrors_parse_params(cmd, lv, lp,
&old_mimage_count, &old_log_count,
@@ -1349,8 +1510,8 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
if (((old_mimage_count < new_mimage_count && old_log_count > new_log_count) ||
(old_mimage_count > new_mimage_count && old_log_count < new_log_count)) &&
lp->pv_count) {
- log_error("Cannot both allocate and free extents when specifying physical"
- " volumes to use.");
+ log_error("Cannot both allocate and free extents when "
+ "specifying physical volumes to use.");
log_error("Please specify the operation in two steps.");
return 0;
}
@@ -1361,27 +1522,162 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
return 1;
if (repair)
- return _lvconvert_mirrors_repair(cmd, lv, lp,
- old_mimage_count,
- old_log_count);
+ return _lvconvert_mirrors_repair(cmd, lv, lp);
if (!_lvconvert_mirrors_aux(cmd, lv, lp, NULL,
new_mimage_count, new_log_count))
return 0;
if (!lp->need_polling)
- log_print("Logical volume %s converted.", lv->name);
+ log_print_unless_silent("Logical volume %s converted.", lv->name);
backup(lv->vg);
return 1;
}
+static int is_valid_raid_conversion(const struct segment_type *from_segtype,
+ const struct segment_type *to_segtype)
+{
+ if (from_segtype == to_segtype)
+ return 1;
+
+ if (!segtype_is_raid(from_segtype) && !segtype_is_raid(to_segtype))
+ return_0; /* Not converting to or from RAID? */
+
+ return 1;
+}
+
+static void _lvconvert_raid_repair_ask(struct cmd_context *cmd, int *replace_dev)
+{
+ const char *dev_policy = NULL;
+
+ int force = arg_count(cmd, force_ARG);
+ int yes = arg_count(cmd, yes_ARG);
+
+ *replace_dev = 0;
+
+ if (arg_count(cmd, use_policies_ARG)) {
+ dev_policy = find_config_tree_str(cmd, "activation/raid_fault_policy", DEFAULT_RAID_FAULT_POLICY);
+
+ if (!strcmp(dev_policy, "allocate") ||
+ !strcmp(dev_policy, "replace"))
+ *replace_dev = 1;
+ /* else if (!strcmp(dev_policy, "anything_else")) -- ignore */
+ return;
+ }
+
+ if (yes) {
+ *replace_dev = 1;
+ return;
+ }
+
+ if (force != PROMPT)
+ return;
+
+ if (yes_no_prompt("Attempt to replace failed RAID images "
+ "(requires full device resync)? [y/n]: ") == 'y') {
+ *replace_dev = 1;
+ }
+}
+
+static int lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp)
+{
+ int replace = 0;
+ int uninitialized_var(image_count);
+ struct dm_list *failed_pvs;
+ struct cmd_context *cmd = lv->vg->cmd;
+ struct lv_segment *seg = first_seg(lv);
+
+ if (!arg_count(cmd, type_ARG))
+ lp->segtype = seg->segtype;
+
+ /* Can only change image count for raid1 and linear */
+ if (arg_count(cmd, mirrors_ARG) &&
+ !seg_is_mirrored(seg) && !seg_is_linear(seg)) {
+ log_error("'--mirrors/-m' is not compatible with %s",
+ seg->segtype->ops->name(seg));
+ return 0;
+ }
+
+ if (!is_valid_raid_conversion(seg->segtype, lp->segtype)) {
+ log_error("Unable to convert %s/%s from %s to %s",
+ lv->vg->name, lv->name,
+ seg->segtype->ops->name(seg), lp->segtype->name);
+ return 0;
+ }
+
+ /* Change number of RAID1 images */
+ if (arg_count(cmd, mirrors_ARG) || arg_count(cmd, splitmirrors_ARG)) {
+ image_count = lv_raid_image_count(lv);
+ if (lp->mirrors_sign == SIGN_PLUS)
+ image_count += lp->mirrors;
+ else if (lp->mirrors_sign == SIGN_MINUS)
+ image_count -= lp->mirrors;
+ else
+ image_count = lp->mirrors + 1;
+
+ if (image_count < 1) {
+ log_error("Unable to %s images by specified amount",
+ arg_count(cmd, splitmirrors_ARG) ?
+ "split" : "reduce");
+ return 0;
+ }
+ }
+
+ if (lp->merge_mirror)
+ return lv_raid_merge(lv);
+
+ if (arg_count(cmd, trackchanges_ARG))
+ return lv_raid_split_and_track(lv, lp->pvh);
+
+ if (arg_count(cmd, splitmirrors_ARG))
+ return lv_raid_split(lv, lp->lv_split_name,
+ image_count, lp->pvh);
+
+ if (arg_count(cmd, mirrors_ARG))
+ return lv_raid_change_image_count(lv, image_count, lp->pvh);
+
+ if (arg_count(cmd, type_ARG))
+ return lv_raid_reshape(lv, lp->segtype);
+
+ if (arg_count(cmd, replace_ARG))
+ return lv_raid_replace(lv, lp->replace_pvh, lp->pvh);
+
+ if (arg_count(cmd, repair_ARG)) {
+ _lvconvert_raid_repair_ask(cmd, &replace);
+
+ if (replace) {
+ if (!(failed_pvs = _failed_pv_list(lv->vg)))
+ return_0;
+
+ if (!lv_raid_replace(lv, failed_pvs, lp->pvh)) {
+ log_error("Failed to replace faulty devices in"
+ " %s/%s.", lv->vg->name, lv->name);
+ return 0;
+ }
+
+ log_print_unless_silent("Faulty devices in %s/%s successfully"
+ " replaced.", lv->vg->name, lv->name);
+ return 1;
+ }
+
+ /* "warn" if policy not set to replace */
+ if (arg_count(cmd, use_policies_ARG))
+ log_error("Use 'lvconvert --repair %s/%s' to "
+ "replace failed device",
+ lv->vg->name, lv->name);
+ return 1;
+ }
+
+ log_error("Conversion operation not yet supported.");
+ return 0;
+}
+
static int lvconvert_snapshot(struct cmd_context *cmd,
struct logical_volume *lv,
struct lvconvert_params *lp)
{
struct logical_volume *org;
- int r = 0;
if (!(org = find_lv(lv->vg, lp->origin))) {
log_error("Couldn't find origin volume '%s'.", lp->origin);
@@ -1395,7 +1691,7 @@ static int lvconvert_snapshot(struct cmd_context *cmd,
}
if (org->status & (LOCKED|PVMOVE|MIRRORED) || lv_is_cow(org)) {
- log_error("Unable to create a snapshot of a %s LV.",
+ log_error("Unable to convert an LV into a snapshot of a %s LV.",
org->status & LOCKED ? "locked" :
org->status & PVMOVE ? "pvmove" :
org->status & MIRRORED ? "mirrored" :
@@ -1422,28 +1718,12 @@ static int lvconvert_snapshot(struct cmd_context *cmd,
}
/* store vg on disk(s) */
- if (!vg_write(lv->vg))
+ if (!_reload_lv(cmd, lv->vg, lv))
return_0;
- if (!suspend_lv(cmd, org)) {
- log_error("Failed to suspend origin %s", org->name);
- vg_revert(lv->vg);
- goto out;
- }
-
- if (!vg_commit(lv->vg))
- goto_out;
+ log_print_unless_silent("Logical volume %s converted to snapshot.", lv->name);
- if (!resume_lv(cmd, org)) {
- log_error("Problem reactivating origin %s", org->name);
- goto out;
- }
-
- log_print("Logical volume %s converted to snapshot.", lv->name);
- r = 1;
-out:
- backup(lv->vg);
- return r;
+ return 1;
}
static int lvconvert_merge(struct cmd_context *cmd,
@@ -1485,7 +1765,7 @@ static int lvconvert_merge(struct cmd_context *cmd,
}
if (lv_info(cmd, lv, 0, &info, 1, 0)) {
if (info.open_count) {
- log_print("Can't merge when snapshot is open");
+ log_print_unless_silent("Can't merge when snapshot is open");
merge_on_activate = 1;
}
}
@@ -1501,8 +1781,8 @@ static int lvconvert_merge(struct cmd_context *cmd,
if (!vg_commit(lv->vg))
return_0;
r = 1;
- log_print("Merging of snapshot %s will start "
- "next activation.", lv->name);
+ log_print_unless_silent("Merging of snapshot %s will start "
+ "next activation.", lv->name);
goto out;
}
@@ -1528,16 +1808,162 @@ static int lvconvert_merge(struct cmd_context *cmd,
lp->lv_to_poll = origin;
r = 1;
- log_print("Merging of volume %s started.", lv->name);
+ log_print_unless_silent("Merging of volume %s started.", lv->name);
out:
backup(lv->vg);
return r;
}
+/*
+ * Thin lvconvert version which
+ * rename metadata
+ * convert/layers thinpool over data
+ * attach metadata
+ */
+static int _lvconvert_thinpool(struct cmd_context *cmd,
+ struct logical_volume *pool_lv,
+ struct lvconvert_params *lp)
+{
+ int r = 0;
+ char *name;
+ int len;
+ struct lv_segment *seg;
+ struct logical_volume *data_lv;
+ struct logical_volume *metadata_lv;
+
+ if (lv_is_thin_type(pool_lv)) {
+ log_error("Can't use thin logical volume %s/%s for thin pool data.",
+ pool_lv->vg->name, pool_lv->name);
+ return 0;
+ }
+
+ /* We are changing target type, so deactivate first */
+ if (!deactivate_lv(cmd, pool_lv)) {
+ log_error("Can't deactivate logical volume %s/%s.",
+ pool_lv->vg->name, pool_lv->name);
+ return 0;
+ }
+
+ if (lp->pool_metadata_lv_name) {
+ metadata_lv = find_lv(pool_lv->vg, lp->pool_metadata_lv_name);
+ if (!metadata_lv) {
+ log_error("Unknown metadata LV %s", lp->pool_metadata_lv_name);
+ return 0;
+ }
+ if (metadata_lv == pool_lv) {
+ log_error("Can't use same LV for thin data and metadata LV %s",
+ lp->pool_metadata_lv_name);
+ return 0;
+ }
+ if (lv_is_thin_type(metadata_lv)) {
+ log_error("Can't use thin pool logical volume %s/%s "
+ "for thin pool metadata.",
+ metadata_lv->vg->name, metadata_lv->name);
+ return 0;
+ }
+ } else if (arg_count(cmd, poolmetadatasize_ARG)) {
+ /* FIXME: allocate metadata LV! */
+ metadata_lv = NULL;
+ log_error("Uncreated metadata.");
+ return 0;
+ } else {
+ log_error("Uknown metadata.");
+ return 0;
+ }
+
+ len = strlen(pool_lv->name) + 16;
+ if (!(name = dm_pool_alloc(pool_lv->vg->vgmem, len))) {
+ log_error("Cannot allocate new name.");
+ return 0;
+ }
+
+ if (!lv_is_active(metadata_lv)) {
+ if (!deactivate_lv(cmd, metadata_lv)) {
+ log_error("Can't deactivate logical volume %s/%s.",
+ metadata_lv->vg->name, metadata_lv->name);
+ return 0;
+ }
+ if (!activate_lv_local(cmd, metadata_lv)) {
+ log_error("Aborting. Failed to activate thin metadata lv.");
+ return 0;
+ }
+ }
+
+ if (!set_lv(cmd, metadata_lv, UINT64_C(0), 0)) {
+ log_error("Aborting. Failed to wipe thin metadata lv.");
+ return 0;
+ }
+
+ if (!deactivate_lv(cmd, metadata_lv)) {
+ log_error("Aborting. Failed to deactivate thin metadata lv. "
+ "Manual intervention required.");
+ return 0;
+ }
+
+ if (dm_snprintf(name, len, "%s_tmeta", pool_lv->name) < 0)
+ return_0;
+
+ /* Rename deactivated metadata LV to have _tmeta suffix */
+ /* Implicit checks if metadata_lv is visible */
+ if (!lv_rename_update(cmd, metadata_lv, name, 0))
+ return_0;
+
+ /*
+ * Since we wish to have underlaying dev, to match _tdata
+ * rename data LV first, also checks for visible LV
+ */
+ /* FIXME: any more types prohibited here? */
+ /* FIXME: revert renamed LVs in fail path? */
+
+ /* FIXME: common code with metadata/thin_manip.c extend_pool() */
+ /* Create layer _tdata */
+ if (!(data_lv = insert_layer_for_lv(pool_lv->vg->cmd, pool_lv,
+ pool_lv->status, "_tdata")))
+ return_0;
+
+ seg = first_seg(pool_lv);
+ seg->segtype = lp->segtype;
+ seg->lv->status |= THIN_POOL;
+
+ seg->chunk_size = lp->chunk_size;
+ seg->zero_new_blocks = lp->zero ? 1 : 0;
+ seg->discards = lp->discards;
+ seg->low_water_mark = 0;
+ seg->transaction_id = 0;
+
+ if (!attach_pool_metadata_lv(seg, metadata_lv))
+ return_0;
+
+ /* Drop reference as attach_pool_data_lv() takes it again */
+ remove_seg_from_segs_using_this_lv(data_lv, seg);
+ if (!attach_pool_data_lv(seg, data_lv))
+ return_0;
+
+ if (!vg_write(pool_lv->vg) || !vg_commit(pool_lv->vg))
+ return_0;
+
+ if (!activate_lv_excl(cmd, pool_lv)) {
+ log_error("Failed to activate pool logical volume %s/%s.",
+ pool_lv->vg->name, pool_lv->name);
+ goto out;
+ }
+
+ log_print_unless_silent("Converted %s/%s to thin pool.",
+ pool_lv->vg->name, pool_lv->name);
+
+ r = 1;
+out:
+ backup(pool_lv->vg);
+ return r;
+}
+
static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
struct lvconvert_params *lp = handle;
+ struct dm_list *failed_pvs;
+ struct lvinfo info;
+ percent_t snap_percent;
if (lv->status & LOCKED) {
log_error("Cannot convert locked LV %s", lv->name);
@@ -1555,19 +1981,30 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
return ECMD_FAILED;
}
- if (arg_count(cmd, repair_ARG) && !(lv->status & MIRRORED)) {
+ if (arg_count(cmd, repair_ARG) &&
+ !(lv->status & MIRRORED) && !(lv->status & RAID)) {
if (arg_count(cmd, use_policies_ARG))
return ECMD_PROCESSED; /* nothing to be done here */
log_error("Can't repair non-mirrored LV \"%s\".", lv->name);
return ECMD_FAILED;
}
+ if (!lp->segtype)
+ lp->segtype = first_seg(lv)->segtype;
+
if (lp->merge) {
if (!lv_is_cow(lv)) {
- log_error("Logical volume \"%s\" is not a snapshot",
+ log_error("\"%s\" is not a mergeable logical volume",
lv->name);
return ECMD_FAILED;
}
+ if (lv_info(lv->vg->cmd, lv, 0, &info, 1, 0)
+ && info.exists && info.live_table &&
+ (!lv_snapshot_percent(lv, &snap_percent) ||
+ snap_percent == PERCENT_INVALID)) {
+ log_error("Unable to merge invalidated snapshot LV \"%s\"", lv->name);
+ return ECMD_FAILED;
+ }
if (!archive(lv->vg)) {
stack;
return ECMD_FAILED;
@@ -1589,6 +2026,34 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
stack;
return ECMD_FAILED;
}
+ } else if (arg_count(cmd, thinpool_ARG)) {
+ if (!archive(lv->vg)) {
+ stack;
+ return ECMD_FAILED;
+ }
+ if (!_lvconvert_thinpool(cmd, lv, lp)) {
+ stack;
+ return ECMD_FAILED;
+ }
+ } else if (segtype_is_raid(lp->segtype) ||
+ (lv->status & RAID) || lp->merge_mirror) {
+ if (!archive(lv->vg)) {
+ stack;
+ return ECMD_FAILED;
+ }
+ if (!lvconvert_raid(lv, lp)) {
+ stack;
+ return ECMD_FAILED;
+ }
+
+ if (!(failed_pvs = _failed_pv_list(lv->vg))) {
+ stack;
+ return ECMD_FAILED;
+ }
+
+ /* If repairing and using policies, remove missing PVs from VG */
+ if (arg_count(cmd, repair_ARG) && arg_count(cmd, use_policies_ARG))
+ _remove_missing_empty_pv(lv->vg, failed_pvs);
} else if (arg_count(cmd, mirrors_ARG) ||
arg_count(cmd, splitmirrors_ARG) ||
(lv->status & MIRRORED)) {
@@ -1601,9 +2066,14 @@ static int _lvconvert_single(struct cmd_context *cmd, struct logical_volume *lv,
return ECMD_FAILED;
}
+ if (!(failed_pvs = _failed_pv_list(lv->vg))) {
+ stack;
+ return ECMD_FAILED;
+ }
+
/* If repairing and using policies, remove missing PVs from VG */
if (arg_count(cmd, repair_ARG) && arg_count(cmd, use_policies_ARG))
- _remove_missing_empty_pv(lv->vg, lp->failed_pvs);
+ _remove_missing_empty_pv(lv->vg, failed_pvs);
}
return ECMD_PROCESSED;
@@ -1619,7 +2089,7 @@ static struct logical_volume *get_vg_lock_and_logical_volume(struct cmd_context
{
/*
* Returns NULL if the requested LV doesn't exist;
- * otherwise the caller must free_vg(lv->vg)
+ * otherwise the caller must release_vg(lv->vg)
* - it is also up to the caller to unlock_vg() as needed
*/
struct volume_group *vg;
@@ -1627,13 +2097,13 @@ static struct logical_volume *get_vg_lock_and_logical_volume(struct cmd_context
vg = _get_lvconvert_vg(cmd, vg_name, NULL);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
return_NULL;
}
if (!(lv = _get_lvconvert_lv(cmd, vg, lv_name, NULL, 0))) {
log_error("Can't find LV %s in VG %s", lv_name, vg_name);
- unlock_and_free_vg(cmd, vg, vg_name);
+ unlock_and_release_vg(cmd, vg, vg_name);
return NULL;
}
@@ -1645,8 +2115,8 @@ static int poll_logical_volume(struct cmd_context *cmd, struct logical_volume *l
{
struct lvinfo info;
- if (!lv_info(cmd, lv, 0, &info, 1, 0) || !info.exists) {
- log_print("Conversion starts after activation.");
+ if (!lv_info(cmd, lv, 0, &info, 0, 0) || !info.exists) {
+ log_print_unless_silent("Conversion starts after activation.");
return ECMD_PROCESSED;
}
return lvconvert_poll(cmd, lv, wait_completion ? 0 : 1U);
@@ -1677,6 +2147,12 @@ static int lvconvert_single(struct cmd_context *cmd, struct lvconvert_params *lp
} else
lp->pvh = &lv->vg->pvs;
+ if (lp->replace_pv_count &&
+ !(lp->replace_pvh = create_pv_list(cmd->mem, lv->vg,
+ lp->replace_pv_count,
+ lp->replace_pvs, 0)))
+ goto_bad;
+
lp->lv_to_poll = lv;
ret = _lvconvert_single(cmd, lv, lp);
bad:
@@ -1686,7 +2162,7 @@ bad:
ret = poll_logical_volume(cmd, lp->lv_to_poll,
lp->wait_completion);
- free_vg(lv->vg);
+ release_vg(lv->vg);
out:
init_ignore_suspended_devices(saved_ignore_suspended_devices);
return ret;
@@ -1736,7 +2212,7 @@ static int lvconvert_merge_single(struct cmd_context *cmd, struct logical_volume
}
}
- free_vg(refreshed_lv->vg);
+ release_vg(refreshed_lv->vg);
return ret;
}
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 13b5926..3ea8f46 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -14,7 +14,6 @@
*/
#include "tools.h"
-#include "lv_alloc.h"
#include <fcntl.h>
@@ -25,46 +24,122 @@ struct lvcreate_cmdline_params {
int pv_count;
};
+static int _set_vg_name(struct lvcreate_params *lp, const char *vg_name)
+{
+ /* Can't do anything */
+ if (!vg_name)
+ return 1;
+
+ /* If VG name already known, ensure this 2nd copy is identical */
+ if (lp->vg_name && strcmp(lp->vg_name, vg_name)) {
+ log_error("Inconsistent volume group names "
+ "given: \"%s\" and \"%s\"",
+ lp->vg_name, vg_name);
+ return 0;
+ }
+ lp->vg_name = vg_name;
+
+ return 1;
+}
+
static int _lvcreate_name_params(struct lvcreate_params *lp,
struct cmd_context *cmd,
int *pargc, char ***pargv)
{
int argc = *pargc;
char **argv = *pargv, *ptr;
- char *vg_name;
+ const char *vg_name;
+
+ lp->pool = arg_str_value(cmd, thinpool_ARG, NULL);
+
+ /* If --thinpool contains VG name, extract it. */
+ if (lp->pool && strchr(lp->pool, '/')) {
+ if (!(lp->vg_name = extract_vgname(cmd, lp->pool)))
+ return 0;
+ /* Strip VG from pool */
+ if ((ptr = strrchr(lp->pool, (int) '/')))
+ lp->pool = ptr + 1;
+ }
lp->lv_name = arg_str_value(cmd, name_ARG, NULL);
+ /* If --name contains VG name, extract it. */
+ if (lp->lv_name && strchr(lp->lv_name, '/')) {
+ if (!_set_vg_name(lp, extract_vgname(cmd, lp->lv_name)))
+ return_0;
+
+ /* Strip VG from lv_name */
+ if ((ptr = strrchr(lp->lv_name, (int) '/')))
+ lp->lv_name = ptr + 1;
+ }
+
+ /* Need an origin? */
if (lp->snapshot && !arg_count(cmd, virtualsize_ARG)) {
+ /* argv[0] might be origin or vg/origin */
if (!argc) {
log_error("Please specify a logical volume to act as "
"the snapshot origin.");
return 0;
}
- lp->origin = argv[0];
- (*pargv)++, (*pargc)--;
- if (!(lp->vg_name = extract_vgname(cmd, lp->origin))) {
+ lp->origin = skip_dev_dir(cmd, argv[0], NULL);
+ if (strrchr(lp->origin, '/')) {
+ if (!_set_vg_name(lp, extract_vgname(cmd, lp->origin)))
+ return_0;
+
+ /* Strip the volume group from the origin */
+ if ((ptr = strrchr(lp->origin, (int) '/')))
+ lp->origin = ptr + 1;
+ }
+
+ if (!lp->vg_name &&
+ !_set_vg_name(lp, extract_vgname(cmd, NULL)))
+ return_0;
+
+ if (!lp->vg_name) {
log_error("The origin name should include the "
"volume group.");
return 0;
}
- /* Strip the volume group from the origin */
- if ((ptr = strrchr(lp->origin, (int) '/')))
- lp->origin = ptr + 1;
+ (*pargv)++, (*pargc)--;
+ } else if (seg_is_thin(lp) && !lp->pool && argc) {
+ /* argv[0] might be vg or vg/Pool */
+
+ vg_name = skip_dev_dir(cmd, argv[0], NULL);
+ if (!strrchr(vg_name, '/')) {
+ if (!_set_vg_name(lp, vg_name))
+ return_0;
+ } else {
+ lp->pool = vg_name;
+ if (!_set_vg_name(lp, extract_vgname(cmd, lp->pool)))
+ return_0;
+
+ if (!lp->vg_name &&
+ !_set_vg_name(lp, extract_vgname(cmd, NULL)))
+ return_0;
+
+ if (!lp->vg_name) {
+ log_error("The pool name should include the "
+ "volume group.");
+ return 0;
+ }
+
+ /* Strip the volume group */
+ if ((ptr = strrchr(lp->pool, (int) '/')))
+ lp->pool = ptr + 1;
+ }
+ (*pargv)++, (*pargc)--;
} else {
/*
- * If VG not on command line, try -n arg and then
- * environment.
+ * If VG not on command line, try environment default.
*/
if (!argc) {
- if (!(lp->vg_name = extract_vgname(cmd, lp->lv_name))) {
+ if (!lp->vg_name && !(lp->vg_name = extract_vgname(cmd, NULL))) {
log_error("Please provide a volume group name");
return 0;
}
-
} else {
vg_name = skip_dev_dir(cmd, argv[0], NULL);
if (strrchr(vg_name, '/')) {
@@ -73,25 +148,9 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
return 0;
}
- /*
- * Ensure lv_name doesn't contain a
- * different VG.
- */
- if (lp->lv_name && strchr(lp->lv_name, '/')) {
- if (!(lp->vg_name =
- extract_vgname(cmd, lp->lv_name)))
- return 0;
-
- if (strcmp(lp->vg_name, vg_name)) {
- log_error("Inconsistent volume group "
- "names "
- "given: \"%s\" and \"%s\"",
- lp->vg_name, vg_name);
- return 0;
- }
- }
+ if (!_set_vg_name(lp, vg_name))
+ return_0;
- lp->vg_name = vg_name;
(*pargv)++, (*pargc)--;
}
}
@@ -103,9 +162,6 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
}
if (lp->lv_name) {
- if ((ptr = strrchr(lp->lv_name, '/')))
- lp->lv_name = ptr + 1;
-
if (!apply_lvname_restrictions(lp->lv_name))
return_0;
@@ -116,12 +172,59 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
}
}
+ if (lp->pool) {
+ if (!apply_lvname_restrictions(lp->pool))
+ return_0;
+
+ if (!validate_name(lp->pool)) {
+ log_error("Logical volume name \"%s\" is invalid",
+ lp->pool);
+ return 0;
+ }
+
+ if (lp->lv_name && !strcmp(lp->lv_name, lp->pool)) {
+ log_error("Logical volume name %s and pool name %s must be different.",
+ lp->lv_name, lp->pool);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Normal snapshot or thinly-provisioned snapshot?
+ */
+static int _determine_snapshot_type(struct volume_group *vg,
+ struct lvcreate_params *lp)
+{
+ struct lv_list *lvl;
+
+ if (!(lvl = find_lv_in_vg(vg, lp->origin))) {
+ log_error("Snapshot origin LV %s not found in Volume group %s.",
+ lp->origin, vg->name);
+ return 0;
+ }
+
+ if (!arg_count(vg->cmd, extents_ARG) && !arg_count(vg->cmd, size_ARG)) {
+ if (!lv_is_thin_volume(lvl->lv)) {
+ log_error("Please specify either size or extents with snapshots.");
+ return 0;
+ }
+
+ lp->thin = 1;
+ if (!(lp->segtype = get_segtype_from_string(vg->cmd, "thin")))
+ return_0;
+
+ lp->pool = first_seg(lvl->lv)->pool_lv->name;
+ }
+
return 1;
}
/*
* Update extents parameters based on other parameters which affect the size
- * calcuation.
+ * calculation.
* NOTE: We must do this here because of the percent_t typedef and because we
* need the vg.
*/
@@ -131,6 +234,9 @@ static int _update_extents_params(struct volume_group *vg,
{
uint32_t pv_extent_count;
struct logical_volume *origin = NULL;
+ int changed = 0;
+ uint32_t size_rest;
+ uint32_t stripesize_extents;
if (lcp->size &&
!(lp->extents = extents_from_size(vg->cmd, lcp->size,
@@ -155,17 +261,17 @@ static int _update_extents_params(struct volume_group *vg,
switch(lcp->percent) {
case PERCENT_VG:
- lp->extents = lp->extents * vg->extent_count / 100;
+ lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0);
break;
case PERCENT_FREE:
- lp->extents = lp->extents * vg->free_count / 100;
+ lp->extents = percent_of_extents(lp->extents, vg->free_count, 0);
break;
case PERCENT_PVS:
if (!lcp->pv_count)
- lp->extents = lp->extents * vg->extent_count / 100;
+ lp->extents = percent_of_extents(lp->extents, vg->extent_count, 0);
else {
pv_extent_count = pv_list_extents_free(lp->pvh);
- lp->extents = lp->extents * pv_extent_count / 100;
+ lp->extents = percent_of_extents(lp->extents, pv_extent_count, 0);
}
break;
case PERCENT_LV:
@@ -183,11 +289,63 @@ static int _update_extents_params(struct volume_group *vg,
log_error(INTERNAL_ERROR "Couldn't find origin volume.");
return 0;
}
- lp->extents = lp->extents * origin->le_count / 100;
+ lp->extents = percent_of_extents(lp->extents, origin->le_count, 0);
break;
case PERCENT_NONE:
break;
}
+
+ if (!(stripesize_extents = lp->stripe_size / vg->extent_size))
+ stripesize_extents = 1;
+
+ if ((lcp->percent != PERCENT_NONE) && lp->stripes &&
+ (size_rest = lp->extents % (lp->stripes * stripesize_extents)) &&
+ (vg->free_count < lp->extents - size_rest + (lp->stripes * stripesize_extents))) {
+ log_print_unless_silent("Rounding size (%d extents) down to stripe boundary "
+ "size (%d extents)", lp->extents,
+ lp->extents - size_rest);
+ lp->extents = lp->extents - size_rest;
+ }
+
+ if (lp->create_thin_pool) {
+ if (!arg_count(vg->cmd, poolmetadatasize_ARG)) {
+ /* Defaults to nr_pool_blocks * 64b */
+ lp->poolmetadatasize = (uint64_t) lp->extents * vg->extent_size /
+ (uint64_t) (lp->chunk_size * (SECTOR_SIZE / UINT64_C(64)));
+
+ /* Check if we could eventually use bigger chunk size */
+ if (!arg_count(vg->cmd, chunksize_ARG)) {
+ while ((lp->poolmetadatasize >
+ (DEFAULT_THIN_POOL_OPTIMAL_SIZE / SECTOR_SIZE)) &&
+ (lp->chunk_size < DM_THIN_MAX_DATA_BLOCK_SIZE)) {
+ lp->chunk_size <<= 1;
+ lp->poolmetadatasize >>= 1;
+ changed++;
+ }
+ if (changed)
+ log_verbose("Changed chunksize to %u sectors.",
+ lp->chunk_size);
+ }
+ }
+
+ if (lp->poolmetadatasize > (2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE)) {
+ if (arg_count(vg->cmd, poolmetadatasize_ARG))
+ log_warn("WARNING: Maximum supported pool metadata size is 16GB.");
+ lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MAX_METADATA_SIZE;
+ } else if (lp->poolmetadatasize < (2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE)) {
+ if (arg_count(vg->cmd, poolmetadatasize_ARG))
+ log_warn("WARNING: Minimum supported pool metadata size is 2M.");
+ lp->poolmetadatasize = 2 * DEFAULT_THIN_POOL_MIN_METADATA_SIZE;
+ }
+
+ log_verbose("Setting pool metadata size to %" PRIu64 " sectors.",
+ lp->poolmetadatasize);
+
+ if (!(lp->poolmetadataextents =
+ extents_from_size(vg->cmd, lp->poolmetadatasize, vg->extent_size)))
+ return_0;
+ }
+
return 1;
}
@@ -195,13 +353,18 @@ static int _read_size_params(struct lvcreate_params *lp,
struct lvcreate_cmdline_params *lcp,
struct cmd_context *cmd)
{
- if (arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) != 1) {
+ if (arg_count(cmd, extents_ARG) && arg_count(cmd, size_ARG)) {
log_error("Please specify either size or extents (not both)");
return 0;
}
+ if (!lp->thin && !lp->snapshot && !arg_count(cmd, extents_ARG) && !arg_count(cmd, size_ARG)) {
+ log_error("Please specify either size or extents");
+ return 0;
+ }
+
if (arg_count(cmd, extents_ARG)) {
- if (arg_sign_value(cmd, extents_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, extents_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Negative number of extents is invalid");
return 0;
}
@@ -211,7 +374,7 @@ static int _read_size_params(struct lvcreate_params *lp,
/* Size returned in kilobyte units; held in sectors */
if (arg_count(cmd, size_ARG)) {
- if (arg_sign_value(cmd, size_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, size_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Negative size is invalid");
return 0;
}
@@ -219,9 +382,29 @@ static int _read_size_params(struct lvcreate_params *lp,
lcp->percent = PERCENT_NONE;
}
+ /* If size/extents given with thin, then we are creating a thin pool */
+ if (lp->thin && (arg_count(cmd, size_ARG) || arg_count(cmd, extents_ARG)))
+ lp->create_thin_pool = 1;
+
+ if (arg_count(cmd, poolmetadatasize_ARG)) {
+ if (!seg_is_thin(lp)) {
+ log_error("--poolmetadatasize may only be specified when allocating the thin pool.");
+ return 0;
+ }
+ if (arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE) == SIGN_MINUS) {
+ log_error("Negative poolmetadatasize is invalid.");
+ return 0;
+ }
+ lp->poolmetadatasize = arg_uint64_value(cmd, poolmetadatasize_ARG, UINT64_C(0));
+ }
+
/* Size returned in kilobyte units; held in sectors */
if (arg_count(cmd, virtualsize_ARG)) {
- if (arg_sign_value(cmd, virtualsize_ARG, 0) == SIGN_MINUS) {
+ if (seg_is_thin_pool(lp)) {
+ log_error("Virtual size in incompatible with thin_pool segment type.");
+ return 0;
+ }
+ if (arg_sign_value(cmd, virtualsize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Negative virtual origin size is invalid");
return 0;
}
@@ -231,6 +414,12 @@ static int _read_size_params(struct lvcreate_params *lp,
log_error("Virtual origin size may not be zero");
return 0;
}
+ } else {
+ /* No virtual size given, so no thin LV to create. */
+ if (seg_is_thin_volume(lp) && !(lp->segtype = get_segtype_from_string(cmd, "thin-pool")))
+ return_0;
+
+ lp->thin = 0;
}
return 1;
@@ -297,7 +486,7 @@ static int _read_mirror_params(struct lvcreate_params *lp,
lp->nosync = arg_is_set(cmd, nosync_ARG);
if (arg_count(cmd, regionsize_ARG)) {
- if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, regionsize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Negative regionsize is invalid");
return 0;
}
@@ -320,15 +509,177 @@ static int _read_mirror_params(struct lvcreate_params *lp,
return 1;
}
+static int _read_raid_params(struct lvcreate_params *lp,
+ struct cmd_context *cmd)
+{
+ if (!segtype_is_raid(lp->segtype))
+ return 1;
+
+ if (arg_count(cmd, corelog_ARG) ||
+ arg_count(cmd, mirrorlog_ARG)) {
+ log_error("Log options not applicable to %s segtype",
+ lp->segtype->name);
+ return 0;
+ }
+
+ /*
+ * get_stripe_params is called before _read_raid_params
+ * and already sets:
+ * lp->stripes
+ * lp->stripe_size
+ *
+ * For RAID 4/5/6, these values must be set.
+ */
+ if (!segtype_is_mirrored(lp->segtype) &&
+ (lp->stripes <= lp->segtype->parity_devs)) {
+ log_error("Number of stripes must be at least %d for %s",
+ lp->segtype->parity_devs + 1, lp->segtype->name);
+ return 0;
+ }
+
+ /*
+ * RAID types without a mirror component do not take '-m' arg
+ */
+ if (!segtype_is_mirrored(lp->segtype) &&
+ arg_count(cmd, mirrors_ARG)) {
+ log_error("Mirror argument cannot be used with segment type, %s",
+ lp->segtype->name);
+ return 0;
+ }
+
+ /*
+ * RAID1 does not take a stripe arg
+ */
+ if ((lp->stripes > 1) &&
+ segtype_is_mirrored(lp->segtype) &&
+ strcmp(lp->segtype->name, "raid10")) {
+ log_error("Stripe argument cannot be used with segment type, %s",
+ lp->segtype->name);
+ return 0;
+ }
+
+ /*
+ * _read_mirror_params is called before _read_raid_params
+ * and already sets:
+ * lp->nosync
+ * lp->region_size
+ *
+ * But let's ensure that programmers don't reorder
+ * that by checking and warning if they aren't set.
+ */
+ if (!lp->region_size) {
+ log_error(INTERNAL_ERROR "region_size not set.");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _read_activation_params(struct lvcreate_params *lp, struct cmd_context *cmd,
+ struct volume_group *vg)
+{
+ unsigned pagesize;
+
+ lp->activate = (activation_change_t)
+ arg_uint_value(cmd, activate_ARG, CHANGE_AY);
+
+ if (lp->activate == CHANGE_AN || lp->activate == CHANGE_ALN) {
+ if (lp->zero && !seg_is_thin(lp)) {
+ log_error("--activate n requires --zero n");
+ return 0;
+ }
+ } else if (lp->activate == CHANGE_AAY) {
+ if (arg_count(cmd, zero_ARG)) {
+ log_error("-Z is incompatible with --activate a");
+ return 0;
+ }
+ lp->zero = 0;
+ }
+
+ /*
+ * Read ahead.
+ */
+ lp->read_ahead = arg_uint_value(cmd, readahead_ARG,
+ cmd->default_settings.read_ahead);
+ pagesize = lvm_getpagesize() >> SECTOR_SHIFT;
+ if (lp->read_ahead != DM_READ_AHEAD_AUTO &&
+ lp->read_ahead != DM_READ_AHEAD_NONE &&
+ lp->read_ahead % pagesize) {
+ if (lp->read_ahead < pagesize)
+ lp->read_ahead = pagesize;
+ else
+ lp->read_ahead = (lp->read_ahead / pagesize) * pagesize;
+ log_warn("WARNING: Overriding readahead to %u sectors, a multiple "
+ "of %uK page size.", lp->read_ahead, pagesize >> 1);
+ }
+
+ /*
+ * Permissions.
+ */
+ lp->permission = arg_uint_value(cmd, permission_ARG,
+ LVM_READ | LVM_WRITE);
+
+ /* Must not zero read only volume */
+ if (!(lp->permission & LVM_WRITE))
+ lp->zero = 0;
+
+ if (arg_count(cmd, major_ARG) > 1) {
+ log_error("Option -j/--major may not be repeated.");
+ return 0;
+ }
+
+ if (arg_count(cmd, minor_ARG) > 1) {
+ log_error("Option --minor may not be repeated.");
+ return 0;
+ }
+
+ lp->minor = arg_int_value(cmd, minor_ARG, -1);
+ lp->major = arg_int_value(cmd, major_ARG, -1);
+
+ /* Persistent minor */
+ if (arg_count(cmd, persistent_ARG)) {
+ if (lp->create_thin_pool && !lp->thin) {
+ log_error("--persistent is not permitted when creating a thin pool device.");
+ return 0;
+ }
+ if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) {
+ if (lp->minor == -1) {
+ log_error("Please specify minor number with "
+ "--minor when using -My");
+ return 0;
+ }
+ if (lp->major == -1) {
+ log_error("Please specify major number with "
+ "--major when using -My");
+ return 0;
+ }
+ if (!major_minor_valid(cmd, vg->fid->fmt, lp->major, lp->minor))
+ return 0;
+ } else {
+ if ((lp->minor != -1) || (lp->major != -1)) {
+ log_error("--major and --minor incompatible "
+ "with -Mn");
+ return 0;
+ }
+ }
+ } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) {
+ log_error("--major and --minor require -My");
+ return 0;
+ }
+
+ return 1;
+}
+
static int _lvcreate_params(struct lvcreate_params *lp,
struct lvcreate_cmdline_params *lcp,
struct cmd_context *cmd,
int argc, char **argv)
{
int contiguous;
- unsigned pagesize;
struct arg_value_group_list *current_group;
+ const char *segtype_str;
const char *tag;
+ unsigned attr = 0;
memset(lp, 0, sizeof(*lp));
memset(lcp, 0, sizeof(*lcp));
@@ -337,64 +688,96 @@ static int _lvcreate_params(struct lvcreate_params *lp,
/*
* Check selected options are compatible and determine segtype
*/
- lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, "striped"));
+// FIXME -m0 implies *striped*
+ if ((arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG)) &&
+ arg_count(cmd,mirrors_ARG)) {
+ log_error("--thin,--thinpool and --mirrors are incompatible.");
+ return 0;
+ }
+
+// FIXME -m0 implies *striped*
+
+ /* Set default segtype */
+ if (arg_count(cmd, mirrors_ARG))
+ /*
+ * FIXME: Add default setting for when -i and -m arguments
+ * are both given. We should default to "raid10".
+ */
+ segtype_str = find_config_tree_str(cmd, "global/mirror_segtype_default", DEFAULT_MIRROR_SEGTYPE);
+ else if (arg_count(cmd, thin_ARG) || arg_count(cmd, thinpool_ARG))
+ segtype_str = "thin";
+ else
+ segtype_str = "striped";
+
+ segtype_str = arg_str_value(cmd, type_ARG, segtype_str);
+
+ if (!(lp->segtype = get_segtype_from_string(cmd, segtype_str)))
+ return_0;
+
+ if (seg_unknown(lp)) {
+ log_error("Unable to create LV with unknown segment type %s.", segtype_str);
+ return 0;
+ }
if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp) ||
- arg_count(cmd, virtualsize_ARG))
+ (!seg_is_thin(lp) && arg_count(cmd, virtualsize_ARG)))
lp->snapshot = 1;
+ if (seg_is_thin_pool(lp)) {
+ if (lp->snapshot) {
+ log_error("Snapshots are incompatible with thin_pool segment_type.");
+ return 0;
+ }
+ lp->create_thin_pool = 1;
+ }
+
+ if (seg_is_thin_volume(lp))
+ lp->thin = 1;
+
lp->mirrors = 1;
- /* Default to 2 mirrored areas if --type mirror */
- if (seg_is_mirrored(lp))
+ /* Default to 2 mirrored areas if '--type mirror|raid1|raid10' */
+ if (segtype_is_mirrored(lp->segtype))
lp->mirrors = 2;
if (arg_count(cmd, mirrors_ARG)) {
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
- if (lp->mirrors == 1)
- log_print("Redundant mirrors argument: default is 0");
- if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
- log_error("Mirrors argument may not be negative");
- return 0;
+ if (lp->mirrors == 1) {
+ if (segtype_is_mirrored(lp->segtype)) {
+ log_error("--mirrors must be at least 1 with segment type %s.", lp->segtype->name);
+ return 0;
+ }
+ log_print_unless_silent("Redundant mirrors argument: default is 0");
}
- }
- if (lp->snapshot) {
- if (arg_count(cmd, zero_ARG)) {
- log_error("-Z is incompatible with snapshots");
- return 0;
- }
- if (arg_sign_value(cmd, chunksize_ARG, 0) == SIGN_MINUS) {
- log_error("Negative chunk size is invalid");
- return 0;
- }
- lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
- if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
- (lp->chunk_size & (lp->chunk_size - 1))) {
- log_error("Chunk size must be a power of 2 in the "
- "range 4K to 512K");
+ if ((lp->mirrors > 2) && !strcmp(lp->segtype->name, "raid10")) {
+ /*
+ * FIXME: When RAID10 is no longer limited to
+ * 2-way mirror, 'lv_mirror_count()'
+ * must also change for RAID10.
+ */
+ log_error("RAID10 currently supports "
+ "only 2-way mirroring (i.e. '-m 1')");
return 0;
}
- log_verbose("Setting chunksize to %d sectors.", lp->chunk_size);
- if (!(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
- return_0;
- } else {
- if (arg_count(cmd, chunksize_ARG)) {
- log_error("-c is only available with snapshots");
+ if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) {
+ log_error("Mirrors argument may not be negative");
return 0;
}
}
- if (lp->mirrors > 1) {
+ if (lp->snapshot && arg_count(cmd, zero_ARG)) {
+ log_error("-Z is incompatible with snapshots");
+ return 0;
+ }
+
+ if (segtype_is_mirrored(lp->segtype) || segtype_is_raid(lp->segtype)) {
if (lp->snapshot) {
log_error("mirrors and snapshots are currently "
"incompatible");
return 0;
}
-
- if (!(lp->segtype = get_segtype_from_string(cmd, "striped")))
- return_0;
} else {
if (arg_count(cmd, corelog_ARG)) {
log_error("--corelog is only available with mirrors");
@@ -413,42 +796,93 @@ static int _lvcreate_params(struct lvcreate_params *lp,
}
if (activation() && lp->segtype->ops->target_present &&
- !lp->segtype->ops->target_present(cmd, NULL, NULL)) {
+ !lp->segtype->ops->target_present(cmd, NULL, &attr)) {
log_error("%s: Required device-mapper target(s) not "
"detected in your kernel", lp->segtype->name);
return 0;
+ } else if (!strcmp(lp->segtype->name, "raid10")) {
+ uint32_t maj, min, patchlevel;
+ if (!target_version("raid", &maj, &min, &patchlevel)) {
+ log_error("Failed to determine version of RAID kernel module");
+ return 0;
+ }
+ if ((maj != 1) || (min < 3)) {
+ log_error("RAID module does not support RAID10");
+ return 0;
+ }
}
- if (!get_activation_monitoring_mode(cmd, NULL,
- &lp->activation_monitoring))
- return_0;
-
if (!_lvcreate_name_params(lp, cmd, &argc, &argv) ||
!_read_size_params(lp, lcp, cmd) ||
!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) ||
- !_read_mirror_params(lp, cmd))
+ !_read_mirror_params(lp, cmd) ||
+ !_read_raid_params(lp, cmd))
return_0;
+ if (lp->create_thin_pool)
+ lp->discards = (thin_discards_t) arg_uint_value(cmd, discards_ARG, THIN_DISCARDS_PASSDOWN);
+ else if (arg_count(cmd, discards_ARG)) {
+ log_error("--discards is only available for thin pool creation.");
+ return 0;
+ }
+
+ if (lp->snapshot && lp->thin && arg_count(cmd, chunksize_ARG))
+ log_warn("WARNING: Ignoring --chunksize with thin snapshots.");
+ else if (lp->thin && !lp->create_thin_pool) {
+ if (arg_count(cmd, chunksize_ARG))
+ log_warn("WARNING: Ignoring --chunksize when using an existing pool.");
+ } else if (lp->snapshot || lp->create_thin_pool) {
+ if (arg_sign_value(cmd, chunksize_ARG, SIGN_NONE) == SIGN_MINUS) {
+ log_error("Negative chunk size is invalid");
+ return 0;
+ }
+ if (lp->snapshot) {
+ lp->chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
+ if (lp->chunk_size < 8 || lp->chunk_size > 1024 ||
+ (lp->chunk_size & (lp->chunk_size - 1))) {
+ log_error("Chunk size must be a power of 2 in the "
+ "range 4K to 512K");
+ return 0;
+ }
+ } else {
+ lp->chunk_size = arg_uint_value(cmd, chunksize_ARG,
+ DM_THIN_MIN_DATA_BLOCK_SIZE);
+ if ((lp->chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE) ||
+ (lp->chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE)) {
+ log_error("Chunk size must be in the range %uK to %uK",
+ (DM_THIN_MIN_DATA_BLOCK_SIZE / 2),
+ (DM_THIN_MAX_DATA_BLOCK_SIZE / 2));
+ return 0;
+ }
+ if (!(attr & THIN_FEATURE_BLOCK_SIZE) &&
+ (lp->chunk_size & (lp->chunk_size - 1))) {
+ log_error("Chunk size must be a power of 2 for this thin target version.");
+ return 0;
+ } else if (lp->chunk_size & (DM_THIN_MIN_DATA_BLOCK_SIZE - 1)) {
+ log_error("Chunk size must be multiple of %uK.",
+ DM_THIN_MIN_DATA_BLOCK_SIZE / 2);
+ return 0;
+ } else if ((lp->discards != THIN_DISCARDS_IGNORE) &&
+ (lp->chunk_size & (lp->chunk_size - 1))) {
+ log_warn("WARNING: Using discards ignore for chunk size non power of 2.");
+ lp->discards = THIN_DISCARDS_IGNORE;
+ }
+ }
+ log_verbose("Setting chunksize to %u sectors.", lp->chunk_size);
+
+ if (!lp->thin && lp->snapshot && !(lp->segtype = get_segtype_from_string(cmd, "snapshot")))
+ return_0;
+ } else if (arg_count(cmd, chunksize_ARG)) {
+ log_error("-c is only available with snapshots and thin pools");
+ return 0;
+ }
+
/*
* Should we zero the lv.
*/
lp->zero = strcmp(arg_str_value(cmd, zero_ARG,
(lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? "n" : "y"), "n");
- /*
- * Alloc policy
- */
- contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
-
- lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
-
- lp->alloc = arg_uint_value(cmd, alloc_ARG, lp->alloc);
-
- if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) {
- log_error("Conflicting contiguous and alloc arguments");
- return 0;
- }
-
if (lp->mirrors > DEFAULT_MIRROR_MAX_IMAGES) {
log_error("Only up to %d images in mirror supported currently.",
DEFAULT_MIRROR_MAX_IMAGES);
@@ -456,57 +890,16 @@ static int _lvcreate_params(struct lvcreate_params *lp,
}
/*
- * Read ahead.
+ * Allocation parameters
*/
- lp->read_ahead = arg_uint_value(cmd, readahead_ARG,
- cmd->default_settings.read_ahead);
- pagesize = lvm_getpagesize() >> SECTOR_SHIFT;
- if (lp->read_ahead != DM_READ_AHEAD_AUTO &&
- lp->read_ahead != DM_READ_AHEAD_NONE &&
- lp->read_ahead % pagesize) {
- if (lp->read_ahead < pagesize)
- lp->read_ahead = pagesize;
- else
- lp->read_ahead = (lp->read_ahead / pagesize) * pagesize;
- log_warn("WARNING: Overriding readahead to %u sectors, a multiple "
- "of %uK page size.", lp->read_ahead, pagesize >> 1);
- }
-
- /*
- * Permissions.
- */
- lp->permission = arg_uint_value(cmd, permission_ARG,
- LVM_READ | LVM_WRITE);
+ contiguous = strcmp(arg_str_value(cmd, contiguous_ARG, "n"), "n");
- /* Must not zero read only volume */
- if (!(lp->permission & LVM_WRITE))
- lp->zero = 0;
+ lp->alloc = contiguous ? ALLOC_CONTIGUOUS : ALLOC_INHERIT;
- lp->minor = arg_int_value(cmd, minor_ARG, -1);
- lp->major = arg_int_value(cmd, major_ARG, -1);
+ lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lp->alloc);
- /* Persistent minor */
- if (arg_count(cmd, persistent_ARG)) {
- if (!strcmp(arg_str_value(cmd, persistent_ARG, "n"), "y")) {
- if (lp->minor == -1) {
- log_error("Please specify minor number with "
- "--minor when using -My");
- return 0;
- }
- if (lp->major == -1) {
- log_error("Please specify major number with "
- "--major when using -My");
- return 0;
- }
- } else {
- if ((lp->minor != -1) || (lp->major != -1)) {
- log_error("--major and --minor incompatible "
- "with -Mn");
- return 0;
- }
- }
- } else if (arg_count(cmd, minor_ARG) || arg_count(cmd, major_ARG)) {
- log_error("--major and --minor require -My");
+ if (contiguous && (lp->alloc != ALLOC_CONTIGUOUS)) {
+ log_error("Conflicting contiguous and alloc arguments");
return 0;
}
@@ -520,10 +913,10 @@ static int _lvcreate_params(struct lvcreate_params *lp,
}
if (!str_list_add(cmd->mem, &lp->tags, tag)) {
- log_error("Unable to allocate memory for tag %s", tag);
+ log_error("Unable to allocate memory for tag %s", tag);
return 0;
}
- }
+ }
lcp->pv_count = argc;
lcp->pvs = argv;
@@ -531,6 +924,144 @@ static int _lvcreate_params(struct lvcreate_params *lp,
return 1;
}
+static int _check_thin_parameters(struct volume_group *vg, struct lvcreate_params *lp,
+ struct lvcreate_cmdline_params *lcp)
+{
+ struct lv_list *lvl;
+
+ if (!lp->thin && !lp->create_thin_pool) {
+ log_error("Please specify device size(s).");
+ return 0;
+ }
+
+ if (lp->thin && !lp->create_thin_pool) {
+ if (arg_count(vg->cmd, chunksize_ARG)) {
+ log_error("Only specify --chunksize when originally creating the thin pool.");
+ return 0;
+ }
+
+ if (lcp->pv_count) {
+ log_error("Only specify Physical volumes when allocating the thin pool.");
+ return 0;
+ }
+
+ if (arg_count(vg->cmd, alloc_ARG)) {
+ log_error("--alloc may only be specified when allocating the thin pool.");
+ return 0;
+ }
+
+ if (arg_count(vg->cmd, poolmetadatasize_ARG)) {
+ log_error("--poolmetadatasize may only be specified when allocating the thin pool.");
+ return 0;
+ }
+
+ if (arg_count(vg->cmd, stripesize_ARG)) {
+ log_error("--stripesize may only be specified when allocating the thin pool.");
+ return 0;
+ }
+
+ if (arg_count(vg->cmd, stripes_ARG)) {
+ log_error("--stripes may only be specified when allocating the thin pool.");
+ return 0;
+ }
+
+ if (arg_count(vg->cmd, contiguous_ARG)) {
+ log_error("--contiguous may only be specified when allocating the thin pool.");
+ return 0;
+ }
+
+ if (arg_count(vg->cmd, zero_ARG)) {
+ log_error("--zero may only be specified when allocating the thin pool.");
+ return 0;
+ }
+ }
+
+ if (lp->create_thin_pool && lp->pool) {
+ if (find_lv_in_vg(vg, lp->pool)) {
+ log_error("Pool %s already exists in Volume group %s.", lp->pool, vg->name);
+ return 0;
+ }
+ } else if (lp->pool) {
+ if (!(lvl = find_lv_in_vg(vg, lp->pool))) {
+ log_error("Pool %s not found in Volume group %s.", lp->pool, vg->name);
+ return 0;
+ }
+ if (!lv_is_thin_pool(lvl->lv)) {
+ log_error("Logical volume %s is not a thin pool.", lp->pool);
+ return 0;
+ }
+ } else if (!lp->create_thin_pool) {
+ log_error("Please specify name of existing pool.");
+ return 0;
+ }
+
+ if (!lp->thin && lp->lv_name) {
+ log_error("--name may only be given when creating a new thin Logical volume or snapshot.");
+ return 0;
+ }
+
+ if (!lp->thin) {
+ if (arg_count(vg->cmd, readahead_ARG)) {
+ log_error("--readhead may only be given when creating a new thin Logical volume or snapshot.");
+ return 0;
+ }
+ if (arg_count(vg->cmd, permission_ARG)) {
+ log_error("--permission may only be given when creating a new thin Logical volume or snapshot.");
+ return 0;
+ }
+ if (arg_count(vg->cmd, persistent_ARG)) {
+ log_error("--persistent may only be given when creating a new thin Logical volume or snapshot.");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Ensure the set of thin parameters extracted from the command line is consistent.
+ */
+static int _validate_internal_thin_processing(const struct lvcreate_params *lp)
+{
+ int r = 1;
+
+ /*
+ The final state should be one of:
+ thin create_thin_pool snapshot origin pool
+ 1 1 0 0 y/n - create new pool and a thin LV in it
+ 1 0 0 0 y - create new thin LV in existing pool
+ 0 1 0 0 y/n - create new pool only
+ 1 0 1 1 y - create thin snapshot of existing thin LV
+ */
+
+ if (!lp->create_thin_pool && !lp->pool) {
+ log_error(INTERNAL_ERROR "--thinpool not identified.");
+ r = 0;
+ }
+
+ if ((lp->snapshot && !lp->origin) || (!lp->snapshot && lp->origin)) {
+ log_error(INTERNAL_ERROR "Inconsistent snapshot and origin parameters identified.");
+ r = 0;
+ }
+
+ if (lp->snapshot && (lp->create_thin_pool || !lp->thin)) {
+ log_error(INTERNAL_ERROR "Inconsistent thin and snapshot parameters identified.");
+ r = 0;
+ }
+
+ if (!lp->thin && !lp->create_thin_pool) {
+ log_error(INTERNAL_ERROR "Failed to identify what type of thin target to use.");
+ r = 0;
+ }
+
+ if (seg_is_thin_pool(lp) && lp->thin) {
+ log_error(INTERNAL_ERROR "Thin volume cannot be created with thin pool segment type.");
+ r = 0;
+ }
+
+ return r;
+}
+
int lvcreate(struct cmd_context *cmd, int argc, char **argv)
{
int r = ECMD_PROCESSED;
@@ -538,29 +1069,62 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
struct lvcreate_cmdline_params lcp;
struct volume_group *vg;
- memset(&lp, 0, sizeof(lp));
-
if (!_lvcreate_params(&lp, &lcp, cmd, argc, argv))
return EINVALID_CMD_LINE;
log_verbose("Finding volume group \"%s\"", lp.vg_name);
vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
stack;
return ECMD_FAILED;
}
+ if (lp.snapshot && lp.origin && !_determine_snapshot_type(vg, &lp)) {
+ r = ECMD_FAILED;
+ goto_out;
+ }
+
+ if (seg_is_thin(&lp) && !_check_thin_parameters(vg, &lp, &lcp)) {
+ r = ECMD_FAILED;
+ goto_out;
+ }
+
+ /*
+ * Check activation parameters to support inactive thin snapshot creation
+ * FIXME: anything else needs to be moved past _determine_snapshot_type()?
+ */
+ if (!_read_activation_params(&lp, cmd, vg)) {
+ r = ECMD_FAILED;
+ goto_out;
+ }
+
if (!_update_extents_params(vg, &lp, &lcp)) {
r = ECMD_FAILED;
goto_out;
}
+ if (seg_is_thin(&lp) && !_validate_internal_thin_processing(&lp)) {
+ r = ECMD_FAILED;
+ goto_out;
+ }
+
+ if (lp.create_thin_pool)
+ log_verbose("Making thin pool %s in VG %s using segtype %s",
+ lp.pool ? : "with generated name", lp.vg_name, lp.segtype->name);
+
+ if (lp.thin)
+ log_verbose("Making thin LV %s in pool %s in VG %s%s%s using segtype %s",
+ lp.lv_name ? : "with generated name",
+ lp.pool ? : "with generated name", lp.vg_name,
+ lp.snapshot ? " as snapshot of " : "",
+ lp.snapshot ? lp.origin : "", lp.segtype->name);
+
if (!lv_create_single(vg, &lp)) {
stack;
r = ECMD_FAILED;
}
out:
- unlock_and_free_vg(cmd, vg, lp.vg_name);
+ unlock_and_release_vg(cmd, vg, lp.vg_name);
return r;
}
diff --git a/tools/lvm.c b/tools/lvm.c
index cec9f80..425549a 100644
--- a/tools/lvm.c
+++ b/tools/lvm.c
@@ -60,7 +60,7 @@ static char *_list_args(const char *text, int state)
/* Initialise if this is a new completion attempt */
if (!state) {
char *s = rl_line_buffer;
- int j = 0;
+ int j;
match_no = 0;
com = NULL;
@@ -167,7 +167,6 @@ static void _read_history(struct cmd_context *cmd)
stifle_history(find_config_tree_int(cmd, "shell/history_size",
DEFAULT_MAX_HISTORY));
-
}
static void _write_history(void)
@@ -200,6 +199,7 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
/* EOF */
if (!input) {
+ /* readline sends prompt to stdout */
printf("\n");
break;
}
diff --git a/tools/lvm2cmd.h b/tools/lvm2cmd.h
index 66651d8..bf93787 100644
--- a/tools/lvm2cmd.h
+++ b/tools/lvm2cmd.h
@@ -52,6 +52,12 @@ void lvm2_log_fn(lvm2_log_fn_t log_fn);
void *lvm2_init(void);
/*
+ * Disable any dmeventd calls that the library may otherwise do. Useful to avoid
+ * recursive calls from dmeventd to itself.
+ */
+void lvm2_disable_dmeventd_monitoring(void *handle);
+
+/*
* Set log level (as above) if using built-in logging function.
* Default is LVM2_LOG_PRINT. Use LVM2_LOG_SUPPRESS to suppress output.
*/
diff --git a/tools/lvmcmdlib.c b/tools/lvmcmdlib.c
index 6b2bc9d..6b641c2 100644
--- a/tools/lvmcmdlib.c
+++ b/tools/lvmcmdlib.c
@@ -17,13 +17,10 @@
#include "lvm2cmdline.h"
#include "label.h"
#include "memlock.h"
-#include "lvm-version.h"
#include "lvm2cmd.h"
#include <signal.h>
-#include <syslog.h>
-#include <libgen.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/resource.h>
@@ -97,6 +94,10 @@ int lvm2_run(void *handle, const char *cmdline)
return ret;
}
+void lvm2_disable_dmeventd_monitoring(void *handle) {
+ init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
+}
+
void lvm2_log_level(void *handle, int level)
{
struct cmd_context *cmd = (struct cmd_context *) handle;
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 836dbaa..39a8c58 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -19,15 +19,14 @@
#include "lvm-version.h"
#include "stub.h"
-#include "lvm2cmd.h"
#include "last-path-component.h"
#include <signal.h>
-#include <syslog.h>
-#include <libgen.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/resource.h>
+#include <dirent.h>
+#include <paths.h>
#ifdef HAVE_GETOPTLONG
# include <getopt.h>
@@ -42,11 +41,6 @@ extern char *optarg;
# define OPTIND_INIT 1
#endif
-#ifdef UDEV_SYNC_SUPPORT
-# define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
-# include <libudev.h>
-#endif
-
/*
* Table of valid switches
*/
@@ -94,9 +88,29 @@ const char *grouped_arg_str_value(const struct arg_values *av, int a, const char
return grouped_arg_count(av, a) ? av[a].value : def;
}
+int32_t grouped_arg_int_value(const struct arg_values *av, int a, const int32_t def)
+{
+ return grouped_arg_count(av, a) ? av[a].i_value : def;
+}
+
+int32_t first_grouped_arg_int_value(struct cmd_context *cmd, int a, const int32_t def)
+{
+ struct arg_value_group_list *current_group;
+ struct arg_values *av;
+
+ dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
+ av = current_group->arg_values;
+ if (grouped_arg_count(av, a))
+ return grouped_arg_int_value(av, a, def);
+ }
+
+ return def;
+}
+
int32_t arg_int_value(struct cmd_context *cmd, int a, const int32_t def)
{
- return arg_count(cmd, a) ? cmd->arg_values[a].i_value : def;
+ return (_cmdline.arg_props[a].flags & ARG_GROUPABLE) ?
+ first_grouped_arg_int_value(cmd, a, def) : (arg_count(cmd, a) ? cmd->arg_values[a].i_value : def);
}
uint32_t arg_uint_value(struct cmd_context *cmd, int a, const uint32_t def)
@@ -157,7 +171,7 @@ int yes_no_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_value
return 1;
}
-int yes_no_excl_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
+int activation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
{
av->sign = SIGN_NONE;
av->percent = PERCENT_NONE;
@@ -173,6 +187,12 @@ int yes_no_excl_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_
av->ui_value = CHANGE_AY;
}
+ else if (!strcmp(av->value, "a") || !strcmp(av->value, "ay") ||
+ !strcmp(av->value, "ya")) {
+ av->i_value = CHANGE_AAY;
+ av->ui_value = CHANGE_AAY;
+ }
+
else if (!strcmp(av->value, "n") || !strcmp(av->value, "en") ||
!strcmp(av->value, "ne")) {
av->i_value = CHANGE_AN;
@@ -195,6 +215,19 @@ int yes_no_excl_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_
return 1;
}
+int discards_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
+{
+ thin_discards_t discards;
+
+ if (!get_pool_discards(av->value, &discards))
+ return_0;
+
+ av->i_value = discards;
+ av->ui_value = discards;
+
+ return 1;
+}
+
int metadatatype_arg(struct cmd_context *cmd, struct arg_values *av)
{
return get_format_by_name(cmd, av->value) ? 1 : 0;
@@ -279,8 +312,8 @@ static int _size_arg(struct cmd_context *cmd __attribute__((unused)), struct arg
if (i < 0) {
return 0;
} else if (i == 7) {
- /* sectors */
- v = v;
+ /* v is already in sectors */
+ ;
} else if (i == 6) {
/* bytes */
v_tmp = (uint64_t) v;
@@ -373,38 +406,6 @@ int int_arg_with_sign_and_percent(struct cmd_context *cmd __attribute__((unused)
return 1;
}
-int minor_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
-{
- char *ptr;
-
- if (!_get_int_arg(av, &ptr) || (*ptr) || (av->sign == SIGN_MINUS))
- return 0;
-
- if (av->i_value > 255) {
- log_error("Minor number outside range 0-255");
- return 0;
- }
-
- return 1;
-}
-
-int major_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
-{
- char *ptr;
-
- if (!_get_int_arg(av, &ptr) || (*ptr) || (av->sign == SIGN_MINUS))
- return 0;
-
- if (av->i_value > 255) {
- log_error("Major number outside range 0-255");
- return 0;
- }
-
- /* FIXME Also Check against /proc/devices */
-
- return 1;
-}
-
int string_arg(struct cmd_context *cmd __attribute__((unused)),
struct arg_values *av __attribute__((unused)))
{
@@ -506,6 +507,35 @@ int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
return int_arg(cmd, av);
}
+int major_minor_valid(const struct cmd_context *cmd, const struct format_type *fmt,
+ int32_t major, int32_t minor)
+{
+ if (!strncmp(cmd->kernel_vsn, "2.4.", 4) ||
+ (fmt->features & FMT_RESTRICTED_LVIDS)) {
+ if (major < 0 || major > 255) {
+ log_error("Major number outside range 0-255");
+ return 0;
+ }
+ if (minor < 0 || minor > 255) {
+ log_error("Minor number outside range 0-255");
+ return 0;
+ }
+ } else {
+ /* 12 bits for major number */
+ if (major < 0 || major > 4095) {
+ log_error("Major number outside range 0-4095");
+ return 0;
+ }
+ /* 20 bits for minor number */
+ if (minor < 0 || minor > 1048575) {
+ log_error("Minor number outside range 0-1048575");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
static void __alloc(int size)
{
if (!(_cmdline.commands = dm_realloc(_cmdline.commands, sizeof(*_cmdline.commands) * size))) {
@@ -646,7 +676,7 @@ static void _add_getopt_arg(int arg, char **ptr, struct option **o)
if (a->short_arg)
(*o)->val = a->short_arg;
else
- (*o)->val = arg;
+ (*o)->val = arg + 128;
(*o)++;
}
#endif
@@ -667,7 +697,7 @@ static int _find_arg(struct command *com, int opt)
* the_args.
*/
if ((a->short_arg && (opt == a->short_arg)) ||
- (!a->short_arg && (opt == arg)))
+ (!a->short_arg && (opt == (arg + 128))))
return arg;
}
@@ -819,6 +849,9 @@ static int _get_settings(struct cmd_context *cmd)
cmd->current_settings.verbose = 0;
}
+ if (arg_count(cmd, quiet_ARG) > 1)
+ cmd->current_settings.silent = 1;
+
if (arg_count(cmd, test_ARG))
cmd->current_settings.test = arg_count(cmd, test_ARG);
@@ -835,7 +868,7 @@ static int _get_settings(struct cmd_context *cmd)
if (arg_count(cmd, partial_ARG)) {
cmd->partial_activation = 1;
- log_print("Partial mode. Incomplete logical volumes will be processed.");
+ log_warn("PARTIAL MODE. Incomplete logical volumes will be processed.");
}
if (arg_count(cmd, ignorelockingfailure_ARG) || arg_count(cmd, sysinit_ARG))
@@ -843,6 +876,9 @@ static int _get_settings(struct cmd_context *cmd)
else
init_ignorelockingfailure(0);
+ if (!arg_count(cmd, sysinit_ARG))
+ lvmetad_warning();
+
if (arg_count(cmd, nosuffix_ARG))
cmd->current_settings.suffix = 0;
@@ -865,14 +901,17 @@ static int _get_settings(struct cmd_context *cmd)
} else
init_trust_cache(0);
- if (arg_count(cmd, noudevsync_ARG))
+ if (arg_count(cmd, noudevsync_ARG)) {
cmd->current_settings.udev_sync = 0;
+ cmd->current_settings.udev_fallback = 1;
+ }
/* Handle synonyms */
if (!_merge_synonym(cmd, resizable_ARG, resizeable_ARG) ||
!_merge_synonym(cmd, allocation_ARG, allocatable_ARG) ||
!_merge_synonym(cmd, allocation_ARG, resizeable_ARG) ||
- !_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG))
+ !_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG) ||
+ !_merge_synonym(cmd, available_ARG, activate_ARG))
return EINVALID_CMD_LINE;
if ((!strncmp(cmd->command->name, "pv", 2) &&
@@ -935,9 +974,11 @@ static void _apply_settings(struct cmd_context *cmd)
{
init_debug(cmd->current_settings.debug);
init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL);
+ init_silent(cmd->current_settings.silent);
init_test(cmd->current_settings.test);
init_full_scan_done(0);
init_mirror_in_sync(0);
+ init_dmeventd_monitor(DEFAULT_DMEVENTD_MONITOR);
init_msg_prefix(cmd->default_settings.msg_prefix);
init_cmd_name(cmd->default_settings.cmd_name);
@@ -953,47 +994,6 @@ static void _apply_settings(struct cmd_context *cmd)
cmd->handles_missing_pvs = 0;
}
-static int _set_udev_checking(struct cmd_context *cmd)
-{
-#ifdef UDEV_SYNC_SUPPORT
- struct udev *udev;
- const char *udev_dev_dir;
- size_t udev_dev_dir_len;
- int dirs_diff;
-
- if (!(udev = udev_new()) ||
- !(udev_dev_dir = udev_get_dev_path(udev)) ||
- !*udev_dev_dir) {
- log_error("Could not get udev dev path.");
- return 0;
- }
- udev_dev_dir_len = strlen(udev_dev_dir);
-
- /* There's always a slash at the end of dev_dir. But check udev_dev_dir! */
- if (udev_dev_dir[udev_dev_dir_len - 1] != '/')
- dirs_diff = strncmp(cmd->dev_dir, udev_dev_dir,
- udev_dev_dir_len);
- else
- dirs_diff = strcmp(cmd->dev_dir, udev_dev_dir);
-
- if (dirs_diff) {
- log_debug("The path %s used for creating device nodes and "
- "symlinks that is set in the configuration differs "
- "from the path %s that is used by udev. All warnings "
- "about udev not working correctly while processing "
- "particular nodes and symlinks will be suppressed. "
- "These nodes and symlinks will be managed in each "
- "directory separately.",
- cmd->dev_dir, udev_dev_dir);
- dm_udev_set_checking(0);
- init_udev_checking(0);
- }
-
- udev_unref(udev);
-#endif
- return 1;
-}
-
static const char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv)
{
int i, space;
@@ -1040,6 +1040,8 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
{
int ret = 0;
int locking_type;
+ int monitoring;
+ struct dm_config_tree *old_cft;
init_error_message_produced(0);
@@ -1064,8 +1066,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
set_cmd_name(cmd->command->name);
if (arg_count(cmd, config_ARG))
- if (override_config_tree_from_string(cmd,
- arg_str_value(cmd, config_ARG, ""))) {
+ if (override_config_tree_from_string(cmd, arg_str_value(cmd, config_ARG, ""))) {
ret = EINVALID_CMD_LINE;
goto_out;
}
@@ -1073,10 +1074,9 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
if (arg_count(cmd, config_ARG) || !cmd->config_valid || config_files_changed(cmd)) {
/* Reinitialise various settings inc. logging, filters */
if (!refresh_toolcontext(cmd)) {
- if (cmd->cft_override) {
- destroy_config_tree(cmd->cft_override);
- cmd->cft_override = NULL;
- }
+ old_cft = remove_overridden_config_tree(cmd);
+ if (old_cft)
+ dm_config_destroy(old_cft);
log_error("Updated config file invalid. Aborting.");
return ECMD_FAILED;
}
@@ -1086,17 +1086,21 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
goto_out;
_apply_settings(cmd);
+ if (!get_activation_monitoring_mode(cmd, &monitoring))
+ goto_out;
+ init_dmeventd_monitor(monitoring);
+
log_debug("Processing: %s", cmd->cmd_line);
#ifdef O_DIRECT_SUPPORT
log_debug("O_DIRECT will be used");
#endif
- if (!_set_udev_checking(cmd))
- goto_out;
-
- if ((ret = _process_common_commands(cmd)))
- goto_out;
+ if ((ret = _process_common_commands(cmd))) {
+ if (ret != ECMD_PROCESSED)
+ stack;
+ goto out;
+ }
if (cmd->metadata_read_only &&
!(cmd->command->flags & PERMITTED_READ_ONLY)) {
@@ -1125,9 +1129,8 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
lvmcache_destroy(cmd, 1);
}
- if (cmd->cft_override) {
- destroy_config_tree(cmd->cft_override);
- cmd->cft_override = NULL;
+ if ((old_cft = remove_overridden_config_tree(cmd))) {
+ dm_config_destroy(old_cft);
/* Move this? */
if (!refresh_toolcontext(cmd))
stack;
@@ -1187,6 +1190,39 @@ int lvm_split(char *str, int *argc, char **argv, int max)
return *argc;
}
+/* Make sure we have always valid filedescriptors 0,1,2 */
+static int _check_standard_fds(void)
+{
+ int err = is_valid_fd(STDERR_FILENO);
+
+ if (!is_valid_fd(STDIN_FILENO) &&
+ !(stdin = fopen(_PATH_DEVNULL, "r"))) {
+ if (err)
+ perror("stdin stream open");
+ else
+ printf("stdin stream open: %s\n",
+ strerror(errno));
+ return 0;
+ }
+
+ if (!is_valid_fd(STDOUT_FILENO) &&
+ !(stdout = fopen(_PATH_DEVNULL, "w"))) {
+ if (err)
+ perror("stdout stream open");
+ /* else no stdout */
+ return 0;
+ }
+
+ if (!is_valid_fd(STDERR_FILENO) &&
+ !(stderr = fopen(_PATH_DEVNULL, "w"))) {
+ printf("stderr stream open: %s\n",
+ strerror(errno));
+ return 0;
+ }
+
+ return 1;
+}
+
static const char *_get_cmdline(pid_t pid)
{
static char _proc_cmdline[32];
@@ -1195,7 +1231,7 @@ static const char *_get_cmdline(pid_t pid)
snprintf(buf, sizeof(buf), DEFAULT_PROC_DIR "/%u/cmdline", pid);
/* FIXME Use generic read code. */
- if ((fd = open(buf, O_RDONLY)) > 0) {
+ if ((fd = open(buf, O_RDONLY)) >= 0) {
if ((n = read(fd, _proc_cmdline, sizeof(_proc_cmdline) - 1)) < 0) {
log_sys_error("read", buf);
n = 0;
@@ -1232,7 +1268,7 @@ static void _close_descriptor(int fd, unsigned suppress_warnings,
const char *filename;
/* Ignore bad file descriptors */
- if (fcntl(fd, F_GETFD) == -1 && errno == EBADF)
+ if (!is_valid_fd(fd))
return;
if (!suppress_warnings)
@@ -1254,39 +1290,70 @@ static void _close_descriptor(int fd, unsigned suppress_warnings,
fprintf(stderr, " Parent PID %" PRIpid_t ": %s\n", ppid, parent_cmdline);
}
-static void _close_stray_fds(const char *command)
+static int _close_stray_fds(const char *command)
{
+#ifndef VALGRIND_POOL
struct rlimit rlim;
int fd;
unsigned suppress_warnings = 0;
pid_t ppid = getppid();
const char *parent_cmdline = _get_cmdline(ppid);
-
- if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
- fprintf(stderr, "getrlimit(RLIMIT_NOFILE) failed: %s\n",
- strerror(errno));
- return;
- }
+ static const char _fd_dir[] = DEFAULT_PROC_DIR "/self/fd";
+ struct dirent *dirent;
+ DIR *d;
if (getenv("LVM_SUPPRESS_FD_WARNINGS"))
suppress_warnings = 1;
- for (fd = 3; fd < rlim.rlim_cur; fd++)
- _close_descriptor(fd, suppress_warnings, command, ppid,
- parent_cmdline);
+ if (!(d = opendir(_fd_dir))) {
+ if (errno != ENOENT) {
+ log_sys_error("opendir", _fd_dir);
+ return 0; /* broken system */
+ }
+
+ /* Path does not exist, use the old way */
+ if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+ log_sys_error("getrlimit", "RLIMIT_NOFILE");
+ return 1;
+ }
+
+ for (fd = 3; fd < (int)rlim.rlim_cur; fd++)
+ _close_descriptor(fd, suppress_warnings, command, ppid,
+ parent_cmdline);
+ return 1;
+ }
+
+ while ((dirent = readdir(d))) {
+ fd = atoi(dirent->d_name);
+ if (fd > 2 && fd != dirfd(d))
+ _close_descriptor(fd, suppress_warnings,
+ command, ppid, parent_cmdline);
+ }
+
+ if (closedir(d))
+ log_sys_error("closedir", _fd_dir);
+#endif
+
+ return 1;
}
struct cmd_context *init_lvm(void)
{
struct cmd_context *cmd;
- if (!(cmd = create_toolcontext(0, NULL)))
+ if (!udev_init_library_context())
+ stack;
+
+ if (!(cmd = create_toolcontext(0, NULL, 1, 0))) {
+ udev_fin_library_context();
return_NULL;
+ }
_cmdline.arg_props = &_arg_props[0];
if (stored_errno()) {
destroy_toolcontext(cmd);
+ udev_fin_library_context();
return_NULL;
}
@@ -1311,6 +1378,7 @@ void lvm_fin(struct cmd_context *cmd)
{
_fin_commands();
destroy_toolcontext(cmd);
+ udev_fin_library_context();
}
static int _run_script(struct cmd_context *cmd, int argc, char **argv)
@@ -1421,14 +1489,21 @@ int lvm2_main(int argc, char **argv)
strcmp(base, "initrd-lvm"))
alias = 1;
- _close_stray_fds(base);
+ if (!_check_standard_fds())
+ return -1;
+
+ if (!_close_stray_fds(base))
+ return -1;
if (is_static() && strcmp(base, "lvm.static") &&
path_exists(LVM_SHARED_PATH) &&
!getenv("LVM_DID_EXEC")) {
- setenv("LVM_DID_EXEC", base, 1);
- execvp(LVM_SHARED_PATH, argv);
- unsetenv("LVM_DID_EXEC");
+ if (setenv("LVM_DID_EXEC", base, 1))
+ log_sys_error("setenv", "LVM_DID_EXEC");
+ if (execvp(LVM_SHARED_PATH, argv) == -1)
+ log_sys_error("execvp", "LVM_SHARED_PATH");
+ if (unsetenv("LVM_DID_EXEC"))
+ log_sys_error("unsetenv", "LVM_DID_EXEC");
}
/* "version" command is simple enough so it doesn't need any complex init */
diff --git a/tools/lvmdiskscan.c b/tools/lvmdiskscan.c
index 9127c15..df3f072 100644
--- a/tools/lvmdiskscan.c
+++ b/tools/lvmdiskscan.c
@@ -72,15 +72,18 @@ static int _check_device(struct cmd_context *cmd, struct device *dev)
char buffer;
uint64_t size;
- if (!dev_open(dev)) {
- return 0;
- }
+ if (!dev_open_readonly(dev))
+ return_0;
+
if (!dev_read(dev, UINT64_C(0), (size_t) 1, &buffer)) {
- dev_close(dev);
+ stack;
+ if (!dev_close(dev))
+ stack;
return 0;
}
if (!dev_get_size(dev, &size)) {
log_error("Couldn't get size of \"%s\"", dev_name(dev));
+ size = 0;
}
_print(cmd, dev, size, NULL);
_count(dev, &disks_found, &parts_found);
diff --git a/tools/lvremove.c b/tools/lvremove.c
index 0252149..54094b1 100644
--- a/tools/lvremove.c
+++ b/tools/lvremove.c
@@ -26,7 +26,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
lv = origin;
- if (!lv_remove_with_dependencies(cmd, lv, arg_count(cmd, force_ARG), 0)) {
+ if (!lv_remove_with_dependencies(cmd, lv, (force_t) arg_count(cmd, force_ARG), 0)) {
stack;
return ECMD_FAILED;
}
diff --git a/tools/lvrename.c b/tools/lvrename.c
index db47a8b..3dc21dc 100644
--- a/tools/lvrename.c
+++ b/tools/lvrename.c
@@ -104,7 +104,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
log_verbose("Checking for existing volume group \"%s\"", vg_name);
vg = vg_read_for_update(cmd, vg_name, NULL, 0);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
stack;
return ECMD_FAILED;
}
@@ -115,14 +115,29 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
goto error;
}
+ if (lvl->lv->status & (RAID_IMAGE | RAID_META)) {
+ log_error("Cannot rename a RAID %s directly",
+ (lvl->lv->status & RAID_IMAGE) ? "image" :
+ "metadata area");
+ r = ECMD_FAILED;
+ goto error;
+ }
+
+ if (lv_is_raid_with_tracking(lvl->lv)) {
+ log_error("Cannot rename %s while it is tracking a split image",
+ lvl->lv->name);
+ r = ECMD_FAILED;
+ goto error;
+ }
+
if (!lv_rename(cmd, lvl->lv, lv_name_new))
goto error;
- log_print("Renamed \"%s\" to \"%s\" in volume group \"%s\"",
- lv_name_old, lv_name_new, vg_name);
+ log_print_unless_silent("Renamed \"%s\" to \"%s\" in volume group \"%s\"",
+ lv_name_old, lv_name_new, vg_name);
r = ECMD_PROCESSED;
error:
- unlock_and_free_vg(cmd, vg, vg_name);
+ unlock_and_release_vg(cmd, vg, vg_name);
return r;
}
diff --git a/tools/lvresize.c b/tools/lvresize.c
index c970f3f..4c9580d 100644
--- a/tools/lvresize.c
+++ b/tools/lvresize.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -50,12 +50,12 @@ static int _validate_stripesize(struct cmd_context *cmd,
const struct volume_group *vg,
struct lvresize_params *lp)
{
- if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, stripesize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Stripesize may not be negative.");
return 0;
}
- if (arg_uint_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) {
+ if (arg_uint64_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) {
log_error("Stripe size cannot be larger than %s",
display_size(cmd, (uint64_t) STRIPE_SIZE_LIMIT));
return 0;
@@ -63,7 +63,7 @@ static int _validate_stripesize(struct cmd_context *cmd,
if (!(vg->fid->fmt->features & FMT_SEGMENTS))
log_warn("Varied stripesize not supported. Ignoring.");
- else if (arg_uint_value(cmd, stripesize_ARG, 0) > vg->extent_size * 2) {
+ else if (arg_uint_value(cmd, stripesize_ARG, 0) > (uint64_t) vg->extent_size * 2) {
log_error("Reducing stripe size %s to maximum, "
"physical extent size %s",
display_size(cmd,
@@ -86,9 +86,7 @@ static int _request_confirmation(struct cmd_context *cmd,
const struct logical_volume *lv,
const struct lvresize_params *lp)
{
- struct lvinfo info;
-
- memset(&info, 0, sizeof(info));
+ struct lvinfo info = { 0 };
if (!lv_info(cmd, lv, 0, &info, 1, 0) && driver_version(NULL, 0)) {
log_error("lv_info failed: aborting");
@@ -159,6 +157,9 @@ static int _fsadm_cmd(struct cmd_context *cmd,
argv[i++] = (fcmd == FSADM_CMD_RESIZE) ? "resize" : "check";
+ if (status)
+ *status = -1;
+
if (dm_snprintf(lv_path, PATH_MAX, "%s%s/%s", cmd->dev_dir, lp->vg_name,
lp->lv_name) < 0) {
log_error("Couldn't create LV path for %s", lp->lv_name);
@@ -179,7 +180,7 @@ static int _fsadm_cmd(struct cmd_context *cmd,
argv[i] = NULL;
- return exec_cmd(cmd, argv, status);
+ return exec_cmd(cmd, argv, status, 1);
}
static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
@@ -285,37 +286,93 @@ static int _adjust_policy_params(struct cmd_context *cmd,
percent_t percent;
int policy_threshold, policy_amount;
- policy_threshold =
- find_config_tree_int(cmd, "activation/snapshot_autoextend_threshold",
- DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD) * PERCENT_1;
- policy_amount =
- find_config_tree_int(cmd, "activation/snapshot_autoextend_percent",
- DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT);
+ if (lv_is_thin_pool(lv)) {
+ policy_threshold =
+ find_config_tree_int(cmd, "activation/thin_pool_autoextend_threshold",
+ DEFAULT_THIN_POOL_AUTOEXTEND_THRESHOLD) * PERCENT_1;
+ policy_amount =
+ find_config_tree_int(cmd, "activation/thin_pool_autoextend_percent",
+ DEFAULT_THIN_POOL_AUTOEXTEND_PERCENT);
+ if (!policy_amount && policy_threshold < PERCENT_100)
+ return 0;
+ } else {
+ policy_threshold =
+ find_config_tree_int(cmd, "activation/snapshot_autoextend_threshold",
+ DEFAULT_SNAPSHOT_AUTOEXTEND_THRESHOLD) * PERCENT_1;
+ policy_amount =
+ find_config_tree_int(cmd, "activation/snapshot_autoextend_percent",
+ DEFAULT_SNAPSHOT_AUTOEXTEND_PERCENT);
+ }
if (policy_threshold >= PERCENT_100)
return 1; /* nothing to do */
- if (!lv_snapshot_percent(lv, &percent))
- return_0;
+ if (lv_is_thin_pool(lv)) {
+ if (!lv_thin_pool_percent(lv, 1, &percent))
+ return_0;
+ if (percent > policy_threshold) {
+ /* FIXME: metadata resize support missing */
+ log_error("Resize for %s/%s is not yet supported.",
+ lp->vg_name, lp->lv_name);
+ return ECMD_FAILED;
+ }
- if (!(PERCENT_0 < percent && percent < PERCENT_100) || percent <= policy_threshold)
- return 1; /* nothing to do */
+ if (!lv_thin_pool_percent(lv, 0, &percent))
+ return_0;
+ if (!(PERCENT_0 < percent && percent <= PERCENT_100) ||
+ percent <= policy_threshold)
+ return 1; /* nothing to do */
+ } else {
+ if (!lv_snapshot_percent(lv, &percent))
+ return_0;
+ if (!(PERCENT_0 < percent && percent < PERCENT_100) || percent <= policy_threshold)
+ return 1; /* nothing to do */
+ }
lp->extents = policy_amount;
+
return 1;
}
+static uint32_t lvseg_get_stripes(struct lv_segment *seg, uint32_t *stripesize)
+{
+ uint32_t s;
+ struct lv_segment *seg_mirr;
+
+ /* If segment mirrored, check if images are striped */
+ if (seg_is_mirrored(seg))
+ for (s = 0; s < seg->area_count; s++) {
+ if (seg_type(seg, s) != AREA_LV)
+ continue;
+ seg_mirr = first_seg(seg_lv(seg, s));
+
+ if (seg_is_striped(seg_mirr)) {
+ seg = seg_mirr;
+ break;
+ }
+ }
+
+
+ if (seg_is_striped(seg)) {
+ *stripesize = seg->stripe_size;
+ return seg->area_count;
+ }
+
+ *stripesize = 0;
+ return 0;
+}
+
static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
struct lvresize_params *lp)
{
struct logical_volume *lv;
struct lvinfo info;
- uint32_t stripesize_extents = 0;
- uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
+ uint32_t stripesize_extents;
+ uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size;
uint32_t seg_mirrors = 0;
- uint32_t extents_used = 0;
+ uint32_t extents_used;
uint32_t size_rest;
- uint32_t pv_extent_count = 0;
+ uint32_t pv_extent_count;
alloc_policy_t alloc;
struct logical_volume *lock_lv;
struct lv_list *lvl;
@@ -333,6 +390,19 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return ECMD_FAILED;
}
+ if (lvl->lv->status & (RAID_IMAGE | RAID_META)) {
+ log_error("Cannot resize a RAID %s directly",
+ (lvl->lv->status & RAID_IMAGE) ? "image" :
+ "metadata area");
+ return ECMD_FAILED;
+ }
+
+ if (lv_is_raid_with_tracking(lvl->lv)) {
+ log_error("Cannot resize %s while it is tracking a split image",
+ lvl->lv->name);
+ return ECMD_FAILED;
+ }
+
if (arg_count(cmd, stripes_ARG)) {
if (vg->fid->fmt->features & FMT_SEGMENTS)
lp->stripes = arg_uint_value(cmd, stripes_ARG, 1);
@@ -345,7 +415,7 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 1) + 1;
else
log_warn("Mirrors not supported. Ignoring.");
- if (arg_sign_value(cmd, mirrors_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, mirrors_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Mirrors argument may not be negative");
return EINVALID_CMD_LINE;
}
@@ -358,11 +428,13 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
lv = lvl->lv;
if (use_policy) {
- if (!lv_is_cow(lv)) {
- log_error("Can't use policy-based resize for non-snapshot volumes.");
+ if (!lv_is_cow(lv) &&
+ !lv_is_thin_pool(lv)) {
+ log_error("Policy-based resize is supported only for snapshot and thin pool volumes.");
return ECMD_FAILED;
}
- _adjust_policy_params(cmd, lv, lp);
+ if (!_adjust_policy_params(cmd, lv, lp))
+ return ECMD_FAILED;
}
if (!lv_is_visible(lv)) {
@@ -380,8 +452,14 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return ECMD_FAILED;
}
- alloc = arg_uint_value(cmd, alloc_ARG, lv->alloc);
+ alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lv->alloc);
+ /*
+ * First adjust to an exact multiple of extent size.
+ * When extending by a relative amount we round that amount up.
+ * When reducing by a relative amount we remove at most that amount.
+ * When changing to an absolute size, we round that size up.
+ */
if (lp->size) {
if (lp->size % vg->extent_size) {
if (lp->sign == SIGN_MINUS)
@@ -390,8 +468,8 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
lp->size += vg->extent_size -
(lp->size % vg->extent_size);
- log_print("Rounding up size to full physical extent %s",
- display_size(cmd, (uint64_t) lp->size));
+ log_print_unless_silent("Rounding size to boundary between physical extents: %s",
+ display_size(cmd, lp->size));
}
lp->extents = lp->size / vg->extent_size;
@@ -405,34 +483,46 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
switch(lp->percent) {
case PERCENT_VG:
- lp->extents = lp->extents * vg->extent_count / 100;
+ lp->extents = percent_of_extents(lp->extents, vg->extent_count,
+ (lp->sign != SIGN_MINUS));
break;
case PERCENT_FREE:
- lp->extents = lp->extents * vg->free_count / 100;
+ lp->extents = percent_of_extents(lp->extents, vg->free_count,
+ (lp->sign != SIGN_MINUS));
break;
case PERCENT_LV:
- lp->extents = lp->extents * lv->le_count / 100;
+ lp->extents = percent_of_extents(lp->extents, lv->le_count,
+ (lp->sign != SIGN_MINUS));
break;
case PERCENT_PVS:
if (lp->argc) {
pv_extent_count = pv_list_extents_free(pvh);
- lp->extents = lp->extents * pv_extent_count / 100;
+ lp->extents = percent_of_extents(lp->extents, pv_extent_count,
+ (lp->sign != SIGN_MINUS));
} else
- lp->extents = lp->extents * vg->extent_count / 100;
+ lp->extents = percent_of_extents(lp->extents, vg->extent_count,
+ (lp->sign != SIGN_MINUS));
break;
case PERCENT_ORIGIN:
if (!lv_is_cow(lv)) {
log_error("Specified LV does not have an origin LV.");
return EINVALID_CMD_LINE;
}
- lp->extents = lp->extents * origin_from_cow(lv)->le_count / 100;
+ lp->extents = percent_of_extents(lp->extents, origin_from_cow(lv)->le_count,
+ (lp->sign != SIGN_MINUS));
break;
case PERCENT_NONE:
break;
}
- if (lp->sign == SIGN_PLUS)
+ if (lp->sign == SIGN_PLUS) {
+ if (lp->extents >= (MAX_EXTENT_COUNT - lv->le_count)) {
+ log_error("Unable to extend %s by %u extents, exceeds limit (%u).",
+ lp->lv_name, lv->le_count, MAX_EXTENT_COUNT);
+ return EINVALID_CMD_LINE;
+ }
lp->extents += lv->le_count;
+ }
if (lp->sign == SIGN_MINUS) {
if (lp->extents >= lv->le_count) {
@@ -476,6 +566,13 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
/* If extending, find mirrors of last segment */
if ((lp->extents > lv->le_count)) {
+ /*
+ * Has the user specified that they would like the additional
+ * extents of a mirror not to have an initial sync?
+ */
+ if (seg_is_mirrored(first_seg(lv)) && arg_count(cmd, nosync_ARG))
+ lv->status |= LV_NOTSYNCED;
+
dm_list_iterate_back_items(mirr_seg, &lv->segments) {
if (seg_is_mirrored(mirr_seg))
seg_mirrors = lv_mirror_count(mirr_seg->lv);
@@ -483,9 +580,10 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
seg_mirrors = 0;
break;
}
+
if (!arg_count(cmd, mirrors_ARG) && seg_mirrors) {
- log_print("Extending %" PRIu32 " mirror images.",
- seg_mirrors);
+ log_print_unless_silent("Extending %" PRIu32 " mirror images.",
+ seg_mirrors);
lp->mirrors = seg_mirrors;
}
if ((arg_count(cmd, mirrors_ARG) || seg_mirrors) &&
@@ -493,18 +591,30 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
log_error("Cannot vary number of mirrors in LV yet.");
return EINVALID_CMD_LINE;
}
+
+ if (seg_mirrors && !strcmp(mirr_seg->segtype->name, "raid10")) {
+ lp->stripes = mirr_seg->area_count / seg_mirrors;
+ lp->stripe_size = mirr_seg->stripe_size;
+ }
}
/* If extending, find stripes, stripesize & size of last segment */
if ((lp->extents > lv->le_count) &&
- !(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size))) {
+ !(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size)) &&
+ strcmp(mirr_seg->segtype->name, "raid10")) {
/* FIXME Don't assume mirror seg will always be AREA_LV */
- dm_list_iterate_items(seg, seg_mirrors ? &seg_lv(mirr_seg, 0)->segments : &lv->segments) {
- if (!seg_is_striped(seg))
+ /* FIXME We will need to support resize for metadata LV as well,
+ * and data LV could be any type (i.e. mirror)) */
+ dm_list_iterate_items(seg, seg_mirrors ? &seg_lv(mirr_seg, 0)->segments :
+ lv_is_thin_pool(lv) ? &seg_lv(first_seg(lv), 0)->segments : &lv->segments) {
+ /* Allow through "striped" and RAID 4/5/6/10 */
+ if (!seg_is_striped(seg) &&
+ (!seg_is_raid(seg) || seg_is_mirrored(seg)) &&
+ strcmp(seg->segtype->name, "raid10"))
continue;
sz = seg->stripe_size;
- str = seg->area_count;
+ str = seg->area_count - lp->segtype->parity_devs;
if ((seg_stripesize && seg_stripesize != sz &&
sz && !lp->stripe_size) ||
@@ -520,19 +630,24 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
if (!lp->stripes)
lp->stripes = seg_stripes;
+ else if (seg_is_raid(first_seg(lv)) &&
+ (lp->stripes != seg_stripes)) {
+ log_error("Unable to extend \"%s\" segment type with different number of stripes.", first_seg(lv)->segtype->ops->name(first_seg(lv)));
+ return ECMD_FAILED;
+ }
if (!lp->stripe_size && lp->stripes > 1) {
if (seg_stripesize) {
- log_print("Using stripesize of last segment %s",
- display_size(cmd, (uint64_t) seg_stripesize));
+ log_print_unless_silent("Using stripesize of last segment %s",
+ display_size(cmd, (uint64_t) seg_stripesize));
lp->stripe_size = seg_stripesize;
} else {
lp->stripe_size =
find_config_tree_int(cmd,
"metadata/stripesize",
DEFAULT_STRIPESIZE) * 2;
- log_print("Using default stripesize %s",
- display_size(cmd, (uint64_t) lp->stripe_size));
+ log_print_unless_silent("Using default stripesize %s",
+ display_size(cmd, (uint64_t) lp->stripe_size));
}
}
}
@@ -548,10 +663,8 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
dm_list_iterate_items(seg, &lv->segments) {
seg_extents = seg->len;
- if (seg_is_striped(seg)) {
- seg_stripesize = seg->stripe_size;
- seg_stripes = seg->area_count;
- }
+ /* Check for underlying stripe sizes */
+ seg_stripes = lvseg_get_stripes(seg, &seg_stripesize);
if (seg_is_mirrored(seg))
seg_mirrors = lv_mirror_count(seg->lv);
@@ -575,22 +688,35 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return EINVALID_CMD_LINE;
}
- if ((lp->stripes > 1)) {
- if (!(stripesize_extents = lp->stripe_size / vg->extent_size))
- stripesize_extents = 1;
-
- if ((size_rest = seg_size % (lp->stripes * stripesize_extents))) {
- log_print("Rounding size (%d extents) down to stripe "
- "boundary size for segment (%d extents)",
- lp->extents, lp->extents - size_rest);
- lp->extents = lp->extents - size_rest;
- }
-
+ if (lp->stripes > 1) {
if (lp->stripe_size < STRIPE_SIZE_MIN) {
log_error("Invalid stripe size %s",
display_size(cmd, (uint64_t) lp->stripe_size));
return EINVALID_CMD_LINE;
}
+
+ if (!(stripesize_extents = lp->stripe_size / vg->extent_size))
+ stripesize_extents = 1;
+
+ size_rest = seg_size % (lp->stripes * stripesize_extents);
+ /* Round toward the original size. */
+ if (size_rest &&
+ ((lp->extents < lv->le_count) ||
+ !lp->percent ||
+ (vg->free_count >= (lp->extents - lv->le_count - size_rest +
+ (lp->stripes * stripesize_extents))))) {
+ log_print_unless_silent("Rounding size (%d extents) up to stripe "
+ "boundary size for segment (%d extents)",
+ lp->extents, lp->extents - size_rest +
+ (lp->stripes * stripesize_extents));
+ lp->extents = lp->extents - size_rest +
+ (lp->stripes * stripesize_extents);
+ } else if (size_rest) {
+ log_print_unless_silent("Rounding size (%d extents) down to stripe "
+ "boundary size for segment (%d extents)",
+ lp->extents, lp->extents - size_rest);
+ lp->extents = lp->extents - size_rest;
+ }
}
if (lp->extents < lv->le_count) {
@@ -609,6 +735,15 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return EINVALID_CMD_LINE;
}
lp->resize = LV_EXTEND;
+ } else if (lp->extents == lv->le_count) {
+ if (use_policy)
+ return ECMD_PROCESSED; /* Nothing to do. */
+ if (!lp->resizefs) {
+ log_error("New size (%d extents) matches existing size "
+ "(%d extents)", lp->extents, lv->le_count);
+ return EINVALID_CMD_LINE;
+ }
+ lp->resize = LV_EXTEND;
}
if (lv_is_origin(lv)) {
@@ -618,8 +753,6 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return ECMD_FAILED;
}
- memset(&info, 0, sizeof(info));
-
if (lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) {
log_error("Snapshot origin volumes can be resized "
"only while inactive: try lvchange -an");
@@ -627,6 +760,18 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
}
}
+ if (lv_is_thin_pool(lv)) {
+ if (lp->resize == LV_REDUCE) {
+ log_error("Thin pool volumes cannot be reduced in size yet.");
+ return ECMD_FAILED;
+ }
+
+ if (lp->resizefs) {
+ log_warn("Thin pool volumes do not have filesystem.");
+ lp->resizefs = 0;
+ }
+ }
+
if ((lp->resize == LV_REDUCE) && lp->argc)
log_warn("Ignoring PVs on command line when reducing");
@@ -641,15 +786,15 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
if (!lp->nofsck &&
!_fsadm_cmd(cmd, vg, lp, FSADM_CMD_CHECK, &status)) {
if (status != FSADM_CHECK_FAILS_FOR_MOUNTED) {
- stack;
+ log_error("Filesystem check failed.");
return ECMD_FAILED;
}
- /* some filesystems supports online resize */
+ /* some filesystems supports online resize */
}
if ((lp->resize == LV_REDUCE) &&
!_fsadm_cmd(cmd, vg, lp, FSADM_CMD_RESIZE, NULL)) {
- stack;
+ log_error("Filesystem resize failed.");
return ECMD_FAILED;
}
}
@@ -659,10 +804,10 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return ECMD_FAILED;
}
- log_print("%sing logical volume %s to %s",
- (lp->resize == LV_REDUCE) ? "Reduc" : "Extend",
- lp->lv_name,
- display_size(cmd, (uint64_t) lp->extents * vg->extent_size));
+ log_print_unless_silent("%sing logical volume %s to %s",
+ (lp->resize == LV_REDUCE) ? "Reduc" : "Extend",
+ lp->lv_name,
+ display_size(cmd, (uint64_t) lp->extents * vg->extent_size));
if (lp->resize == LV_REDUCE) {
if (!lv_reduce(lv, lv->le_count - lp->extents)) {
@@ -670,10 +815,11 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return ECMD_FAILED;
}
} else if ((lp->extents > lv->le_count) && /* Ensure we extend */
- !lv_extend(lv, lp->segtype, lp->stripes,
- lp->stripe_size, lp->mirrors,
- lp->extents - lv->le_count,
- NULL, 0u, 0u, pvh, alloc)) {
+ !lv_extend(lv, lp->segtype,
+ lp->stripes, lp->stripe_size,
+ lp->mirrors, first_seg(lv)->region_size,
+ lp->extents - lv->le_count, NULL,
+ pvh, alloc)) {
stack;
return ECMD_FAILED;
}
@@ -713,7 +859,21 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
backup(vg);
- log_print("Logical volume %s successfully resized", lp->lv_name);
+ /*
+ * Update lvm pool metadata (drop messages) if the pool has been
+ * resumed and do a pool active/deactivate in other case.
+ *
+ * Note: Active thin pool can be waiting for resize.
+ *
+ * FIXME: Activate only when thin volume is active
+ */
+ if (lv_is_thin_pool(lv) &&
+ !update_pool_lv(lv, !lv_is_active(lv))) {
+ stack;
+ return ECMD_FAILED;
+ }
+
+ log_print_unless_silent("Logical volume %s successfully resized", lp->lv_name);
if (lp->resizefs && (lp->resize == LV_EXTEND) &&
!_fsadm_cmd(cmd, vg, lp, FSADM_CMD_RESIZE, NULL)) {
@@ -726,19 +886,17 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
int lvresize(struct cmd_context *cmd, int argc, char **argv)
{
- struct lvresize_params lp;
+ struct lvresize_params lp = { 0 };
struct volume_group *vg;
int r;
- memset(&lp, 0, sizeof(lp));
-
if (!_lvresize_params(cmd, argc, argv, &lp))
return EINVALID_CMD_LINE;
log_verbose("Finding volume group %s", lp.vg_name);
vg = vg_read_for_update(cmd, lp.vg_name, NULL, 0);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
stack;
return ECMD_FAILED;
}
@@ -746,7 +904,7 @@ int lvresize(struct cmd_context *cmd, int argc, char **argv)
if (!(r = _lvresize(cmd, vg, &lp)))
stack;
- unlock_and_free_vg(cmd, vg, lp.vg_name);
+ unlock_and_release_vg(cmd, vg, lp.vg_name);
return r;
}
diff --git a/tools/lvscan.c b/tools/lvscan.c
index 638d2f5..636ac45 100644
--- a/tools/lvscan.c
+++ b/tools/lvscan.c
@@ -19,8 +19,6 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle __attribute__((unused)))
{
struct lvinfo info;
- int lv_total = 0;
- uint64_t lv_capacity_total = 0;
int inkernel, snap_active = 1;
struct lv_segment *snap_seg = NULL;
percent_t snap_percent; /* fused, fsize; */
@@ -30,7 +28,7 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
return ECMD_PROCESSED;
- inkernel = lv_info(cmd, lv, 0, &info, 1, 0) && info.exists;
+ inkernel = lv_info(cmd, lv, 0, &info, 0, 0) && info.exists;
if (lv_is_origin(lv)) {
dm_list_iterate_items_gen(snap_seg, &lv->snapshot_segs,
origin_list) {
@@ -61,14 +59,10 @@ static int lvscan_single(struct cmd_context *cmd, struct logical_volume *lv,
else
snapshot_str = " ";
- log_print("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str,
- cmd->dev_dir, lv->vg->name, lv->name,
- display_size(cmd, lv->size),
- get_alloc_string(lv->alloc));
-
- lv_total++;
-
- lv_capacity_total += lv->size;
+ log_print_unless_silent("%s%s '%s%s/%s' [%s] %s", active_str, snapshot_str,
+ cmd->dev_dir, lv->vg->name, lv->name,
+ display_size(cmd, lv->size),
+ get_alloc_string(lv->alloc));
return ECMD_PROCESSED;
}
diff --git a/tools/polldaemon.c b/tools/polldaemon.c
index 50579ba..a9138a1 100644
--- a/tools/polldaemon.c
+++ b/tools/polldaemon.c
@@ -32,6 +32,8 @@ static void _sigchld_handler(int sig __attribute__((unused)))
*/
static int _become_daemon(struct cmd_context *cmd)
{
+ static const char devnull[] = "/dev/null";
+ int null_fd;
pid_t pid;
struct sigaction act = {
{_sigchld_handler},
@@ -42,6 +44,8 @@ static int _become_daemon(struct cmd_context *cmd)
sigaction(SIGCHLD, &act, NULL);
+ sync_local_dev_names(cmd); /* Flush ops and reset dm cookie */
+
if ((pid = fork()) == -1) {
log_error("fork failed: %s", strerror(errno));
return -1;
@@ -55,16 +59,33 @@ static int _become_daemon(struct cmd_context *cmd)
if (setsid() == -1)
log_error("Background process failed to setsid: %s",
strerror(errno));
- init_verbose(VERBOSE_BASE_LEVEL);
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
+ /* For poll debugging it's best to disable for compilation */
+#if 1
+ if ((null_fd = open(devnull, O_RDWR)) == -1) {
+ log_sys_error("open", devnull);
+ _exit(ECMD_FAILED);
+ }
+
+ if ((dup2(null_fd, STDIN_FILENO) < 0) || /* reopen stdin */
+ (dup2(null_fd, STDOUT_FILENO) < 0) || /* reopen stdout */
+ (dup2(null_fd, STDERR_FILENO) < 0)) { /* reopen stderr */
+ log_sys_error("dup2", "redirect");
+ (void) close(null_fd);
+ _exit(ECMD_FAILED);
+ }
+
+ if (null_fd > STDERR_FILENO)
+ (void) close(null_fd);
+ init_verbose(VERBOSE_BASE_LEVEL);
+#endif
strncpy(*cmd->argv, "(lvm2)", strlen(*cmd->argv));
reset_locking();
- lvmcache_init();
+ if (!lvmcache_init())
+ /* FIXME Clean up properly here */
+ _exit(ECMD_FAILED);
dev_close_all();
return 1;
@@ -87,8 +108,8 @@ progress_t poll_mirror_progress(struct cmd_context *cmd,
overall_percent = copy_percent(lv);
if (parms->progress_display)
- log_print("%s: %s: %.1f%%", name, parms->progress_title,
- percent_to_float(overall_percent));
+ log_print_unless_silent("%s: %s: %.1f%%", name, parms->progress_title,
+ percent_to_float(overall_percent));
else
log_verbose("%s: %s: %.1f%%", name, parms->progress_title,
percent_to_float(overall_percent));
@@ -144,7 +165,7 @@ static int _check_lv_status(struct cmd_context *cmd,
/* Finished? Or progress to next segment? */
if (progress == PROGRESS_FINISHED_ALL) {
if (!parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed))
- return 0;
+ return_0;
} else {
if (parms->poll_fns->update_metadata &&
!parms->poll_fns->update_metadata(cmd, vg, lv, lvs_changed, 0)) {
@@ -183,26 +204,34 @@ static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const
/* Locks the (possibly renamed) VG again */
vg = parms->poll_fns->get_copy_vg(cmd, name, uuid);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
log_error("ABORTING: Can't reread VG for %s", name);
/* What more could we do here? */
return 0;
}
- if (!(lv = parms->poll_fns->get_copy_lv(cmd, vg, name, uuid,
- parms->lv_type))) {
+ lv = parms->poll_fns->get_copy_lv(cmd, vg, name, uuid, parms->lv_type);
+
+ if (!lv && parms->lv_type == PVMOVE) {
+ log_print_unless_silent("%s: no pvmove in progress - already finished or aborted.",
+ name);
+ unlock_and_release_vg(cmd, vg, vg->name);
+ return 1;
+ }
+
+ if (!lv) {
log_error("ABORTING: Can't find LV in %s for %s",
vg->name, name);
- unlock_and_free_vg(cmd, vg, vg->name);
+ unlock_and_release_vg(cmd, vg, vg->name);
return 0;
}
if (!_check_lv_status(cmd, vg, lv, name, parms, &finished)) {
- unlock_and_free_vg(cmd, vg, vg->name);
- return 0;
+ unlock_and_release_vg(cmd, vg, vg->name);
+ return_0;
}
- unlock_and_free_vg(cmd, vg, vg->name);
+ unlock_and_release_vg(cmd, vg, vg->name);
/*
* FIXME Sleeping after testing, while preferred, also works around
@@ -232,6 +261,11 @@ static int _poll_vg(struct cmd_context *cmd, const char *vgname,
const char *name;
int finished;
+ if (!parms) {
+ log_error(INTERNAL_ERROR "Handle is undefined.");
+ return ECMD_FAILED;
+ }
+
dm_list_iterate_items(lvl, &vg->lvs) {
lv = lvl->lv;
if (!(lv->status & parms->lv_type))
@@ -271,7 +305,7 @@ static void _poll_for_all_vgs(struct cmd_context *cmd,
*/
int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
unsigned background,
- uint32_t lv_type, struct poll_functions *poll_fns,
+ uint64_t lv_type, struct poll_functions *poll_fns,
const char *progress_title)
{
struct daemon_parms parms;
@@ -281,7 +315,7 @@ int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
parms.aborting = arg_is_set(cmd, abort_ARG);
parms.background = background;
- interval_sign = arg_sign_value(cmd, interval_ARG, 0);
+ interval_sign = arg_sign_value(cmd, interval_ARG, SIGN_NONE);
if (interval_sign == SIGN_MINUS)
log_error("Argument to --interval cannot be negative");
parms.interval = arg_uint_value(cmd, interval_ARG,
diff --git a/tools/polldaemon.h b/tools/polldaemon.h
index 8ebbb25..78ea783 100644
--- a/tools/polldaemon.h
+++ b/tools/polldaemon.h
@@ -36,7 +36,7 @@ struct poll_functions {
struct volume_group *vg,
const char *name,
const char *uuid,
- uint32_t lv_type);
+ uint64_t lv_type);
progress_t (*poll_progress)(struct cmd_context *cmd,
struct logical_volume *lv,
const char *name,
@@ -59,13 +59,13 @@ struct daemon_parms {
unsigned outstanding_count;
unsigned progress_display;
const char *progress_title;
- uint32_t lv_type;
+ uint64_t lv_type;
struct poll_functions *poll_fns;
};
int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
unsigned background,
- uint32_t lv_type, struct poll_functions *poll_fns,
+ uint64_t lv_type, struct poll_functions *poll_fns,
const char *progress_title);
progress_t poll_mirror_progress(struct cmd_context *cmd,
diff --git a/tools/pvchange.c b/tools/pvchange.c
index 28e71b8..70f1e62 100644
--- a/tools/pvchange.c
+++ b/tools/pvchange.c
@@ -15,8 +15,6 @@
#include "tools.h"
-/* FIXME Locking. PVs in VG. */
-
static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv,
void *handle __attribute__((unused)))
@@ -27,21 +25,14 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
uint64_t orig_pe_start;
const char *pv_name = pv_dev_name(pv);
- const char *tag = NULL;
const char *orig_vg_name;
char uuid[64] __attribute__((aligned(8)));
int allocatable = 0;
- int tagarg = 0;
- int r = 0;
+ int tagargs = 0;
int mda_ignore = 0;
- struct arg_value_group_list *current_group;
-
- if (arg_count(cmd, addtag_ARG))
- tagarg = addtag_ARG;
- else if (arg_count(cmd, deltag_ARG))
- tagarg = deltag_ARG;
+ tagargs = arg_count(cmd, addtag_ARG) + arg_count(cmd, deltag_ARG);
if (arg_count(cmd, allocatable_ARG))
allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"),
@@ -52,20 +43,20 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
/* If in a VG, must change using volume group. */
if (!is_orphan(pv)) {
- if (tagarg && !(vg->fid->fmt->features & FMT_TAGS)) {
+ if (tagargs && !(vg->fid->fmt->features & FMT_TAGS)) {
log_error("Volume group containing %s does not "
"support tags", pv_name);
- goto out;
+ return 0;
}
if (arg_count(cmd, uuid_ARG) && lvs_in_vg_activated(vg)) {
log_error("Volume group containing %s has active "
"logical volumes", pv_name);
- goto out;
+ return 0;
}
if (!archive(vg))
- goto out;
+ return 0;
} else {
- if (tagarg) {
+ if (tagargs) {
log_error("Can't change tag on Physical Volume %s not "
"in volume group", pv_name);
return 0;
@@ -77,22 +68,20 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
!(pv->fmt->features & FMT_ORPHAN_ALLOCATABLE)) {
log_error("Allocatability not supported by orphan "
"%s format PV %s", pv->fmt->name, pv_name);
- goto out;
+ return 0;
}
/* change allocatability for a PV */
if (allocatable && (pv_status(pv) & ALLOCATABLE_PV)) {
log_error("Physical volume \"%s\" is already "
"allocatable", pv_name);
- r = 1;
- goto out;
+ return 1;
}
if (!allocatable && !(pv_status(pv) & ALLOCATABLE_PV)) {
log_error("Physical volume \"%s\" is already "
"unallocatable", pv_name);
- r = 1;
- goto out;
+ return 1;
}
if (allocatable) {
@@ -104,50 +93,41 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
"allocatable", pv_name);
pv->status &= ~ALLOCATABLE_PV;
}
- } else if (tagarg) {
- /* tag or deltag */
+ }
- dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
- if (!grouped_arg_is_set(current_group->arg_values, tagarg))
- continue;
+ if (tagargs) {
+ /* tag or deltag */
+ if (arg_count(cmd, addtag_ARG) && !change_tag(cmd, NULL, NULL, pv, addtag_ARG))
+ return_0;
- if (!(tag = grouped_arg_str_value(current_group->arg_values, tagarg, NULL))) {
- log_error("Failed to get tag");
- goto out;
- }
+ if (arg_count(cmd, deltag_ARG) && !change_tag(cmd, NULL, NULL, pv, deltag_ARG))
+ return_0;
+
+ }
- if ((tagarg == addtag_ARG)) {
- if (!str_list_add(cmd->mem, &pv->tags, tag)) {
- log_error("Failed to add tag %s to physical "
- "volume %s", tag, pv_name);
- goto out;
- }
- } else if (!str_list_del(&pv->tags, tag)) {
- log_error("Failed to remove tag %s from "
- "physical volume" "%s", tag, pv_name);
- goto out;
- }
- }
- } else if (arg_count(cmd, metadataignore_ARG)) {
+ if (arg_count(cmd, metadataignore_ARG)) {
if ((vg_mda_copies(vg) != VGMETADATACOPIES_UNMANAGED) &&
(arg_count(cmd, force_ARG) == PROMPT) &&
yes_no_prompt("Override preferred number of copies "
"of VG %s metadata? [y/n]: ",
pv_vg_name(pv)) == 'n') {
log_error("Physical volume %s not changed", pv_name);
- goto out;
+ return 0;
}
if (!pv_change_metadataignore(pv, mda_ignore))
- goto out;
- } else {
+ return_0;
+ }
+
+ if (arg_count(cmd, uuid_ARG)) {
/* --uuid: Change PV ID randomly */
+ memcpy(&pv->old_id, &pv->id, sizeof(pv->id));
if (!id_create(&pv->id)) {
log_error("Failed to generate new random UUID for %s.",
pv_name);
- goto out;
+ return 0;
}
if (!id_write_format(&pv->id, uuid, sizeof(uuid)))
- goto_out;
+ return 0;
log_verbose("Changing uuid of %s to %s.", pv_name, uuid);
if (!is_orphan(pv)) {
orig_vg_name = pv_vg_name(pv);
@@ -160,10 +140,10 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
pv->vg_name = pv->fmt->orphan_vg_name;
pv->pe_alloc_count = 0;
- if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
+ if (!(pv_write(cmd, pv, 0))) {
log_error("pv_write with new uuid failed "
"for %s.", pv_name);
- goto out;
+ return 0;
}
pv->vg_name = orig_vg_name;
pv->pe_alloc_count = orig_pe_alloc_count;
@@ -179,20 +159,18 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg,
if (!vg_write(vg) || !vg_commit(vg)) {
log_error("Failed to store physical volume \"%s\" in "
"volume group \"%s\"", pv_name, vg->name);
- goto out;
+ return 0;
}
backup(vg);
- } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
+ } else if (!(pv_write(cmd, pv, 0))) {
log_error("Failed to store physical volume \"%s\"",
pv_name);
- goto out;
+ return 0;
}
- log_print("Physical volume \"%s\" changed", pv_name);
- r = 1;
-out:
- return r;
+ log_print_unless_silent("Physical volume \"%s\" changed", pv_name);
+ return 1;
}
int pvchange(struct cmd_context *cmd, int argc, char **argv)
@@ -209,11 +187,11 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
struct dm_list *vgnames;
struct str_list *sll;
- if (arg_count(cmd, allocatable_ARG) + arg_is_set(cmd, addtag_ARG) +
+ if (!(arg_count(cmd, allocatable_ARG) + arg_is_set(cmd, addtag_ARG) +
arg_is_set(cmd, deltag_ARG) + arg_count(cmd, uuid_ARG) +
- arg_count(cmd, metadataignore_ARG) != 1) {
- log_error("Please give exactly one option of -x, -uuid, "
- "--addtag or --deltag");
+ arg_count(cmd, metadataignore_ARG))) {
+ log_error("Please give one or more of -x, -uuid, "
+ "--addtag, --deltag or --metadataignore");
return EINVALID_CMD_LINE;
}
@@ -231,7 +209,7 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
log_verbose("Using physical volume(s) on command line");
for (; opt < argc; opt++) {
pv_name = argv[opt];
- unescape_colons_and_at_signs(pv_name, NULL, NULL);
+ dm_unescape_colons_and_at_signs(pv_name, NULL, NULL);
vg_name = find_vgname_from_pvname(cmd, pv_name);
if (!vg_name) {
log_error("Failed to read physical volume %s",
@@ -240,7 +218,7 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
}
vg = vg_read_for_update(cmd, vg_name, NULL, 0);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
stack;
continue;
}
@@ -254,7 +232,7 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
total++;
done += _pvchange_single(cmd, vg,
pvl->pv, NULL);
- unlock_and_free_vg(cmd, vg, vg_name);
+ unlock_and_release_vg(cmd, vg, vg_name);
}
} else {
log_verbose("Scanning for physical volume names");
@@ -275,7 +253,7 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
dm_list_iterate_items(sll, vgnames) {
vg = vg_read_for_update(cmd, sll->str, NULL, 0);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
stack;
continue;
}
@@ -285,16 +263,16 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv)
pvl->pv,
NULL);
}
- unlock_and_free_vg(cmd, vg, sll->str);
+ unlock_and_release_vg(cmd, vg, sll->str);
}
}
+ unlock_vg(cmd, VG_GLOBAL);
}
- unlock_vg(cmd, VG_GLOBAL);
- log_print("%d physical volume%s changed / %d physical volume%s "
- "not changed",
- done, done == 1 ? "" : "s",
- total - done, (total - done) == 1 ? "" : "s");
+ log_print_unless_silent("%d physical volume%s changed / %d physical volume%s "
+ "not changed",
+ done, done == 1 ? "" : "s",
+ total - done, (total - done) == 1 ? "" : "s");
return (total == done) ? ECMD_PROCESSED : ECMD_FAILED;
}
diff --git a/tools/pvck.c b/tools/pvck.c
index 2ec7597..e45e77a 100644
--- a/tools/pvck.c
+++ b/tools/pvck.c
@@ -31,7 +31,7 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
/* FIXME: warning and/or check if in use? */
log_verbose("Scanning %s", argv[i]);
- unescape_colons_and_at_signs(argv[i], NULL, NULL);
+ dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
pv_analyze(cmd, argv[i],
arg_uint64_value(cmd, labelsector_ARG,
UINT64_C(0)));
diff --git a/tools/pvcreate.c b/tools/pvcreate.c
index a955d37..5c12acb 100644
--- a/tools/pvcreate.c
+++ b/tools/pvcreate.c
@@ -56,6 +56,7 @@ static int pvcreate_restore_params_validate(struct cmd_context *cmd,
if (!id_read_format(&pp->id, uuid))
return 0;
pp->idp = &pp->id;
+ lvmcache_seed_infos_from_lvmetad(cmd); /* need to check for UUID dups */
}
if (arg_count(cmd, restorefile_ARG)) {
@@ -74,10 +75,10 @@ static int pvcreate_restore_params_validate(struct cmd_context *cmd,
pp->pe_start = pv_pe_start(existing_pvl->pv);
pp->extent_size = pv_pe_size(existing_pvl->pv);
pp->extent_count = pv_pe_count(existing_pvl->pv);
- free_vg(vg);
+ release_vg(vg);
}
- if (arg_sign_value(cmd, physicalvolumesize_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, physicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Physical volume size may not be negative");
return 0;
}
@@ -93,6 +94,7 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
int i;
int ret = ECMD_PROCESSED;
struct pvcreate_params pp;
+ struct physical_volume *pv;
pvcreate_params_set_defaults(&pp);
@@ -109,9 +111,9 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- unescape_colons_and_at_signs(argv[i], NULL, NULL);
+ dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
- if (!pvcreate_single(cmd, argv[i], &pp)) {
+ if (!(pv = pvcreate_single(cmd, argv[i], &pp, 1))) {
stack;
ret = ECMD_FAILED;
}
diff --git a/tools/pvdisplay.c b/tools/pvdisplay.c
index 1ae0339..c6cd412 100644
--- a/tools/pvdisplay.c
+++ b/tools/pvdisplay.c
@@ -32,7 +32,7 @@ static int _pvdisplay_single(struct cmd_context *cmd,
vg = vg_read(cmd, vg_name, (char *)&pv->vgid, 0);
if (vg_read_error(vg)) {
log_error("Skipping volume group %s", vg_name);
- free_vg(vg);
+ release_vg(vg);
/* FIXME If CLUSTERED should return ECMD_PROCESSED here */
return ECMD_FAILED;
}
@@ -54,7 +54,7 @@ static int _pvdisplay_single(struct cmd_context *cmd,
if (is_orphan(pv))
size = pv_size(pv);
else
- size = (pv_pe_count(pv) - pv_pe_alloc_count(pv)) *
+ size = (uint64_t)(pv_pe_count(pv) - pv_pe_alloc_count(pv)) *
pv_pe_size(pv);
if (arg_count(cmd, short_ARG)) {
@@ -85,7 +85,7 @@ out:
if (vg_name)
unlock_vg(cmd, vg_name);
if (!old_vg)
- free_vg(vg);
+ release_vg(vg);
return ret;
}
diff --git a/tools/pvmove.c b/tools/pvmove.c
index 51f442f..9649f11 100644
--- a/tools/pvmove.c
+++ b/tools/pvmove.c
@@ -18,6 +18,7 @@
#include "display.h"
#define PVMOVE_FIRST_TIME 0x00000001 /* Called for first time */
+#define PVMOVE_EXCLUSIVE 0x00000002 /* Require exclusive LV */
static int _pvmove_target_present(struct cmd_context *cmd, int clustered)
{
@@ -121,7 +122,7 @@ static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
}
/* Remove PV if full */
- if ((pvl->pv->pe_count == pvl->pv->pe_alloc_count))
+ if (pvl->pv->pe_count == pvl->pv->pe_alloc_count)
dm_list_del(&pvl->list);
}
@@ -174,13 +175,16 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
const char *lv_name,
struct dm_list *allocatable_pvs,
alloc_policy_t alloc,
- struct dm_list **lvs_changed)
+ struct dm_list **lvs_changed,
+ unsigned *exclusive)
{
struct logical_volume *lv_mirr, *lv;
struct lv_list *lvl;
uint32_t log_count = 0;
int lv_found = 0;
int lv_skipped = 0;
+ int lv_active_count = 0;
+ int lv_exclusive_count = 0;
/* FIXME Cope with non-contiguous => splitting existing segments */
if (!(lv_mirr = lv_create_empty("pvmove%d", NULL,
@@ -202,7 +206,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
/* Find segments to be moved and set up mirrors */
dm_list_iterate_items(lvl, &vg->lvs) {
lv = lvl->lv;
- if ((lv == lv_mirr))
+ if (lv == lv_mirr)
continue;
if (lv_name) {
if (strcmp(lv->name, lv_name))
@@ -211,29 +215,45 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
}
if (lv_is_origin(lv) || lv_is_cow(lv)) {
lv_skipped = 1;
- log_print("Skipping snapshot-related LV %s", lv->name);
+ log_print_unless_silent("Skipping snapshot-related LV %s", lv->name);
continue;
}
if (lv->status & MIRRORED) {
lv_skipped = 1;
- log_print("Skipping mirror LV %s", lv->name);
+ log_print_unless_silent("Skipping mirror LV %s", lv->name);
continue;
}
if (lv->status & MIRROR_LOG) {
lv_skipped = 1;
- log_print("Skipping mirror log LV %s", lv->name);
+ log_print_unless_silent("Skipping mirror log LV %s", lv->name);
continue;
}
if (lv->status & MIRROR_IMAGE) {
lv_skipped = 1;
- log_print("Skipping mirror image LV %s", lv->name);
+ log_print_unless_silent("Skipping mirror image LV %s", lv->name);
continue;
}
if (lv->status & LOCKED) {
lv_skipped = 1;
- log_print("Skipping locked LV %s", lv->name);
+ log_print_unless_silent("Skipping locked LV %s", lv->name);
continue;
}
+
+ if (vg_is_clustered(vg) &&
+ lv_is_active_exclusive_remotely(lv)) {
+ lv_skipped = 1;
+ log_print_unless_silent("Skipping LV %s which is activated "
+ "exclusively on remote node.", lv->name);
+ continue;
+ }
+
+ if (vg_is_clustered(vg)) {
+ if (lv_is_active_exclusive_locally(lv))
+ lv_exclusive_count++;
+ else if (lv_is_active(lv))
+ lv_active_count++;
+ }
+
if (!_insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
*lvs_changed))
return_NULL;
@@ -254,6 +274,25 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
return NULL;
}
+ if (vg_is_clustered(vg) && lv_active_count && *exclusive) {
+ log_error("Cannot move in clustered VG %s, "
+ "clustered mirror (cmirror) not detected "
+ "and LVs are activated non-exclusively.",
+ vg->name);
+ return NULL;
+ }
+
+ if (vg_is_clustered(vg) && lv_exclusive_count) {
+ if (lv_active_count) {
+ log_error("Cannot move in clustered VG %s "
+ "if some LVs are activated "
+ "exclusively while others don't.",
+ vg->name);
+ return NULL;
+ }
+ *exclusive = 1;
+ }
+
if (!lv_add_mirrors(cmd, lv_mirr, 1, 1, 0, 0, log_count,
allocatable_pvs, alloc, MIRROR_BY_SEG)) {
log_error("Failed to convert pvmove LV to mirrored");
@@ -273,7 +312,7 @@ static int _activate_lv(struct cmd_context *cmd, struct logical_volume *lv_mirr,
{
int r = 0;
- if (exclusive)
+ if (exclusive || lv_is_active_exclusive(lv_mirr))
r = activate_lv_excl(cmd, lv_mirr);
else
r = activate_lv(cmd, lv_mirr);
@@ -305,11 +344,60 @@ static int _detach_pvmove_mirror(struct cmd_context *cmd,
return 1;
}
+static int _suspend_lvs(struct cmd_context *cmd, unsigned first_time,
+ struct logical_volume *lv_mirr,
+ struct dm_list *lvs_changed,
+ struct volume_group *vg_to_revert)
+{
+ /*
+ * Suspend lvs_changed the first time.
+ * Suspend mirrors on subsequent calls.
+ */
+ if (first_time) {
+ if (!suspend_lvs(cmd, lvs_changed, vg_to_revert))
+ return_0;
+ } else if (!suspend_lv(cmd, lv_mirr)) {
+ if (vg_to_revert)
+ vg_revert(vg_to_revert);
+ return_0;
+ }
+
+ return 1;
+}
+
+static int _resume_lvs(struct cmd_context *cmd, unsigned first_time,
+ struct logical_volume *lv_mirr,
+ struct dm_list *lvs_changed)
+{
+ /*
+ * Suspend lvs_changed the first time.
+ * Suspend mirrors on subsequent calls.
+ */
+
+ if (first_time) {
+ if (!resume_lvs(cmd, lvs_changed)) {
+ log_error("Unable to resume logical volumes");
+ return 0;
+ }
+ } else if (!resume_lv(cmd, lv_mirr)) {
+ log_error("Unable to reactivate logical volume \"%s\"",
+ lv_mirr->name);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Called to set up initial pvmove LV and to advance the mirror
+ * to successive sections of it.
+ * (Not called after the last section completes.)
+ */
static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
struct logical_volume *lv_mirr,
struct dm_list *lvs_changed, unsigned flags)
{
- unsigned exclusive = _pvmove_is_exclusive(cmd, vg);
+ unsigned exclusive = (flags & PVMOVE_EXCLUSIVE) ? 1 : 0;
unsigned first_time = (flags & PVMOVE_FIRST_TIME) ? 1 : 0;
int r = 0;
@@ -319,38 +407,31 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
return 0;
}
- /* Suspend lvs_changed */
- if (!suspend_lvs(cmd, lvs_changed)) {
- vg_revert(vg);
- goto_out;
- }
-
- /* Suspend mirrors on subsequent calls */
- if (!first_time) {
- if (!suspend_lv(cmd, lv_mirr)) {
- if (!resume_lvs(cmd, lvs_changed))
- stack;
- vg_revert(vg);
- goto_out;
- }
+ if (!_suspend_lvs(cmd, first_time, lv_mirr, lvs_changed, vg)) {
+ log_error("ABORTING: Temporary pvmove mirror %s failed.", first_time ? "activation" : "reload");
+ /* FIXME Add a recovery path for first time too. */
+ if (!first_time && !revert_lv(cmd, lv_mirr))
+ stack;
+ return 0;
}
/* Commit on-disk metadata */
if (!vg_commit(vg)) {
log_error("ABORTING: Volume group metadata update failed.");
- if (!first_time)
- if (!resume_lv(cmd, lv_mirr))
- stack;
- if (!resume_lvs(cmd, lvs_changed))
+ if (!_resume_lvs(cmd, first_time, lv_mirr, lvs_changed))
+ stack;
+ if (!first_time && !revert_lv(cmd, lv_mirr))
stack;
- vg_revert(vg);
- goto out;
+ return 0;
}
/* Activate the temporary mirror LV */
/* Only the first mirror segment gets activated as a mirror */
/* FIXME: Add option to use a log */
if (first_time) {
+ if (!exclusive && _pvmove_is_exclusive(cmd, vg))
+ exclusive = 1;
+
if (!_activate_lv(cmd, lv_mirr, exclusive)) {
if (test_mode()) {
r = 1;
@@ -358,46 +439,22 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
}
/*
- * FIXME: review ordering of operations above,
- * temporary mirror should be preloaded in suspend.
- * Also banned operation here when suspended.
- * Nothing changed yet, try to revert pvmove.
+ * FIXME Run --abort internally here.
*/
- log_error("Temporary pvmove mirror activation failed.");
-
- /* Ensure that temporary mrror is deactivate even on other nodes. */
- (void)deactivate_lv(cmd, lv_mirr);
-
- /* Revert metadata */
- if (!_detach_pvmove_mirror(cmd, lv_mirr) ||
- !lv_remove(lv_mirr) ||
- !vg_write(vg) || !vg_commit(vg))
- log_error("ABORTING: Restoring original configuration "
- "before pvmove failed. Run pvmove --abort.");
-
- /* Unsuspend LVs */
- if(!resume_lvs(cmd, lvs_changed))
- stack;
-
- goto out;
+ log_error("ABORTING: Temporary pvmove mirror activation failed. Run pvmove --abort.");
+ goto_out;
}
- } else if (!resume_lv(cmd, lv_mirr)) {
- log_error("Unable to reactivate logical volume \"%s\"",
- lv_mirr->name);
- if (!resume_lvs(cmd, lvs_changed))
- stack;
- goto out;
- }
-
- /* Unsuspend LVs */
- if (!resume_lvs(cmd, lvs_changed)) {
- log_error("Unable to resume logical volumes");
- goto out;
}
r = 1;
+
out:
- backup(vg);
+ if (!_resume_lvs(cmd, first_time, lv_mirr, lvs_changed))
+ r = 0;
+
+ if (r)
+ backup(vg);
+
return r;
}
@@ -413,7 +470,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
struct dm_list *lvs_changed;
struct physical_volume *pv;
struct logical_volume *lv_mirr;
- unsigned first_time = 1;
+ unsigned flags = PVMOVE_FIRST_TIME;
unsigned exclusive;
int r = ECMD_FAILED;
@@ -431,11 +488,13 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
if (!(lv_name = _extract_lvname(cmd, pv_vg_name(pv),
arg_value(cmd, name_ARG)))) {
stack;
+ free_pv_fid(pv);
return EINVALID_CMD_LINE;
}
if (!validate_name(lv_name)) {
log_error("Logical volume name %s is invalid", lv_name);
+ free_pv_fid(pv);
return EINVALID_CMD_LINE;
}
}
@@ -445,7 +504,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
vg = _get_vg(cmd, pv_vg_name(pv));
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
stack;
return ECMD_FAILED;
}
@@ -453,7 +512,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
exclusive = _pvmove_is_exclusive(cmd, vg);
if ((lv_mirr = find_pvmove_lv(vg, pv_dev(pv), PVMOVE))) {
- log_print("Detected pvmove in progress for %s", pv_name);
+ log_print_unless_silent("Detected pvmove in progress for %s", pv_name);
if (argc || lv_name)
log_error("Ignoring remaining command line arguments");
@@ -468,14 +527,14 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
goto out;
}
- first_time = 0;
+ flags &= ~PVMOVE_FIRST_TIME;
} else {
/* Determine PE ranges to be moved */
if (!(source_pvl = create_pv_list(cmd->mem, vg, 1,
&pv_name_arg, 0)))
goto_out;
- alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
+ alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
if (alloc == ALLOC_INHERIT)
alloc = vg->alloc;
@@ -489,7 +548,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, source_pvl, lv_name,
allocatable_pvs, alloc,
- &lvs_changed)))
+ &lvs_changed, &exclusive)))
goto_out;
}
@@ -501,16 +560,19 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
/* init_pvmove(1); */
/* vg->status |= PVMOVE; */
- if (first_time) {
+ if (flags & PVMOVE_FIRST_TIME) {
+ if (exclusive)
+ flags |= PVMOVE_EXCLUSIVE;
if (!_update_metadata
- (cmd, vg, lv_mirr, lvs_changed, PVMOVE_FIRST_TIME))
+ (cmd, vg, lv_mirr, lvs_changed, flags))
goto_out;
}
/* LVs are all in status LOCKED */
r = ECMD_PROCESSED;
out:
- unlock_and_free_vg(cmd, vg, pv_vg_name(pv));
+ free_pv_fid(pv);
+ unlock_and_release_vg(cmd, vg, pv_vg_name(pv));
return r;
}
@@ -521,7 +583,8 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
int r = 1;
if (!dm_list_empty(lvs_changed) &&
- !_detach_pvmove_mirror(cmd, lv_mirr)) {
+ (!_detach_pvmove_mirror(cmd, lv_mirr) ||
+ !replace_lv_with_error_segment(lv_mirr))) {
log_error("ABORTING: Removal of temporary mirror failed");
return 0;
}
@@ -533,26 +596,21 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
return 0;
}
- /* Suspend LVs changed */
- if (!suspend_lvs(cmd, lvs_changed)) {
- log_error("Locking LVs to remove temporary mirror failed");
- r = 0;
- }
-
- /* Suspend mirror LV to flush pending I/O */
- if (!suspend_lv(cmd, lv_mirr)) {
- log_error("Suspension of temporary mirror LV failed");
- r = 0;
+ /* Suspend LVs changed (implicitly suspends lv_mirr) */
+ if (!suspend_lvs(cmd, lvs_changed, vg)) {
+ log_error("ABORTING: Locking LVs to remove temporary mirror failed");
+ if (!revert_lv(cmd, lv_mirr))
+ stack;
+ return 0;
}
/* Store metadata without dependencies on mirror segments */
if (!vg_commit(vg)) {
log_error("ABORTING: Failed to write new data locations "
"to disk.");
- vg_revert(vg);
- if (!resume_lv(cmd, lv_mirr))
+ if (!revert_lv(cmd, lv_mirr))
stack;
- if (!resume_lvs(cmd, lvs_changed))
+ if (!revert_lvs(cmd, lvs_changed))
stack;
return 0;
}
@@ -600,6 +658,7 @@ static struct volume_group *_get_move_vg(struct cmd_context *cmd,
const char *uuid __attribute__((unused)))
{
struct physical_volume *pv;
+ struct volume_group *vg;
/* Reread all metadata in case it got changed */
if (!(pv = find_pv_by_name(cmd, name))) {
@@ -608,7 +667,10 @@ static struct volume_group *_get_move_vg(struct cmd_context *cmd,
return NULL;
}
- return _get_vg(cmd, pv_vg_name(pv));
+ vg = _get_vg(cmd, pv_vg_name(pv));
+ free_pv_fid(pv);
+
+ return vg;
}
static struct poll_functions _pvmove_fns = {
@@ -649,7 +711,7 @@ int pvmove(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- unescape_colons_and_at_signs(pv_name, &colon, NULL);
+ dm_unescape_colons_and_at_signs(pv_name, &colon, NULL);
/* Drop any PE lists from PV name */
if (colon)
diff --git a/tools/pvremove.c b/tools/pvremove.c
index a8717e0..823c069 100644
--- a/tools/pvremove.c
+++ b/tools/pvremove.c
@@ -25,15 +25,12 @@ const char _really_wipe[] =
static int pvremove_check(struct cmd_context *cmd, const char *name)
{
struct physical_volume *pv;
- struct dm_list mdas;
-
- dm_list_init(&mdas);
/* FIXME Check partition type is LVM unless --force is given */
/* Is there a pv here already? */
/* If not, this is an error unless you used -f. */
- if (!(pv = pv_read(cmd, name, &mdas, NULL, 1, 0))) {
+ if (!(pv = pv_read(cmd, name, 1, 0))) {
if (arg_count(cmd, force_ARG))
return 1;
log_error("Physical Volume %s not found", name);
@@ -47,35 +44,39 @@ static int pvremove_check(struct cmd_context *cmd, const char *name)
* means checking every VG by scanning every
* PV on the system.
*/
- if (is_orphan(pv) && !dm_list_size(&mdas)) {
+ if (is_orphan(pv) && !dm_list_size(&pv->fid->metadata_areas_in_use) &&
+ !dm_list_size(&pv->fid->metadata_areas_ignored)) {
if (!scan_vgs_for_pvs(cmd, 0)) {
log_error("Rescan for PVs without metadata areas "
"failed.");
- return 0;
+ goto bad;
}
- if (!(pv = pv_read(cmd, name, NULL, NULL, 1, 0))) {
+ free_pv_fid(pv);
+ if (!(pv = pv_read(cmd, name, 1, 0))) {
log_error("Failed to read physical volume %s", name);
- return 0;
+ goto bad;
}
}
/* orphan ? */
- if (is_orphan(pv))
+ if (is_orphan(pv)) {
+ free_pv_fid(pv);
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(pv));
- return 0;
+ log_error("PV %s belongs to Volume Group %s so please use vgreduce first.", name, pv_vg_name(pv));
+ log_error("(If you are certain you need pvremove, then confirm by using --force twice.)");
+ goto bad;
}
/* prompt */
if (!arg_count(cmd, yes_ARG) &&
yes_no_prompt(_really_wipe, name, pv_vg_name(pv)) == 'n') {
log_error("%s: physical volume label not removed", name);
- return 0;
+ goto bad;
}
if (arg_count(cmd, force_ARG)) {
@@ -86,7 +87,12 @@ static int pvremove_check(struct cmd_context *cmd, const char *name)
!is_orphan(pv) ? "\"" : "");
}
+ free_pv_fid(pv);
return 1;
+
+bad:
+ free_pv_fid(pv);
+ return 0;
}
static int pvremove_single(struct cmd_context *cmd, const char *pv_name,
@@ -101,33 +107,36 @@ static int pvremove_single(struct cmd_context *cmd, const char *pv_name,
}
if (!pvremove_check(cmd, pv_name))
- goto error;
+ goto out;
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
log_error("%s: Couldn't find device. Check your filters?",
pv_name);
- goto error;
+ goto out;
}
if (!dev_test_excl(dev)) {
/* FIXME Detect whether device-mapper is still using the device */
log_error("Can't open %s exclusively - not removing. "
"Mounted filesystem?", dev_name(dev));
- goto error;
+ goto out;
}
/* Wipe existing label(s) */
if (!label_remove(dev)) {
log_error("Failed to wipe existing label(s) on %s", pv_name);
- goto error;
+ goto out;
}
- log_print("Labels on physical volume \"%s\" successfully wiped",
- pv_name);
+ if (!lvmetad_pv_gone_by_dev(dev, NULL))
+ goto_out;
+
+ log_print_unless_silent("Labels on physical volume \"%s\" successfully wiped",
+ pv_name);
ret = ECMD_PROCESSED;
- error:
+out:
unlock_vg(cmd, VG_ORPHANS);
return ret;
@@ -144,7 +153,7 @@ int pvremove(struct cmd_context *cmd, int argc, char **argv)
}
for (i = 0; i < argc; i++) {
- unescape_colons_and_at_signs(argv[i], NULL, NULL);
+ dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
r = pvremove_single(cmd, argv[i], NULL);
if (r > ret)
ret = r;
diff --git a/tools/pvresize.c b/tools/pvresize.c
index 8582ef4..2f0693a 100644
--- a/tools/pvresize.c
+++ b/tools/pvresize.c
@@ -15,6 +15,7 @@
*/
#include "tools.h"
+#include "metadata.h"
struct pvresize_params {
uint64_t new_size;
@@ -30,16 +31,11 @@ static int _pv_resize_single(struct cmd_context *cmd,
{
struct pv_list *pvl;
uint64_t size = 0;
- uint32_t new_pe_count = 0;
int r = 0;
- struct dm_list mdas;
const char *pv_name = pv_dev_name(pv);
const char *vg_name = pv_vg_name(pv);
- struct lvmcache_info *info;
- int mda_count = 0;
struct volume_group *old_vg = vg;
-
- dm_list_init(&mdas);
+ int vg_needs_pv_write = 0;
if (is_orphan_vg(vg_name)) {
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
@@ -47,18 +43,16 @@ static int _pv_resize_single(struct cmd_context *cmd,
return 0;
}
- if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) {
+ if (!(pv = pv_read(cmd, pv_name, 1, 0))) {
unlock_vg(cmd, vg_name);
log_error("Unable to read PV \"%s\"", pv_name);
return 0;
}
-
- mda_count = dm_list_size(&mdas);
} else {
vg = vg_read_for_update(cmd, vg_name, NULL, 0);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
log_error("Unable to read volume group \"%s\".",
vg_name);
return 0;
@@ -72,24 +66,10 @@ static int _pv_resize_single(struct cmd_context *cmd,
pv = pvl->pv;
- if (!(info = info_from_pvid(pv->dev->pvid, 0))) {
- log_error("Can't get info for PV %s in volume group %s",
- pv_name, vg->name);
- goto out;
- }
-
- mda_count = dm_list_size(&info->mdas);
-
if (!archive(vg))
goto out;
}
- /* FIXME Create function to test compatibility properly */
- if (mda_count > 1) {
- log_error("%s: too many metadata areas for pvresize", pv_name);
- goto out;
- }
-
if (!(pv->fmt->features & FMT_RESIZE_PV)) {
log_error("Physical volume %s format does not support resizing.",
pv_name);
@@ -111,40 +91,24 @@ static int _pv_resize_single(struct cmd_context *cmd,
size = new_size;
}
- if (size < PV_MIN_SIZE) {
- log_error("%s: Size must exceed minimum of %ld sectors.",
- pv_name, PV_MIN_SIZE);
- goto out;
- }
-
- if (size < pv_pe_start(pv)) {
- log_error("%s: Size must exceed physical extent start of "
- "%" PRIu64 " sectors.", pv_name, pv_pe_start(pv));
- goto out;
- }
-
- pv->size = size;
+ log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
+ pv_name, pv_size(pv));
- if (vg) {
- pv->size -= pv_pe_start(pv);
- new_pe_count = pv_size(pv) / vg->extent_size;
+ if (!pv_resize(pv, vg, size))
+ goto_out;
- if (!new_pe_count) {
- log_error("%s: Size must leave space for at "
- "least one physical extent of "
- "%" PRIu32 " sectors.", pv_name,
- pv_pe_size(pv));
- goto out;
- }
+ log_verbose("Updating physical volume \"%s\"", pv_name);
- if (!pv_resize(pv, vg, new_pe_count))
- goto_out;
+ /* Write PV label only if this an orphan PV or it has 2nd mda. */
+ if ((is_orphan_vg(vg_name) ||
+ (vg_needs_pv_write = (fid_get_mda_indexed(vg->fid,
+ (const char *) &pv->id, ID_LEN, 1) != NULL))) &&
+ !pv_write(cmd, pv, 1)) {
+ log_error("Failed to store physical volume \"%s\"",
+ pv_name);
+ goto out;
}
- log_verbose("Resizing volume \"%s\" to %" PRIu64 " sectors.",
- pv_name, pv_size(pv));
-
- log_verbose("Updating physical volume \"%s\"", pv_name);
if (!is_orphan_vg(vg_name)) {
if (!vg_write(vg) || !vg_commit(vg)) {
log_error("Failed to store physical volume \"%s\" in "
@@ -152,19 +116,20 @@ static int _pv_resize_single(struct cmd_context *cmd,
goto out;
}
backup(vg);
- } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
- log_error("Failed to store physical volume \"%s\"",
- pv_name);
- goto out;
}
- log_print("Physical volume \"%s\" changed", pv_name);
+ log_print_unless_silent("Physical volume \"%s\" changed", pv_name);
r = 1;
out:
+ if (!r && vg_needs_pv_write)
+ log_error("Use pvcreate and vgcfgrestore "
+ "to repair from archived metadata.");
unlock_vg(cmd, vg_name);
+ if (is_orphan_vg(vg_name))
+ free_pv_fid(pv);
if (!old_vg)
- free_vg(vg);
+ release_vg(vg);
return r;
}
@@ -197,7 +162,7 @@ int pvresize(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
- if (arg_sign_value(cmd, physicalvolumesize_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, physicalvolumesize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Physical volume size may not be negative");
return 0;
}
@@ -211,8 +176,8 @@ int pvresize(struct cmd_context *cmd, int argc, char **argv)
ret = process_each_pv(cmd, argc, argv, NULL, READ_FOR_UPDATE, 0, &params,
_pvresize_single);
- log_print("%d physical volume(s) resized / %d physical volume(s) "
- "not resized", params.done, params.total - params.done);
+ log_print_unless_silent("%d physical volume(s) resized / %d physical volume(s) "
+ "not resized", params.done, params.total - params.done);
return ret;
}
diff --git a/tools/pvscan.c b/tools/pvscan.c
index b24b7ab..3d5ddef 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -15,6 +15,9 @@
#include "tools.h"
+#include "lvmetad.h"
+#include "lvmcache.h"
+
int pv_max_name_len = 0;
int vg_max_name_len = 0;
@@ -25,13 +28,13 @@ static void _pvscan_display_single(struct cmd_context *cmd,
char uuid[64] __attribute__((aligned(8)));
unsigned vg_name_len = 0;
- char pv_tmp_name[NAME_LEN] = { 0, };
- char vg_tmp_name[NAME_LEN] = { 0, };
- char vg_name_this[NAME_LEN] = { 0, };
+ 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", pv_dev_name(pv));
+ log_print_unless_silent("%s", pv_dev_name(pv));
return;
}
@@ -46,8 +49,6 @@ static void _pvscan_display_single(struct cmd_context *cmd,
/* return; */
}
- memset(pv_tmp_name, 0, sizeof(pv_tmp_name));
-
vg_name_len = strlen(pv_vg_name(pv)) + 1;
if (arg_count(cmd, uuid_ARG)) {
@@ -63,41 +64,156 @@ static void _pvscan_display_single(struct cmd_context *cmd,
}
if (is_orphan(pv)) {
- log_print("PV %-*s %-*s %s [%s]",
- pv_max_name_len, pv_tmp_name,
- vg_max_name_len, " ",
- pv->fmt ? pv->fmt->name : " ",
- display_size(cmd, pv_size(pv)));
+ log_print_unless_silent("PV %-*s %-*s %s [%s]",
+ pv_max_name_len, pv_tmp_name,
+ vg_max_name_len, " ",
+ pv->fmt ? pv->fmt->name : " ",
+ display_size(cmd, pv_size(pv)));
return;
}
if (pv_status(pv) & EXPORTED_VG) {
strncpy(vg_name_this, pv_vg_name(pv), 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,
- display_size(cmd, (uint64_t) pv_pe_count(pv) *
- pv_pe_size(pv)),
- display_size(cmd, (uint64_t) (pv_pe_count(pv) -
- pv_pe_alloc_count(pv))
- * pv_pe_size(pv)));
+ log_print_unless_silent("PV %-*s is in exported VG %s "
+ "[%s / %s free]",
+ pv_max_name_len, pv_tmp_name,
+ vg_name_this,
+ display_size(cmd, (uint64_t) pv_pe_count(pv) * pv_pe_size(pv)),
+ display_size(cmd, (uint64_t) (pv_pe_count(pv) - pv_pe_alloc_count(pv)) * pv_pe_size(pv)));
return;
}
sprintf(vg_tmp_name, "%s", pv_vg_name(pv));
- 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 : " ",
- display_size(cmd, (uint64_t) pv_pe_count(pv) *
- pv_pe_size(pv)),
- display_size(cmd, (uint64_t) (pv_pe_count(pv) -
- pv_pe_alloc_count(pv)) *
- pv_pe_size(pv)));
+ log_print_unless_silent("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 : " ",
+ display_size(cmd, (uint64_t) pv_pe_count(pv) * pv_pe_size(pv)),
+ display_size(cmd, (uint64_t) (pv_pe_count(pv) - pv_pe_alloc_count(pv)) * pv_pe_size(pv)));
+}
+
+static int _auto_activation_handler(struct volume_group *vg, int partial,
+ activation_change_t activate)
+{
+ /* TODO: add support for partial and clustered VGs */
+ if (partial || vg_is_clustered(vg))
+ return 1;
+
+ if (!vgchange_activate(vg->cmd, vg, activate)) {
+ log_error("%s: autoactivation failed.", vg->name);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
+{
+ int ret = ECMD_PROCESSED;
+ struct device *dev;
+ const char *pv_name;
+ int32_t major = -1;
+ int32_t minor = -1;
+ int devno_args = 0;
+ struct arg_value_group_list *current_group;
+ dev_t devno;
+ char *buf;
+ activation_handler handler = NULL;
+
+ if (arg_count(cmd, activate_ARG)) {
+ if (arg_uint_value(cmd, activate_ARG, CHANGE_AAY) != CHANGE_AAY) {
+ log_error("Only --activate ay allowed with pvscan.");
+ return 0;
+ }
+ handler = _auto_activation_handler;
+ }
+
+ if (arg_count(cmd, major_ARG) + arg_count(cmd, minor_ARG))
+ devno_args = 1;
+
+ if (devno_args && (!arg_count(cmd, major_ARG) || !arg_count(cmd, minor_ARG))) {
+ log_error("Both --major and --minor required to identify devices.");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_READ)) {
+ log_error("Unable to obtain global lock.");
+ return ECMD_FAILED;
+ }
+
+ /* Scan everything? */
+ if (!argc && !devno_args) {
+ if (!lvmetad_pvscan_all_devs(cmd, handler))
+ ret = ECMD_FAILED;
+ goto out;
+ }
+
+ log_verbose("Using physical volume(s) on command line");
+
+ /* Process any command line PVs first. */
+ while (argc--) {
+ pv_name = *argv++;
+ dev = dev_cache_get(pv_name, NULL);
+ if (!dev) {
+ log_error("Physical Volume %s not found.", pv_name);
+ ret = ECMD_FAILED;
+ continue;
+ }
+
+ if (!lvmetad_pvscan_single(cmd, dev, handler)) {
+ ret = ECMD_FAILED;
+ break;
+ }
+ if (sigint_caught())
+ break;
+ }
+
+ if (!devno_args)
+ goto out;
+
+ /* Process any grouped --major --minor args */
+ dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
+ major = grouped_arg_int_value(current_group->arg_values, major_ARG, major);
+ minor = grouped_arg_int_value(current_group->arg_values, minor_ARG, minor);
+
+ if (major < 0 || minor < 0)
+ continue;
+
+ devno = MKDEV((dev_t)major, minor);
+
+ if (!(dev = dev_cache_get_by_devt(devno, NULL))) {
+ if (!dm_asprintf(&buf, "%" PRIi32 ":%" PRIi32, major, minor))
+ stack;
+ /* FIXME Filters? */
+ if (!lvmetad_pv_gone(devno, buf ? : "", handler)) {
+ ret = ECMD_FAILED;
+ if (buf)
+ dm_free(buf);
+ break;
+ }
+
+ log_print_unless_silent("Device %s not found. "
+ "Cleared from lvmetad cache.", buf ? : "");
+ if (buf)
+ dm_free(buf);
+ continue;
+ }
+
+ if (!lvmetad_pvscan_single(cmd, dev, handler)) {
+ ret = ECMD_FAILED;
+ break;
+ }
+
+ if (sigint_caught())
+ break;
+ }
+
+out:
+ unlock_vg(cmd, VG_GLOBAL);
+
+ return ret;
}
-int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
- char **argv __attribute__((unused)))
+int pvscan(struct cmd_context *cmd, int argc, char **argv)
{
int new_pvs_found = 0;
int pvs_found = 0;
@@ -113,6 +229,19 @@ int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
pv_max_name_len = 0;
vg_max_name_len = 0;
+ if (arg_count(cmd, cache_ARG))
+ return _pvscan_lvmetad(cmd, argc, argv);
+
+ if (arg_count(cmd, activate_ARG)) {
+ log_error("--activate is only valid with --cache.");
+ return EINVALID_CMD_LINE;
+ }
+
+ if (arg_count(cmd, major_ARG) + arg_count(cmd, minor_ARG)) {
+ log_error("--major and --minor are only valid with --cache.");
+ return EINVALID_CMD_LINE;
+ }
+
if (arg_count(cmd, novolumegroup_ARG) && arg_count(cmd, exported_ARG)) {
log_error("Options -e and -n are incompatible");
return EINVALID_CMD_LINE;
@@ -128,9 +257,14 @@ int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
return ECMD_FAILED;
}
- persistent_filter_wipe(cmd->filter);
+ if (cmd->filter->wipe)
+ cmd->filter->wipe(cmd->filter);
lvmcache_destroy(cmd, 1);
+ /* populate lvmcache */
+ if (!lvmetad_vg_list_to_lvmcache(cmd))
+ stack;
+
log_verbose("Walking through all physical volumes");
if (!(pvslist = get_pvs(cmd))) {
unlock_vg(cmd, VG_GLOBAL);
@@ -143,9 +277,10 @@ int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
pv = pvl->pv;
if ((arg_count(cmd, exported_ARG)
- && !(pv_status(pv) & EXPORTED_VG))
- || (arg_count(cmd, novolumegroup_ARG) && (!is_orphan(pv)))) {
+ && !(pv_status(pv) & EXPORTED_VG)) ||
+ (arg_count(cmd, novolumegroup_ARG) && (!is_orphan(pv)))) {
dm_list_del(&pvl->list);
+ free_pv_fid(pv);
continue;
}
@@ -183,21 +318,23 @@ int pvscan(struct cmd_context *cmd, int argc __attribute__((unused)),
pv_max_name_len += 2;
vg_max_name_len += 2;
- dm_list_iterate_items(pvl, pvslist)
- _pvscan_display_single(cmd, pvl->pv, NULL);
+ dm_list_iterate_items(pvl, pvslist) {
+ _pvscan_display_single(cmd, pvl->pv, NULL);
+ free_pv_fid(pvl->pv);
+ }
if (!pvs_found) {
- log_print("No matching physical volumes found");
+ log_print_unless_silent("No matching physical volumes found");
unlock_vg(cmd, VG_GLOBAL);
return ECMD_PROCESSED;
}
- log_print("Total: %d [%s] / in use: %d [%s] / in no VG: %d [%s]",
- pvs_found,
- display_size(cmd, size_total),
- pvs_found - new_pvs_found,
- display_size(cmd, (size_total - size_new)),
- new_pvs_found, display_size(cmd, size_new));
+ log_print_unless_silent("Total: %d [%s] / in use: %d [%s] / in no VG: %d [%s]",
+ pvs_found,
+ display_size(cmd, size_total),
+ pvs_found - new_pvs_found,
+ display_size(cmd, (size_total - size_new)),
+ new_pvs_found, display_size(cmd, size_new));
unlock_vg(cmd, VG_GLOBAL);
diff --git a/tools/reporter.c b/tools/reporter.c
index fbd0c27..1c8e39d 100644
--- a/tools/reporter.c
+++ b/tools/reporter.c
@@ -51,7 +51,6 @@ static int _segs_single(struct cmd_context *cmd __attribute__((unused)),
return ECMD_PROCESSED;
}
-
static int _pvsegs_sub_single(struct cmd_context *cmd,
struct volume_group *vg,
struct pv_segment *pvseg, void *handle)
@@ -61,15 +60,13 @@ static int _pvsegs_sub_single(struct cmd_context *cmd,
struct volume_group _free_vg = {
.cmd = cmd,
- .name = (char *)"",
+ .name = "",
+ .vgmem = NULL,
};
- if (!(_free_vg.vgmem = dm_pool_create("_free_vg", 10240)))
- return ECMD_FAILED;
-
struct logical_volume _free_logical_volume = {
.vg = vg ?: &_free_vg,
- .name = (char *) "",
+ .name = "",
.snapshot = NULL,
.status = VISIBLE_LV,
.major = -1,
@@ -109,8 +106,8 @@ static int _pvsegs_sub_single(struct cmd_context *cmd,
ret = ECMD_FAILED;
goto_out;
}
+
out:
- free_vg(&_free_vg);
return ret;
}
@@ -145,7 +142,7 @@ static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
vg = vg_read(cmd, vg_name, (char *)&pv->vgid, 0);
if (vg_read_error(vg)) {
log_error("Skipping volume group %s", vg_name);
- free_vg(vg);
+ release_vg(vg);
return ECMD_FAILED;
}
@@ -185,7 +182,7 @@ out:
unlock_vg(cmd, vg_name);
if (!old_vg)
- free_vg(vg);
+ release_vg(vg);
return ret;
}
@@ -318,6 +315,9 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
"report/pvsegs_cols_verbose",
DEFAULT_PVSEGS_COLS_VERB);
break;
+ default:
+ log_error(INTERNAL_ERROR "Unknown report type.");
+ return ECMD_FAILED;
}
/* If -o supplied use it, else use default for report_type */
diff --git a/tools/toollib.c b/tools/toollib.c
index f76aacd..3fe1c14 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -14,11 +14,7 @@
*/
#include "tools.h"
-#include "lv_alloc.h"
-#include "xlate.h"
-
#include <sys/stat.h>
-#include <sys/wait.h>
const char *command_name(struct cmd_context *cmd)
{
@@ -28,7 +24,7 @@ const char *command_name(struct cmd_context *cmd)
/*
* Strip dev_dir if present
*/
-char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
+const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
unsigned *dev_dir_found)
{
const char *dmdir = dm_dir();
@@ -54,7 +50,7 @@ char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
*layer) {
log_error("skip_dev_dir: Couldn't split up device name %s",
vg_name);
- return (char *) vg_name;
+ return vg_name;
}
vglv_sz = strlen(vgname) + strlen(lvname) + 2;
if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
@@ -62,7 +58,7 @@ char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
*lvname ? "/" : "",
lvname) < 0) {
log_error("vg/lv string alloc failed");
- return (char *) vg_name;
+ return vg_name;
}
return vglv;
}
@@ -76,7 +72,7 @@ char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
} else if (dev_dir_found)
*dev_dir_found = 0;
- return (char *) vg_name;
+ return vg_name;
}
/*
@@ -119,10 +115,20 @@ int process_each_lv_in_vg(struct cmd_context *cmd,
process_all = 1;
}
+ /*
+ * FIXME: In case of remove it goes through deleted entries,
+ * but it works since entries are allocated from vg mem pool.
+ */
dm_list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->status & SNAPSHOT)
continue;
+ /* Skip availability change for non-virt snaps when processing all LVs */
+ /* FIXME: pass process_all to process_single_lv() */
+ if (process_all && arg_count(cmd, activate_ARG) &&
+ lv_is_cow(lvl->lv) && !lv_is_virtual_origin(origin_from_cow(lvl->lv)))
+ continue;
+
if (lv_is_virtual_origin(lvl->lv) && !arg_count(cmd, all_ARG))
continue;
@@ -169,11 +175,17 @@ int process_each_lv_in_vg(struct cmd_context *cmd,
}
if (ret > ret_max)
ret_max = ret;
- if (sigint_caught())
+ if (sigint_caught()) {
+ stack;
return ret_max;
+ }
}
if (lvargs_supplied && lvargs_matched != dm_list_size(arg_lvnames)) {
+ /*
+ * FIXME: lvm supports removal of LV with all its dependencies
+ * this leads to miscalculation that depends on the order of args.
+ */
log_error("One or more specified logical volume(s) not found.");
if (ret_max < ECMD_FAILED)
ret_max = ECMD_FAILED;
@@ -253,8 +265,10 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
while (*lv_name == '/')
lv_name++;
if (!(vgname = extract_vgname(cmd, vgname))) {
- if (ret_max < ECMD_FAILED)
+ if (ret_max < ECMD_FAILED) {
+ stack;
ret_max = ECMD_FAILED;
+ }
continue;
}
} else if (!dev_dir_found &&
@@ -295,6 +309,8 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
if (!argc || !dm_list_empty(&tags)) {
log_verbose("Finding all logical volumes");
+ if (!lvmetad_vg_list_to_lvmcache(cmd))
+ stack;
if (!(vgnames = get_vgnames(cmd, 0)) || dm_list_empty(vgnames)) {
log_error("No volume groups found");
return ret_max;
@@ -347,8 +363,12 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
ret = process_each_lv_in_vg(cmd, cvl_vg->vg, &lvnames,
tags_arg, &failed_lvnames,
handle, process_single_lv);
- if (ret != ECMD_PROCESSED ||
- dm_list_empty(&failed_lvnames))
+ if (ret != ECMD_PROCESSED) {
+ stack;
+ break;
+ }
+
+ if (dm_list_empty(&failed_lvnames))
break;
/* Try again with failed LVs in this VG */
@@ -357,6 +377,7 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
free_cmd_vgs(&cmd_vgs);
if (!cmd_vg_read(cmd, &cmd_vgs)) {
+ stack;
ret = ECMD_FAILED; /* break */
break;
}
@@ -366,8 +387,10 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
free_cmd_vgs(&cmd_vgs);
/* FIXME: logic for breaking command is not consistent */
- if (sigint_caught())
+ if (sigint_caught()) {
+ stack;
return ECMD_FAILED;
+ }
}
return ret_max;
@@ -392,7 +415,7 @@ int process_each_segment_in_pv(struct cmd_context *cmd,
vg = vg_read(cmd, vg_name, NULL, 0);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
log_error("Skipping volume group %s", vg_name);
return ECMD_FAILED;
}
@@ -404,7 +427,7 @@ int process_each_segment_in_pv(struct cmd_context *cmd,
if (!(pvl = find_pv_in_vg(vg, pv_dev_name(pv)))) {
log_error("Unable to find %s in volume group %s",
pv_dev_name(pv), vg_name);
- unlock_and_free_vg(cmd, vg, vg_name);
+ unlock_and_release_vg(cmd, vg, vg_name);
return ECMD_FAILED;
}
@@ -427,7 +450,7 @@ int process_each_segment_in_pv(struct cmd_context *cmd,
if (vg_name)
unlock_vg(cmd, vg_name);
if (!old_vg)
- free_vg(vg);
+ release_vg(vg);
return ret_max;
}
@@ -472,7 +495,7 @@ static int _process_one_vg(struct cmd_context *cmd, const char *vg_name,
for (;;) {
/* FIXME: consistent handling of command break */
if (sigint_caught()) {
- ret = ECMD_FAILED;
+ ret = ECMD_FAILED;
break;
}
if (!cmd_vg_read(cmd, &cmd_vgs))
@@ -564,13 +587,15 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
if (!argc || !dm_list_empty(&tags)) {
log_verbose("Finding all volume groups");
+ if (!lvmetad_vg_list_to_lvmcache(cmd))
+ stack;
if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) {
log_error("No volume groups found");
return ret_max;
}
dm_list_iterate_items(sl, vgids) {
vgid = sl->str;
- if (!(vgid) || !(vg_name = vgname_from_vgid(cmd->mem, vgid)))
+ if (!(vgid) || !(vg_name = lvmcache_vgname_from_vgid(cmd->mem, vgid)))
continue;
ret_max = _process_one_vg(cmd, vg_name, vgid, &tags,
&arg_vgnames,
@@ -640,15 +665,17 @@ static int _process_all_devs(struct cmd_context *cmd, void *handle,
}
while ((dev = dev_iter_get(iter))) {
- if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 0, 0))) {
+ if (!(pv = pv_read(cmd, dev_name(dev), 0, 0))) {
memset(&pv_dummy, 0, sizeof(pv_dummy));
dm_list_init(&pv_dummy.tags);
dm_list_init(&pv_dummy.segments);
pv_dummy.dev = dev;
- pv_dummy.fmt = NULL;
pv = &pv_dummy;
}
ret = process_single_pv(cmd, NULL, pv, handle);
+
+ free_pv_fid(pv);
+
if (ret > ret_max)
ret_max = ret;
if (sigint_caught())
@@ -682,7 +709,6 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
struct str_list *sll;
char *at_sign, *tagname;
int scanned = 0;
- struct dm_list mdas;
dm_list_init(&tags);
@@ -694,7 +720,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
if (argc) {
log_verbose("Using physical volume(s) on command line");
for (; opt < argc; opt++) {
- unescape_colons_and_at_signs(argv[opt], NULL, &at_sign);
+ dm_unescape_colons_and_at_signs(argv[opt], NULL, &at_sign);
if (at_sign && (at_sign == argv[opt])) {
tagname = at_sign + 1;
@@ -724,10 +750,8 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
}
pv = pvl->pv;
} else {
-
- dm_list_init(&mdas);
- if (!(pv = pv_read(cmd, argv[opt], &mdas,
- NULL, 1, scan_label_only))) {
+ if (!(pv = pv_read(cmd, argv[opt],
+ 1, scan_label_only))) {
log_error("Failed to read physical "
"volume \"%s\"", argv[opt]);
ret_max = ECMD_FAILED;
@@ -742,7 +766,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
* PV on the system.
*/
if (!scanned && is_orphan(pv) &&
- !dm_list_size(&mdas)) {
+ !dm_list_size(&pv->fid->metadata_areas_in_use)) {
if (!scan_label_only &&
!scan_vgs_for_pvs(cmd, 1)) {
stack;
@@ -750,8 +774,9 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
continue;
}
scanned = 1;
+ free_pv_fid(pv);
if (!(pv = pv_read(cmd, argv[opt],
- NULL, NULL, 1,
+ 1,
scan_label_only))) {
log_error("Failed to read "
"physical volume "
@@ -763,6 +788,14 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
}
ret = process_single_pv(cmd, vg, pv, handle);
+
+ /*
+ * Free PV only if we called pv_read before,
+ * otherwise the PV structure is part of the VG.
+ */
+ if (!vg)
+ free_pv_fid(pv);
+
if (ret > ret_max)
ret_max = ret;
if (sigint_caught())
@@ -774,7 +807,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
vg = vg_read(cmd, sll->str, NULL, flags);
if (vg_read_error(vg)) {
ret_max = ECMD_FAILED;
- free_vg(vg);
+ release_vg(vg);
stack;
continue;
}
@@ -783,7 +816,7 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
handle,
process_single_pv);
- unlock_and_free_vg(cmd, vg, sll->str);
+ unlock_and_release_vg(cmd, vg, sll->str);
if (ret > ret_max)
ret_max = ret;
@@ -810,12 +843,14 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
} else {
log_verbose("Scanning for physical volume names");
+ lvmcache_seed_infos_from_lvmetad(cmd);
if (!(pvslist = get_pvs(cmd)))
goto bad;
dm_list_iterate_items(pvl, pvslist) {
ret = process_single_pv(cmd, NULL, pvl->pv,
handle);
+ free_pv_fid(pvl->pv);
if (ret > ret_max)
ret_max = ret;
if (sigint_caught())
@@ -898,7 +933,7 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name)
*/
char *default_vgname(struct cmd_context *cmd)
{
- char *vg_path;
+ const char *vg_path;
/* Take default VG from environment? */
vg_path = getenv("LVM_VG_NAME");
@@ -959,10 +994,11 @@ static int xstrtouint32(const char *s, char **p, int base, uint32_t *result)
errno = 0;
ul = strtoul(s, p, base);
- if (errno || *p == s || (uint32_t) ul != ul)
- return -1;
+ if (errno || *p == s || ul > UINT32_MAX)
+ return 0;
*result = ul;
- return 0;
+
+ return 1;
}
static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges,
@@ -994,7 +1030,7 @@ static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges,
/* Start extent given? */
if (isdigit(*c)) {
- if (xstrtouint32(c, &endptr, 10, &start))
+ if (!xstrtouint32(c, &endptr, 10, &start))
goto error;
c = endptr;
/* Just one number given? */
@@ -1005,7 +1041,7 @@ static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges,
if (*c == '-') {
c++;
if (isdigit(*c)) {
- if (xstrtouint32(c, &endptr, 10, &end))
+ if (!xstrtouint32(c, &endptr, 10, &end))
goto error;
c = endptr;
}
@@ -1107,7 +1143,7 @@ struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int
dm_list_init(&arg_pvnames);
for (i = 0; i < argc; i++) {
- unescape_colons_and_at_signs(argv[i], &colon, &at_sign);
+ dm_unescape_colons_and_at_signs(argv[i], &colon, &at_sign);
if (at_sign && (at_sign == argv[i])) {
tagname = at_sign + 1;
@@ -1212,7 +1248,7 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
vp_def->max_lv);
vp_new->max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG,
vp_def->max_pv);
- vp_new->alloc = arg_uint_value(cmd, alloc_ARG, vp_def->alloc);
+ vp_new->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, vp_def->alloc);
/* Units of 512-byte sectors */
vp_new->extent_size =
@@ -1226,17 +1262,23 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
/* Default depends on current locking type */
vp_new->clustered = locking_is_clustered();
- if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, physicalextentsize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Physical extent size may not be negative");
return 1;
}
- if (arg_sign_value(cmd, maxlogicalvolumes_ARG, 0) == SIGN_MINUS) {
+ if (arg_uint64_value(cmd, physicalextentsize_ARG, 0) > MAX_EXTENT_SIZE) {
+ log_error("Physical extent size cannot be larger than %s",
+ display_size(cmd, (uint64_t) MAX_EXTENT_SIZE));
+ return 1;
+ }
+
+ if (arg_sign_value(cmd, maxlogicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Max Logical Volumes may not be negative");
return 1;
}
- if (arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, maxphysicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Max Physical Volumes may not be negative");
return 1;
}
@@ -1295,10 +1337,17 @@ int vg_refresh_visible(struct cmd_context *cmd, struct volume_group *vg)
struct lv_list *lvl;
int r = 1;
- dm_list_iterate_items(lvl, &vg->lvs)
+ sigint_allow();
+ dm_list_iterate_items(lvl, &vg->lvs) {
+ if (sigint_caught())
+ return_0;
+
if (lv_is_visible(lvl->lv))
if (!lv_refresh(cmd, lvl->lv))
r = 0;
+ }
+
+ sigint_restore();
return r;
}
@@ -1343,7 +1392,7 @@ int pvcreate_params_validate(struct cmd_context *cmd,
}
pp->yes = arg_count(cmd, yes_ARG);
- pp->force = arg_count(cmd, force_ARG);
+ pp->force = (force_t) arg_count(cmd, force_ARG);
if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) {
log_error("labelsector must be less than %lu",
@@ -1391,13 +1440,13 @@ int pvcreate_params_validate(struct cmd_context *cmd,
if (arg_count(cmd, zero_ARG))
pp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n");
- if (arg_sign_value(cmd, dataalignment_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, dataalignment_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Physical volume data alignment may not be negative");
return 0;
}
pp->data_alignment = arg_uint64_value(cmd, dataalignment_ARG, UINT64_C(0));
- if (pp->data_alignment > ULONG_MAX) {
+ if (pp->data_alignment > UINT32_MAX) {
log_error("Physical volume data alignment is too big.");
return 0;
}
@@ -1410,13 +1459,13 @@ int pvcreate_params_validate(struct cmd_context *cmd,
pp->data_alignment = 0;
}
- if (arg_sign_value(cmd, dataalignmentoffset_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, dataalignmentoffset_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Physical volume data alignment offset may not be negative");
return 0;
}
pp->data_alignment_offset = arg_uint64_value(cmd, dataalignmentoffset_ARG, UINT64_C(0));
- if (pp->data_alignment_offset > ULONG_MAX) {
+ if (pp->data_alignment_offset > UINT32_MAX) {
log_error("Physical volume data alignment offset is too big.");
return 0;
}
@@ -1428,7 +1477,7 @@ int pvcreate_params_validate(struct cmd_context *cmd,
pp->data_alignment_offset = 0;
}
- if (arg_sign_value(cmd, metadatasize_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Metadata size may not be negative");
return 0;
}
@@ -1449,7 +1498,6 @@ int pvcreate_params_validate(struct cmd_context *cmd,
}
int get_activation_monitoring_mode(struct cmd_context *cmd,
- struct volume_group *vg,
int *monitoring_mode)
{
*monitoring_mode = DEFAULT_DMEVENTD_MONITOR;
@@ -1470,16 +1518,6 @@ int get_activation_monitoring_mode(struct cmd_context *cmd,
DEFAULT_DMEVENTD_MONITOR))
*monitoring_mode = DMEVENTD_MONITOR_IGNORE;
- if (vg && vg_is_clustered(vg) &&
- *monitoring_mode == DMEVENTD_MONITOR_IGNORE) {
- log_error("%s is incompatible with clustered Volume Group "
- "\"%s\": Skipping.",
- (arg_count(cmd, ignoremonitoring_ARG) ?
- "--ignoremonitoring" : "activation/monitoring=0"),
- vg->name);
- return 0;
- }
-
return 1;
}
@@ -1490,13 +1528,13 @@ static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
uint32_t *stripe_size)
{
if (*stripes == 1 && *stripe_size) {
- log_print("Ignoring stripesize argument with single stripe");
+ log_print_unless_silent("Ignoring stripesize argument with single stripe");
*stripe_size = 0;
}
if (*stripes > 1 && !*stripe_size) {
*stripe_size = find_config_tree_int(cmd, "metadata/stripesize", DEFAULT_STRIPESIZE) * 2;
- log_print("Using default stripesize %s",
+ log_print_unless_silent("Using default stripesize %s",
display_size(cmd, (uint64_t) *stripe_size));
}
@@ -1525,16 +1563,16 @@ static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stripe_size)
{
/* stripes_long_ARG takes precedence (for lvconvert) */
- *stripes = arg_uint_value(cmd, arg_count(cmd, stripes_long_ARG) ? stripes_long_ARG : stripes_ARG, 1);
+ *stripes = arg_uint_value(cmd, arg_count(cmd, stripes_long_ARG) ? stripes_long_ARG : stripes_ARG, 1);
*stripe_size = arg_uint_value(cmd, stripesize_ARG, 0);
if (*stripe_size) {
- if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, stripesize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Negative stripesize is invalid");
return 0;
}
- if(*stripe_size > STRIPE_SIZE_LIMIT * 2) {
+ if(arg_uint64_value(cmd, stripesize_ARG, 0) > STRIPE_SIZE_LIMIT * 2) {
log_error("Stripe size cannot be larger than %s",
display_size(cmd, (uint64_t) STRIPE_SIZE_LIMIT));
return 0;
@@ -1544,3 +1582,51 @@ int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stri
return _validate_stripe_params(cmd, stripes, stripe_size);
}
+/* FIXME move to lib */
+static int _pv_change_tag(struct physical_volume *pv, const char *tag, int addtag)
+{
+ if (addtag) {
+ if (!str_list_add(pv->fmt->cmd->mem, &pv->tags, tag)) {
+ log_error("Failed to add tag %s to physical volume %s",
+ tag, pv_dev_name(pv));
+ return 0;
+ }
+ } else
+ str_list_del(&pv->tags, tag);
+
+ return 1;
+}
+
+/* Set exactly one of VG, LV or PV */
+int change_tag(struct cmd_context *cmd, struct volume_group *vg,
+ struct logical_volume *lv, struct physical_volume *pv, int arg)
+{
+ const char *tag;
+ struct arg_value_group_list *current_group;
+
+ dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
+ if (!grouped_arg_is_set(current_group->arg_values, arg))
+ continue;
+
+ if (!(tag = grouped_arg_str_value(current_group->arg_values, arg, NULL))) {
+ log_error("Failed to get tag");
+ return 0;
+ }
+
+ if (vg && !vg_change_tag(vg, tag, arg == addtag_ARG))
+ return_0;
+ else if (lv && !lv_change_tag(lv, tag, arg == addtag_ARG))
+ return_0;
+ else if (pv && !_pv_change_tag(pv, tag, arg == addtag_ARG))
+ return_0;
+ }
+
+ return 1;
+}
+
+/* Return percents of extents and avoid overflow, with optional roundup */
+uint32_t percent_of_extents(uint32_t percents, uint32_t count, int roundup)
+{
+ return (uint32_t)(((uint64_t)percents * (uint64_t)count +
+ ((roundup) ? 99 : 0)) / 100);
+}
diff --git a/tools/toollib.h b/tools/toollib.h
index 71e516f..b3b0a7c 100644
--- a/tools/toollib.h
+++ b/tools/toollib.h
@@ -84,8 +84,8 @@ int process_each_lv_in_vg(struct cmd_context *cmd,
char *default_vgname(struct cmd_context *cmd);
const char *extract_vgname(struct cmd_context *cmd, const char *lv_name);
-char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
- unsigned *dev_dir_found);
+const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
+ unsigned *dev_dir_found);
/*
* Builds a list of pv's from the names in argv. Used in
@@ -110,9 +110,11 @@ int pvcreate_params_validate(struct cmd_context *cmd,
struct pvcreate_params *pp);
int get_activation_monitoring_mode(struct cmd_context *cmd,
- struct volume_group *vg,
int *monitoring_mode);
int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
uint32_t *stripe_size);
+int change_tag(struct cmd_context *cmd, struct volume_group *vg,
+ struct logical_volume *lv, struct physical_volume *pv, int arg);
+
#endif
diff --git a/tools/tools.h b/tools/tools.h
index cfbceeb..a3ad9fd 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -28,6 +28,7 @@
#include "activate.h"
#include "archiver.h"
#include "lvmcache.h"
+#include "lvmetad.h"
#include "config.h"
#include "defaults.h"
#include "dev-cache.h"
@@ -87,14 +88,6 @@ typedef enum {
PERCENT_ORIGIN
} percent_type_t;
-enum {
- CHANGE_AY = 0,
- CHANGE_AN = 1,
- CHANGE_AE = 2,
- CHANGE_ALY = 3,
- CHANGE_ALN = 4
-};
-
#define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */
#define ARG_GROUPABLE 0x00000002 /* E.g. --addtag */
@@ -145,7 +138,8 @@ void usage(const char *name);
/* the argument verify/normalise functions */
int yes_no_arg(struct cmd_context *cmd, struct arg_values *av);
-int yes_no_excl_arg(struct cmd_context *cmd, struct arg_values *av);
+int activation_arg(struct cmd_context *cmd, struct arg_values *av);
+int discards_arg(struct cmd_context *cmd, struct arg_values *av);
int size_kb_arg(struct cmd_context *cmd, struct arg_values *av);
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av);
int int_arg(struct cmd_context *cmd, struct arg_values *av);
@@ -162,6 +156,8 @@ int segtype_arg(struct cmd_context *cmd, struct arg_values *av);
int alloc_arg(struct cmd_context *cmd, struct arg_values *av);
int readahead_arg(struct cmd_context *cmd, struct arg_values *av);
int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
+int major_minor_valid(const struct cmd_context * cmd, const struct format_type *fmt,
+ int32_t major, int32_t minor);
/* we use the enums to access the switches */
unsigned arg_count(const struct cmd_context *cmd, int a);
@@ -169,6 +165,7 @@ unsigned arg_is_set(const struct cmd_context *cmd, int a);
const char *arg_value(struct cmd_context *cmd, int a);
const char *arg_str_value(struct cmd_context *cmd, int a, const char *def);
int32_t arg_int_value(struct cmd_context *cmd, int a, const int32_t def);
+int32_t first_grouped_arg_int_value(struct cmd_context *cmd, int a, const int32_t def);
uint32_t arg_uint_value(struct cmd_context *cmd, int a, const uint32_t def);
int64_t arg_int64_value(struct cmd_context *cmd, int a, const int64_t def);
uint64_t arg_uint64_value(struct cmd_context *cmd, int a, const uint64_t def);
@@ -180,10 +177,18 @@ int arg_count_increment(struct cmd_context *cmd, int a);
unsigned grouped_arg_count(const struct arg_values *av, int a);
unsigned grouped_arg_is_set(const struct arg_values *av, int a);
const char *grouped_arg_str_value(const struct arg_values *av, int a, const char *def);
+int32_t grouped_arg_int_value(const struct arg_values *av, int a, const int32_t def);
const char *command_name(struct cmd_context *cmd);
int pvmove_poll(struct cmd_context *cmd, const char *pv, unsigned background);
int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv, unsigned background);
+int mirror_remove_missing(struct cmd_context *cmd,
+ struct logical_volume *lv, int force);
+
+uint32_t percent_of_extents(uint32_t percents, uint32_t count, int roundup);
+
+int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
+ activation_change_t activate);
#endif
diff --git a/tools/vgcfgbackup.c b/tools/vgcfgbackup.c
index 2be3949..32948d8 100644
--- a/tools/vgcfgbackup.c
+++ b/tools/vgcfgbackup.c
@@ -28,7 +28,7 @@ static char *_expand_filename(const char *template, const char *vg_name,
return NULL;
}
- if (snprintf(filename, PATH_MAX, template, vg_name) < 0) {
+ if (dm_snprintf(filename, PATH_MAX, template, vg_name) < 0) {
log_error("Error processing filename template %s",
template);
dm_free(filename);
@@ -81,7 +81,7 @@ static int vg_backup_single(struct cmd_context *cmd, const char *vg_name,
}
}
- log_print("Volume group \"%s\" successfully backed up.", vg_name);
+ log_print_unless_silent("Volume group \"%s\" successfully backed up.", vg_name);
return ECMD_PROCESSED;
}
diff --git a/tools/vgcfgrestore.c b/tools/vgcfgrestore.c
index dc0158f..d62df99 100644
--- a/tools/vgcfgrestore.c
+++ b/tools/vgcfgrestore.c
@@ -17,7 +17,7 @@
int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
{
- char *vg_name = NULL;
+ const char *vg_name = NULL;
if (argc == 1) {
vg_name = skip_dev_dir(cmd, argv[0], NULL);
@@ -45,6 +45,8 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
return ECMD_PROCESSED;
}
+ lvmcache_seed_infos_from_lvmetad(cmd);
+
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
log_error("Unable to lock volume group %s", vg_name);
return ECMD_FAILED;
@@ -68,7 +70,7 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- log_print("Restored volume group %s", vg_name);
+ log_print_unless_silent("Restored volume group %s", vg_name);
unlock_vg(cmd, VG_ORPHANS);
unlock_vg(cmd, vg_name);
diff --git a/tools/vgchange.c b/tools/vgchange.c
index bf7ebd8..a897a85 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -24,21 +24,19 @@ static int _monitor_lvs_in_vg(struct cmd_context *cmd,
struct lv_list *lvl;
struct logical_volume *lv;
struct lvinfo info;
- int lv_active;
int r = 1;
dm_list_iterate_items(lvl, &vg->lvs) {
lv = lvl->lv;
- if (!lv_info(cmd, lv, 0, &info, 0, 0))
- lv_active = 0;
- else
- lv_active = info.exists;
-
+ if (!lv_info(cmd, lv, lv_is_thin_pool(lv) ? 1 : 0,
+ &info, 0, 0) ||
+ !info.exists)
+ continue;
/*
* FIXME: Need to consider all cases... PVMOVE, etc
*/
- if ((lv->status & PVMOVE) || !lv_active)
+ if (lv->status & PVMOVE)
continue;
if (!monitor_dev_for_events(cmd, lv, 0, reg)) {
@@ -83,19 +81,27 @@ static int _poll_lvs_in_vg(struct cmd_context *cmd,
return count;
}
-static int _activate_lvs_in_vg(struct cmd_context *cmd,
- struct volume_group *vg, int activate)
+static int _activate_lvs_in_vg(struct cmd_context *cmd, struct volume_group *vg,
+ activation_change_t activate)
{
struct lv_list *lvl;
struct logical_volume *lv;
int count = 0, expected_count = 0;
+ sigint_allow();
dm_list_iterate_items(lvl, &vg->lvs) {
+ if (sigint_caught())
+ return_0;
+
lv = lvl->lv;
if (!lv_is_visible(lv))
continue;
+ /* If LV is sparse, activate origin instead */
+ if (lv_is_cow(lv) && lv_is_virtual_origin(origin_from_cow(lv)))
+ lv = origin_from_cow(lv);
+
/* Only request activation of snapshot origin devices */
if ((lv->status & SNAPSHOT) || lv_is_cow(lv))
continue;
@@ -115,6 +121,19 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
((lv->status & PVMOVE) ))
continue;
+ /*
+ * If the LV is active exclusive remotely,
+ * then ignore it here
+ */
+ if (lv_is_active_exclusive_remotely(lv)) {
+ log_verbose("%s/%s is exclusively active on"
+ " a remote node", vg->name, lv->name);
+ continue;
+ }
+
+ if (activate == CHANGE_AAY && !lv_passes_auto_activation_filter(cmd, lv))
+ continue;
+
expected_count++;
if (activate == CHANGE_AN) {
@@ -127,12 +146,15 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
stack;
continue;
}
- } else if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
+ } else if ((activate == CHANGE_AE) ||
+ lv_is_origin(lv) ||
+ lv_is_thin_type(lv)) {
+ /* FIXME: duplicated test code with lvchange */
if (!activate_lv_excl(cmd, lv)) {
stack;
continue;
}
- } else if (activate == CHANGE_ALY) {
+ } else if (activate == CHANGE_AAY || activate == CHANGE_ALY) {
if (!activate_lv_local(cmd, lv)) {
stack;
continue;
@@ -150,6 +172,8 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
count++;
}
+ sigint_restore();
+
if (expected_count)
log_verbose("%s %d logical volumes in volume group %s",
(activate == CHANGE_AN || activate == CHANGE_ALN)?
@@ -167,9 +191,9 @@ static int _vgchange_monitoring(struct cmd_context *cmd, struct volume_group *vg
dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
if (!_monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode(), &monitored))
r = 0;
- log_print("%d logical volume(s) in volume group "
- "\"%s\" %smonitored",
- monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un");
+ log_print_unless_silent("%d logical volume(s) in volume group "
+ "\"%s\" %smonitored",
+ monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un");
}
return r;
@@ -182,43 +206,40 @@ static int _vgchange_background_polling(struct cmd_context *cmd, struct volume_g
if (lvs_in_vg_activated(vg) && background_polling()) {
polled = _poll_lvs_in_vg(cmd, vg);
if (polled)
- log_print("Background polling started for %d logical volume(s) "
- "in volume group \"%s\"",
- polled, vg->name);
+ log_print_unless_silent("Background polling started for %d logical volume(s) "
+ "in volume group \"%s\"",
+ polled, vg->name);
}
return 1;
}
-static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
+int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
+ activation_change_t activate)
{
- int lv_open, active, monitored = 0;
- int available, r = 1;
- int activate = 1;
+ int lv_open, active, monitored = 0, r = 1, do_activate = 1;
+
+ if ((activate == CHANGE_AN) || (activate == CHANGE_ALN))
+ do_activate = 0;
/*
* Safe, since we never write out new metadata here. Required for
* partial activation to work.
*/
- cmd->handles_missing_pvs = 1;
-
- available = arg_uint_value(cmd, available_ARG, 0);
-
- if ((available == CHANGE_AN) || (available == CHANGE_ALN))
- activate = 0;
+ cmd->handles_missing_pvs = 1;
/* FIXME: Force argument to deactivate them? */
- if (!activate && (lv_open = lvs_in_vg_opened(vg))) {
+ if (!do_activate && (lv_open = lvs_in_vg_opened(vg))) {
log_error("Can't deactivate volume group \"%s\" with %d open "
"logical volume(s)", vg->name, lv_open);
return 0;
}
/* FIXME Move into library where clvmd can use it */
- if (activate)
+ if (do_activate)
check_current_backup(vg);
- if (activate && (active = lvs_in_vg_activated(vg))) {
+ if (do_activate && (active = lvs_in_vg_activated(vg))) {
log_verbose("%d logical volume(s) in volume group \"%s\" "
"already active", active, vg->name);
if (dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
@@ -231,13 +252,13 @@ static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
}
}
- if (!_activate_lvs_in_vg(cmd, vg, available))
+ if (!_activate_lvs_in_vg(cmd, vg, activate))
r = 0;
/* Print message only if there was not found a missing VG */
if (!vg->cmd_missing_vgs)
- log_print("%d logical volume(s) in volume group \"%s\" now active",
- lvs_in_vg_activated(vg), vg->name);
+ log_print_unless_silent("%d logical volume(s) in volume group \"%s\" now active",
+ lvs_in_vg_activated(vg), vg->name);
return r;
}
@@ -257,7 +278,7 @@ static int _vgchange_alloc(struct cmd_context *cmd, struct volume_group *vg)
{
alloc_policy_t alloc;
- alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL);
+ alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL);
/* FIXME: make consistent with vg_set_alloc_policy() */
if (alloc == vg->alloc) {
@@ -346,6 +367,12 @@ static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
{
uint32_t extent_size;
+ if (arg_uint64_value(cmd, physicalextentsize_ARG, 0) > MAX_EXTENT_SIZE) {
+ log_error("Physical extent size cannot be larger than %s",
+ display_size(cmd, (uint64_t) MAX_EXTENT_SIZE));
+ return 1;
+ }
+
extent_size = arg_uint_value(cmd, physicalextentsize_ARG, 0);
/* FIXME: remove check - redundant with vg_change_pesize */
if (extent_size == vg->extent_size) {
@@ -360,37 +387,14 @@ static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
return 1;
}
-static int _vgchange_tag(struct cmd_context *cmd, struct volume_group *vg,
- int arg)
-{
- const char *tag;
- struct arg_value_group_list *current_group;
-
- dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
- if (!grouped_arg_is_set(current_group->arg_values, arg))
- continue;
-
- if (!(tag = grouped_arg_str_value(current_group->arg_values, arg, NULL))) {
- log_error("Failed to get tag");
- return 0;
- }
-
- if (!vg_change_tag(vg, tag, arg == addtag_ARG))
- return_0;
-
- }
-
- return 1;
-}
-
static int _vgchange_addtag(struct cmd_context *cmd, struct volume_group *vg)
{
- return _vgchange_tag(cmd, vg, addtag_ARG);
+ return change_tag(cmd, vg, NULL, NULL, addtag_ARG);
}
static int _vgchange_deltag(struct cmd_context *cmd, struct volume_group *vg)
{
- return _vgchange_tag(cmd, vg, deltag_ARG);
+ return change_tag(cmd, vg, NULL, NULL, deltag_ARG);
}
static int _vgchange_uuid(struct cmd_context *cmd __attribute__((unused)),
@@ -441,7 +445,6 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg,
void *handle __attribute__((unused)))
{
- int dmeventd_mode;
int archived = 0;
int i;
@@ -467,11 +470,6 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
return ECMD_FAILED;
}
- if (!get_activation_monitoring_mode(cmd, vg, &dmeventd_mode))
- return ECMD_FAILED;
-
- init_dmeventd_monitor(dmeventd_mode);
-
/*
* FIXME: DEFAULT_BACKGROUND_POLLING should be "unspecified".
* If --poll is explicitly provided use it; otherwise polling
@@ -507,11 +505,12 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
backup(vg);
- log_print("Volume group \"%s\" successfully changed", vg->name);
+ log_print_unless_silent("Volume group \"%s\" successfully changed", vg->name);
}
- if (arg_count(cmd, available_ARG)) {
- if (!_vgchange_available(cmd, vg))
+ if (arg_count(cmd, activate_ARG)) {
+ if (!vgchange_activate(cmd, vg, (activation_change_t)
+ arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
return ECMD_FAILED;
}
@@ -521,7 +520,7 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
return ECMD_FAILED;
}
- if (!arg_count(cmd, available_ARG) &&
+ if (!arg_count(cmd, activate_ARG) &&
!arg_count(cmd, refresh_ARG) &&
arg_count(cmd, monitor_ARG)) {
/* -ay* will have already done monitoring changes */
@@ -530,7 +529,7 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
}
if (!arg_count(cmd, refresh_ARG) &&
- arg_count(cmd, poll_ARG))
+ background_polling())
if (!_vgchange_background_polling(cmd, vg))
return ECMD_FAILED;
@@ -540,20 +539,22 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
int vgchange(struct cmd_context *cmd, int argc, char **argv)
{
/* Update commands that can be combined */
- int update =
+ int update_partial_safe =
+ arg_count(cmd, deltag_ARG) ||
+ arg_count(cmd, addtag_ARG);
+ int update_partial_unsafe =
arg_count(cmd, logicalvolume_ARG) ||
arg_count(cmd, maxphysicalvolumes_ARG) ||
arg_count(cmd, resizeable_ARG) ||
- arg_count(cmd, deltag_ARG) ||
- arg_count(cmd, addtag_ARG) ||
arg_count(cmd, uuid_ARG) ||
arg_count(cmd, physicalextentsize_ARG) ||
arg_count(cmd, clustered_ARG) ||
arg_count(cmd, alloc_ARG) ||
arg_count(cmd, vgmetadatacopies_ARG);
+ int update = update_partial_safe || update_partial_unsafe;
if (!update &&
- !arg_count(cmd, available_ARG) &&
+ !arg_count(cmd, activate_ARG) &&
!arg_count(cmd, monitor_ARG) &&
!arg_count(cmd, poll_ARG) &&
!arg_count(cmd, refresh_ARG)) {
@@ -564,7 +565,7 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
- if (arg_count(cmd, available_ARG) && arg_count(cmd, refresh_ARG)) {
+ if (arg_count(cmd, activate_ARG) && arg_count(cmd, refresh_ARG)) {
log_error("Only one of -a and --refresh permitted.");
return EINVALID_CMD_LINE;
}
@@ -575,9 +576,9 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
- if (arg_count(cmd, available_ARG) &&
+ if (arg_count(cmd, activate_ARG) &&
(arg_count(cmd, monitor_ARG) || arg_count(cmd, poll_ARG))) {
- int activate = arg_uint_value(cmd, available_ARG, 0);
+ int activate = arg_uint_value(cmd, activate_ARG, 0);
if (activate == CHANGE_AN || activate == CHANGE_ALN) {
log_error("Only -ay* allowed with --monitor or --poll.");
return EINVALID_CMD_LINE;
@@ -589,24 +590,34 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
- if (arg_count(cmd, available_ARG) == 1
+ if (arg_count(cmd, activate_ARG) == 1
&& arg_count(cmd, autobackup_ARG)) {
log_error("-A option not necessary with -a option");
return EINVALID_CMD_LINE;
}
if (arg_count(cmd, maxphysicalvolumes_ARG) &&
- arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) {
+ arg_sign_value(cmd, maxphysicalvolumes_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("MaxPhysicalVolumes may not be negative");
return EINVALID_CMD_LINE;
}
if (arg_count(cmd, physicalextentsize_ARG) &&
- arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
+ arg_sign_value(cmd, physicalextentsize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Physical extent size may not be negative");
return EINVALID_CMD_LINE;
}
+ if (arg_count(cmd, sysinit_ARG) && lvmetad_active() &&
+ arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY) {
+ log_warn("lvmetad is active while using --sysinit -a ay, "
+ "skipping manual activation");
+ return ECMD_PROCESSED;
+ }
+
+ if (!update || !update_partial_unsafe)
+ cmd->handles_missing_pvs = 1;
+
return process_each_vg(cmd, argc, argv, update ? READ_FOR_UPDATE : 0,
NULL, &vgchange_single);
}
diff --git a/tools/vgconvert.c b/tools/vgconvert.c
index acae0fc..2ba4095 100644
--- a/tools/vgconvert.c
+++ b/tools/vgconvert.c
@@ -22,11 +22,9 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
struct physical_volume *pv, *existing_pv;
struct logical_volume *lv;
struct lv_list *lvl;
- uint64_t size = 0;
- struct dm_list mdas;
int pvmetadatacopies = 0;
uint64_t pvmetadatasize = 0;
- uint64_t pe_end = 0, pe_start = 0;
+ uint64_t pe_start = 0;
struct pv_list *pvl;
int change_made = 0;
struct lvinfo info;
@@ -44,7 +42,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
}
if (cmd->fmt->features & FMT_MDAS) {
- if (arg_sign_value(cmd, metadatasize_ARG, 0) == SIGN_MINUS) {
+ if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Metadata size may not be negative");
return EINVALID_CMD_LINE;
}
@@ -119,15 +117,15 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
existing_pv = pvl->pv;
pe_start = pv_pe_start(existing_pv);
- pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv)
- + pe_start - 1;
+ /* pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv) + pe_start - 1; */
- dm_list_init(&mdas);
if (!(pv = pv_create(cmd, pv_dev(existing_pv),
- &existing_pv->id, size, 0, 0,
+ &existing_pv->id, 0, 0, 0,
pe_start, pv_pe_count(existing_pv),
- pv_pe_size(existing_pv), pvmetadatacopies,
- pvmetadatasize, 0, &mdas))) {
+ pv_pe_size(existing_pv),
+ arg_int64_value(cmd, labelsector_ARG,
+ DEFAULT_LABELSECTOR),
+ pvmetadatacopies, pvmetadatasize, 0))) {
log_error("Failed to setup physical volume \"%s\"",
pv_dev_name(existing_pv));
if (change_made)
@@ -153,9 +151,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
log_very_verbose("Writing physical volume data to disk \"%s\"",
pv_dev_name(pv));
- if (!(pv_write(cmd, pv, &mdas,
- arg_int64_value(cmd, labelsector_ARG,
- DEFAULT_LABELSECTOR)))) {
+ if (!(pv_write(cmd, pv, 0))) {
log_error("Failed to write physical volume \"%s\"",
pv_dev_name(pv));
log_error("Use pvcreate and vgcfgrestore to repair "
@@ -164,7 +160,6 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
}
log_verbose("Physical volume \"%s\" successfully created",
pv_dev_name(pv));
-
}
log_verbose("Deleting existing metadata for VG %s", vg_name);
@@ -191,7 +186,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
"archived metadata.");
return ECMD_FAILED;
}
- log_print("Volume group %s successfully converted", vg_name);
+ log_print_unless_silent("Volume group %s successfully converted", vg_name);
backup(vg);
diff --git a/tools/vgcreate.c b/tools/vgcreate.c
index 49574f3..2b9fb2f 100644
--- a/tools/vgcreate.c
+++ b/tools/vgcreate.c
@@ -49,6 +49,8 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
if (vgcreate_params_validate(cmd, &vp_new))
return EINVALID_CMD_LINE;
+ lvmcache_seed_infos_from_lvmetad(cmd);
+
/* Create the new VG */
vg = vg_create(cmd, vp_new.vg_name);
if (vg_read_error(vg)) {
@@ -56,7 +58,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
log_error("A volume group called %s already exists.", vp_new.vg_name);
else
log_error("Can't get lock for %s.", vp_new.vg_name);
- free_vg(vg);
+ release_vg(vg);
return ECMD_FAILED;
}
@@ -74,7 +76,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
}
/* attach the pv's */
- if (!vg_extend(vg, argc, argv, &pp))
+ if (!vg_extend(vg, argc, (const char* const*)argv, &pp))
goto_bad;
if (vp_new.max_lv != vg->max_lv)
@@ -117,16 +119,16 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
backup(vg);
- log_print("%s%colume group \"%s\" successfully created",
- clustered_message, *clustered_message ? 'v' : 'V', vg->name);
+ log_print_unless_silent("%s%colume group \"%s\" successfully created",
+ clustered_message, *clustered_message ? 'v' : 'V', vg->name);
- free_vg(vg);
+ release_vg(vg);
return ECMD_PROCESSED;
bad:
unlock_vg(cmd, VG_ORPHANS);
bad_orphan:
- free_vg(vg);
+ release_vg(vg);
unlock_vg(cmd, vp_new.vg_name);
return ECMD_FAILED;
}
diff --git a/tools/vgexport.c b/tools/vgexport.c
index a1043d2..c573619 100644
--- a/tools/vgexport.c
+++ b/tools/vgexport.c
@@ -44,7 +44,7 @@ static int vgexport_single(struct cmd_context *cmd __attribute__((unused)),
backup(vg);
- log_print("Volume group \"%s\" successfully exported", vg->name);
+ log_print_unless_silent("Volume group \"%s\" successfully exported", vg->name);
return ECMD_PROCESSED;
diff --git a/tools/vgextend.c b/tools/vgextend.c
index a0c166b..2ce7edb 100644
--- a/tools/vgextend.c
+++ b/tools/vgextend.c
@@ -40,7 +40,7 @@ static int _restore_pv(struct volume_group *vg, char *pv_name)
int vgextend(struct cmd_context *cmd, int argc, char **argv)
{
- char *vg_name;
+ const char *vg_name;
struct volume_group *vg = NULL;
int r = ECMD_FAILED;
struct pvcreate_params pp;
@@ -66,13 +66,18 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
- if (arg_count(cmd, restoremissing_ARG))
- cmd->handles_missing_pvs = 1;
+ /*
+ * It is always ok to add new PVs to a VG - even if there are
+ * missing PVs. No LVs are affected by this operation, but
+ * repair processes - particularly for RAID segtypes - can
+ * be facilitated.
+ */
+ cmd->handles_missing_pvs = 1;
log_verbose("Checking for volume group \"%s\"", vg_name);
vg = vg_read_for_update(cmd, vg_name, NULL, 0);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
stack;
return ECMD_FAILED;
}
@@ -92,7 +97,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
} else { /* no --restore, normal vgextend */
if (!lock_vol(cmd, VG_ORPHANS, LCK_VG_WRITE)) {
log_error("Can't get lock for orphan PVs");
- unlock_and_free_vg(cmd, vg, vg_name);
+ unlock_and_release_vg(cmd, vg, vg_name);
return ECMD_FAILED;
}
@@ -107,7 +112,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
}
/* extend vg */
- if (!vg_extend(vg, argc, argv, &pp))
+ if (!vg_extend(vg, argc, (const char* const*)argv, &pp))
goto_bad;
if (arg_count(cmd, metadataignore_ARG) &&
@@ -129,12 +134,12 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
goto_bad;
backup(vg);
- log_print("Volume group \"%s\" successfully extended", vg_name);
+ log_print_unless_silent("Volume group \"%s\" successfully extended", vg_name);
r = ECMD_PROCESSED;
bad:
if (!arg_count(cmd, restoremissing_ARG))
unlock_vg(cmd, VG_ORPHANS);
- unlock_and_free_vg(cmd, vg, vg_name);
+ unlock_and_release_vg(cmd, vg, vg_name);
return r;
}
diff --git a/tools/vgimport.c b/tools/vgimport.c
index 284f536..5badcb5 100644
--- a/tools/vgimport.c
+++ b/tools/vgimport.c
@@ -48,7 +48,7 @@ static int vgimport_single(struct cmd_context *cmd __attribute__((unused)),
backup(vg);
- log_print("Volume group \"%s\" successfully imported", vg->name);
+ log_print_unless_silent("Volume group \"%s\" successfully imported", vg->name);
return ECMD_PROCESSED;
diff --git a/tools/vgmerge.c b/tools/vgmerge.c
index 391764f..2cecb05 100644
--- a/tools/vgmerge.c
+++ b/tools/vgmerge.c
@@ -22,7 +22,7 @@ static struct volume_group *_vgmerge_vg_read(struct cmd_context *cmd,
log_verbose("Checking for volume group \"%s\"", vg_name);
vg = vg_read_for_update(cmd, vg_name, NULL, 0);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
return NULL;
}
return vg;
@@ -54,7 +54,7 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
vg_to = _vgmerge_vg_read(cmd, vg_name_to);
if (!vg_to) {
stack;
- unlock_and_free_vg(cmd, vg_from, vg_name_from);
+ unlock_and_release_vg(cmd, vg_from, vg_name_from);
return ECMD_FAILED;
}
} else {
@@ -67,7 +67,7 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
vg_from = _vgmerge_vg_read(cmd, vg_name_from);
if (!vg_from) {
stack;
- unlock_and_free_vg(cmd, vg_to, vg_name_to);
+ unlock_and_release_vg(cmd, vg_to, vg_name_to);
return ECMD_FAILED;
}
}
@@ -80,7 +80,8 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
if (!archive(vg_from) || !archive(vg_to))
goto_bad;
- drop_cached_metadata(vg_from);
+ if (!drop_cached_metadata(vg_from))
+ stack;
/* Merge volume groups */
dm_list_iterate_items_safe(pvl, tpvl, &vg_from->pvs) {
@@ -147,23 +148,23 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
/* FIXME Remove /dev/vgfrom */
backup(vg_to);
- log_print("Volume group \"%s\" successfully merged into \"%s\"",
- vg_from->name, vg_to->name);
+ log_print_unless_silent("Volume group \"%s\" successfully merged into \"%s\"",
+ vg_from->name, vg_to->name);
r = ECMD_PROCESSED;
bad:
- if (lock_vg_from_first) {
- unlock_and_free_vg(cmd, vg_to, vg_name_to);
- unlock_and_free_vg(cmd, vg_from, vg_name_from);
- } else {
- unlock_and_free_vg(cmd, vg_from, vg_name_from);
- unlock_and_free_vg(cmd, vg_to, vg_name_to);
- }
+ /*
+ * Note: as vg_to is referencing moved elements from vg_from
+ * the order of release_vg calls is mandatory.
+ */
+ unlock_and_release_vg(cmd, vg_to, vg_name_to);
+ unlock_and_release_vg(cmd, vg_from, vg_name_from);
+
return r;
}
int vgmerge(struct cmd_context *cmd, int argc, char **argv)
{
- char *vg_name_to, *vg_name_from;
+ const char *vg_name_to, *vg_name_from;
int opt = 0;
int ret = 0, ret_max = 0;
diff --git a/tools/vgreduce.c b/tools/vgreduce.c
index 4aa8f01..1b04a49 100644
--- a/tools/vgreduce.c
+++ b/tools/vgreduce.c
@@ -14,7 +14,6 @@
*/
#include "tools.h"
-#include "lv_alloc.h"
static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
{
@@ -40,91 +39,7 @@ static int _remove_pv(struct volume_group *vg, struct pv_list *pvl, int silent)
vg->free_count -= pvl->pv->pe_count;
vg->extent_count -= pvl->pv->pe_count;
del_pvl_from_vgs(vg, pvl);
-
- return 1;
-}
-
-static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
- int *list_unsafe, struct dm_list *lvs_changed)
-{
- struct lv_segment *snap_seg;
- struct dm_list *snh, *snht;
- struct logical_volume *cow;
- struct lv_list *lvl;
- struct lvinfo info;
- int first = 1;
-
- log_verbose("%s/%s has missing extents: removing (including "
- "dependencies)", lv->vg->name, lv->name);
-
- /* FIXME Cope properly with stacked devices & snapshots. */
-
- /* If snapshot device is missing, deactivate origin. */
- if (lv_is_cow(lv) && (snap_seg = find_cow(lv))) {
- log_verbose("Deactivating (if active) logical volume %s "
- "(origin of %s)", snap_seg->origin->name, lv->name);
-
- if (!test_mode() && !deactivate_lv(cmd, snap_seg->origin)) {
- log_error("Failed to deactivate LV %s",
- snap_seg->origin->name);
- return 0;
- }
-
- /* Use the origin LV */
- lv = snap_seg->origin;
- }
-
- /* Remove snapshot dependencies */
- dm_list_iterate_safe(snh, snht, &lv->snapshot_segs) {
- snap_seg = dm_list_struct_base(snh, struct lv_segment,
- origin_list);
- cow = snap_seg->cow;
-
- if (first && !test_mode() &&
- !deactivate_lv(cmd, snap_seg->origin)) {
- log_error("Failed to deactivate LV %s",
- snap_seg->origin->name);
- return 0;
- }
-
- *list_unsafe = 1; /* May remove caller's lvht! */
- if (!vg_remove_snapshot(cow))
- return_0;
- log_verbose("Removing LV %s from VG %s", cow->name,
- lv->vg->name);
- if (!lv_remove(cow))
- return_0;
-
- first = 0;
- }
-
- /*
- * If LV is active, replace it with error segment
- * and add to list of LVs to be removed later.
- * Doesn't apply to snapshots/origins yet - they're already deactivated.
- */
- /*
- * If the LV is a part of mirror segment,
- * the mirrored LV also should be cleaned up.
- * Clean-up is currently done by caller (_make_vg_consistent()).
- */
- if ((lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) ||
- find_mirror_seg(first_seg(lv))) {
- if (!replace_lv_with_error_segment(lv))
- return_0;
-
- if (!(lvl = dm_pool_alloc(cmd->mem, sizeof(*lvl)))) {
- log_error("lv_list alloc failed");
- return 0;
- }
- lvl->lv = lv;
- dm_list_add(lvs_changed, &lvl->list);
- } else {
- /* Remove LV immediately. */
- log_verbose("Removing LV %s from VG %s", lv->name, lv->vg->name);
- if (!lv_remove(lv))
- return_0;
- }
+ free_pv_fid(pvl->pv);
return 1;
}
@@ -144,8 +59,8 @@ static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
if (!r) {
cmd->handles_missing_pvs = 1;
- log_warn("WARNING: There are still partial LVs in VG %s.", vg->name);
- log_warn("To remove them unconditionally use: vgreduce --removemissing --force.");
+ log_error("There are still partial LVs in VG %s.", vg->name);
+ log_error("To remove them unconditionally use: vgreduce --removemissing --force.");
log_warn("Proceeding to remove empty missing PVs.");
}
@@ -161,215 +76,41 @@ static int _consolidate_vg(struct cmd_context *cmd, struct volume_group *vg)
static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
{
- struct dm_list *pvh, *pvht;
- struct dm_list *lvh, *lvht;
- struct pv_list *pvl;
- struct lv_list *lvl, *lvl2, *lvlt;
+ struct lv_list *lvl;
struct logical_volume *lv;
- struct physical_volume *pv;
- struct lv_segment *seg, *mirrored_seg;
- unsigned s;
- uint32_t mimages, remove_log;
- int list_unsafe, only_mirror_images_found;
- DM_LIST_INIT(lvs_changed);
- only_mirror_images_found = 1;
-
- /* Deactivate & remove necessary LVs */
- restart_loop:
- list_unsafe = 0; /* Set if we delete a different list-member */
-
- dm_list_iterate_safe(lvh, lvht, &vg->lvs) {
- lv = dm_list_item(lvh, struct lv_list)->lv;
-
- /* Are any segments of this LV on missing PVs? */
- dm_list_iterate_items(seg, &lv->segments) {
- for (s = 0; s < seg->area_count; s++) {
- if (seg_type(seg, s) != AREA_PV)
- continue;
-
- /* FIXME Also check for segs on deleted LVs (incl pvmove) */
-
- pv = seg_pv(seg, s);
- if (!pv || !pv_dev(pv) ||
- is_missing_pv(pv)) {
- if (arg_count(cmd, mirrorsonly_ARG) &&
- !(lv->status & MIRROR_IMAGE)) {
- log_error("Non-mirror-image LV %s found: can't remove.", lv->name);
- only_mirror_images_found = 0;
- continue;
- }
- if (!_remove_lv(cmd, lv, &list_unsafe, &lvs_changed))
- return_0;
- if (list_unsafe)
- goto restart_loop;
- }
- }
- }
- }
-
- if (!only_mirror_images_found) {
- log_error("Aborting because --mirrorsonly was specified.");
- return 0;
- }
- /*
- * Remove missing PVs. FIXME: This duplicates _consolidate_vg above,
- * but we cannot use that right now, since the LV removal code in this
- * function leaves the VG in a "somewhat inconsistent" state and
- * _consolidate_vg doesn't like that -- specifically, mirrors are fixed
- * up *after* the PVs are removed. All this should be gradually
- * superseded by lvconvert --repair.
- */
- dm_list_iterate_safe(pvh, pvht, &vg->pvs) {
- pvl = dm_list_item(pvh, struct pv_list);
- if (pvl->pv->dev && !is_missing_pv(pvl->pv))
- continue;
- if (!_remove_pv(vg, pvl, 0))
- return_0;
- }
+ cmd->partial_activation = 1;
- /* FIXME Recovery. For now people must clean up by hand. */
+ restart:
+ vg_mark_partial_lvs(vg, 1);
- if (!dm_list_empty(&lvs_changed)) {
- if (!vg_write(vg)) {
- log_error("Failed to write out a consistent VG for %s",
- vg->name);
- return 0;
- }
+ dm_list_iterate_items(lvl, &vg->lvs) {
+ lv = lvl->lv;
- if (!test_mode()) {
- /* Suspend lvs_changed */
- if (!suspend_lvs(cmd, &lvs_changed)) {
- stack;
- vg_revert(vg);
- return 0;
- }
- }
-
- if (!vg_commit(vg)) {
- log_error("Failed to commit consistent VG for %s",
- vg->name);
- vg_revert(vg);
- return 0;
- }
-
- if (!test_mode()) {
- if (!resume_lvs(cmd, &lvs_changed)) {
- log_error("Failed to resume LVs using error segments.");
- return 0;
- }
- }
-
- lvs_changed_altered:
- /* Remove lost mirror images from mirrors */
- dm_list_iterate_items(lvl, &vg->lvs) {
- mirrored_seg_altered:
- mirrored_seg = first_seg(lvl->lv);
- if (!seg_is_mirrored(mirrored_seg))
- continue;
-
- mimages = mirrored_seg->area_count;
- remove_log = 0;
-
- for (s = 0; s < mirrored_seg->area_count; s++) {
- dm_list_iterate_items_safe(lvl2, lvlt, &lvs_changed) {
- if (seg_type(mirrored_seg, s) != AREA_LV ||
- lvl2->lv != seg_lv(mirrored_seg, s))
- continue;
- dm_list_del(&lvl2->list);
- if (!shift_mirror_images(mirrored_seg, s))
- return_0;
- mimages--; /* FIXME Assumes uniqueness */
- }
- }
-
- if (mirrored_seg->log_lv) {
- dm_list_iterate_items(seg, &mirrored_seg->log_lv->segments) {
- /* FIXME: The second test shouldn't be required */
- if ((seg->segtype ==
- get_segtype_from_string(vg->cmd, "error"))) {
- log_print("The log device for %s/%s has failed.",
- vg->name, mirrored_seg->lv->name);
- remove_log = 1;
- break;
- }
- if (!strcmp(seg->segtype->name, "error")) {
- log_print("Log device for %s/%s has failed.",
- vg->name, mirrored_seg->lv->name);
- remove_log = 1;
- break;
- }
- }
- }
-
- if ((mimages != mirrored_seg->area_count) || remove_log){
- if (!reconfigure_mirror_images(mirrored_seg, mimages,
- NULL, remove_log))
+ /* Are any segments of this LV on missing PVs? */
+ if (lv->status & PARTIAL_LV) {
+ if (lv->status & MIRRORED) {
+ if (!mirror_remove_missing(cmd, lv, 1))
return_0;
-
- if (!vg_write(vg)) {
- log_error("Failed to write out updated "
- "VG for %s", vg->name);
- return 0;
- }
-
- if (!vg_commit(vg)) {
- log_error("Failed to commit updated VG "
- "for %s", vg->name);
- vg_revert(vg);
- return 0;
- }
-
- /* mirrored LV no longer has valid mimages.
- * So add it to lvs_changed for removal.
- * For this LV may be an area of other mirror,
- * restart the loop. */
- if (!mimages) {
- if (!_remove_lv(cmd, lvl->lv,
- &list_unsafe, &lvs_changed))
- return_0;
- goto lvs_changed_altered;
- }
-
- /* As a result of reconfigure_mirror_images(),
- * first_seg(lv) may now be different seg.
- * e.g. a temporary layer might be removed.
- * So check the mirrored_seg again. */
- goto mirrored_seg_altered;
+ goto restart;
}
- }
- /* Deactivate error LVs */
- if (!test_mode()) {
- dm_list_iterate_items_safe(lvl, lvlt, &lvs_changed) {
- log_verbose("Deactivating (if active) logical volume %s",
- lvl->lv->name);
-
- if (!deactivate_lv(cmd, lvl->lv)) {
- log_error("Failed to deactivate LV %s",
- lvl->lv->name);
- /*
- * We failed to deactivate.
- * Probably because this was a mirror log.
- * Don't try to lv_remove it.
- * Continue work on others.
- */
- dm_list_del(&lvl->list);
- }
+ if (arg_count(cmd, mirrorsonly_ARG) &&!(lv->status & MIRRORED)) {
+ log_error("Non-mirror-image LV %s found: can't remove.", lv->name);
+ continue;
}
- }
- /* Remove remaining LVs */
- dm_list_iterate_items(lvl, &lvs_changed) {
- log_verbose("Removing LV %s from VG %s", lvl->lv->name,
- lvl->lv->vg->name);
- /* Skip LVs already removed by mirror code */
- if (find_lv_in_vg(vg, lvl->lv->name) &&
- !lv_remove(lvl->lv))
- return_0;
+ if (!lv_is_visible(lv))
+ continue;
+ log_warn("Removing partial LV %s.", lv->name);
+ if (!lv_remove_with_dependencies(cmd, lv, DONT_PROMPT, 0))
+ return_0;
+ goto restart;
}
}
+ _consolidate_vg(cmd, vg);
+
return 1;
}
@@ -383,6 +124,11 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
int r = ECMD_FAILED;
const char *name = pv_dev_name(pv);
+ if (!vg) {
+ log_error(INTERNAL_ERROR "VG is NULL.");
+ return ECMD_FAILED;
+ }
+
if (pv_pe_alloc_count(pv)) {
log_error("Physical volume \"%s\" still in use", name);
return ECMD_FAILED;
@@ -438,7 +184,7 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
goto bad;
}
- if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
+ if (!pv_write(cmd, pv, 0)) {
log_error("Failed to clear metadata from physical "
"volume \"%s\" "
"after removal from \"%s\"", name, vg->name);
@@ -447,21 +193,24 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
backup(vg);
- log_print("Removed \"%s\" from volume group \"%s\"", name, vg->name);
+ log_print_unless_silent("Removed \"%s\" from volume group \"%s\"", name, vg->name);
r = ECMD_PROCESSED;
bad:
- unlock_and_free_vg(cmd, orphan_vg, VG_ORPHANS);
+ if (pvl)
+ free_pv_fid(pvl->pv);
+ unlock_and_release_vg(cmd, orphan_vg, VG_ORPHANS);
return r;
}
int vgreduce(struct cmd_context *cmd, int argc, char **argv)
{
struct volume_group *vg;
- char *vg_name;
+ const char *vg_name;
int ret = ECMD_FAILED;
int fixed = 1;
int repairing = arg_count(cmd, removemissing_ARG);
int saved_ignore_suspended_devices = ignore_suspended_devices();
+ int locked = 0;
if (!argc && !repairing) {
log_error("Please give volume group name and "
@@ -469,7 +218,7 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
- if (!argc && repairing) {
+ if (!argc) { /* repairing */
log_error("Please give volume group name");
return EINVALID_CMD_LINE;
}
@@ -516,6 +265,8 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
&& !arg_count(cmd, removemissing_ARG))
goto_out;
+ locked = !vg_read_error(vg);
+
if (repairing) {
if (!vg_read_error(vg) && !vg_missing_pv_count(vg)) {
log_error("Volume group \"%s\" is already consistent",
@@ -524,13 +275,14 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
goto out;
}
- free_vg(vg);
+ release_vg(vg);
log_verbose("Trying to open VG %s for recovery...", vg_name);
vg = vg_read_for_update(cmd, vg_name, NULL,
READ_ALLOW_INCONSISTENT
| READ_ALLOW_EXPORTED);
+ locked |= !vg_read_error(vg);
if (vg_read_error(vg) && vg_read_error(vg) != FAILED_READ_ONLY
&& vg_read_error(vg) != FAILED_INCONSISTENT)
goto_out;
@@ -552,8 +304,8 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
backup(vg);
if (fixed) {
- log_print("Wrote out consistent volume group %s",
- vg_name);
+ log_print_unless_silent("Wrote out consistent volume group %s",
+ vg_name);
ret = ECMD_PROCESSED;
} else
ret = ECMD_FAILED;
@@ -570,7 +322,10 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
}
out:
init_ignore_suspended_devices(saved_ignore_suspended_devices);
- unlock_and_free_vg(cmd, vg, vg_name);
+ if (locked)
+ unlock_vg(cmd, vg_name);
+
+ release_vg(vg);
return ret;
diff --git a/tools/vgremove.c b/tools/vgremove.c
index 67e3767..6804f2a 100644
--- a/tools/vgremove.c
+++ b/tools/vgremove.c
@@ -29,7 +29,7 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name,
lv_count = vg_visible_lvs(vg);
- force = arg_count(cmd, force_ARG);
+ force = (force_t) arg_count(cmd, force_ARG);
if (lv_count) {
if (force == PROMPT) {
if ((missing = vg_missing_pv_count(vg)))
diff --git a/tools/vgrename.c b/tools/vgrename.c
index 98be9a9..b476602 100644
--- a/tools/vgrename.c
+++ b/tools/vgrename.c
@@ -25,7 +25,7 @@ static struct volume_group *_get_old_vg_for_rename(struct cmd_context *cmd,
nevertheless. */
vg = vg_read_for_update(cmd, vg_name_old, vgid, READ_ALLOW_EXPORTED);
if (vg_read_error(vg)) {
- free_vg(vg);
+ release_vg(vg);
return_NULL;
}
@@ -63,7 +63,7 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
int found_id = 0;
struct dm_list *vgids;
struct str_list *sl;
- char *vg_name_new;
+ const char *vg_name_new;
const char *vgid = NULL, *vg_name, *vg_name_old;
char old_path[NAME_LEN], new_path[NAME_LEN];
struct volume_group *vg = NULL;
@@ -79,6 +79,10 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
log_verbose("Checking for existing volume group \"%s\"", vg_name_old);
+ /* populate lvmcache */
+ if (!lvmetad_vg_list_to_lvmcache(cmd))
+ stack;
+
/* Avoid duplicates */
if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) {
log_error("No complete volume groups found");
@@ -87,7 +91,7 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
dm_list_iterate_items(sl, vgids) {
vgid = sl->str;
- if (!vgid || !(vg_name = vgname_from_vgid(NULL, vgid)))
+ if (!vgid || !(vg_name = lvmcache_vgname_from_vgid(NULL, vgid)))
continue;
if (!strcmp(vg_name, vg_name_old)) {
if (match) {
@@ -102,7 +106,7 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
log_suppress(2);
found_id = id_read_format(&id, vg_name_old);
log_suppress(0);
- if (found_id && (vg_name = vgname_from_vgid(cmd->mem, (char *)id.uuid))) {
+ if (found_id && (vg_name = lvmcache_vgname_from_vgid(cmd->mem, (char *)id.uuid))) {
vg_name_old = vg_name;
vgid = (char *)id.uuid;
} else
@@ -117,7 +121,7 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
return_0;
if (!_lock_new_vg_for_rename(cmd, vg_name_new)) {
- unlock_and_free_vg(cmd, vg, vg_name_old);
+ unlock_and_release_vg(cmd, vg, vg_name_old);
return_0;
}
} else {
@@ -135,7 +139,8 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
goto error;
/* Remove references based on old name */
- drop_cached_metadata(vg);
+ if (!drop_cached_metadata(vg))
+ stack;
/* Change the volume group name */
vg_rename(cmd, vg, vg_name_new);
@@ -164,17 +169,20 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
}
}
- backup(vg);
- backup_remove(cmd, vg_name_old);
+ if (!backup(vg))
+ stack;
+ if (!backup_remove(cmd, vg_name_old))
+ stack;
unlock_vg(cmd, vg_name_new);
- unlock_and_free_vg(cmd, vg, vg_name_old);
+ unlock_and_release_vg(cmd, vg, vg_name_old);
- log_print("Volume group \"%s\" successfully renamed to \"%s\"",
- vg_name_old, vg_name_new);
+ log_print_unless_silent("Volume group \"%s\" successfully renamed to \"%s\"",
+ vg_name_old, vg_name_new);
/* FIXME lvmcache corruption - vginfo duplicated instead of renamed */
- persistent_filter_wipe(cmd->filter);
+ if (cmd->filter->wipe)
+ cmd->filter->wipe(cmd->filter);
lvmcache_destroy(cmd, 1);
return 1;
@@ -182,9 +190,9 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path,
error:
if (lock_vg_old_first) {
unlock_vg(cmd, vg_name_new);
- unlock_and_free_vg(cmd, vg, vg_name_old);
+ unlock_and_release_vg(cmd, vg, vg_name_old);
} else {
- unlock_and_free_vg(cmd, vg, vg_name_old);
+ unlock_and_release_vg(cmd, vg, vg_name_old);
unlock_vg(cmd, vg_name_new);
}
return 0;
diff --git a/tools/vgscan.c b/tools/vgscan.c
index 4e12914..99124ef 100644
--- a/tools/vgscan.c
+++ b/tools/vgscan.c
@@ -19,9 +19,9 @@ static int vgscan_single(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg,
void *handle __attribute__((unused)))
{
- log_print("Found %svolume group \"%s\" using metadata type %s",
- vg_is_exported(vg) ? "exported " : "", vg_name,
- vg->fid->fmt->name);
+ log_print_unless_silent("Found %svolume group \"%s\" using metadata type %s",
+ vg_is_exported(vg) ? "exported " : "", vg_name,
+ vg->fid->fmt->name);
check_current_backup(vg);
@@ -42,10 +42,23 @@ int vgscan(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
- persistent_filter_wipe(cmd->filter);
+ if (cmd->filter->wipe)
+ cmd->filter->wipe(cmd->filter);
lvmcache_destroy(cmd, 1);
- log_print("Reading all physical volumes. This may take a while...");
+ if (arg_count(cmd, cache_ARG)) {
+ if (lvmetad_active()) {
+ if (!lvmetad_pvscan_all_devs(cmd, NULL))
+ return ECMD_FAILED;
+ }
+ else {
+ log_error("Cannot proceed since lvmetad is not active.");
+ unlock_vg(cmd, VG_GLOBAL);
+ return ECMD_FAILED;
+ }
+ }
+
+ log_print_unless_silent("Reading all physical volumes. This may take a while...");
maxret = process_each_vg(cmd, argc, argv, 0, NULL,
&vgscan_single);
diff --git a/tools/vgsplit.c b/tools/vgsplit.c
index bd2f0ab..3bbb9fa 100644
--- a/tools/vgsplit.c
+++ b/tools/vgsplit.c
@@ -163,7 +163,7 @@ static int _move_mirrors(struct volume_group *vg_from,
{
struct dm_list *lvh, *lvht;
struct logical_volume *lv;
- struct lv_segment *seg;
+ struct lv_segment *seg, *log_seg;
unsigned s, seg_in, log_in;
dm_list_iterate_safe(lvh, lvht, &vg_from->lvs) {
@@ -179,7 +179,20 @@ static int _move_mirrors(struct volume_group *vg_from,
if (_lv_is_in_vg(vg_to, seg_lv(seg, s)))
seg_in++;
- log_in = (!seg->log_lv || _lv_is_in_vg(vg_to, seg->log_lv));
+ log_in = !seg->log_lv;
+ if (seg->log_lv) {
+ log_seg = first_seg(seg->log_lv);
+ if (seg_is_mirrored(log_seg)) {
+ log_in = 1;
+
+ /* Ensure each log dev is in vg_to */
+ for (s = 0; s < log_seg->area_count; s++)
+ log_in = log_in &&
+ _lv_is_in_vg(vg_to,
+ seg_lv(log_seg, s));
+ } else
+ log_in = _lv_is_in_vg(vg_to, seg->log_lv);
+ }
if ((seg_in && seg_in < seg->area_count) ||
(seg_in && seg->log_lv && !log_in) ||
@@ -224,16 +237,16 @@ static struct volume_group *_vgsplit_to(struct cmd_context *cmd,
vg_to = vg_create(cmd, vg_name_to);
if (vg_read_error(vg_to) == FAILED_LOCKING) {
log_error("Can't get lock for %s", vg_name_to);
- free_vg(vg_to);
+ release_vg(vg_to);
return NULL;
}
if (vg_read_error(vg_to) == FAILED_EXIST) {
*existing_vg = 1;
- free_vg(vg_to);
+ release_vg(vg_to);
vg_to = vg_read_for_update(cmd, vg_name_to, NULL, 0);
if (vg_read_error(vg_to)) {
- free_vg(vg_to);
+ release_vg(vg_to);
stack;
return NULL;
}
@@ -259,7 +272,7 @@ static struct volume_group *_vgsplit_from(struct cmd_context *cmd,
vg_from = vg_read_for_update(cmd, vg_name_from, NULL, 0);
if (vg_read_error(vg_from)) {
- free_vg(vg_from);
+ release_vg(vg_from);
return NULL;
}
return vg_from;
@@ -281,7 +294,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
{
struct vgcreate_params vp_new;
struct vgcreate_params vp_def;
- char *vg_name_from, *vg_name_to;
+ const char *vg_name_from, *vg_name_to;
struct volume_group *vg_to = NULL, *vg_from = NULL;
int opt;
int existing_vg = 0;
@@ -334,7 +347,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
vg_to = _vgsplit_to(cmd, vg_name_to, &existing_vg);
if (!vg_to) {
- unlock_and_free_vg(cmd, vg_from, vg_name_from);
+ unlock_and_release_vg(cmd, vg_from, vg_name_from);
stack;
return ECMD_FAILED;
}
@@ -346,7 +359,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
}
vg_from = _vgsplit_from(cmd, vg_name_from);
if (!vg_from) {
- unlock_and_free_vg(cmd, vg_to, vg_name_to);
+ unlock_and_release_vg(cmd, vg_to, vg_name_to);
stack;
return ECMD_FAILED;
}
@@ -395,7 +408,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
/* Move PVs across to new structure */
for (opt = 0; opt < argc; opt++) {
- unescape_colons_and_at_signs(argv[opt], NULL, NULL);
+ dm_unescape_colons_and_at_signs(argv[opt], NULL, NULL);
if (!move_pv(vg_from, vg_to, argv[opt]))
goto_bad;
}
@@ -463,7 +476,7 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
* Finally, remove the EXPORTED flag from the new VG and write it out.
*/
if (!test_mode()) {
- free_vg(vg_to);
+ release_vg(vg_to);
vg_to = vg_read_for_update(cmd, vg_name_to, NULL,
READ_ALLOW_EXPORTED);
if (vg_read_error(vg_to)) {
@@ -480,19 +493,19 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
backup(vg_to);
- log_print("%s volume group \"%s\" successfully split from \"%s\"",
- existing_vg ? "Existing" : "New",
- vg_to->name, vg_from->name);
+ log_print_unless_silent("%s volume group \"%s\" successfully split from \"%s\"",
+ existing_vg ? "Existing" : "New",
+ vg_to->name, vg_from->name);
r = ECMD_PROCESSED;
bad:
- if (lock_vg_from_first) {
- unlock_and_free_vg(cmd, vg_to, vg_name_to);
- unlock_and_free_vg(cmd, vg_from, vg_name_from);
- } else {
- unlock_and_free_vg(cmd, vg_from, vg_name_from);
- unlock_and_free_vg(cmd, vg_to, vg_name_to);
- }
+ /*
+ * vg_to references elements moved from vg_from
+ * so vg_to has to be freed first.
+ */
+ unlock_and_release_vg(cmd, vg_to, vg_name_to);
+ unlock_and_release_vg(cmd, vg_from, vg_name_from);
+
return r;
}