mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-11-03 08:23:48 +03:00 
			
		
		
		
	Compare commits
	
		
			16 Commits
		
	
	
		
			v2_02_172
			...
			dev-dct-cm
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					02965225da | ||
| 
						 | 
					720c0e326c | ||
| 
						 | 
					6806fcca0a | ||
| 
						 | 
					209312fd7e | ||
| 
						 | 
					aec2b1c4a9 | ||
| 
						 | 
					2c85362c91 | ||
| 
						 | 
					a2b3b88e63 | ||
| 
						 | 
					ceff1eef5c | ||
| 
						 | 
					749e7cf81b | ||
| 
						 | 
					efce1bc2d2 | ||
| 
						 | 
					3f0eded331 | ||
| 
						 | 
					94d0bc7304 | ||
| 
						 | 
					0ccc467608 | ||
| 
						 | 
					ba5ae30bb7 | ||
| 
						 | 
					b9b60a73ae | ||
| 
						 | 
					c677e0e70b | 
@@ -88,11 +88,19 @@ struct cmd_context {
 | 
			
		||||
	 * Command line and arguments.
 | 
			
		||||
	 */
 | 
			
		||||
	const char *cmd_line;
 | 
			
		||||
	const char *name; /* needed before cmd->command is set */
 | 
			
		||||
	struct command *command;
 | 
			
		||||
	char **argv;
 | 
			
		||||
	struct arg_values *arg_values;
 | 
			
		||||
	struct arg_values *opt_arg_values;
 | 
			
		||||
	struct dm_list arg_value_groups;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Position args remaining after command name
 | 
			
		||||
	 * and --options are removed from original argc/argv.
 | 
			
		||||
	 */
 | 
			
		||||
	int position_argc;
 | 
			
		||||
	char **position_argv;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Format handlers.
 | 
			
		||||
	 */
 | 
			
		||||
 
 | 
			
		||||
@@ -319,7 +319,6 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
 | 
			
		||||
{
 | 
			
		||||
	int top_level = 0;
 | 
			
		||||
	unsigned snap_count;
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
 | 
			
		||||
	/* non-top-level LVs */
 | 
			
		||||
	if (lv_is_thin_pool_metadata(lv)) {
 | 
			
		||||
@@ -353,7 +352,7 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
 | 
			
		||||
			    !str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_MULTITHINORIGIN]))
 | 
			
		||||
				goto_bad;
 | 
			
		||||
		}
 | 
			
		||||
		if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
 | 
			
		||||
		if (lv_is_thin_snapshot(lv))
 | 
			
		||||
			if (!str_list_add(mem, role, _lv_type_names[LV_TYPE_SNAPSHOT]) ||
 | 
			
		||||
			    !str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_THINSNAPSHOT]))
 | 
			
		||||
				goto_bad;
 | 
			
		||||
 
 | 
			
		||||
@@ -1066,9 +1066,16 @@ struct lv_segment *get_only_segment_using_this_lv(const struct logical_volume *l
 | 
			
		||||
* Useful functions for managing snapshots.
 | 
			
		||||
*/
 | 
			
		||||
int lv_is_origin(const struct logical_volume *lv);
 | 
			
		||||
#define lv_is_thick_origin lv_is_origin
 | 
			
		||||
 | 
			
		||||
int lv_is_thin_origin(const struct logical_volume *lv, unsigned *snap_count);
 | 
			
		||||
int lv_is_cache_origin(const struct logical_volume *lv);
 | 
			
		||||
int lv_is_thin_snapshot(const struct logical_volume *lv);
 | 
			
		||||
 | 
			
		||||
int lv_is_cow(const struct logical_volume *lv);
 | 
			
		||||
#define lv_is_thick_snapshot lv_is_cow
 | 
			
		||||
 | 
			
		||||
int lv_is_cache_origin(const struct logical_volume *lv);
 | 
			
		||||
 | 
			
		||||
int lv_is_merging_cow(const struct logical_volume *cow);
 | 
			
		||||
uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
 | 
			
		||||
int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size);
 | 
			
		||||
 
 | 
			
		||||
@@ -748,6 +748,19 @@ int lv_is_thin_origin(const struct logical_volume *lv, unsigned int *snap_count)
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lv_is_thin_snapshot(const struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_segment *seg;
 | 
			
		||||
 | 
			
		||||
	if (!lv_is_thin_volume(lv))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Explict check of new thin pool for usability
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
@@ -140,6 +140,13 @@ Makefile: Makefile.in
 | 
			
		||||
	  *) echo "Creating $@" ; $(SED) -e "s+#VERSION#+$(LVM_VERSION)+;s+#DEFAULT_SYS_DIR#+$(DEFAULT_SYS_DIR)+;s+#DEFAULT_ARCHIVE_DIR#+$(DEFAULT_ARCHIVE_DIR)+;s+#DEFAULT_BACKUP_DIR#+$(DEFAULT_BACKUP_DIR)+;s+#DEFAULT_PROFILE_DIR#+$(DEFAULT_PROFILE_DIR)+;s+#DEFAULT_CACHE_DIR#+$(DEFAULT_CACHE_DIR)+;s+#DEFAULT_LOCK_DIR#+$(DEFAULT_LOCK_DIR)+;s+#CLVMD_PATH#+@CLVMD_PATH@+;s+#LVM_PATH#+@LVM_PATH@+;s+#DEFAULT_RUN_DIR#+@DEFAULT_RUN_DIR@+;s+#DEFAULT_PID_DIR#+@DEFAULT_PID_DIR@+;s+#SYSTEMD_GENERATOR_DIR#+$(SYSTEMD_GENERATOR_DIR)+;s+#DEFAULT_MANGLING#+$(DEFAULT_MANGLING)+;" $< > $@ ;; \
 | 
			
		||||
	esac
 | 
			
		||||
 | 
			
		||||
ccmd: ../tools/create-commands.c
 | 
			
		||||
	$(CC) ../tools/create-commands.c -o ccmd
 | 
			
		||||
 | 
			
		||||
generate: ccmd
 | 
			
		||||
	./ccmd --output man -s 0 -p 1 -c lvcreate ../tools/command-lines.in > lvcreate.8.a
 | 
			
		||||
	cat lvcreate.8.a lvcreate.8.b > lvcreate.8.in
 | 
			
		||||
 | 
			
		||||
install_man5: $(MAN5)
 | 
			
		||||
	$(INSTALL) -d $(MAN5DIR)
 | 
			
		||||
	$(INSTALL_DATA) $(MAN5) $(MAN5DIR)/
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@ check lv_field $vg/$lv2 cache_settings "random_threshold=56,sequential_threshold
 | 
			
		||||
# Check swap of cache pool metadata
 | 
			
		||||
lvconvert --yes --type cache-pool --poolmetadata $lv4 $vg/$lv3
 | 
			
		||||
UUID=$(get lv_field $vg/$lv5 uuid)
 | 
			
		||||
lvconvert --yes --cachepool $vg/$lv3 --poolmetadata $lv5
 | 
			
		||||
lvconvert --yes --swapmetadata --poolmetadata $lv5 $vg/$lv3
 | 
			
		||||
check lv_field $vg/${lv3}_cmeta uuid "$UUID"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -109,30 +109,30 @@ lvcreate -an -Zn -L 8 -n $lv4 $vg
 | 
			
		||||
invalid lvconvert --type cache --poolmetadata $vg/$lv2 $vg/$lv1
 | 
			
		||||
 | 
			
		||||
# Cannot mix with thins
 | 
			
		||||
invalid lvconvert --type cache --poolmetadata $vg/$lv2 --thinpool $vg/$lv1
 | 
			
		||||
invalid lvconvert --type cache --thin --poolmetadata $vg/$lv2 $vg/$lv1
 | 
			
		||||
not lvconvert --type cache --poolmetadata $vg/$lv2 --thinpool $vg/$lv1
 | 
			
		||||
not lvconvert --type cache --thin --poolmetadata $vg/$lv2 $vg/$lv1
 | 
			
		||||
 | 
			
		||||
# Undefined cached volume
 | 
			
		||||
invalid lvconvert --type cache --cachepool $vg/$lv1
 | 
			
		||||
invalid lvconvert --cache --cachepool $vg/$lv1
 | 
			
		||||
not lvconvert --type cache --cachepool $vg/$lv1
 | 
			
		||||
not lvconvert --cache --cachepool $vg/$lv1
 | 
			
		||||
 | 
			
		||||
# Single vg is required
 | 
			
		||||
invalid lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $vg1/$lv2 $vg/$lv3
 | 
			
		||||
invalid lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $lv2 $vg1/$lv3
 | 
			
		||||
invalid lvconvert --type cache --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2 $vg/$lv3
 | 
			
		||||
invalid lvconvert --type cache-pool --poolmetadata $vg2/$lv2 $vg1/$lv1
 | 
			
		||||
not lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $vg1/$lv2 $vg/$lv3
 | 
			
		||||
not lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $lv2 $vg1/$lv3
 | 
			
		||||
not lvconvert --type cache --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2 $vg/$lv3
 | 
			
		||||
not lvconvert --type cache-pool --poolmetadata $vg2/$lv2 $vg1/$lv1
 | 
			
		||||
 | 
			
		||||
invalid lvconvert --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2
 | 
			
		||||
not lvconvert --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2
 | 
			
		||||
 | 
			
		||||
# Invalid syntax, vg is unknown
 | 
			
		||||
invalid lvconvert --yes --cachepool $lv3 --poolmetadata $lv4
 | 
			
		||||
not lvconvert --yes --cachepool $lv3 --poolmetadata $lv4
 | 
			
		||||
 | 
			
		||||
# Invalid chunk size is <32KiB >1GiB
 | 
			
		||||
invalid lvconvert --type cache-pool --chunksize 16 --poolmetadata $lv2 $vg/$lv1
 | 
			
		||||
invalid lvconvert --type cache-pool --chunksize 2G --poolmetadata $lv2 $vg/$lv1
 | 
			
		||||
not lvconvert --type cache-pool --chunksize 16 --poolmetadata $lv2 $vg/$lv1
 | 
			
		||||
not lvconvert --type cache-pool --chunksize 2G --poolmetadata $lv2 $vg/$lv1
 | 
			
		||||
 | 
			
		||||
# Invalid chunk size is bigger then data size, needs to open VG
 | 
			
		||||
fail lvconvert --yes --type cache-pool --chunksize 16M --poolmetadata $lv2 $vg/$lv1
 | 
			
		||||
not lvconvert --yes --type cache-pool --chunksize 16M --poolmetadata $lv2 $vg/$lv1
 | 
			
		||||
 | 
			
		||||
lvremove -f $vg
 | 
			
		||||
 | 
			
		||||
@@ -143,7 +143,7 @@ lvcreate --type cache-pool -an -v -L 2 -n cpool $vg
 | 
			
		||||
lvcreate -H -L 4 -n corigin --cachepool $vg/cpool
 | 
			
		||||
 | 
			
		||||
# unsupported yet
 | 
			
		||||
fail lvconvert --repair $vg/cpool 2>&1 | tee out
 | 
			
		||||
not lvconvert --repair $vg/cpool 2>&1 | tee out
 | 
			
		||||
#grep "Cannot convert internal LV" out
 | 
			
		||||
 | 
			
		||||
lvremove -f $vg
 | 
			
		||||
@@ -155,13 +155,13 @@ lvcreate --type cache-pool -L10 $vg/$lv1
 | 
			
		||||
lvcreate --cache -L20 $vg/$lv1
 | 
			
		||||
lvcreate -L10 -n $lv2 $vg
 | 
			
		||||
 | 
			
		||||
fail lvconvert --yes --type cache $vg/$lv2 --cachepool $vg/$lv1
 | 
			
		||||
fail lvconvert --yes --type cache $vg/$lv1 --cachepool $vg/$lv2
 | 
			
		||||
fail lvconvert --yes --type cache-pool $vg/$lv1
 | 
			
		||||
fail lvconvert --yes --type mirror -m1 $vg/$lv1
 | 
			
		||||
not lvconvert --yes --type cache $vg/$lv2 --cachepool $vg/$lv1
 | 
			
		||||
not lvconvert --yes --type cache $vg/$lv1 --cachepool $vg/$lv2
 | 
			
		||||
not lvconvert --yes --type cache-pool $vg/$lv1
 | 
			
		||||
not lvconvert --yes --type mirror -m1 $vg/$lv1
 | 
			
		||||
not aux have_raid 1 0 0 || fail lvconvert --yes --type raid1 -m1 $vg/$lv1
 | 
			
		||||
fail lvconvert --yes --type snapshot $vg/$lv1 $vg/$lv2
 | 
			
		||||
fail lvconvert --yes --type snapshot $vg/$lv2 $vg/$lv1
 | 
			
		||||
not lvconvert --yes --type snapshot $vg/$lv1 $vg/$lv2
 | 
			
		||||
not lvconvert --yes --type snapshot $vg/$lv2 $vg/$lv1
 | 
			
		||||
not aux have_thin 1 0 0 || fail lvconvert --yes -T --thinpool $vg/$lv2 $vg/$lv1
 | 
			
		||||
 | 
			
		||||
lvremove -f $vg
 | 
			
		||||
 
 | 
			
		||||
@@ -85,12 +85,9 @@ offset=$(( offset + 2 ))
 | 
			
		||||
# update in case  mirror ever gets faster and allows parallel read
 | 
			
		||||
aux delay_dev "$dev2" 0 2000 ${offset}:1
 | 
			
		||||
lvcreate -aey -l5 -Zn -Wn --type mirror --regionsize 16K -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3:$DEVRANGE"
 | 
			
		||||
# FIXME: add a new explicit option to define the polling behavior
 | 
			
		||||
# done here with 'lvconvert vg/lv'.  That option can specify
 | 
			
		||||
# that the command succeeds even if the LV doesn't need polling.
 | 
			
		||||
should not lvconvert -m-1 $vg/$lv1 "$dev1"
 | 
			
		||||
aux enable_dev "$dev2"
 | 
			
		||||
should lvconvert $vg/$lv1 # wait
 | 
			
		||||
lvconvert --startpoll $vg/$lv1 || true # wait
 | 
			
		||||
lvconvert -m2 $vg/$lv1 "$dev1" "$dev2" "$dev4" "$dev3:0" # If the above "should" failed...
 | 
			
		||||
 | 
			
		||||
aux wait_for_sync $vg $lv1
 | 
			
		||||
@@ -116,7 +113,7 @@ LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
 | 
			
		||||
# Next convert should fail b/c we can't have 2 at once
 | 
			
		||||
should not lvconvert -m+1 $vg/$lv1 "$dev5"
 | 
			
		||||
aux enable_dev "$dev4"
 | 
			
		||||
should lvconvert $vg/$lv1 # wait
 | 
			
		||||
lvconvert --startpoll $vg/$lv1 || true # wait
 | 
			
		||||
lvconvert -m2 $vg/$lv1 # In case the above "should" actually failed
 | 
			
		||||
 | 
			
		||||
check mirror $vg $lv1 "$dev3"
 | 
			
		||||
@@ -159,7 +156,7 @@ lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE
 | 
			
		||||
lvchange -an $vg/$lv1
 | 
			
		||||
lvconvert -m+1 $vg/$lv1 "$dev4"
 | 
			
		||||
lvchange -aey $vg/$lv1
 | 
			
		||||
should lvconvert $vg/$lv1 # wait
 | 
			
		||||
lvconvert --startpoll $vg/$lv1 || true # wait
 | 
			
		||||
check mirror $vg $lv1 "$dev3"
 | 
			
		||||
check mirror_no_temporaries $vg $lv1
 | 
			
		||||
lvremove -ff $vg
 | 
			
		||||
@@ -171,7 +168,7 @@ lvremove -ff $vg
 | 
			
		||||
lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
 | 
			
		||||
LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
 | 
			
		||||
lvconvert -m-1 $vg/$lv1 "$dev4"
 | 
			
		||||
should lvconvert $vg/$lv1 # wait
 | 
			
		||||
lvconvert --startpoll $vg/$lv1 || true # wait
 | 
			
		||||
 | 
			
		||||
check mirror $vg $lv1 "$dev3"
 | 
			
		||||
check mirror_no_temporaries $vg $lv1
 | 
			
		||||
@@ -182,7 +179,7 @@ lvremove -ff $vg
 | 
			
		||||
lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
 | 
			
		||||
LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+2 -b $vg/$lv1 "$dev4" "$dev5"
 | 
			
		||||
lvconvert -m-1 $vg/$lv1 "$dev4"
 | 
			
		||||
should lvconvert $vg/$lv1 # wait
 | 
			
		||||
lvconvert --startpoll $vg/$lv1 || true # wait
 | 
			
		||||
 | 
			
		||||
check mirror $vg $lv1 "$dev3"
 | 
			
		||||
check mirror_no_temporaries $vg $lv1
 | 
			
		||||
@@ -195,9 +192,9 @@ LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
 | 
			
		||||
# FIXME: Extra wait here for mirror upconvert synchronization
 | 
			
		||||
# otherwise we may fail her on parallel upconvert and downconvert
 | 
			
		||||
# lvconvert-mirror-updown.sh tests this errornous case separately
 | 
			
		||||
should lvconvert $vg/$lv1
 | 
			
		||||
lvconvert --startpoll $vg/$lv1 || true
 | 
			
		||||
lvconvert -m-1 $vg/$lv1 "$dev2"
 | 
			
		||||
should lvconvert $vg/$lv1
 | 
			
		||||
lvconvert --startpoll $vg/$lv1 || true
 | 
			
		||||
 | 
			
		||||
check mirror $vg $lv1 "$dev3"
 | 
			
		||||
check mirror_no_temporaries $vg $lv1
 | 
			
		||||
@@ -210,9 +207,9 @@ LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
 | 
			
		||||
# FIXME: Extra wait here for mirror upconvert synchronization
 | 
			
		||||
# otherwise we may fail her on parallel upconvert and downconvert
 | 
			
		||||
# lvconvert-mirror-updown.sh tests this errornous case separately
 | 
			
		||||
should lvconvert $vg/$lv1
 | 
			
		||||
lvconvert --startpoll $vg/$lv1 || true
 | 
			
		||||
lvconvert -m-1 $vg/$lv1 "$dev2"
 | 
			
		||||
should lvconvert $vg/$lv1
 | 
			
		||||
lvconvert --startpoll $vg/$lv1 || true
 | 
			
		||||
 | 
			
		||||
check mirror $vg $lv1 "$dev3"
 | 
			
		||||
check mirror_no_temporaries $vg $lv1
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +45,7 @@ lvchange -an $vg/$lv2 $vg/$lv1 $vg/pool $vg/repair
 | 
			
		||||
 | 
			
		||||
# Manual repair steps:
 | 
			
		||||
# Test swapping - swap out thin-pool's metadata with our repair volume
 | 
			
		||||
lvconvert -y -f --poolmetadata $vg/repair --thinpool $vg/pool
 | 
			
		||||
lvconvert -y -f --swapmetadata --poolmetadata $vg/repair $vg/pool
 | 
			
		||||
 | 
			
		||||
lvchange -ay $vg/repair
 | 
			
		||||
 | 
			
		||||
@@ -74,7 +74,7 @@ not "$LVM_TEST_THIN_DUMP_CMD" "$DM_DEV_DIR/$vg/repair" | tee dump
 | 
			
		||||
lvchange -an $vg
 | 
			
		||||
 | 
			
		||||
# Swap repaired metadata back
 | 
			
		||||
lvconvert -y -f --poolmetadata $vg/fixed --thinpool $vg/pool
 | 
			
		||||
lvconvert -y -f --swapmetadata --poolmetadata $vg/fixed $vg/pool
 | 
			
		||||
 | 
			
		||||
# Check pool still preserves its original settings
 | 
			
		||||
check lv_field $vg/pool chunksize "128.00k"
 | 
			
		||||
@@ -87,7 +87,7 @@ vgchange -ay $vg
 | 
			
		||||
vgchange -an $vg
 | 
			
		||||
 | 
			
		||||
# Put back 'broken' metadata
 | 
			
		||||
lvconvert -y -f --poolmetadata $vg/repair --thinpool $vg/pool
 | 
			
		||||
lvconvert -y -f --swapmetadata --poolmetadata $vg/repair $vg/pool
 | 
			
		||||
 | 
			
		||||
# Check --repair usage
 | 
			
		||||
lvconvert -v --repair $vg/pool
 | 
			
		||||
@@ -98,7 +98,7 @@ lvchange -ay $vg/pool
 | 
			
		||||
vgchange -an $vg
 | 
			
		||||
 | 
			
		||||
# Restore damaged metadata
 | 
			
		||||
lvconvert -y -f --poolmetadata $vg/pool_meta0 --thinpool $vg/pool
 | 
			
		||||
lvconvert -y -f --swapmetadata --poolmetadata $vg/pool_meta0 $vg/pool
 | 
			
		||||
 | 
			
		||||
# Check lvremove -ff works even with damaged pool
 | 
			
		||||
lvremove -ff $vg
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,8 @@ aux wait_for_sync $vg $lv2
 | 
			
		||||
lvchange -an $vg/$lv1
 | 
			
		||||
 | 
			
		||||
# conversion fails for internal volumes
 | 
			
		||||
invalid lvconvert --thinpool $vg/${lv1}_rimage_0
 | 
			
		||||
invalid lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/${lv2}_rimage_0
 | 
			
		||||
not lvconvert --thinpool $vg/${lv1}_rimage_0
 | 
			
		||||
not lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/${lv2}_rimage_0
 | 
			
		||||
 | 
			
		||||
lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -58,13 +58,13 @@ lvchange -an $vg/$lv1
 | 
			
		||||
# conversion fails for mirror segment type
 | 
			
		||||
fail lvconvert --thinpool $vg/$lv1
 | 
			
		||||
# cannot use same LV
 | 
			
		||||
invalid lvconvert --yes --thinpool $vg/$lv2 --poolmetadata $vg/$lv2
 | 
			
		||||
not lvconvert --yes --thinpool $vg/$lv2 --poolmetadata $vg/$lv2
 | 
			
		||||
 | 
			
		||||
prepare_lvs
 | 
			
		||||
 | 
			
		||||
# conversion fails for internal volumes
 | 
			
		||||
# can't use --readahead with --poolmetadata
 | 
			
		||||
invalid lvconvert --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 --readahead 512
 | 
			
		||||
not lvconvert --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 --readahead 512
 | 
			
		||||
lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
 | 
			
		||||
prepare_lvs
 | 
			
		||||
@@ -81,9 +81,9 @@ grep "Pool zeroing and large" err
 | 
			
		||||
UUID=$(get lv_field $vg/$lv2 uuid)
 | 
			
		||||
# Fail is pool is active
 | 
			
		||||
# TODO  maybe detect inactive pool and deactivate
 | 
			
		||||
fail lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2
 | 
			
		||||
fail lvconvert --swapmetadata --yes --poolmetadata $lv2 $vg/$lv1
 | 
			
		||||
lvchange -an $vg
 | 
			
		||||
lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2
 | 
			
		||||
lvconvert --swapmetadata --yes --poolmetadata $lv2 $vg/$lv1
 | 
			
		||||
check lv_field $vg/${lv1}_tmeta uuid "$UUID"
 | 
			
		||||
lvremove -f $vg
 | 
			
		||||
 | 
			
		||||
@@ -96,20 +96,20 @@ lvcreate -L1M -n $lv3 $vg
 | 
			
		||||
# chunk size is bigger then size of thin pool data
 | 
			
		||||
fail lvconvert --yes -c 1G --thinpool $vg/$lv3
 | 
			
		||||
# stripes can't be used with poolmetadata
 | 
			
		||||
invalid lvconvert --stripes 2 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
not lvconvert --stripes 2 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
# too small metadata (<2M)
 | 
			
		||||
fail lvconvert --yes -c 64 --thinpool $vg/$lv1 --poolmetadata $vg/$lv3
 | 
			
		||||
# too small chunk size fails
 | 
			
		||||
invalid lvconvert -c 4 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
not lvconvert -c 4 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
# too big chunk size fails
 | 
			
		||||
invalid lvconvert -c 2G --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
not lvconvert -c 2G --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
# negative chunk size fails
 | 
			
		||||
invalid lvconvert -c -256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
not lvconvert -c -256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
# non multiple of 64KiB fails
 | 
			
		||||
invalid lvconvert -c 88 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
not lvconvert -c 88 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
 | 
			
		||||
 | 
			
		||||
# cannot use same LV for pool and convertion
 | 
			
		||||
invalid lvconvert --yes --thinpool $vg/$lv3 -T $vg/$lv3
 | 
			
		||||
not lvconvert --yes --thinpool $vg/$lv3 -T $vg/$lv3
 | 
			
		||||
 | 
			
		||||
# Warning about smaller then suggested
 | 
			
		||||
lvconvert --yes -c 256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 2>&1 | tee err
 | 
			
		||||
@@ -129,7 +129,7 @@ if test "$TSIZE" = 64T; then
 | 
			
		||||
lvcreate -L24T -n $lv1 $vg
 | 
			
		||||
# Warning about bigger then needed (24T data and 16G -> 128K chunk)
 | 
			
		||||
lvconvert --yes -c 64 --thinpool $vg/$lv1 2>&1 | tee err
 | 
			
		||||
grep "WARNING: Chunk size is too small" err
 | 
			
		||||
grep "too small" err
 | 
			
		||||
lvremove -f $vg
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ fail lvcreate -l 1 --cachepool pool8 $vg
 | 
			
		||||
 | 
			
		||||
# no size specified
 | 
			
		||||
invalid lvcreate --cachepool pool $vg 2>&1 | tee err
 | 
			
		||||
grep "specify either size or extents" err
 | 
			
		||||
# grep "specify either size or extents" err
 | 
			
		||||
 | 
			
		||||
# Check nothing has been created yet
 | 
			
		||||
check vg_field $vg lv_count 0
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ lvchange -an $vg
 | 
			
		||||
 | 
			
		||||
lvcreate -L2M -n $lv1 $vg
 | 
			
		||||
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
 | 
			
		||||
lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
 | 
			
		||||
lvconvert -y --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
 | 
			
		||||
 | 
			
		||||
# Cannot resize if set to 0%
 | 
			
		||||
not lvextend --use-policies --config 'activation{thin_pool_autoextend_percent = 0}' $vg/pool 2>&1 | tee err
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ fake_metadata_ 400 2 >data
 | 
			
		||||
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
 | 
			
		||||
 | 
			
		||||
# Swap volume with restored fake metadata
 | 
			
		||||
lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv1
 | 
			
		||||
lvconvert -y --chunksize 64k --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
 | 
			
		||||
 | 
			
		||||
# Not alllowed when thin-pool metadata free space is <75% for 2M meta
 | 
			
		||||
fail lvcreate -V20 $vg/pool
 | 
			
		||||
@@ -91,7 +91,7 @@ lvchange -an $vg/pool
 | 
			
		||||
fake_metadata_ 7400 2 >data
 | 
			
		||||
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv2"
 | 
			
		||||
# Swap volume with restored fake metadata
 | 
			
		||||
lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv2
 | 
			
		||||
lvconvert -y --chunksize 64k --swapmetadata --poolmetadata $vg/$lv2 $vg/pool
 | 
			
		||||
lvchange -ay $vg/pool
 | 
			
		||||
# Check generated metadata consume more then 88%
 | 
			
		||||
test "$(meta_percent_)" -gt "88"
 | 
			
		||||
@@ -138,7 +138,7 @@ lvchange -an $vg/thin $vg/thin2 $vg/pool
 | 
			
		||||
# Transaction_id is lower by 1 and there are no messages -> ERROR
 | 
			
		||||
fake_metadata_ 10 0 >data
 | 
			
		||||
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
 | 
			
		||||
lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
 | 
			
		||||
lvconvert -y --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
 | 
			
		||||
not vgchange -ay $vg 2>&1 | tee out
 | 
			
		||||
grep expected out
 | 
			
		||||
 | 
			
		||||
@@ -147,7 +147,7 @@ check inactive $vg pool_tmeta
 | 
			
		||||
# Transaction_id is higher by 1
 | 
			
		||||
fake_metadata_ 10 3 >data
 | 
			
		||||
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
 | 
			
		||||
lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
 | 
			
		||||
lvconvert -y --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
 | 
			
		||||
not vgchange -ay $vg 2>&1 | tee out
 | 
			
		||||
grep expected out
 | 
			
		||||
 | 
			
		||||
@@ -158,7 +158,7 @@ fake_metadata_ 400 2 >data
 | 
			
		||||
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
 | 
			
		||||
 | 
			
		||||
# Swap volume with restored fake metadata
 | 
			
		||||
lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv1
 | 
			
		||||
lvconvert -y --chunksize 64k --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
 | 
			
		||||
 | 
			
		||||
vgchange -ay $vg
 | 
			
		||||
 | 
			
		||||
@@ -173,7 +173,7 @@ fake_metadata_ 350 2 >data
 | 
			
		||||
lvchange -ay $vg/$lv1
 | 
			
		||||
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
 | 
			
		||||
 | 
			
		||||
lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv1
 | 
			
		||||
lvconvert -y --chunksize 64k --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
 | 
			
		||||
lvchange -ay $vg/pool  $vg/$lv1
 | 
			
		||||
lvs -a $vg
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ mkdir test_mnt
 | 
			
		||||
 | 
			
		||||
setup_merge_ $vg1 $lv1
 | 
			
		||||
mount "$(lvdev_ $vg1 $lv1)" test_mnt
 | 
			
		||||
lvconvert --merge $vg1/$(snap_lv_name_ $lv1)
 | 
			
		||||
lvconvert --mergesnapshot $vg1/$(snap_lv_name_ $lv1)
 | 
			
		||||
umount test_mnt
 | 
			
		||||
vgchange -an $vg1
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ snap_and_merge() {
 | 
			
		||||
	SLEEP_PID=$!
 | 
			
		||||
 | 
			
		||||
	# initiate background merge
 | 
			
		||||
	lvconvert -b --merge $vg/$lv2
 | 
			
		||||
	lvconvert -b --mergesnapshot $vg/$lv2
 | 
			
		||||
 | 
			
		||||
	lvs -a -o+lv_merging,lv_merge_failed $vg
 | 
			
		||||
	get lv_field $vg/$lv1 lv_attr | grep "Owi-ao"
 | 
			
		||||
 
 | 
			
		||||
@@ -51,15 +51,15 @@ mkdir test_mnt
 | 
			
		||||
# test full merge of a single LV
 | 
			
		||||
setup_merge_ $vg $lv1
 | 
			
		||||
 | 
			
		||||
# make sure lvconvert --merge requires explicit LV listing
 | 
			
		||||
not lvconvert --merge
 | 
			
		||||
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
# make sure lvconvert --mergesnapshot requires explicit LV listing
 | 
			
		||||
not lvconvert --mergesnapshot
 | 
			
		||||
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
lvremove -f $vg/$lv1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# test that an actively merging snapshot may not be removed
 | 
			
		||||
setup_merge_ $vg $lv1
 | 
			
		||||
lvconvert -i+100 --merge --background $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
lvconvert -i+100 --mergesnapshot --background $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
not lvremove -f $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
lvremove -f $vg/$lv1
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +67,7 @@ lvremove -f $vg/$lv1
 | 
			
		||||
# "onactivate merge" test
 | 
			
		||||
setup_merge_ $vg $lv1
 | 
			
		||||
mount "$(lvdev_ $vg $lv1)" test_mnt
 | 
			
		||||
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
# -- refresh LV while FS is still mounted (merge must not start),
 | 
			
		||||
#    verify 'snapshot-origin' target is still being used
 | 
			
		||||
lvchange --refresh $vg/$lv1
 | 
			
		||||
@@ -88,7 +88,7 @@ lvremove -f $vg/$lv1
 | 
			
		||||
#    to make sure preload of origin's metadata is _not_ performed
 | 
			
		||||
setup_merge_ $vg $lv1
 | 
			
		||||
mount "$(lvdev_ $vg $lv1)" test_mnt
 | 
			
		||||
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
# -- refresh LV while FS is still mounted (merge must not start),
 | 
			
		||||
#    verify 'snapshot-origin' target is still being used
 | 
			
		||||
lvchange --refresh $vg/$lv1
 | 
			
		||||
@@ -99,7 +99,7 @@ lvremove -f $vg/$lv1
 | 
			
		||||
 | 
			
		||||
# test multiple snapshot merge; tests copy out that is driven by merge
 | 
			
		||||
setup_merge_ $vg $lv1 1
 | 
			
		||||
lvconvert --merge $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
lvconvert --mergesnapshot $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
lvremove -f $vg/$lv1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -108,7 +108,7 @@ setup_merge_ $vg $lv1
 | 
			
		||||
setup_merge_ $vg $lv2
 | 
			
		||||
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv1)
 | 
			
		||||
lvchange --addtag this_is_a_test $vg/$(snap_lv_name_ $lv2)
 | 
			
		||||
lvconvert --merge @this_is_a_test
 | 
			
		||||
lvconvert --mergesnapshot @this_is_a_test
 | 
			
		||||
lvs $vg | tee out
 | 
			
		||||
not grep $(snap_lv_name_ $lv1) out
 | 
			
		||||
not grep $(snap_lv_name_ $lv2) out
 | 
			
		||||
 
 | 
			
		||||
@@ -71,7 +71,7 @@ aux prepare_thin_metadata 490 1 | tee data
 | 
			
		||||
"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
 | 
			
		||||
 | 
			
		||||
# Swap volume with restored fake metadata
 | 
			
		||||
lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
 | 
			
		||||
lvconvert -y --swapmetadata --poolmetadata $vg/$lv1 $vg/pool
 | 
			
		||||
 | 
			
		||||
lvchange -ay $vg
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,7 +44,7 @@ touch mntsnap/test_snap
 | 
			
		||||
 | 
			
		||||
lvs -o+tags,thin_id $vg
 | 
			
		||||
 | 
			
		||||
lvconvert --merge $vg/snap
 | 
			
		||||
lvconvert --mergethin $vg/snap
 | 
			
		||||
 | 
			
		||||
umount mnt
 | 
			
		||||
 | 
			
		||||
@@ -102,12 +102,12 @@ lvcreate -s -n snap $vg/$lv1
 | 
			
		||||
lvcreate -s -L10 -n oldsnapof_${lv1} $vg/$lv1
 | 
			
		||||
not lvconvert --merge $vg/snap
 | 
			
		||||
$MKFS "$DM_DEV_DIR/$vg/oldsnapof_${lv1}"
 | 
			
		||||
lvconvert --merge $vg/oldsnapof_${lv1}
 | 
			
		||||
lvconvert --mergesnapshot $vg/oldsnapof_${lv1}
 | 
			
		||||
fsck -n "$DM_DEV_DIR/$vg/$lv1"
 | 
			
		||||
check lv_not_exists $vg oldsnapof_${lv1}
 | 
			
		||||
# Add old snapshot to thin snapshot
 | 
			
		||||
lvcreate -s -L10 -n oldsnapof_snap $vg/snap
 | 
			
		||||
lvconvert --merge $vg/snap
 | 
			
		||||
lvconvert --mergethin $vg/snap
 | 
			
		||||
lvremove -f $vg/oldsnapof_snap
 | 
			
		||||
 | 
			
		||||
vgremove -ff $vg
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ mount "$DM_DEV_DIR/$vg/$lv1" mnt
 | 
			
		||||
lvcreate -s -n snap $vg/$lv1
 | 
			
		||||
check lv_field $vg/snap thin_id "3"
 | 
			
		||||
 | 
			
		||||
lvconvert --merge $vg/snap
 | 
			
		||||
lvconvert --mergethin $vg/snap
 | 
			
		||||
 | 
			
		||||
umount mnt
 | 
			
		||||
vgchange -an $vg
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@ lvcreate -l 1 -n lv1 $vg "$dev1"
 | 
			
		||||
invalid vgextend
 | 
			
		||||
# --metadatacopies => use --pvmetadatacopies
 | 
			
		||||
invalid vgextend --metadatacopies 3 $vg "$dev1" 2>&1 | tee out
 | 
			
		||||
grep -- "use --pvmetadatacopies" out
 | 
			
		||||
 | 
			
		||||
# VG name should exist
 | 
			
		||||
fail vgextend --restoremissing $vg-invalid "$dev1"
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,9 @@ SOURCES =\
 | 
			
		||||
	formats.c \
 | 
			
		||||
	lvchange.c \
 | 
			
		||||
	lvconvert.c \
 | 
			
		||||
	lvconvert_pool.c \
 | 
			
		||||
	lvconvert_snapshot.c \
 | 
			
		||||
	lvconvert_other.c \
 | 
			
		||||
	lvconvert_poll.c \
 | 
			
		||||
	lvcreate.c \
 | 
			
		||||
	lvdisplay.c \
 | 
			
		||||
@@ -76,6 +79,7 @@ SOURCES2 =\
 | 
			
		||||
 | 
			
		||||
TARGETS =\
 | 
			
		||||
	.commands \
 | 
			
		||||
	command-lines.h \
 | 
			
		||||
	liblvm2cmd.a \
 | 
			
		||||
	lvm
 | 
			
		||||
 | 
			
		||||
@@ -99,7 +103,8 @@ LIB_VERSION = $(LIB_VERSION_LVM)
 | 
			
		||||
CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \
 | 
			
		||||
	liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION) lvm-static.o \
 | 
			
		||||
	liblvm2cmd-static.a dmsetup.static lvm.static \
 | 
			
		||||
	$(LDDEPS) .exported_symbols_generated
 | 
			
		||||
	$(LDDEPS) .exported_symbols_generated \
 | 
			
		||||
	ccmd command-lines.h command-lines-count.h
 | 
			
		||||
 | 
			
		||||
ifeq ("@CMDLIB@", "yes")
 | 
			
		||||
	TARGETS += liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION)
 | 
			
		||||
@@ -171,6 +176,13 @@ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX)
 | 
			
		||||
	$(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \
 | 
			
		||||
		egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands
 | 
			
		||||
 | 
			
		||||
ccmd: create-commands.c
 | 
			
		||||
	$(CC) create-commands.c -o ccmd
 | 
			
		||||
 | 
			
		||||
command-lines.h: ccmd
 | 
			
		||||
	./ccmd --output struct command-lines.in > command-lines.h
 | 
			
		||||
	./ccmd --output count command-lines.in > command-lines-count.h
 | 
			
		||||
 | 
			
		||||
ifneq ("$(CFLOW_CMD)", "")
 | 
			
		||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
 | 
			
		||||
-include $(top_builddir)/libdm/libdevmapper.cflow
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										412
									
								
								tools/args.h
									
									
									
									
									
								
							
							
						
						
									
										412
									
								
								tools/args.h
									
									
									
									
									
								
							@@ -17,215 +17,221 @@
 | 
			
		||||
 * Put all long args that don't have a corresponding short option first.
 | 
			
		||||
 */
 | 
			
		||||
/* *INDENT-OFF* */
 | 
			
		||||
arg(abort_ARG, '\0', "abort", NULL, 0, 0)
 | 
			
		||||
arg(activationmode_ARG, '\0', "activationmode", string_arg, 0, 0)
 | 
			
		||||
arg(addtag_ARG, '\0', "addtag", tag_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(aligned_ARG, '\0', "aligned", NULL, 0, 0)
 | 
			
		||||
arg(alloc_ARG, '\0', "alloc", alloc_arg, 0, 0)
 | 
			
		||||
arg(atomic_ARG, '\0', "atomic", NULL, 0, 0)
 | 
			
		||||
arg(atversion_ARG, '\0', "atversion", string_arg, 0, 0)
 | 
			
		||||
arg(binary_ARG, '\0', "binary", NULL, 0, 0)
 | 
			
		||||
arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", size_mb_arg, 0, 0)
 | 
			
		||||
arg(cache_long_ARG, '\0', "cache", NULL, 0, 0)
 | 
			
		||||
arg(cachemode_ARG, '\0', "cachemode", cachemode_arg, 0, 0)
 | 
			
		||||
arg(cachepool_ARG, '\0', "cachepool", string_arg, 0, 0)
 | 
			
		||||
arg(commandprofile_ARG, '\0', "commandprofile", string_arg, 0, 0)
 | 
			
		||||
arg(config_ARG, '\0', "config", string_arg, 0, 0)
 | 
			
		||||
arg(configreport_ARG, '\0', "configreport", string_arg, ARG_GROUPABLE, 1)
 | 
			
		||||
arg(configtype_ARG, '\0', "type", string_arg, 0, 0)
 | 
			
		||||
arg(corelog_ARG, '\0', "corelog", NULL, 0, 0)
 | 
			
		||||
arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0, 0)
 | 
			
		||||
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0, 0)
 | 
			
		||||
arg(deltag_ARG, '\0', "deltag", tag_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(detachprofile_ARG, '\0', "detachprofile", NULL, 0, 0)
 | 
			
		||||
arg(discards_ARG, '\0', "discards", discards_arg, 0, 0)
 | 
			
		||||
arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg, 0, 0)
 | 
			
		||||
arg(errorwhenfull_ARG, '\0', "errorwhenfull", yes_no_arg, 0, 0)
 | 
			
		||||
arg(force_long_ARG, '\0', "force", NULL, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(foreign_ARG, '\0', "foreign", NULL, 0, 0)
 | 
			
		||||
arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", NULL, 0, 0)
 | 
			
		||||
arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", NULL, 0, 0)
 | 
			
		||||
arg(ignorelocal_ARG, '\0', "ignorelocal", NULL, 0, 0)
 | 
			
		||||
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL, 0, 0)
 | 
			
		||||
arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0, 0)
 | 
			
		||||
arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", NULL, 0, 0)
 | 
			
		||||
arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", NULL, 0, 0)
 | 
			
		||||
arg(labelsector_ARG, '\0', "labelsector", int_arg, 0, 0)
 | 
			
		||||
arg(lockopt_ARG, '\0', "lockopt", string_arg, 0, 0)
 | 
			
		||||
arg(lockstart_ARG, '\0', "lockstart", NULL, 0, 0)
 | 
			
		||||
arg(lockstop_ARG, '\0', "lockstop", NULL, 0, 0)
 | 
			
		||||
arg(locktype_ARG, '\0', "locktype", locktype_arg, 0, 0)
 | 
			
		||||
arg(logonly_ARG, '\0', "logonly", NULL, 0, 0)
 | 
			
		||||
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", size_kb_arg, 0, 0)
 | 
			
		||||
arg(merge_ARG, '\0', "merge", NULL, 0, 0)
 | 
			
		||||
arg(mergedconfig_ARG, '\0', "mergedconfig", NULL, 0, 0)
 | 
			
		||||
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_arg, 0, 0)
 | 
			
		||||
arg(metadataignore_ARG, '\0', "metadataignore", yes_no_arg, 0, 0)
 | 
			
		||||
arg(metadataprofile_ARG, '\0', "metadataprofile", string_arg, 0, 0)
 | 
			
		||||
arg(metadatasize_ARG, '\0', "metadatasize", size_mb_arg, 0, 0)
 | 
			
		||||
arg(minor_ARG, '\0', "minor", int_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", size_kb_arg, 0, 0)
 | 
			
		||||
arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_arg, 0, 0)
 | 
			
		||||
arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL, 0, 0)
 | 
			
		||||
arg(mknodes_ARG, '\0', "mknodes", NULL, 0, 0)
 | 
			
		||||
arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0, 0)
 | 
			
		||||
arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0, 0)
 | 
			
		||||
arg(noheadings_ARG, '\0', "noheadings", NULL, 0, 0)
 | 
			
		||||
arg(nohistory_ARG, '\0', "nohistory", NULL, 0, 0)
 | 
			
		||||
arg(nolocking_ARG, '\0', "nolocking", NULL, 0, 0)
 | 
			
		||||
arg(norestorefile_ARG, '\0', "norestorefile", NULL, 0, 0)
 | 
			
		||||
arg(nosuffix_ARG, '\0', "nosuffix", NULL, 0, 0)
 | 
			
		||||
arg(nosync_ARG, '\0', "nosync", NULL, 0, 0)
 | 
			
		||||
arg(notifydbus_ARG, '\0', "notifydbus", NULL, 0, 0)
 | 
			
		||||
arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0, 0)
 | 
			
		||||
arg(originname_ARG, '\0', "originname", string_arg, 0, 0)
 | 
			
		||||
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_mb_arg, 0, 0)
 | 
			
		||||
arg(poll_ARG, '\0', "poll", yes_no_arg, 0, 0)
 | 
			
		||||
arg(polloperation_ARG, '\0', "polloperation", string_arg, 0, 0)
 | 
			
		||||
arg(pooldatasize_ARG, '\0', "pooldatasize", size_mb_arg, 0, 0)
 | 
			
		||||
arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0, 0)
 | 
			
		||||
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0, 0)
 | 
			
		||||
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", yes_no_arg, 0, 0)
 | 
			
		||||
arg(profile_ARG, '\0', "profile", string_arg, 0, 0)
 | 
			
		||||
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", int_arg, 0, 0)
 | 
			
		||||
arg(raidrebuild_ARG, '\0', "raidrebuild", string_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", size_kb_arg, 0, 0)
 | 
			
		||||
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", size_kb_arg, 0, 0)
 | 
			
		||||
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_arg, 0, 0)
 | 
			
		||||
arg(raidwritebehind_ARG, '\0', "raidwritebehind", int_arg, 0, 0)
 | 
			
		||||
arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(readonly_ARG, '\0', "readonly", NULL, 0, 0)
 | 
			
		||||
arg(refresh_ARG, '\0', "refresh", NULL, 0, 0)
 | 
			
		||||
arg(removemissing_ARG, '\0', "removemissing", NULL, 0, 0)
 | 
			
		||||
arg(rebuild_ARG, '\0', "rebuild", string_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(repair_ARG, '\0', "repair", NULL, 0, 0)
 | 
			
		||||
arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(reportformat_ARG, '\0', "reportformat", string_arg, 0, 0)
 | 
			
		||||
arg(restorefile_ARG, '\0', "restorefile", string_arg, 0, 0)
 | 
			
		||||
arg(restoremissing_ARG, '\0', "restoremissing", NULL, 0, 0)
 | 
			
		||||
arg(resync_ARG, '\0', "resync", NULL, 0, 0)
 | 
			
		||||
arg(rows_ARG, '\0', "rows", NULL, 0, 0)
 | 
			
		||||
arg(segments_ARG, '\0', "segments", NULL, 0, 0)
 | 
			
		||||
arg(separator_ARG, '\0', "separator", string_arg, 0, 0)
 | 
			
		||||
arg(shared_ARG, '\0', "shared", NULL, 0, 0)
 | 
			
		||||
arg(sinceversion_ARG, '\0', "sinceversion", string_arg, 0, 0)
 | 
			
		||||
arg(split_ARG, '\0', "split", NULL, 0, 0)
 | 
			
		||||
arg(splitcache_ARG, '\0', "splitcache", NULL, 0, 0)
 | 
			
		||||
arg(splitmirrors_ARG, '\0', "splitmirrors", int_arg, 0, 0)
 | 
			
		||||
arg(splitsnapshot_ARG, '\0', "splitsnapshot", NULL, 0, 0)
 | 
			
		||||
arg(showdeprecated_ARG, '\0', "showdeprecated", NULL, 0, 0)
 | 
			
		||||
arg(showunsupported_ARG, '\0', "showunsupported", NULL, 0, 0)
 | 
			
		||||
arg(stripes_long_ARG, '\0', "stripes", int_arg, 0, 0)
 | 
			
		||||
arg(syncaction_ARG, '\0', "syncaction", string_arg, 0, 0)	/* FIXME Use custom validation fn */
 | 
			
		||||
arg(sysinit_ARG, '\0', "sysinit", NULL, 0, 0)
 | 
			
		||||
arg(systemid_ARG, '\0', "systemid", string_arg, 0, 0)
 | 
			
		||||
arg(thinpool_ARG, '\0', "thinpool", string_arg, 0, 0)
 | 
			
		||||
arg(trackchanges_ARG, '\0', "trackchanges", NULL, 0, 0)
 | 
			
		||||
arg(trustcache_ARG, '\0', "trustcache", NULL, 0, 0)
 | 
			
		||||
arg(type_ARG, '\0', "type", segtype_arg, 0, 0)
 | 
			
		||||
arg(unbuffered_ARG, '\0', "unbuffered", NULL, 0, 0)
 | 
			
		||||
arg(uncache_ARG, '\0', "uncache", NULL, 0, 0)
 | 
			
		||||
arg(cachepolicy_ARG, '\0', "cachepolicy", string_arg, 0, 0)
 | 
			
		||||
arg(cachesettings_ARG, '\0', "cachesettings", string_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(unconfigured_ARG, '\0', "unconfigured", NULL, 0, 0)
 | 
			
		||||
arg(units_ARG, '\0', "units", string_arg, 0, 0)
 | 
			
		||||
arg(unquoted_ARG, '\0', "unquoted", NULL, 0, 0)
 | 
			
		||||
arg(usepolicies_ARG, '\0', "usepolicies", NULL, 0, 0)
 | 
			
		||||
arg(validate_ARG, '\0', "validate", NULL, 0, 0)
 | 
			
		||||
arg(version_ARG, '\0', "version", NULL, 0, 0)
 | 
			
		||||
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", metadatacopies_arg, 0, 0)
 | 
			
		||||
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0, 0)
 | 
			
		||||
arg(withsummary_ARG, '\0', "withsummary", NULL, 0, 0)
 | 
			
		||||
arg(withcomments_ARG, '\0', "withcomments", NULL, 0, 0)
 | 
			
		||||
arg(withspaces_ARG, '\0', "withspaces", NULL, 0, 0)
 | 
			
		||||
arg(withversions_ARG, '\0', "withversions", NULL, 0, 0)
 | 
			
		||||
arg(writebehind_ARG, '\0', "writebehind", int_arg, 0, 0)
 | 
			
		||||
arg(writemostly_ARG, '\0', "writemostly", string_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(ARG_UNUSED, '-', "", 0, 0, 0)  /* place holder for unused 0 value */
 | 
			
		||||
 | 
			
		||||
arg(abort_ARG, '\0', "abort", 0, 0, 0)
 | 
			
		||||
arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0)
 | 
			
		||||
arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(aligned_ARG, '\0', "aligned", 0, 0, 0)
 | 
			
		||||
arg(alloc_ARG, '\0', "alloc", alloc_VAL, 0, 0)
 | 
			
		||||
arg(atomic_ARG, '\0', "atomic", 0, 0, 0)
 | 
			
		||||
arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0)
 | 
			
		||||
arg(binary_ARG, '\0', "binary", 0, 0, 0)
 | 
			
		||||
arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(cache_long_ARG, '\0', "cache", 0, 0, 0)
 | 
			
		||||
arg(cachemode_ARG, '\0', "cachemode", cachemode_VAL, 0, 0)
 | 
			
		||||
arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0)
 | 
			
		||||
arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0)
 | 
			
		||||
arg(config_ARG, '\0', "config", string_VAL, 0, 0)
 | 
			
		||||
arg(configreport_ARG, '\0', "configreport", configreport_VAL, ARG_GROUPABLE, 1)
 | 
			
		||||
arg(configtype_ARG, '\0', "typeconfig", configtype_VAL, 0, 0)
 | 
			
		||||
arg(corelog_ARG, '\0', "corelog", 0, 0, 0)
 | 
			
		||||
arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0)
 | 
			
		||||
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0)
 | 
			
		||||
arg(deltag_ARG, '\0', "deltag", tag_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(detachprofile_ARG, '\0', "detachprofile", 0, 0, 0)
 | 
			
		||||
arg(discards_ARG, '\0', "discards", discards_VAL, 0, 0)
 | 
			
		||||
arg(driverloaded_ARG, '\0', "driverloaded", bool_VAL, 0, 0)
 | 
			
		||||
arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0)
 | 
			
		||||
arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(foreign_ARG, '\0', "foreign", 0, 0, 0)
 | 
			
		||||
arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0)
 | 
			
		||||
arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0)
 | 
			
		||||
arg(ignorelocal_ARG, '\0', "ignorelocal", 0, 0, 0)
 | 
			
		||||
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", 0, 0, 0)
 | 
			
		||||
arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", 0, 0, 0)
 | 
			
		||||
arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", 0, 0, 0)
 | 
			
		||||
arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0)
 | 
			
		||||
arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0)
 | 
			
		||||
arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0)
 | 
			
		||||
arg(lockstart_ARG, '\0', "lockstart", 0, 0, 0)
 | 
			
		||||
arg(lockstop_ARG, '\0', "lockstop", 0, 0, 0)
 | 
			
		||||
arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0)
 | 
			
		||||
arg(logonly_ARG, '\0', "logonly", 0, 0, 0)
 | 
			
		||||
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0)
 | 
			
		||||
arg(merge_ARG, '\0', "merge", 0, 0, 0)
 | 
			
		||||
arg(mergemirrors_ARG, '\0', "mergemirrors", 0, 0, 0)
 | 
			
		||||
arg(mergesnapshot_ARG, '\0', "mergesnapshot", 0, 0, 0)
 | 
			
		||||
arg(mergethin_ARG, '\0', "mergethin", 0, 0, 0)
 | 
			
		||||
arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0)
 | 
			
		||||
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0)
 | 
			
		||||
arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0)
 | 
			
		||||
arg(metadataprofile_ARG, '\0', "metadataprofile", string_VAL, 0, 0)
 | 
			
		||||
arg(metadatasize_ARG, '\0', "metadatasize", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(minor_ARG, '\0', "minor", number_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", sizekb_VAL, 0, 0)
 | 
			
		||||
arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_VAL, 0, 0)
 | 
			
		||||
arg(mirrorsonly_ARG, '\0', "mirrorsonly", 0, 0, 0)
 | 
			
		||||
arg(mknodes_ARG, '\0', "mknodes", 0, 0, 0)
 | 
			
		||||
arg(monitor_ARG, '\0', "monitor", bool_VAL, 0, 0)
 | 
			
		||||
arg(nameprefixes_ARG, '\0', "nameprefixes", 0, 0, 0)
 | 
			
		||||
arg(noheadings_ARG, '\0', "noheadings", 0, 0, 0)
 | 
			
		||||
arg(nohistory_ARG, '\0', "nohistory", 0, 0, 0)
 | 
			
		||||
arg(nolocking_ARG, '\0', "nolocking", 0, 0, 0)
 | 
			
		||||
arg(norestorefile_ARG, '\0', "norestorefile", 0, 0, 0)
 | 
			
		||||
arg(nosuffix_ARG, '\0', "nosuffix", 0, 0, 0)
 | 
			
		||||
arg(nosync_ARG, '\0', "nosync", 0, 0, 0)
 | 
			
		||||
arg(notifydbus_ARG, '\0', "notifydbus", 0, 0, 0)
 | 
			
		||||
arg(noudevsync_ARG, '\0', "noudevsync", 0, 0, 0)
 | 
			
		||||
arg(originname_ARG, '\0', "originname", lv_VAL, 0, 0)
 | 
			
		||||
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0)
 | 
			
		||||
arg(polloperation_ARG, '\0', "polloperation", polloperation_VAL, 0, 0)
 | 
			
		||||
arg(pooldatasize_ARG, '\0', "pooldatasize", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(poolmetadata_ARG, '\0', "poolmetadata", lv_VAL, 0, 0)
 | 
			
		||||
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", bool_VAL, 0, 0)
 | 
			
		||||
arg(profile_ARG, '\0', "profile", string_VAL, 0, 0)
 | 
			
		||||
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", pvmetadatacopies_VAL, 0, 0)
 | 
			
		||||
arg(raidrebuild_ARG, '\0', "raidrebuild", pv_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", sizekb_VAL, 0, 0)
 | 
			
		||||
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", sizekb_VAL, 0, 0)
 | 
			
		||||
arg(raidsyncaction_ARG, '\0', "raidsyncaction", syncaction_VAL, 0, 0)
 | 
			
		||||
arg(raidwritebehind_ARG, '\0', "raidwritebehind", number_VAL, 0, 0)
 | 
			
		||||
arg(raidwritemostly_ARG, '\0', "raidwritemostly", writemostly_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(readonly_ARG, '\0', "readonly", 0, 0, 0)
 | 
			
		||||
arg(refresh_ARG, '\0', "refresh", 0, 0, 0)
 | 
			
		||||
arg(removemissing_ARG, '\0', "removemissing", 0, 0, 0)
 | 
			
		||||
arg(rebuild_ARG, '\0', "rebuild", pv_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(repair_ARG, '\0', "repair", 0, 0, 0)
 | 
			
		||||
arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(reportformat_ARG, '\0', "reportformat", reportformat_VAL, 0, 0)
 | 
			
		||||
arg(restorefile_ARG, '\0', "restorefile", string_VAL, 0, 0)
 | 
			
		||||
arg(restoremissing_ARG, '\0', "restoremissing", 0, 0, 0)
 | 
			
		||||
arg(resync_ARG, '\0', "resync", 0, 0, 0)
 | 
			
		||||
arg(rows_ARG, '\0', "rows", 0, 0, 0)
 | 
			
		||||
arg(segments_ARG, '\0', "segments", 0, 0, 0)
 | 
			
		||||
arg(separator_ARG, '\0', "separator", string_VAL, 0, 0)
 | 
			
		||||
arg(shared_ARG, '\0', "shared", 0, 0, 0)
 | 
			
		||||
arg(sinceversion_ARG, '\0', "sinceversion", string_VAL, 0, 0)
 | 
			
		||||
arg(split_ARG, '\0', "split", 0, 0, 0)
 | 
			
		||||
arg(splitcache_ARG, '\0', "splitcache", 0, 0, 0)
 | 
			
		||||
arg(splitmirrors_ARG, '\0', "splitmirrors", number_VAL, 0, 0)
 | 
			
		||||
arg(splitsnapshot_ARG, '\0', "splitsnapshot", 0, 0, 0)
 | 
			
		||||
arg(showdeprecated_ARG, '\0', "showdeprecated", 0, 0, 0)
 | 
			
		||||
arg(showunsupported_ARG, '\0', "showunsupported", 0, 0, 0)
 | 
			
		||||
arg(startpoll_ARG, '\0', "startpoll", 0, 0, 0)
 | 
			
		||||
arg(stripes_long_ARG, '\0', "stripes", number_VAL, 0, 0)
 | 
			
		||||
arg(swapmetadata_ARG, '\0', "swapmetadata", 0, 0, 0)
 | 
			
		||||
arg(syncaction_ARG, '\0', "syncaction", syncaction_VAL, 0, 0)
 | 
			
		||||
arg(sysinit_ARG, '\0', "sysinit", 0, 0, 0)
 | 
			
		||||
arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0)
 | 
			
		||||
arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0)
 | 
			
		||||
arg(trackchanges_ARG, '\0', "trackchanges", 0, 0, 0)
 | 
			
		||||
arg(trustcache_ARG, '\0', "trustcache", 0, 0, 0)
 | 
			
		||||
arg(type_ARG, '\0', "type", segtype_VAL, 0, 0)
 | 
			
		||||
arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0)
 | 
			
		||||
arg(uncache_ARG, '\0', "uncache", 0, 0, 0)
 | 
			
		||||
arg(cachepolicy_ARG, '\0', "cachepolicy", string_VAL, 0, 0)
 | 
			
		||||
arg(cachesettings_ARG, '\0', "cachesettings", string_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(unconfigured_ARG, '\0', "unconfigured", 0, 0, 0)
 | 
			
		||||
arg(units_ARG, '\0', "units", units_VAL, 0, 0)
 | 
			
		||||
arg(unquoted_ARG, '\0', "unquoted", 0, 0, 0)
 | 
			
		||||
arg(usepolicies_ARG, '\0', "usepolicies", 0, 0, 0)
 | 
			
		||||
arg(validate_ARG, '\0', "validate", 0, 0, 0)
 | 
			
		||||
arg(version_ARG, '\0', "version", 0, 0, 0)
 | 
			
		||||
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0)
 | 
			
		||||
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0)
 | 
			
		||||
arg(withcomments_ARG, '\0', "withcomments", 0, 0, 0)
 | 
			
		||||
arg(withspaces_ARG, '\0', "withspaces", 0, 0, 0)
 | 
			
		||||
arg(withversions_ARG, '\0', "withversions", 0, 0, 0)
 | 
			
		||||
arg(writebehind_ARG, '\0', "writebehind", number_VAL, 0, 0)
 | 
			
		||||
arg(writemostly_ARG, '\0', "writemostly", writemostly_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
 | 
			
		||||
/* Allow some variations */
 | 
			
		||||
arg(allocation_ARG, '\0', "allocation", yes_no_arg, 0, 0)
 | 
			
		||||
arg(available_ARG, '\0', "available", activation_arg, 0, 0)
 | 
			
		||||
arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0, 0)
 | 
			
		||||
arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0)
 | 
			
		||||
arg(available_ARG, '\0', "available", activation_VAL, 0, 0)
 | 
			
		||||
arg(resizable_ARG, '\0', "resizable", bool_VAL, 0, 0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ... and now the short args.
 | 
			
		||||
 */
 | 
			
		||||
arg(activate_ARG, 'a', "activate", activation_arg, 0, 0)
 | 
			
		||||
arg(all_ARG, 'a', "all", NULL, 0, 0)
 | 
			
		||||
arg(autobackup_ARG, 'A', "autobackup", yes_no_arg, 0, 0)
 | 
			
		||||
arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL, 0, 0)
 | 
			
		||||
arg(background_ARG, 'b', "background", NULL, 0, 0)
 | 
			
		||||
arg(backgroundfork_ARG, 'b', "background", NULL, 0, 0)
 | 
			
		||||
arg(basevgname_ARG, 'n', "basevgname", string_arg, 0, 0)
 | 
			
		||||
arg(blockdevice_ARG, 'b', "blockdevice", NULL, 0, 0)
 | 
			
		||||
arg(chunksize_ARG, 'c', "chunksize", size_kb_arg, 0, 0)
 | 
			
		||||
arg(clustered_ARG, 'c', "clustered", yes_no_arg, 0, 0)
 | 
			
		||||
arg(colon_ARG, 'c', "colon", NULL, 0, 0)
 | 
			
		||||
arg(columns_ARG, 'C', "columns", NULL, 0, 0)
 | 
			
		||||
arg(contiguous_ARG, 'C', "contiguous", yes_no_arg, 0, 0)
 | 
			
		||||
arg(debug_ARG, 'd', "debug", NULL, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(exported_ARG, 'e', "exported", NULL, 0, 0)
 | 
			
		||||
arg(physicalextent_ARG, 'E', "physicalextent", NULL, 0, 0)
 | 
			
		||||
arg(file_ARG, 'f', "file", string_arg, 0, 0)
 | 
			
		||||
arg(force_ARG, 'f', "force", NULL, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(full_ARG, 'f', "full", NULL, 0, 0)
 | 
			
		||||
arg(help_ARG, 'h', "help", NULL, 0, 0)
 | 
			
		||||
arg(cache_ARG, 'H', "cache", NULL, 0, 0)
 | 
			
		||||
arg(history_ARG, 'H', "history", NULL, 0, 0)
 | 
			
		||||
arg(help2_ARG, '?', "", NULL, 0, 0)
 | 
			
		||||
arg(import_ARG, 'i', "import", NULL, 0, 0)
 | 
			
		||||
arg(interval_ARG, 'i', "interval", int_arg, 0, 0)
 | 
			
		||||
arg(iop_version_ARG, 'i', "iop_version", NULL, 0, 0)
 | 
			
		||||
arg(stripes_ARG, 'i', "stripes", int_arg, 0, 0)
 | 
			
		||||
arg(stripesize_ARG, 'I', "stripesize", size_kb_arg, 0, 0)
 | 
			
		||||
arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg, 0, 0)
 | 
			
		||||
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg, 0, 0)
 | 
			
		||||
arg(extents_ARG, 'l', "extents", int_arg_with_sign_and_percent, 0, 0)
 | 
			
		||||
arg(list_ARG, 'l', "list", NULL, 0, 0)
 | 
			
		||||
arg(lvmpartition_ARG, 'l', "lvmpartition", NULL, 0, 0)
 | 
			
		||||
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign, 0, 0)
 | 
			
		||||
arg(size_ARG, 'L', "size", size_mb_arg, 0, 0)
 | 
			
		||||
arg(persistent_ARG, 'M', "persistent", yes_no_arg, 0, 0)
 | 
			
		||||
arg(major_ARG, 'j', "major", int_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(setactivationskip_ARG, 'k', "setactivationskip", yes_no_arg, 0, 0)
 | 
			
		||||
arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", NULL, 0, 0)
 | 
			
		||||
arg(maps_ARG, 'm', "maps", NULL, 0, 0)
 | 
			
		||||
arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0, 0)
 | 
			
		||||
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0, 0)
 | 
			
		||||
arg(name_ARG, 'n', "name", string_arg, 0, 0)
 | 
			
		||||
arg(nofsck_ARG, 'n', "nofsck", NULL, 0, 0)
 | 
			
		||||
arg(novolumegroup_ARG, 'n', "novolumegroup", NULL, 0, 0)
 | 
			
		||||
arg(oldpath_ARG, 'n', "oldpath", NULL, 0, 0)
 | 
			
		||||
arg(options_ARG, 'o', "options", string_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(sort_ARG, 'O', "sort", string_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg, 0, 0)
 | 
			
		||||
arg(permission_ARG, 'p', "permission", permission_arg, 0, 0)
 | 
			
		||||
arg(partial_ARG, 'P', "partial", NULL, 0, 0)
 | 
			
		||||
arg(physicalvolume_ARG, 'P', "physicalvolume", NULL, 0, 0)
 | 
			
		||||
arg(quiet_ARG, 'q', "quiet", NULL, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(readahead_ARG, 'r', "readahead", readahead_arg, 0, 0)
 | 
			
		||||
arg(resizefs_ARG, 'r', "resizefs", NULL, 0, 0)
 | 
			
		||||
arg(reset_ARG, 'R', "reset", NULL, 0, 0)
 | 
			
		||||
arg(regionsize_ARG, 'R', "regionsize", size_mb_arg, 0, 0)
 | 
			
		||||
arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0, 0)
 | 
			
		||||
arg(snapshot_ARG, 's', "snapshot", NULL, 0, 0)
 | 
			
		||||
arg(short_ARG, 's', "short", NULL, 0, 0)
 | 
			
		||||
arg(stdin_ARG, 's', "stdin", NULL, 0, 0)
 | 
			
		||||
arg(select_ARG, 'S', "select", string_arg, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(test_ARG, 't', "test", NULL, 0, 0)
 | 
			
		||||
arg(thin_ARG, 'T', "thin", NULL, 0, 0)
 | 
			
		||||
arg(uuid_ARG, 'u', "uuid", NULL, 0, 0)
 | 
			
		||||
arg(uuidstr_ARG, 'u', "uuid", string_arg, 0, 0)
 | 
			
		||||
arg(uuidlist_ARG, 'U', "uuidlist", NULL, 0, 0)
 | 
			
		||||
arg(verbose_ARG, 'v', "verbose", NULL, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(volumegroup_ARG, 'V', "volumegroup", NULL, 0, 0)
 | 
			
		||||
arg(virtualsize_ARG, 'V', "virtualsize", size_mb_arg, 0, 0)
 | 
			
		||||
arg(wipesignatures_ARG, 'W', "wipesignatures", yes_no_arg, 0, 0)
 | 
			
		||||
arg(allocatable_ARG, 'x', "allocatable", yes_no_arg, 0, 0)
 | 
			
		||||
arg(resizeable_ARG, 'x', "resizeable", yes_no_arg, 0, 0)
 | 
			
		||||
arg(yes_ARG, 'y', "yes", NULL, 0, 0)
 | 
			
		||||
arg(zero_ARG, 'Z', "zero", yes_no_arg, 0, 0)
 | 
			
		||||
arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0)
 | 
			
		||||
arg(all_ARG, 'a', "all", 0, 0, 0)
 | 
			
		||||
arg(autobackup_ARG, 'A', "autobackup", bool_VAL, 0, 0)
 | 
			
		||||
arg(activevolumegroups_ARG, 'A', "activevolumegroups", 0, 0, 0)
 | 
			
		||||
arg(background_ARG, 'b', "background", 0, 0, 0)
 | 
			
		||||
arg(backgroundfork_ARG, 'b', "background", 0, 0, 0)
 | 
			
		||||
arg(basevgname_ARG, 'n', "basevgname", string_VAL, 0, 0)
 | 
			
		||||
arg(blockdevice_ARG, 'b', "blockdevice", 0, 0, 0)
 | 
			
		||||
arg(chunksize_ARG, 'c', "chunksize", sizekb_VAL, 0, 0)
 | 
			
		||||
arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0)
 | 
			
		||||
arg(colon_ARG, 'c', "colon", 0, 0, 0)
 | 
			
		||||
arg(columns_ARG, 'C', "columns", 0, 0, 0)
 | 
			
		||||
arg(contiguous_ARG, 'C', "contiguous", bool_VAL, 0, 0)
 | 
			
		||||
arg(debug_ARG, 'd', "debug", 0, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(exported_ARG, 'e', "exported", 0, 0, 0)
 | 
			
		||||
arg(physicalextent_ARG, 'E', "physicalextent", 0, 0, 0)
 | 
			
		||||
arg(file_ARG, 'f', "file", string_VAL, 0, 0)
 | 
			
		||||
arg(force_ARG, 'f', "force", 0, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(full_ARG, 'f', "full", 0, 0, 0)
 | 
			
		||||
arg(help_ARG, 'h', "help", 0, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(cache_ARG, 'H', "cache", 0, 0, 0)
 | 
			
		||||
arg(history_ARG, 'H', "history", 0, 0, 0)
 | 
			
		||||
arg(help2_ARG, '?', "", 0, 0, 0)
 | 
			
		||||
arg(import_ARG, 'i', "import", 0, 0, 0)
 | 
			
		||||
arg(interval_ARG, 'i', "interval", number_VAL, 0, 0)
 | 
			
		||||
arg(iop_version_ARG, 'i', "iop_version", 0, 0, 0)
 | 
			
		||||
arg(stripes_ARG, 'i', "stripes", number_VAL, 0, 0)
 | 
			
		||||
arg(stripesize_ARG, 'I', "stripesize", sizekb_VAL, 0, 0)
 | 
			
		||||
arg(logicalvolume_ARG, 'l', "logicalvolume", number_VAL, 0, 0)
 | 
			
		||||
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", number_VAL, 0, 0)
 | 
			
		||||
arg(extents_ARG, 'l', "extents", numsignedper_VAL, 0, 0)
 | 
			
		||||
arg(list_ARG, 'l', "list", 0, 0, 0)
 | 
			
		||||
arg(lvmpartition_ARG, 'l', "lvmpartition", 0, 0, 0)
 | 
			
		||||
arg(size_ARG, 'L', "size", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(persistent_ARG, 'M', "persistent", bool_VAL, 0, 0)
 | 
			
		||||
arg(major_ARG, 'j', "major", number_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(setactivationskip_ARG, 'k', "setactivationskip", bool_VAL, 0, 0)
 | 
			
		||||
arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", 0, 0, 0)
 | 
			
		||||
arg(maps_ARG, 'm', "maps", 0, 0, 0)
 | 
			
		||||
arg(mirrors_ARG, 'm', "mirrors", numsigned_VAL, 0, 0)
 | 
			
		||||
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_VAL, 0, 0)
 | 
			
		||||
arg(name_ARG, 'n', "name", string_VAL, 0, 0)
 | 
			
		||||
arg(nofsck_ARG, 'n', "nofsck", 0, 0, 0)
 | 
			
		||||
arg(novolumegroup_ARG, 'n', "novolumegroup", 0, 0, 0)
 | 
			
		||||
arg(oldpath_ARG, 'n', "oldpath", 0, 0, 0)
 | 
			
		||||
arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", number_VAL, 0, 0)
 | 
			
		||||
arg(permission_ARG, 'p', "permission", permission_VAL, 0, 0)
 | 
			
		||||
arg(partial_ARG, 'P', "partial", 0, 0, 0)
 | 
			
		||||
arg(physicalvolume_ARG, 'P', "physicalvolume", 0, 0, 0)
 | 
			
		||||
arg(quiet_ARG, 'q', "quiet", 0, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(readahead_ARG, 'r', "readahead", readahead_VAL, 0, 0)
 | 
			
		||||
arg(resizefs_ARG, 'r', "resizefs", 0, 0, 0)
 | 
			
		||||
arg(reset_ARG, 'R', "reset", 0, 0, 0)
 | 
			
		||||
arg(regionsize_ARG, 'R', "regionsize", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(physicalextentsize_ARG, 's', "physicalextentsize", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(snapshot_ARG, 's', "snapshot", 0, 0, 0)
 | 
			
		||||
arg(short_ARG, 's', "short", 0, 0, 0)
 | 
			
		||||
arg(stdin_ARG, 's', "stdin", 0, 0, 0)
 | 
			
		||||
arg(select_ARG, 'S', "select", string_VAL, ARG_GROUPABLE, 0)
 | 
			
		||||
arg(test_ARG, 't', "test", 0, 0, 0)
 | 
			
		||||
arg(thin_ARG, 'T', "thin", 0, 0, 0)
 | 
			
		||||
arg(uuid_ARG, 'u', "uuid", 0, 0, 0)
 | 
			
		||||
arg(uuidstr_ARG, 'u', "uuid", string_VAL, 0, 0)
 | 
			
		||||
arg(uuidlist_ARG, 'U', "uuidlist", 0, 0, 0)
 | 
			
		||||
arg(verbose_ARG, 'v', "verbose", 0, ARG_COUNTABLE, 0)
 | 
			
		||||
arg(volumegroup_ARG, 'V', "volumegroup", 0, 0, 0)
 | 
			
		||||
arg(virtualsize_ARG, 'V', "virtualsize", sizemb_VAL, 0, 0)
 | 
			
		||||
arg(wipesignatures_ARG, 'W', "wipesignatures", bool_VAL, 0, 0)
 | 
			
		||||
arg(allocatable_ARG, 'x', "allocatable", bool_VAL, 0, 0)
 | 
			
		||||
arg(resizeable_ARG, 'x', "resizeable", bool_VAL, 0, 0)
 | 
			
		||||
arg(yes_ARG, 'y', "yes", 0, 0, 0)
 | 
			
		||||
arg(zero_ARG, 'Z', "zero", bool_VAL, 0, 0)
 | 
			
		||||
 | 
			
		||||
/* this should always be last */
 | 
			
		||||
arg(ARG_COUNT, '-', "", NULL, 0, 0)
 | 
			
		||||
arg(ARG_COUNT, '-', "", 0, 0, 0)
 | 
			
		||||
/* *INDENT-ON* */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1620
									
								
								tools/command-lines.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1620
									
								
								tools/command-lines.in
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										201
									
								
								tools/command.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								tools/command.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,201 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.  
 | 
			
		||||
 * Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _LVM_COMMAND_H
 | 
			
		||||
#define _LVM_COMMAND_H
 | 
			
		||||
 | 
			
		||||
struct cmd_context;
 | 
			
		||||
 | 
			
		||||
/* old per-command-name function */
 | 
			
		||||
typedef int (*command_fn) (struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
/* new per-command-line-id functions */
 | 
			
		||||
typedef int (*command_line_fn) (struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
struct command_function {
 | 
			
		||||
	int command_line_enum;
 | 
			
		||||
	command_line_fn fn;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct command_name {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	const char *desc; /* general command description from commands.h */
 | 
			
		||||
	unsigned int flags;
 | 
			
		||||
 | 
			
		||||
	/* union of {required,optional}_opt_args for all commands with this name */
 | 
			
		||||
	int valid_args[ARG_COUNT];
 | 
			
		||||
	int num_args;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Command defintion
 | 
			
		||||
 *
 | 
			
		||||
 * A command is defined in terms of a command name,
 | 
			
		||||
 * required options (+args), optional options (+args),
 | 
			
		||||
 * required positional args, optional positional args.
 | 
			
		||||
 *
 | 
			
		||||
 * A positional arg always has non-zero pos_arg.def.types.
 | 
			
		||||
 * The first positional arg has pos_arg.pos of 1.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* arg_def flags */
 | 
			
		||||
#define ARG_DEF_FLAG_NEW                1 << 0
 | 
			
		||||
#define ARG_DEF_FLAG_MAY_REPEAT         1 << 1
 | 
			
		||||
 | 
			
		||||
static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
 | 
			
		||||
{
 | 
			
		||||
	return (val_bits & (1 << val_enum)) ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint64_t val_enum_to_bit(int val_enum)
 | 
			
		||||
{
 | 
			
		||||
	return (1ULL << val_enum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lvp_bit_is_set(uint64_t lvp_bits, int lvp_enum)
 | 
			
		||||
{
 | 
			
		||||
	return (lvp_bits & (1 << lvp_enum)) ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint64_t lvp_enum_to_bit(int lvp_enum)
 | 
			
		||||
{
 | 
			
		||||
	return (1ULL << lvp_enum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int lvt_bit_is_set(uint64_t lvt_bits, int lvt_enum)
 | 
			
		||||
{
 | 
			
		||||
	return (lvt_bits & (1 << lvt_enum)) ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint64_t lvt_enum_to_bit(int lvt_enum)
 | 
			
		||||
{
 | 
			
		||||
	return (1ULL << lvt_enum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Description a value that follows an option or exists in a position. */
 | 
			
		||||
 | 
			
		||||
struct arg_def {
 | 
			
		||||
	uint64_t val_bits;   /* bits of x_VAL, can be multiple for pos_arg */
 | 
			
		||||
	uint64_t lvt_bits;   /* lvt_enum_to_bit(x_LVT) for lv_VAL, can be multiple */
 | 
			
		||||
	uint64_t num;        /* a literal number for conststr_VAL */
 | 
			
		||||
	const char *str;     /* a literal string for constnum_VAL */
 | 
			
		||||
	uint32_t flags;      /* ARG_DEF_FLAG_ */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Description of an option and the value that follows it. */
 | 
			
		||||
 | 
			
		||||
struct opt_arg {
 | 
			
		||||
	int opt;             /* option, e.g. foo_ARG */
 | 
			
		||||
	struct arg_def def;  /* defines accepted values */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Description of a position and the value that exists there. */
 | 
			
		||||
 | 
			
		||||
struct pos_arg {
 | 
			
		||||
	int pos;             /* position, e.g. first is 1 */
 | 
			
		||||
	struct arg_def def;  /* defines accepted values */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *
 | 
			
		||||
 * Commands using a given command definition must follow a set
 | 
			
		||||
 * of rules.  If a given command+LV matches the conditions in
 | 
			
		||||
 * opts/lvt_bits/lvp_bits, then the checks are applied.
 | 
			
		||||
 * If one condition is not met, the checks are not applied.
 | 
			
		||||
 * If no conditions are set, the checks are always applied.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define RULE_INVALID 1
 | 
			
		||||
#define RULE_REQUIRE 2
 | 
			
		||||
 | 
			
		||||
struct cmd_rule {
 | 
			
		||||
	int *opts;			/* if any option in this list is set, the check may apply */
 | 
			
		||||
	uint64_t lvt_bits;		/* if LV has one of these types (lvt_enum_to_bit), the check may apply */
 | 
			
		||||
	uint64_t lvp_bits;		/* if LV has all of these properties (lvp_enum_to_bit), the check may apply */
 | 
			
		||||
 | 
			
		||||
	int *check_opts;		/* used options must [not] be in this list */
 | 
			
		||||
	uint64_t check_lvt_bits;	/* LV must [not] have one of these type */
 | 
			
		||||
	uint64_t check_lvp_bits;	/* LV must [not] have all of these properties */
 | 
			
		||||
 | 
			
		||||
	uint32_t rule;			/* RULE_INVALID, RULE_REQUIRE: check values must [not] be true */
 | 
			
		||||
	int opts_count;			/* entries in opts[] */
 | 
			
		||||
	int check_opts_count;		/* entries in check_opts[] */
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * CMD_RO_ARGS needs to accomodate a list of options,
 | 
			
		||||
 * of which one is required after which the rest are
 | 
			
		||||
 * optional.
 | 
			
		||||
 */
 | 
			
		||||
#define CMD_RO_ARGS 64          /* required opt args */
 | 
			
		||||
#define CMD_OO_ARGS 150         /* optional opt args */
 | 
			
		||||
#define CMD_RP_ARGS 8           /* required positional args */
 | 
			
		||||
#define CMD_OP_ARGS 8           /* optional positional args */
 | 
			
		||||
#define CMD_MAX_RULES 32        /* max number of rules per command def */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * one or more from required_opt_args is required,
 | 
			
		||||
 * then the rest are optional.
 | 
			
		||||
 */
 | 
			
		||||
#define CMD_FLAG_ONE_REQUIRED_OPT   1
 | 
			
		||||
#define CMD_FLAG_SECONDARY_SYNTAX   2
 | 
			
		||||
 | 
			
		||||
/* a register of the lvm commands */
 | 
			
		||||
struct command {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	const char *desc; /* specific command description from command-lines.h */
 | 
			
		||||
	const char *usage; /* excludes common options like --help, --debug */
 | 
			
		||||
	const char *usage_common; /* includes commmon options like --help, --debug */
 | 
			
		||||
	const char *command_line_id;
 | 
			
		||||
	int command_line_enum; /* <command_line_id>_CMD */
 | 
			
		||||
 | 
			
		||||
	struct command_name *cname;
 | 
			
		||||
 | 
			
		||||
	command_fn fn;                      /* old style */
 | 
			
		||||
	struct command_function *functions; /* new style */
 | 
			
		||||
 | 
			
		||||
	unsigned int flags; /* copied from command_name.flags from commands.h */
 | 
			
		||||
 | 
			
		||||
	unsigned int cmd_flags; /* CMD_FLAG_ */
 | 
			
		||||
 | 
			
		||||
	/* definitions of opt/pos args */
 | 
			
		||||
 | 
			
		||||
	/* required args following an --opt */
 | 
			
		||||
	struct opt_arg required_opt_args[CMD_RO_ARGS];
 | 
			
		||||
 | 
			
		||||
	/* optional args following an --opt */
 | 
			
		||||
	struct opt_arg optional_opt_args[CMD_OO_ARGS];
 | 
			
		||||
 | 
			
		||||
	/* required positional args */
 | 
			
		||||
	struct pos_arg required_pos_args[CMD_RP_ARGS];
 | 
			
		||||
 | 
			
		||||
	/* optional positional args */
 | 
			
		||||
	struct pos_arg optional_pos_args[CMD_OP_ARGS];
 | 
			
		||||
 | 
			
		||||
	struct cmd_rule rules[CMD_MAX_RULES];
 | 
			
		||||
 | 
			
		||||
	int ro_count;
 | 
			
		||||
	int oo_count;
 | 
			
		||||
	int rp_count;
 | 
			
		||||
	int op_count;
 | 
			
		||||
 | 
			
		||||
	/* used for processing current position */
 | 
			
		||||
	int pos_count;
 | 
			
		||||
 | 
			
		||||
	int rule_count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1428
									
								
								tools/commands.h
									
									
									
									
									
								
							
							
						
						
									
										1428
									
								
								tools/commands.h
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2898
									
								
								tools/create-commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2898
									
								
								tools/create-commands.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										56
									
								
								tools/lv_props.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								tools/lv_props.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * NULL in the last arg can be replaced with actual
 | 
			
		||||
 * calls to the lv_is_prop() function when those
 | 
			
		||||
 * become functions (are #define now), take uniform
 | 
			
		||||
 * args (e.g. some take cmd others don't), and are
 | 
			
		||||
 * exposed in tools.h
 | 
			
		||||
 *
 | 
			
		||||
 * Until then, the lv_is_prop() functions are
 | 
			
		||||
 * called indirectly through _lv_is_prop().
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
lvp(LVP_NONE, "", NULL) /* enum value 0 means none */
 | 
			
		||||
lvp(is_locked_LVP, "lv_is_locked", NULL)
 | 
			
		||||
lvp(is_partial_LVP, "lv_is_partial", NULL)
 | 
			
		||||
lvp(is_virtual_LVP, "lv_is_virtual", NULL)
 | 
			
		||||
lvp(is_merging_LVP, "lv_is_merging", NULL)
 | 
			
		||||
lvp(is_merging_origin_LVP, "lv_is_merging_origin", NULL)
 | 
			
		||||
lvp(is_converting_LVP, "lv_is_converting", NULL)
 | 
			
		||||
lvp(is_external_origin_LVP, "lv_is_external_origin", NULL)
 | 
			
		||||
lvp(is_virtual_origin_LVP, "lv_is_virtual_origin", NULL)
 | 
			
		||||
lvp(is_not_synced_LVP, "lv_is_not_synced", NULL)
 | 
			
		||||
lvp(is_pending_delete_LVP, "lv_is_pending_delete", NULL)
 | 
			
		||||
lvp(is_error_when_full_LVP, "lv_is_error_when_full", NULL)
 | 
			
		||||
lvp(is_pvmove_LVP, "lv_is_pvmove", NULL)
 | 
			
		||||
lvp(is_removed_LVP, "lv_is_removed", NULL)
 | 
			
		||||
lvp(is_vg_writable_LVP, "lv_is_vg_writable", NULL)
 | 
			
		||||
 | 
			
		||||
/* kinds of sub LV */
 | 
			
		||||
lvp(is_thinpool_data_LVP, "lv_is_thinpool_data", NULL)
 | 
			
		||||
lvp(is_thinpool_metadata_LVP, "lv_is_thinpool_metadata", NULL)
 | 
			
		||||
lvp(is_cachepool_data_LVP, "lv_is_cachepool_data", NULL)
 | 
			
		||||
lvp(is_cachepool_metadata_LVP, "lv_is_cachepool_metadata", NULL)
 | 
			
		||||
lvp(is_mirror_image_LVP, "lv_is_mirror_image", NULL)
 | 
			
		||||
lvp(is_mirror_log_LVP, "lv_is_mirror_log", NULL)
 | 
			
		||||
lvp(is_raid_image_LVP, "lv_is_raid_image", NULL)
 | 
			
		||||
lvp(is_raid_metadata_LVP, "lv_is_raid_metadata", NULL)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * is_thick_origin should be used instead of is_origin
 | 
			
		||||
 * is_thick_snapshot is generally used as LV_snapshot from lv_types.h
 | 
			
		||||
 */
 | 
			
		||||
lvp(is_origin_LVP, "lv_is_origin", NULL)
 | 
			
		||||
lvp(is_thick_origin_LVP, "lv_is_thick_origin", NULL)
 | 
			
		||||
lvp(is_thick_snapshot_LVP, "lv_is_thick_snapshot", NULL)
 | 
			
		||||
lvp(is_thin_origin_LVP, "lv_is_thin_origin", NULL)
 | 
			
		||||
lvp(is_thin_snapshot_LVP, "lv_is_thin_snapshot", NULL)
 | 
			
		||||
 | 
			
		||||
lvp(is_cache_origin_LVP, "lv_is_cache_origin", NULL)
 | 
			
		||||
lvp(is_merging_cow_LVP, "lv_is_merging_cow", NULL)
 | 
			
		||||
lvp(is_cow_covering_origin_LVP, "lv_is_cow_covering_origin", NULL)
 | 
			
		||||
lvp(is_visible_LVP, "lv_is_visible", NULL)
 | 
			
		||||
lvp(is_historical_LVP, "lv_is_historical", NULL)
 | 
			
		||||
lvp(is_raid_with_tracking_LVP, "lv_is_raid_with_tracking", NULL)
 | 
			
		||||
lvp(LVP_COUNT, "", NULL)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										34
									
								
								tools/lv_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tools/lv_types.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * LV types used in command definitions.  The type strings are used
 | 
			
		||||
 * as LV suffixes, e.g. LV_type or LV_type1_type2.
 | 
			
		||||
 *
 | 
			
		||||
 * The final NULL arg can be replaced with lv_is_type() functions
 | 
			
		||||
 * if the current lv_is_type #defines become functions and are
 | 
			
		||||
 * moved to tools.h
 | 
			
		||||
 *
 | 
			
		||||
 * Until then, the lv_is_type() functions are called indirectly
 | 
			
		||||
 * through _lv_is_type().
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
lvt(LVT_NONE, "", NULL)
 | 
			
		||||
lvt(linear_LVT, "linear", NULL)
 | 
			
		||||
lvt(striped_LVT, "striped", NULL)
 | 
			
		||||
lvt(snapshot_LVT, "snapshot", NULL) /* lv_is_cow, lv_is_thick_snapshot */
 | 
			
		||||
lvt(thin_LVT, "thin", NULL)
 | 
			
		||||
lvt(thinpool_LVT, "thinpool", NULL)
 | 
			
		||||
lvt(cache_LVT, "cache", NULL)
 | 
			
		||||
lvt(cachepool_LVT, "cachepool", NULL)
 | 
			
		||||
lvt(mirror_LVT, "mirror", NULL)
 | 
			
		||||
lvt(raid_LVT, "raid", NULL)
 | 
			
		||||
lvt(raid0_LVT, "raid0", NULL)
 | 
			
		||||
lvt(raid1_LVT, "raid1", NULL)
 | 
			
		||||
lvt(raid4_LVT, "raid4", NULL)
 | 
			
		||||
lvt(raid5_LVT, "raid5", NULL)
 | 
			
		||||
lvt(raid6_LVT, "raid6", NULL)
 | 
			
		||||
lvt(raid10_LVT, "raid10", NULL)
 | 
			
		||||
lvt(error_LVT, "error", NULL)
 | 
			
		||||
lvt(zero_LVT, "zero", NULL)
 | 
			
		||||
lvt(LVT_COUNT, "", NULL)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										922
									
								
								tools/lvchange.c
									
									
									
									
									
								
							
							
						
						
									
										922
									
								
								tools/lvchange.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3569
									
								
								tools/lvconvert.c
									
									
									
									
									
								
							
							
						
						
									
										3569
									
								
								tools/lvconvert.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										350
									
								
								tools/lvconvert_other.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								tools/lvconvert_other.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,350 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2005-2016 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "tools.h"
 | 
			
		||||
 | 
			
		||||
#include "polldaemon.h"
 | 
			
		||||
#include "lv_alloc.h"
 | 
			
		||||
#include "lvconvert_poll.h"
 | 
			
		||||
#include "command-lines-count.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * FIXME: it's very unlikely that the same !visible exceptions apply to every
 | 
			
		||||
 * lvconvert command.  Add specific !visible exceptions in command-specific
 | 
			
		||||
 * check functions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int lvconvert_generic_check(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
			struct processing_handle *handle,
 | 
			
		||||
			int lv_is_named_arg)
 | 
			
		||||
{
 | 
			
		||||
	if (!lv_is_visible(lv)) {
 | 
			
		||||
		if (lv_is_cache_pool_metadata(lv) ||
 | 
			
		||||
		    lv_is_cache_pool_data(lv) ||
 | 
			
		||||
		    lv_is_thin_pool_metadata(lv) ||
 | 
			
		||||
		    lv_is_thin_pool_data(lv) ||
 | 
			
		||||
		    lv_is_used_cache_pool(lv) ||
 | 
			
		||||
		    lv_is_mirrored(lv) ||
 | 
			
		||||
		    lv_is_raid(lv)) {
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log_error("Operation not permitted (%s %d) on hidden LV %s.",
 | 
			
		||||
			  cmd->command->command_line_id, cmd->command->command_line_enum,
 | 
			
		||||
			  display_lvname(lv));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Reomove missing and empty PVs from VG, if are also in provided list
 | 
			
		||||
 */
 | 
			
		||||
static void _remove_missing_empty_pv(struct volume_group *vg, struct dm_list *remove_pvs)
 | 
			
		||||
{
 | 
			
		||||
	struct pv_list *pvl, *pvl_vg, *pvlt;
 | 
			
		||||
	int removed = 0;
 | 
			
		||||
 | 
			
		||||
	if (!remove_pvs)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	dm_list_iterate_items(pvl, remove_pvs) {
 | 
			
		||||
		dm_list_iterate_items_safe(pvl_vg, pvlt, &vg->pvs) {
 | 
			
		||||
			if (!id_equal(&pvl->pv->id, &pvl_vg->pv->id) ||
 | 
			
		||||
			    !is_missing_pv(pvl_vg->pv) ||
 | 
			
		||||
			    pvl_vg->pv->pe_alloc_count != 0)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			/* FIXME: duplication of vgreduce code, move this to library */
 | 
			
		||||
			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++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (removed) {
 | 
			
		||||
		if (!vg_write(vg) || !vg_commit(vg)) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		log_warn("%d missing and now unallocated Physical Volumes removed from VG.", removed);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_repair_pvs(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
			struct processing_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_list *failed_pvs;
 | 
			
		||||
	struct dm_list *use_pvh;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (cmd->position_argc > 1) {
 | 
			
		||||
		/* First pos arg is required LV, remaining are optional PVs. */
 | 
			
		||||
		if (!(use_pvh = create_pv_list(cmd->mem, lv->vg, cmd->position_argc - 1, cmd->position_argv + 1, 0)))
 | 
			
		||||
			return_ECMD_FAILED;
 | 
			
		||||
	} else
 | 
			
		||||
		use_pvh = &lv->vg->pvs;
 | 
			
		||||
 | 
			
		||||
	if (lv_is_raid(lv))
 | 
			
		||||
		ret = lvconvert_repair_pvs_raid(cmd, lv, handle, use_pvh);
 | 
			
		||||
	else if (lv_is_mirror(lv))
 | 
			
		||||
		ret = lvconvert_repair_pvs_mirror(cmd, lv, handle, use_pvh);
 | 
			
		||||
	else
 | 
			
		||||
		ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (ret && arg_is_set(cmd, usepolicies_ARG)) {
 | 
			
		||||
		if ((failed_pvs = failed_pv_list(lv->vg)))
 | 
			
		||||
			_remove_missing_empty_pv(lv->vg, failed_pvs);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret ? ECMD_PROCESSED : ECMD_FAILED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_repair_pvs_or_thinpool_single(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
			struct processing_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	if (lv_is_thin_pool(lv))
 | 
			
		||||
		return lvconvert_repair_thinpool(cmd, lv, handle);
 | 
			
		||||
	else if (lv_is_raid(lv) || lv_is_mirror(lv))
 | 
			
		||||
		return _lvconvert_repair_pvs(cmd, lv, handle);
 | 
			
		||||
	else
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * FIXME: add option --repair-pvs to call _lvconvert_repair_pvs() directly,
 | 
			
		||||
 * and option --repair-thinpool to call _lvconvert_repair_thinpool().
 | 
			
		||||
 */
 | 
			
		||||
int lvconvert_repair_pvs_or_thinpool_cmd(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	struct processing_handle *handle;
 | 
			
		||||
	struct lvconvert_result lr = { 0 };
 | 
			
		||||
	struct convert_poll_id_list *idl;
 | 
			
		||||
	int saved_ignore_suspended_devices;
 | 
			
		||||
	int ret, poll_ret;
 | 
			
		||||
 | 
			
		||||
	dm_list_init(&lr.poll_idls);
 | 
			
		||||
 | 
			
		||||
	if (!(handle = init_processing_handle(cmd, NULL))) {
 | 
			
		||||
		log_error("Failed to initialize processing handle.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handle->custom_handle = &lr;
 | 
			
		||||
 | 
			
		||||
	saved_ignore_suspended_devices = ignore_suspended_devices();
 | 
			
		||||
	init_ignore_suspended_devices(1);
 | 
			
		||||
 | 
			
		||||
	cmd->handles_missing_pvs = 1;
 | 
			
		||||
 | 
			
		||||
	ret = process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
 | 
			
		||||
			      handle, &lvconvert_generic_check, &_lvconvert_repair_pvs_or_thinpool_single);
 | 
			
		||||
 | 
			
		||||
	init_ignore_suspended_devices(saved_ignore_suspended_devices);
 | 
			
		||||
 | 
			
		||||
	if (lr.need_polling) {
 | 
			
		||||
		dm_list_iterate_items(idl, &lr.poll_idls) {
 | 
			
		||||
			poll_ret = lvconvert_poll_by_id(cmd, idl->id,
 | 
			
		||||
						arg_is_set(cmd, background_ARG), 0, 0);
 | 
			
		||||
			if (poll_ret > ret)
 | 
			
		||||
				ret = poll_ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	destroy_processing_handle(cmd, handle);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_replace_pv_single(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
			struct processing_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	struct arg_value_group_list *group;
 | 
			
		||||
	const char *tmp_str;
 | 
			
		||||
	struct dm_list *use_pvh;
 | 
			
		||||
	struct dm_list *replace_pvh;
 | 
			
		||||
	char **replace_pvs;
 | 
			
		||||
	int replace_pv_count;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (cmd->position_argc > 1) {
 | 
			
		||||
		/* First pos arg is required LV, remaining are optional PVs. */
 | 
			
		||||
		if (!(use_pvh = create_pv_list(cmd->mem, lv->vg, cmd->position_argc - 1, cmd->position_argv + 1, 0)))
 | 
			
		||||
			return_ECMD_FAILED;
 | 
			
		||||
	} else
 | 
			
		||||
		use_pvh = &lv->vg->pvs;
 | 
			
		||||
 | 
			
		||||
	if (!(replace_pv_count = arg_count(cmd, replace_ARG)))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
	if (!(replace_pvs = dm_pool_alloc(cmd->mem, sizeof(char *) * replace_pv_count)))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
	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_ECMD_FAILED;
 | 
			
		||||
		}
 | 
			
		||||
		if (!(replace_pvs[i++] = dm_pool_strdup(cmd->mem, tmp_str)))
 | 
			
		||||
			return_ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(replace_pvh = create_pv_list(cmd->mem, lv->vg, replace_pv_count, replace_pvs, 0)))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
	if (!lv_raid_replace(lv, arg_count(cmd, force_ARG), replace_pvh, use_pvh))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
	return ECMD_PROCESSED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvconvert_replace_pv_cmd(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	struct processing_handle *handle;
 | 
			
		||||
	struct lvconvert_result lr = { 0 };
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!(handle = init_processing_handle(cmd, NULL))) {
 | 
			
		||||
		log_error("Failed to initialize processing handle.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handle->custom_handle = &lr;
 | 
			
		||||
 | 
			
		||||
	ret = process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
 | 
			
		||||
			      handle, &lvconvert_generic_check, &_lvconvert_replace_pv_single);
 | 
			
		||||
 | 
			
		||||
	destroy_processing_handle(cmd, handle);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_start_poll_single(struct cmd_context *cmd,
 | 
			
		||||
                                       struct logical_volume *lv,
 | 
			
		||||
                                       struct processing_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	struct lvconvert_result *lr = (struct lvconvert_result *) handle->custom_handle;
 | 
			
		||||
	struct convert_poll_id_list *idl;
 | 
			
		||||
 | 
			
		||||
	if (!(idl = convert_poll_id_list_create(cmd, lv)))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
	dm_list_add(&lr->poll_idls, &idl->list);
 | 
			
		||||
 | 
			
		||||
	lr->need_polling = 1;
 | 
			
		||||
 | 
			
		||||
	return ECMD_PROCESSED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvconvert_start_poll_cmd(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	struct processing_handle *handle;
 | 
			
		||||
	struct lvconvert_result lr = { 0 };
 | 
			
		||||
	struct convert_poll_id_list *idl;
 | 
			
		||||
	int saved_ignore_suspended_devices;
 | 
			
		||||
	int ret, poll_ret;
 | 
			
		||||
 | 
			
		||||
	dm_list_init(&lr.poll_idls);
 | 
			
		||||
 | 
			
		||||
	if (!(handle = init_processing_handle(cmd, NULL))) {
 | 
			
		||||
		log_error("Failed to initialize processing handle.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handle->custom_handle = &lr;
 | 
			
		||||
 | 
			
		||||
	saved_ignore_suspended_devices = ignore_suspended_devices();
 | 
			
		||||
	init_ignore_suspended_devices(1);
 | 
			
		||||
 | 
			
		||||
	cmd->handles_missing_pvs = 1;
 | 
			
		||||
 | 
			
		||||
	ret = process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
 | 
			
		||||
			      handle, NULL, &_lvconvert_start_poll_single);
 | 
			
		||||
 | 
			
		||||
	init_ignore_suspended_devices(saved_ignore_suspended_devices);
 | 
			
		||||
 | 
			
		||||
	if (lr.need_polling) {
 | 
			
		||||
		dm_list_iterate_items(idl, &lr.poll_idls) {
 | 
			
		||||
			poll_ret = lvconvert_poll_by_id(cmd, idl->id,
 | 
			
		||||
						arg_is_set(cmd, background_ARG), 0, 0);
 | 
			
		||||
			if (poll_ret > ret)
 | 
			
		||||
				ret = poll_ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	destroy_processing_handle(cmd, handle);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_merge_generic_single(struct cmd_context *cmd,
 | 
			
		||||
					 struct logical_volume *lv,
 | 
			
		||||
					 struct processing_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (lv_is_cow(lv))
 | 
			
		||||
		ret = lvconvert_merge_snapshot_single(cmd, lv, handle);
 | 
			
		||||
 | 
			
		||||
	else if (lv_is_thin_volume(lv))
 | 
			
		||||
		ret = lvconvert_merge_thin_single(cmd, lv, handle);
 | 
			
		||||
 | 
			
		||||
	else
 | 
			
		||||
		ret = lvconvert_merge_mirror_images_single(cmd, lv, handle);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	struct processing_handle *handle;
 | 
			
		||||
	struct lvconvert_result lr = { 0 };
 | 
			
		||||
	struct convert_poll_id_list *idl;
 | 
			
		||||
	int ret, poll_ret;
 | 
			
		||||
 | 
			
		||||
	dm_list_init(&lr.poll_idls);
 | 
			
		||||
 | 
			
		||||
	if (!(handle = init_processing_handle(cmd, NULL))) {
 | 
			
		||||
		log_error("Failed to initialize processing handle.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handle->custom_handle = &lr;
 | 
			
		||||
 | 
			
		||||
	cmd->command->flags &= ~GET_VGNAME_FROM_OPTIONS;
 | 
			
		||||
 | 
			
		||||
	ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
 | 
			
		||||
			      handle, NULL, &_lvconvert_merge_generic_single);
 | 
			
		||||
 | 
			
		||||
	/* polling is only used by merge_snapshot */
 | 
			
		||||
	if (lr.need_polling) {
 | 
			
		||||
		dm_list_iterate_items(idl, &lr.poll_idls) {
 | 
			
		||||
			poll_ret = lvconvert_poll_by_id(cmd, idl->id,
 | 
			
		||||
						arg_is_set(cmd, background_ARG), 1, 0);
 | 
			
		||||
			if (poll_ret > ret)
 | 
			
		||||
				ret = poll_ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	destroy_processing_handle(cmd, handle);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -188,3 +188,118 @@ progress_t poll_thin_merge_progress(struct cmd_context *cmd,
 | 
			
		||||
 | 
			
		||||
	return PROGRESS_FINISHED_ALL; /* Merging happend */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct poll_operation_id *_create_id(struct cmd_context *cmd,
 | 
			
		||||
					    const char *vg_name,
 | 
			
		||||
					    const char *lv_name,
 | 
			
		||||
					    const char *uuid)
 | 
			
		||||
{
 | 
			
		||||
	struct poll_operation_id *id;
 | 
			
		||||
	char lv_full_name[NAME_LEN];
 | 
			
		||||
 | 
			
		||||
	if (!vg_name || !lv_name || !uuid) {
 | 
			
		||||
		log_error(INTERNAL_ERROR "Wrong params for lvconvert _create_id.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (dm_snprintf(lv_full_name, sizeof(lv_full_name), "%s/%s", vg_name, lv_name) < 0) {
 | 
			
		||||
		log_error(INTERNAL_ERROR "Name \"%s/%s\" is too long.", vg_name, lv_name);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(id = dm_pool_alloc(cmd->mem, sizeof(*id)))) {
 | 
			
		||||
		log_error("Poll operation ID allocation failed.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(id->display_name = dm_pool_strdup(cmd->mem, lv_full_name)) ||
 | 
			
		||||
	    !(id->lv_name = strchr(id->display_name, '/')) ||
 | 
			
		||||
	    !(id->vg_name = dm_pool_strdup(cmd->mem, vg_name)) ||
 | 
			
		||||
	    !(id->uuid = dm_pool_strdup(cmd->mem, uuid))) {
 | 
			
		||||
		log_error("Failed to copy one or more poll operation ID members.");
 | 
			
		||||
		dm_pool_free(cmd->mem, id);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	id->lv_name++; /* skip over '/' */
 | 
			
		||||
 | 
			
		||||
	return id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct poll_functions _lvconvert_mirror_fns = {
 | 
			
		||||
	.poll_progress = poll_mirror_progress,
 | 
			
		||||
	.finish_copy = lvconvert_mirror_finish,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct poll_functions _lvconvert_merge_fns = {
 | 
			
		||||
	.poll_progress = poll_merge_progress,
 | 
			
		||||
	.finish_copy = lvconvert_merge_finish,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct poll_functions _lvconvert_thin_merge_fns = {
 | 
			
		||||
	.poll_progress = poll_thin_merge_progress,
 | 
			
		||||
	.finish_copy = lvconvert_merge_finish,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int lvconvert_poll_by_id(struct cmd_context *cmd, struct poll_operation_id *id,
 | 
			
		||||
				 unsigned background,
 | 
			
		||||
				 int is_merging_origin,
 | 
			
		||||
				 int is_merging_origin_thin)
 | 
			
		||||
{
 | 
			
		||||
	if (test_mode())
 | 
			
		||||
		return ECMD_PROCESSED;
 | 
			
		||||
 | 
			
		||||
	if (is_merging_origin)
 | 
			
		||||
		return poll_daemon(cmd, background,
 | 
			
		||||
				(MERGING | (is_merging_origin_thin ? THIN_VOLUME : SNAPSHOT)),
 | 
			
		||||
				is_merging_origin_thin ? &_lvconvert_thin_merge_fns : &_lvconvert_merge_fns,
 | 
			
		||||
				"Merged", id);
 | 
			
		||||
	else
 | 
			
		||||
		return poll_daemon(cmd, background, CONVERTING,
 | 
			
		||||
				&_lvconvert_mirror_fns, "Converted", id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvconvert_poll(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
		   unsigned background)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
	struct poll_operation_id *id = _create_id(cmd, lv->vg->name, lv->name, lv->lvid.s);
 | 
			
		||||
	int is_merging_origin = 0;
 | 
			
		||||
	int is_merging_origin_thin = 0;
 | 
			
		||||
 | 
			
		||||
	if (!id) {
 | 
			
		||||
		log_error("Failed to allocate poll identifier for lvconvert.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME: check this in polling instead */
 | 
			
		||||
	if (lv_is_merging_origin(lv)) {
 | 
			
		||||
		is_merging_origin = 1;
 | 
			
		||||
		is_merging_origin_thin = seg_is_thin_volume(find_snapshot(lv));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = lvconvert_poll_by_id(cmd, id, background, is_merging_origin, is_merging_origin_thin);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct convert_poll_id_list *convert_poll_id_list_create(struct cmd_context *cmd, const struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct convert_poll_id_list *idl = (struct convert_poll_id_list *) dm_pool_alloc(cmd->mem, sizeof(struct convert_poll_id_list));
 | 
			
		||||
 | 
			
		||||
	if (!idl) {
 | 
			
		||||
		log_error("Convert poll ID list allocation failed.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(idl->id = _create_id(cmd, lv->vg->name, lv->name, lv->lvid.s))) {
 | 
			
		||||
		dm_pool_free(cmd->mem, idl);
 | 
			
		||||
		return_NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	idl->is_merging_origin = lv_is_merging_origin(lv);
 | 
			
		||||
	idl->is_merging_origin_thin = idl->is_merging_origin && seg_is_thin_volume(find_snapshot(lv));
 | 
			
		||||
 | 
			
		||||
	return idl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,26 @@ struct cmd_context;
 | 
			
		||||
struct logical_volume;
 | 
			
		||||
struct volume_group;
 | 
			
		||||
 | 
			
		||||
 /*
 | 
			
		||||
  * Data/results accumulated during processing.
 | 
			
		||||
  */
 | 
			
		||||
struct lvconvert_result {
 | 
			
		||||
	int need_polling;
 | 
			
		||||
	struct dm_list poll_idls;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct convert_poll_id_list {
 | 
			
		||||
	struct dm_list list;
 | 
			
		||||
	struct poll_operation_id *id;
 | 
			
		||||
	unsigned is_merging_origin:1;
 | 
			
		||||
	unsigned is_merging_origin_thin:1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int lvconvert_poll_by_id(struct cmd_context *cmd, struct poll_operation_id *id,
 | 
			
		||||
		unsigned background, int is_merging_origin, int is_merging_origin_thin);
 | 
			
		||||
struct convert_poll_id_list *convert_poll_id_list_create(struct cmd_context *cmd,
 | 
			
		||||
		const struct logical_volume *lv);
 | 
			
		||||
 | 
			
		||||
int lvconvert_mirror_finish(struct cmd_context *cmd,
 | 
			
		||||
			    struct volume_group *vg,
 | 
			
		||||
			    struct logical_volume *lv,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1660
									
								
								tools/lvconvert_pool.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1660
									
								
								tools/lvconvert_pool.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										423
									
								
								tools/lvconvert_snapshot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										423
									
								
								tools/lvconvert_snapshot.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,423 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2005-2016 Red Hat, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of LVM2.
 | 
			
		||||
 *
 | 
			
		||||
 * This copyrighted material is made available to anyone wishing to use,
 | 
			
		||||
 * modify, copy, or redistribute it subject to the terms and conditions
 | 
			
		||||
 * of the GNU Lesser General Public License v.2.1.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software Foundation,
 | 
			
		||||
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "tools.h"
 | 
			
		||||
 | 
			
		||||
#include "polldaemon.h"
 | 
			
		||||
#include "lv_alloc.h"
 | 
			
		||||
#include "lvconvert_poll.h"
 | 
			
		||||
#include "command-lines-count.h"
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_snapshot(struct cmd_context *cmd,
 | 
			
		||||
			       struct logical_volume *lv,
 | 
			
		||||
			       const char *origin_name)
 | 
			
		||||
{
 | 
			
		||||
	struct logical_volume *org;
 | 
			
		||||
	const char *snap_name = display_lvname(lv);
 | 
			
		||||
	uint32_t chunk_size;
 | 
			
		||||
	int zero;
 | 
			
		||||
 | 
			
		||||
	if (!(org = find_lv(lv->vg, origin_name))) {
 | 
			
		||||
		log_error("Couldn't find origin volume %s in Volume group %s.",
 | 
			
		||||
			  origin_name, lv->vg->name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (org == lv) {
 | 
			
		||||
		log_error("Unable to use %s as both snapshot and origin.", snap_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	chunk_size = arg_uint_value(cmd, chunksize_ARG, 8);
 | 
			
		||||
	if (chunk_size < 8 || chunk_size > 1024 || !is_power_of_2(chunk_size)) {
 | 
			
		||||
		log_error("Chunk size must be a power of 2 in the range 4K to 512K.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	log_verbose("Setting chunk size to %s.", display_size(cmd, chunk_size));
 | 
			
		||||
 | 
			
		||||
	if (!cow_has_min_chunks(lv->vg, lv->le_count, chunk_size))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * check_lv_rules() checks cannot be done via command definition
 | 
			
		||||
	 * rules because this LV is not processed by process_each_lv.
 | 
			
		||||
	 */
 | 
			
		||||
	if (lv_is_locked(org) || lv_is_pvmove(org)) {
 | 
			
		||||
		log_error("Unable to use LV %s as snapshot origin: LV is %s.",
 | 
			
		||||
			  display_lvname(lv), lv_is_locked(org) ? "locked" : "pvmove");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * check_lv_types() checks cannot be done via command definition
 | 
			
		||||
	 * LV_foo specification because this LV is not processed by process_each_lv.
 | 
			
		||||
	 */
 | 
			
		||||
	if (lv_is_cache_type(org) ||
 | 
			
		||||
	    lv_is_thin_type(org) ||
 | 
			
		||||
	    lv_is_mirrored(org) ||
 | 
			
		||||
	    lv_is_cow(org)) {
 | 
			
		||||
		log_error("Unable to use LV %s as snapshot origin: invald LV type.",
 | 
			
		||||
			  display_lvname(lv));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_warn("WARNING: Converting logical volume %s to snapshot exception store.",
 | 
			
		||||
		 snap_name);
 | 
			
		||||
	log_warn("THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)");
 | 
			
		||||
 | 
			
		||||
	if (!arg_count(cmd, yes_ARG) &&
 | 
			
		||||
	    yes_no_prompt("Do you really want to convert %s? [y/n]: ",
 | 
			
		||||
			  snap_name) == 'n') {
 | 
			
		||||
		log_error("Conversion aborted.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!deactivate_lv(cmd, lv)) {
 | 
			
		||||
		log_error("Couldn't deactivate logical volume %s.", snap_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (first_seg(lv)->segtype->flags & SEG_CANNOT_BE_ZEROED)
 | 
			
		||||
		zero = 0;
 | 
			
		||||
	else
 | 
			
		||||
		zero = arg_int_value(cmd, zero_ARG, 1);
 | 
			
		||||
 | 
			
		||||
	if (!zero || !(lv->status & LVM_WRITE))
 | 
			
		||||
		log_warn("WARNING: %s not zeroed.", snap_name);
 | 
			
		||||
	else {
 | 
			
		||||
		lv->status |= LV_TEMPORARY;
 | 
			
		||||
		if (!activate_lv_local(cmd, lv) ||
 | 
			
		||||
		    !wipe_lv(lv, (struct wipe_params) { .do_zero = 1 })) {
 | 
			
		||||
			log_error("Aborting. Failed to wipe snapshot exception store.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		lv->status &= ~LV_TEMPORARY;
 | 
			
		||||
		/* Deactivates cleared metadata LV */
 | 
			
		||||
		if (!deactivate_lv_local(lv->vg->cmd, lv)) {
 | 
			
		||||
			log_error("Failed to deactivate zeroed snapshot exception store.");
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!archive(lv->vg))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	if (!vg_add_snapshot(org, lv, NULL, org->le_count, chunk_size)) {
 | 
			
		||||
		log_error("Couldn't create snapshot.");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* store vg on disk(s) */
 | 
			
		||||
	if (!lv_update_and_reload(org))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	log_print_unless_silent("Logical volume %s converted to snapshot.", snap_name);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_merge_old_snapshot(struct cmd_context *cmd,
 | 
			
		||||
					 struct logical_volume *lv,
 | 
			
		||||
					 struct logical_volume **lv_to_poll)
 | 
			
		||||
{
 | 
			
		||||
	int merge_on_activate = 0;
 | 
			
		||||
	struct logical_volume *origin = origin_from_cow(lv);
 | 
			
		||||
	struct lv_segment *snap_seg = find_snapshot(lv);
 | 
			
		||||
	struct lvinfo info;
 | 
			
		||||
	dm_percent_t snap_percent;
 | 
			
		||||
 | 
			
		||||
	if (lv_is_external_origin(origin_from_cow(lv))) {
 | 
			
		||||
		log_error("Cannot merge snapshot \"%s\" into "
 | 
			
		||||
			  "the read-only external origin \"%s\".",
 | 
			
		||||
			  lv->name, origin_from_cow(lv)->name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME: test when snapshot is remotely active */
 | 
			
		||||
	if (lv_info(cmd, lv, 0, &info, 1, 0)
 | 
			
		||||
	    && info.exists && info.live_table &&
 | 
			
		||||
	    (!lv_snapshot_percent(lv, &snap_percent) ||
 | 
			
		||||
	     snap_percent == DM_PERCENT_INVALID)) {
 | 
			
		||||
		log_error("Unable to merge invalidated snapshot LV \"%s\".",
 | 
			
		||||
			  lv->name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (snap_seg->segtype->ops->target_present &&
 | 
			
		||||
	    !snap_seg->segtype->ops->target_present(cmd, snap_seg, NULL)) {
 | 
			
		||||
		log_error("Can't initialize snapshot merge. "
 | 
			
		||||
			  "Missing support in kernel?");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!archive(lv->vg))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Prevent merge with open device(s) as it would likely lead
 | 
			
		||||
	 * to application/filesystem failure.  Merge on origin's next
 | 
			
		||||
	 * activation if either the origin or snapshot LV are currently
 | 
			
		||||
	 * open.
 | 
			
		||||
	 *
 | 
			
		||||
	 * FIXME testing open_count is racey; snapshot-merge target's
 | 
			
		||||
	 * constructor and DM should prevent appropriate devices from
 | 
			
		||||
	 * being open.
 | 
			
		||||
	 */
 | 
			
		||||
	if (lv_is_active_locally(origin)) {
 | 
			
		||||
		if (!lv_check_not_in_use(origin, 0)) {
 | 
			
		||||
			log_print_unless_silent("Can't merge until origin volume is closed.");
 | 
			
		||||
			merge_on_activate = 1;
 | 
			
		||||
		} else if (!lv_check_not_in_use(lv, 0)) {
 | 
			
		||||
			log_print_unless_silent("Can't merge until snapshot is closed.");
 | 
			
		||||
			merge_on_activate = 1;
 | 
			
		||||
		}
 | 
			
		||||
	} else if (vg_is_clustered(origin->vg) && lv_is_active(origin)) {
 | 
			
		||||
		/* When it's active somewhere else */
 | 
			
		||||
		log_print_unless_silent("Can't check whether remotely active snapshot is open.");
 | 
			
		||||
		merge_on_activate = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init_snapshot_merge(snap_seg, origin);
 | 
			
		||||
 | 
			
		||||
	if (merge_on_activate) {
 | 
			
		||||
		/* Store and commit vg but skip starting the merge */
 | 
			
		||||
		if (!vg_write(lv->vg) || !vg_commit(lv->vg))
 | 
			
		||||
			return_0;
 | 
			
		||||
		backup(lv->vg);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Perform merge */
 | 
			
		||||
		if (!lv_update_and_reload(origin))
 | 
			
		||||
			return_0;
 | 
			
		||||
 | 
			
		||||
		*lv_to_poll = origin;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (merge_on_activate)
 | 
			
		||||
		log_print_unless_silent("Merging of snapshot %s will occur on "
 | 
			
		||||
					"next activation of %s.",
 | 
			
		||||
					display_lvname(lv), display_lvname(origin));
 | 
			
		||||
	else
 | 
			
		||||
		log_print_unless_silent("Merging of volume %s started.",
 | 
			
		||||
					display_lvname(lv));
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volume *cow)
 | 
			
		||||
{
 | 
			
		||||
	struct volume_group *vg = cow->vg;
 | 
			
		||||
	const char *cow_name = display_lvname(cow);
 | 
			
		||||
 | 
			
		||||
	if (lv_is_virtual_origin(origin_from_cow(cow))) {
 | 
			
		||||
		log_error("Unable to split off snapshot %s with virtual origin.", cow_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(vg->fid->fmt->features & FMT_MDAS)) {
 | 
			
		||||
		log_error("Unable to split off snapshot %s using old LVM1-style metadata.", cow_name);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (is_lockd_type(vg->lock_type)) {
 | 
			
		||||
		/* FIXME: we need to create a lock for the new LV. */
 | 
			
		||||
		log_error("Unable to split snapshots in VG with lock_type %s.", vg->lock_type);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lv_is_active_locally(cow)) {
 | 
			
		||||
		if (!lv_check_not_in_use(cow, 1))
 | 
			
		||||
			return_0;
 | 
			
		||||
 | 
			
		||||
		if ((arg_count(cmd, force_ARG) == PROMPT) &&
 | 
			
		||||
		    !arg_count(cmd, yes_ARG) &&
 | 
			
		||||
		    lv_is_visible(cow) &&
 | 
			
		||||
		    lv_is_active(cow)) {
 | 
			
		||||
			if (yes_no_prompt("Do you really want to split off active "
 | 
			
		||||
					  "logical volume %s? [y/n]: ", cow_name) == 'n') {
 | 
			
		||||
				log_error("Logical volume %s not split.", cow_name);
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!archive(vg))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	log_verbose("Splitting snapshot %s from its origin.", cow_name);
 | 
			
		||||
 | 
			
		||||
	if (!vg_remove_snapshot(cow))
 | 
			
		||||
		return_0;
 | 
			
		||||
 | 
			
		||||
	backup(vg);
 | 
			
		||||
 | 
			
		||||
	log_print_unless_silent("Logical Volume %s split from its origin.", cow_name);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Merge a COW snapshot LV into its origin.
 | 
			
		||||
 */
 | 
			
		||||
int lvconvert_merge_snapshot_single(struct cmd_context *cmd,
 | 
			
		||||
                                       struct logical_volume *lv,
 | 
			
		||||
                                       struct processing_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	struct lvconvert_result *lr = (struct lvconvert_result *) handle->custom_handle;
 | 
			
		||||
	struct logical_volume *lv_to_poll = NULL;
 | 
			
		||||
	struct convert_poll_id_list *idl;
 | 
			
		||||
 | 
			
		||||
	if (!_lvconvert_merge_old_snapshot(cmd, lv, &lv_to_poll))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
	if (lv_to_poll) {
 | 
			
		||||
		if (!(idl = convert_poll_id_list_create(cmd, lv_to_poll)))
 | 
			
		||||
			return_ECMD_FAILED;
 | 
			
		||||
		dm_list_add(&lr->poll_idls, &idl->list);
 | 
			
		||||
		lr->need_polling = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ECMD_PROCESSED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_merge_snapshot_check(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
			struct processing_handle *handle,
 | 
			
		||||
			int lv_is_named_arg)
 | 
			
		||||
{
 | 
			
		||||
	if (!lv_is_visible(lv)) {
 | 
			
		||||
		log_error("Operation not permitted (%s %d) on hidden LV %s.",
 | 
			
		||||
			  cmd->command->command_line_id, cmd->command->command_line_enum,
 | 
			
		||||
			  display_lvname(lv));
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvconvert_merge_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	struct processing_handle *handle;
 | 
			
		||||
	struct lvconvert_result lr = { 0 };
 | 
			
		||||
	struct convert_poll_id_list *idl;
 | 
			
		||||
	int ret, poll_ret;
 | 
			
		||||
 | 
			
		||||
	dm_list_init(&lr.poll_idls);
 | 
			
		||||
 | 
			
		||||
	if (!(handle = init_processing_handle(cmd, NULL))) {
 | 
			
		||||
		log_error("Failed to initialize processing handle.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handle->custom_handle = &lr;
 | 
			
		||||
 | 
			
		||||
	ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
 | 
			
		||||
			      handle, &_lvconvert_merge_snapshot_check, &lvconvert_merge_snapshot_single);
 | 
			
		||||
 | 
			
		||||
	if (lr.need_polling) {
 | 
			
		||||
		dm_list_iterate_items(idl, &lr.poll_idls) {
 | 
			
		||||
			poll_ret = lvconvert_poll_by_id(cmd, idl->id,
 | 
			
		||||
						arg_is_set(cmd, background_ARG), 1, 0);
 | 
			
		||||
			if (poll_ret > ret)
 | 
			
		||||
				ret = poll_ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	destroy_processing_handle(cmd, handle);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Separate a COW snapshot from its origin.
 | 
			
		||||
 *
 | 
			
		||||
 * lvconvert --splitsnapshot LV_snapshot
 | 
			
		||||
 * lvconvert_split_cow_snapshot
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_split_snapshot_single(struct cmd_context *cmd,
 | 
			
		||||
                                       struct logical_volume *lv,
 | 
			
		||||
                                       struct processing_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	if (!_lvconvert_splitsnapshot(cmd, lv))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
	return ECMD_PROCESSED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvconvert_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	return process_each_lv(cmd, 1, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE,
 | 
			
		||||
			       NULL, &lvconvert_generic_check, &_lvconvert_split_snapshot_single);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Combine two LVs that were once an origin/cow pair of LVs, were then
 | 
			
		||||
 * separated with --splitsnapshot, and now with this command are combined again
 | 
			
		||||
 * into the origin/cow pair.
 | 
			
		||||
 *
 | 
			
		||||
 * This is an obscure command that has little to no real uses.
 | 
			
		||||
 *
 | 
			
		||||
 * The command has unusual handling of position args.  The first position arg
 | 
			
		||||
 * will become the origin LV, and is not processed by process_each_lv.  The
 | 
			
		||||
 * second position arg will become the cow LV and is processed by
 | 
			
		||||
 * process_each_lv.
 | 
			
		||||
 *
 | 
			
		||||
 * The single function can grab the origin LV from position_argv[0].
 | 
			
		||||
 *
 | 
			
		||||
 * begin with an ordinary LV foo:
 | 
			
		||||
 * lvcreate -n foo -L 1 vg
 | 
			
		||||
 *
 | 
			
		||||
 * create a cow snapshot of foo named foosnap:
 | 
			
		||||
 * lvcreate -s -L 1 -n foosnap vg/foo
 | 
			
		||||
 *
 | 
			
		||||
 * now, foo is an "origin LV" and foosnap is a "cow LV"
 | 
			
		||||
 * (foosnap matches LV_snapshot aka lv_is_cow)
 | 
			
		||||
 *
 | 
			
		||||
 * split the two LVs apart:
 | 
			
		||||
 * lvconvert --splitsnapshot vg/foosnap
 | 
			
		||||
 *
 | 
			
		||||
 * now, foo is *not* an origin LV and foosnap is *not* a cow LV
 | 
			
		||||
 * (foosnap does not match LV_snapshot)
 | 
			
		||||
 *
 | 
			
		||||
 * now, combine the two LVs again:
 | 
			
		||||
 * lvconvert --snapshot vg/foo vg/foosnap
 | 
			
		||||
 *
 | 
			
		||||
 * after this, foosnap will match LV_snapshot again.
 | 
			
		||||
 *
 | 
			
		||||
 * FIXME: when splitsnapshot is run, the previous cow LV should be
 | 
			
		||||
 * flagged in the metadata somehow, and then that flag should be
 | 
			
		||||
 * required here.  As it is now, the first and second args
 | 
			
		||||
 * (origin and cow) can be swapped and nothing catches it.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int _lvconvert_combine_split_snapshot_single(struct cmd_context *cmd,
 | 
			
		||||
                                       struct logical_volume *lv,
 | 
			
		||||
                                       struct processing_handle *handle)
 | 
			
		||||
{
 | 
			
		||||
	const char *origin_name = cmd->position_argv[0];
 | 
			
		||||
 | 
			
		||||
	/* If origin_name includes VG name, the VG name is removed. */
 | 
			
		||||
	if (!validate_lvname_param(cmd, &lv->vg->name, &origin_name))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
	if (!_lvconvert_snapshot(cmd, lv, origin_name))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
	return ECMD_PROCESSED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int lvconvert_combine_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	return process_each_lv(cmd, 1, cmd->position_argv + 1, NULL, NULL, READ_FOR_UPDATE,
 | 
			
		||||
			       NULL, &lvconvert_generic_check, &_lvconvert_combine_split_snapshot_single);
 | 
			
		||||
}
 | 
			
		||||
@@ -58,5 +58,5 @@ int lvdisplay(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
		return EINVALID_CMD_LINE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, &_lvdisplay_single);
 | 
			
		||||
	return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, NULL, &_lvdisplay_single);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								tools/lvm.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								tools/lvm.c
									
									
									
									
									
								
							@@ -45,9 +45,9 @@ static char *_list_cmds(const char *text, int state)
 | 
			
		||||
		len = strlen(text);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (i < _cmdline->num_commands)
 | 
			
		||||
		if (!strncmp(text, _cmdline->commands[i++].name, len))
 | 
			
		||||
			return strdup(_cmdline->commands[i - 1].name);
 | 
			
		||||
	while (i < _cmdline->num_command_names)
 | 
			
		||||
		if (!strncmp(text, _cmdline->command_names[i++].name, len))
 | 
			
		||||
			return strdup(_cmdline->command_names[i - 1].name);
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
@@ -57,7 +57,7 @@ static char *_list_args(const char *text, int state)
 | 
			
		||||
{
 | 
			
		||||
	static int match_no = 0;
 | 
			
		||||
	static size_t len = 0;
 | 
			
		||||
	static struct command *com;
 | 
			
		||||
	static struct command_name *cname;
 | 
			
		||||
 | 
			
		||||
	/* Initialise if this is a new completion attempt */
 | 
			
		||||
	if (!state) {
 | 
			
		||||
@@ -65,40 +65,40 @@ static char *_list_args(const char *text, int state)
 | 
			
		||||
		int j;
 | 
			
		||||
 | 
			
		||||
		match_no = 0;
 | 
			
		||||
		com = NULL;
 | 
			
		||||
		cname = NULL;
 | 
			
		||||
		len = strlen(text);
 | 
			
		||||
 | 
			
		||||
		/* Find start of first word in line buffer */
 | 
			
		||||
		while (isspace(*s))
 | 
			
		||||
			s++;
 | 
			
		||||
 | 
			
		||||
		/* Look for word in list of commands */
 | 
			
		||||
		for (j = 0; j < _cmdline->num_commands; j++) {
 | 
			
		||||
		/* Look for word in list of command names */
 | 
			
		||||
		for (j = 0; j < _cmdline->num_command_names; j++) {
 | 
			
		||||
			const char *p;
 | 
			
		||||
			char *q = s;
 | 
			
		||||
 | 
			
		||||
			p = _cmdline->commands[j].name;
 | 
			
		||||
			p = _cmdline->command_names[j].name;
 | 
			
		||||
			while (*p == *q) {
 | 
			
		||||
				p++;
 | 
			
		||||
				q++;
 | 
			
		||||
			}
 | 
			
		||||
			if ((!*p) && *q == ' ') {
 | 
			
		||||
				com = _cmdline->commands + j;
 | 
			
		||||
				cname = _cmdline->command_names + j;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!com)
 | 
			
		||||
	if (!cname)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	/* Short form arguments */
 | 
			
		||||
	if (len < 3) {
 | 
			
		||||
		while (match_no < com->num_args) {
 | 
			
		||||
		while (match_no < cname->num_args) {
 | 
			
		||||
			char s[3];
 | 
			
		||||
			char c;
 | 
			
		||||
			if (!(c = (_cmdline->arg_props +
 | 
			
		||||
				   com->valid_args[match_no++])->short_arg))
 | 
			
		||||
				   cname->valid_args[match_no++])->short_arg))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			sprintf(s, "-%c", c);
 | 
			
		||||
@@ -108,13 +108,13 @@ static char *_list_args(const char *text, int state)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Long form arguments */
 | 
			
		||||
	if (match_no < com->num_args)
 | 
			
		||||
		match_no = com->num_args;
 | 
			
		||||
	if (match_no < cname->num_args)
 | 
			
		||||
		match_no = cname->num_args;
 | 
			
		||||
 | 
			
		||||
	while (match_no - com->num_args < com->num_args) {
 | 
			
		||||
	while (match_no - cname->num_args < cname->num_args) {
 | 
			
		||||
		const char *l;
 | 
			
		||||
		l = (_cmdline->arg_props +
 | 
			
		||||
		     com->valid_args[match_no++ - com->num_args])->long_arg;
 | 
			
		||||
		     cname->valid_args[match_no++ - cname->num_args])->long_arg;
 | 
			
		||||
		if (*(l + 2) && !strncmp(text, l, len))
 | 
			
		||||
			return strdup(l);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,10 +19,11 @@
 | 
			
		||||
struct cmd_context;
 | 
			
		||||
 | 
			
		||||
struct cmdline_context {
 | 
			
		||||
        struct arg_props *arg_props;
 | 
			
		||||
        struct command *commands;
 | 
			
		||||
        int num_commands;
 | 
			
		||||
        int commands_size;
 | 
			
		||||
	struct arg_props *arg_props;
 | 
			
		||||
	struct command *commands;
 | 
			
		||||
	int num_commands;
 | 
			
		||||
	struct command_name *command_names;
 | 
			
		||||
	int num_command_names;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int lvm2_main(int argc, char **argv);
 | 
			
		||||
 
 | 
			
		||||
@@ -30,12 +30,12 @@ void *cmdlib_lvm2_init(unsigned static_compile)
 | 
			
		||||
{
 | 
			
		||||
	struct cmd_context *cmd;
 | 
			
		||||
 | 
			
		||||
	lvm_register_commands();
 | 
			
		||||
 | 
			
		||||
	init_is_static(static_compile);
 | 
			
		||||
	if (!(cmd = init_lvm(1, 1)))
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	lvm_register_commands();
 | 
			
		||||
 | 
			
		||||
	return (void *) cmd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1466
									
								
								tools/lvmcmdline.c
									
									
									
									
									
								
							
							
						
						
									
										1466
									
								
								tools/lvmcmdline.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -27,5 +27,5 @@ int lvremove(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
	cmd->include_historical_lvs = 1;
 | 
			
		||||
 | 
			
		||||
	return process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, NULL,
 | 
			
		||||
			       &lvremove_single);
 | 
			
		||||
			       NULL, &lvremove_single);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -119,5 +119,5 @@ int lvscan(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
		 */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, &lvscan_single);
 | 
			
		||||
	return process_each_lv(cmd, argc, argv, NULL, NULL, 0, NULL, NULL, &lvscan_single);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -484,14 +484,14 @@ static int _report_all_in_vg(struct cmd_context *cmd, struct processing_handle *
 | 
			
		||||
			r = _vgs_single(cmd, vg->name, vg, handle);
 | 
			
		||||
			break;
 | 
			
		||||
		case LVS:
 | 
			
		||||
			r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle,
 | 
			
		||||
			r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle, NULL,
 | 
			
		||||
						  do_lv_info && !do_lv_seg_status ? &_lvs_with_info_single :
 | 
			
		||||
						  !do_lv_info && do_lv_seg_status ? &_lvs_with_status_single :
 | 
			
		||||
						  do_lv_info && do_lv_seg_status ? &_lvs_with_info_and_status_single :
 | 
			
		||||
										   &_lvs_single);
 | 
			
		||||
			break;
 | 
			
		||||
		case SEGS:
 | 
			
		||||
			r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle,
 | 
			
		||||
			r = process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, handle, NULL,
 | 
			
		||||
						  do_lv_info && !do_lv_seg_status ? &_lvsegs_with_info_single :
 | 
			
		||||
						  !do_lv_info && do_lv_seg_status ? &_lvsegs_with_status_single :
 | 
			
		||||
						  do_lv_info && do_lv_seg_status ? &_lvsegs_with_info_and_status_single :
 | 
			
		||||
@@ -1066,7 +1066,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
 | 
			
		||||
			if (args->full_report_vg)
 | 
			
		||||
				r = _report_all_in_vg(cmd, handle, args->full_report_vg, LVS, lv_info_needed, lv_segment_status_needed);
 | 
			
		||||
			else
 | 
			
		||||
				r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle,
 | 
			
		||||
				r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle, NULL,
 | 
			
		||||
						    lv_info_needed && !lv_segment_status_needed ? &_lvs_with_info_single :
 | 
			
		||||
						    !lv_info_needed && lv_segment_status_needed ? &_lvs_with_status_single :
 | 
			
		||||
						    lv_info_needed && lv_segment_status_needed ? &_lvs_with_info_and_status_single :
 | 
			
		||||
@@ -1100,7 +1100,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
 | 
			
		||||
			if (args->full_report_vg)
 | 
			
		||||
				r = _report_all_in_vg(cmd, handle, args->full_report_vg, SEGS, lv_info_needed, lv_segment_status_needed);
 | 
			
		||||
			else
 | 
			
		||||
				r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle,
 | 
			
		||||
				r = process_each_lv(cmd, args->argc, args->argv, NULL, NULL, 0, handle, NULL,
 | 
			
		||||
						    lv_info_needed && !lv_segment_status_needed ? &_lvsegs_with_info_single :
 | 
			
		||||
						    !lv_info_needed && lv_segment_status_needed ? &_lvsegs_with_status_single :
 | 
			
		||||
						    lv_info_needed && lv_segment_status_needed ? &_lvsegs_with_info_and_status_single :
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										849
									
								
								tools/toollib.c
									
									
									
									
									
								
							
							
						
						
									
										849
									
								
								tools/toollib.c
									
									
									
									
									
								
							@@ -800,10 +800,7 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (arg_is_set(cmd, metadatacopies_ARG))
 | 
			
		||||
		vp_new->vgmetadatacopies = arg_int_value(cmd, metadatacopies_ARG,
 | 
			
		||||
							DEFAULT_VGMETADATACOPIES);
 | 
			
		||||
	else if (arg_is_set(cmd, vgmetadatacopies_ARG))
 | 
			
		||||
	if (arg_is_set(cmd, vgmetadatacopies_ARG))
 | 
			
		||||
		vp_new->vgmetadatacopies = arg_int_value(cmd, vgmetadatacopies_ARG,
 | 
			
		||||
							DEFAULT_VGMETADATACOPIES);
 | 
			
		||||
	else
 | 
			
		||||
@@ -2328,10 +2325,606 @@ static struct lv_segment _historical_lv_segment = {
 | 
			
		||||
	.origin_list = DM_LIST_HEAD_INIT(_historical_lv_segment.origin_list),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count,
 | 
			
		||||
		       int *match_count, int *unmatch_count)
 | 
			
		||||
{
 | 
			
		||||
	int match = 0;
 | 
			
		||||
	int unmatch = 0;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < count; i++) {
 | 
			
		||||
		if (arg_is_set(cmd, opts[i]))
 | 
			
		||||
			match++;
 | 
			
		||||
		else
 | 
			
		||||
			unmatch++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (match_count)
 | 
			
		||||
		*match_count = match;
 | 
			
		||||
	if (unmatch_count)
 | 
			
		||||
		*unmatch_count = unmatch;
 | 
			
		||||
 | 
			
		||||
	return match ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
      
 | 
			
		||||
void opt_array_to_str(struct cmd_context *cmd, int *opts, int count,
 | 
			
		||||
		      char *buf, int len)
 | 
			
		||||
{
 | 
			
		||||
	int pos = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < count; i++) {
 | 
			
		||||
		ret = snprintf(buf + pos, len - pos, "%s ", arg_long_option_name(opts[i]));
 | 
			
		||||
		if (ret >= len - pos)
 | 
			
		||||
			break;
 | 
			
		||||
		pos += ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buf[len - 1] = '\0';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lvp_bits_to_str(uint64_t bits, char *buf, int len)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_props *prop;
 | 
			
		||||
	int lvp_enum;
 | 
			
		||||
	int pos = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	for (lvp_enum = 0; lvp_enum < LVP_COUNT; lvp_enum++) {
 | 
			
		||||
		if (!(prop = get_lv_prop(lvp_enum)))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (lvp_bit_is_set(bits, lvp_enum)) {
 | 
			
		||||
			ret = snprintf(buf + pos, len - pos, "%s ", prop->name);
 | 
			
		||||
			if (ret >= len - pos)
 | 
			
		||||
				break;
 | 
			
		||||
			pos += ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	buf[len - 1] = '\0';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lvt_bits_to_str(uint64_t bits, char *buf, int len)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_types *type;
 | 
			
		||||
	int lvt_enum;
 | 
			
		||||
	int pos = 0;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	for (lvt_enum = 0; lvt_enum < LVT_COUNT; lvt_enum++) {
 | 
			
		||||
		if (!(type = get_lv_type(lvt_enum)))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (lvt_bit_is_set(bits, lvt_enum)) {
 | 
			
		||||
			ret = snprintf(buf + pos, len - pos, "%s ", type->name);
 | 
			
		||||
			if (ret >= len - pos)
 | 
			
		||||
				break;
 | 
			
		||||
			pos += ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	buf[len - 1] = '\0';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is the lv_prop function pointer used for lv_is_foo() #defines.
 | 
			
		||||
 * Alternatively, lv_is_foo() could all be turned into functions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int _lv_is_prop(struct cmd_context *cmd, struct logical_volume *lv, int lvp_enum)
 | 
			
		||||
{
 | 
			
		||||
	switch (lvp_enum) {
 | 
			
		||||
	case is_locked_LVP:
 | 
			
		||||
		return lv_is_locked(lv);
 | 
			
		||||
	case is_partial_LVP:
 | 
			
		||||
		return lv_is_partial(lv);
 | 
			
		||||
	case is_virtual_LVP:
 | 
			
		||||
		return lv_is_virtual(lv);
 | 
			
		||||
	case is_merging_LVP:
 | 
			
		||||
		return lv_is_merging(lv);
 | 
			
		||||
	case is_merging_origin_LVP:
 | 
			
		||||
		return lv_is_merging_origin(lv);
 | 
			
		||||
	case is_converting_LVP:
 | 
			
		||||
		return lv_is_converting(lv);
 | 
			
		||||
	case is_external_origin_LVP:
 | 
			
		||||
		return lv_is_external_origin(lv);
 | 
			
		||||
	case is_virtual_origin_LVP:
 | 
			
		||||
		return lv_is_virtual_origin(lv);
 | 
			
		||||
	case is_not_synced_LVP:
 | 
			
		||||
		return lv_is_not_synced(lv);
 | 
			
		||||
	case is_pending_delete_LVP:
 | 
			
		||||
		return lv_is_pending_delete(lv);
 | 
			
		||||
	case is_error_when_full_LVP:
 | 
			
		||||
		return lv_is_error_when_full(lv);
 | 
			
		||||
	case is_pvmove_LVP:
 | 
			
		||||
		return lv_is_pvmove(lv);
 | 
			
		||||
	case is_removed_LVP:
 | 
			
		||||
		return lv_is_removed(lv);
 | 
			
		||||
	case is_vg_writable_LVP:
 | 
			
		||||
		return (lv->vg->status & LVM_WRITE) ? 1 : 0;
 | 
			
		||||
	case is_thinpool_data_LVP:
 | 
			
		||||
		return lv_is_thin_pool_data(lv);
 | 
			
		||||
	case is_thinpool_metadata_LVP:
 | 
			
		||||
		return lv_is_thin_pool_metadata(lv);
 | 
			
		||||
	case is_cachepool_data_LVP:
 | 
			
		||||
		return lv_is_cache_pool_data(lv);
 | 
			
		||||
	case is_cachepool_metadata_LVP:
 | 
			
		||||
		return lv_is_cache_pool_metadata(lv);
 | 
			
		||||
	case is_mirror_image_LVP:
 | 
			
		||||
		return lv_is_mirror_image(lv);
 | 
			
		||||
	case is_mirror_log_LVP:
 | 
			
		||||
		return lv_is_mirror_log(lv);
 | 
			
		||||
	case is_raid_image_LVP:
 | 
			
		||||
		return lv_is_raid_image(lv);
 | 
			
		||||
	case is_raid_metadata_LVP:
 | 
			
		||||
		return lv_is_raid_metadata(lv);
 | 
			
		||||
	case is_origin_LVP: /* use lv_is_thick_origin */
 | 
			
		||||
		return lv_is_origin(lv);
 | 
			
		||||
	case is_thick_origin_LVP:
 | 
			
		||||
		return lv_is_thick_origin(lv);
 | 
			
		||||
	case is_thick_snapshot_LVP:
 | 
			
		||||
		return lv_is_thick_snapshot(lv);
 | 
			
		||||
	case is_thin_origin_LVP:
 | 
			
		||||
		return lv_is_thin_origin(lv, NULL);
 | 
			
		||||
	case is_thin_snapshot_LVP:
 | 
			
		||||
		return lv_is_thin_snapshot(lv);
 | 
			
		||||
	case is_cache_origin_LVP:
 | 
			
		||||
		return lv_is_cache_origin(lv);
 | 
			
		||||
	case is_merging_cow_LVP:
 | 
			
		||||
		return lv_is_merging_cow(lv);
 | 
			
		||||
	case is_cow_covering_origin_LVP:
 | 
			
		||||
		return lv_is_cow_covering_origin(lv);
 | 
			
		||||
	case is_visible_LVP:
 | 
			
		||||
		return lv_is_visible(lv);
 | 
			
		||||
	case is_historical_LVP:
 | 
			
		||||
		return lv_is_historical(lv);
 | 
			
		||||
	case is_raid_with_tracking_LVP:
 | 
			
		||||
		return lv_is_raid_with_tracking(lv);
 | 
			
		||||
	default:
 | 
			
		||||
		log_error(INTERNAL_ERROR "unknown lv property value lvp_enum %d", lvp_enum);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Check if an LV matches a given LV type enum.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int _lv_is_type(struct cmd_context *cmd, struct logical_volume *lv, int lvt_enum)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_segment *seg = first_seg(lv);
 | 
			
		||||
 | 
			
		||||
	switch (lvt_enum) {
 | 
			
		||||
	case striped_LVT:
 | 
			
		||||
		return seg_is_striped(seg) && !lv_is_cow(lv);
 | 
			
		||||
	case linear_LVT:
 | 
			
		||||
		return seg_is_linear(seg) && !lv_is_cow(lv);
 | 
			
		||||
	case snapshot_LVT:
 | 
			
		||||
		return lv_is_cow(lv);
 | 
			
		||||
	case thin_LVT:
 | 
			
		||||
		return lv_is_thin_volume(lv);
 | 
			
		||||
	case thinpool_LVT:
 | 
			
		||||
		return lv_is_thin_pool(lv);
 | 
			
		||||
	case cache_LVT:
 | 
			
		||||
		return lv_is_cache(lv);
 | 
			
		||||
	case cachepool_LVT:
 | 
			
		||||
		return lv_is_cache_pool(lv);
 | 
			
		||||
	case mirror_LVT:
 | 
			
		||||
		return lv_is_mirror(lv);
 | 
			
		||||
	case raid_LVT:
 | 
			
		||||
		return lv_is_raid(lv);
 | 
			
		||||
	case raid0_LVT:
 | 
			
		||||
		return seg_is_raid0(seg);
 | 
			
		||||
	case raid1_LVT:
 | 
			
		||||
		return seg_is_raid1(seg);
 | 
			
		||||
	case raid4_LVT:
 | 
			
		||||
		return seg_is_raid4(seg);
 | 
			
		||||
#if 0
 | 
			
		||||
	case raid5_LVT:
 | 
			
		||||
		return seg_is_raid5(seg);
 | 
			
		||||
	case raid6_LVT:
 | 
			
		||||
		return seg_is_raid6(seg);
 | 
			
		||||
#endif
 | 
			
		||||
	case raid10_LVT:
 | 
			
		||||
		return seg_is_raid10(seg);
 | 
			
		||||
	case error_LVT:
 | 
			
		||||
		return !strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR);
 | 
			
		||||
	case zero_LVT:
 | 
			
		||||
		return !strcmp(seg->segtype->name, SEG_TYPE_NAME_ZERO);
 | 
			
		||||
	default:
 | 
			
		||||
		log_error(INTERNAL_ERROR "unknown lv type value lvt_enum %d", lvt_enum);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int get_lvt_enum(struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_segment *seg = first_seg(lv);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * The order these are checked is important, because a snapshot LV has
 | 
			
		||||
	 * a linear seg type.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	if (lv_is_cow(lv))
 | 
			
		||||
		return snapshot_LVT;
 | 
			
		||||
	if (seg_is_linear(seg))
 | 
			
		||||
		return linear_LVT;
 | 
			
		||||
	if (seg_is_striped(seg))
 | 
			
		||||
		return striped_LVT;
 | 
			
		||||
	if (lv_is_thin_volume(lv))
 | 
			
		||||
		return thin_LVT;
 | 
			
		||||
	if (lv_is_thin_pool(lv))
 | 
			
		||||
		return thinpool_LVT;
 | 
			
		||||
	if (lv_is_cache(lv))
 | 
			
		||||
		return cache_LVT;
 | 
			
		||||
	if (lv_is_cache_pool(lv))
 | 
			
		||||
		return cachepool_LVT;
 | 
			
		||||
	if (lv_is_mirror(lv))
 | 
			
		||||
		return mirror_LVT;
 | 
			
		||||
	if (lv_is_raid(lv))
 | 
			
		||||
		return raid_LVT;
 | 
			
		||||
	if (seg_is_raid0(seg))
 | 
			
		||||
		return raid0_LVT;
 | 
			
		||||
	if (seg_is_raid1(seg))
 | 
			
		||||
		return raid1_LVT;
 | 
			
		||||
	if (seg_is_raid4(seg))
 | 
			
		||||
		return raid4_LVT;
 | 
			
		||||
#if 0
 | 
			
		||||
	if (seg_is_raid5(seg))
 | 
			
		||||
		return raid5_LVT;
 | 
			
		||||
	if (seg_is_raid6(seg))
 | 
			
		||||
		return raid6_LVT;
 | 
			
		||||
#endif
 | 
			
		||||
	if (seg_is_raid10(seg))
 | 
			
		||||
		return raid10_LVT;
 | 
			
		||||
 | 
			
		||||
	if (!strcmp(seg->segtype->name, SEG_TYPE_NAME_ERROR))
 | 
			
		||||
		return error_LVT;
 | 
			
		||||
	if (!strcmp(seg->segtype->name, SEG_TYPE_NAME_ZERO))
 | 
			
		||||
		return zero_LVT;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Call lv_is_<type> for each <type>_LVT bit set in lvt_bits.
 | 
			
		||||
 * If lv matches one of the specified lv types, then return 1.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int _lv_types_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvt_bits,
 | 
			
		||||
			   uint64_t *match_bits, uint64_t *unmatch_bits)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_types *type;
 | 
			
		||||
	int lvt_enum;
 | 
			
		||||
	int found_a_match = 0;
 | 
			
		||||
	int match;
 | 
			
		||||
 | 
			
		||||
	if (match_bits)
 | 
			
		||||
		*match_bits = 0;
 | 
			
		||||
	if (unmatch_bits)
 | 
			
		||||
		*unmatch_bits = 0;
 | 
			
		||||
 | 
			
		||||
	for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
 | 
			
		||||
		if (!lvt_bit_is_set(lvt_bits, lvt_enum))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(type = get_lv_type(lvt_enum)))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * All types are currently handled by _lv_is_type()
 | 
			
		||||
		 * because lv_is_type() are #defines and not exposed
 | 
			
		||||
		 * in tools.h
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		if (!type->fn)
 | 
			
		||||
			match = _lv_is_type(cmd, lv, lvt_enum);
 | 
			
		||||
		else
 | 
			
		||||
			match = type->fn(cmd, lv);
 | 
			
		||||
 | 
			
		||||
		if (match)
 | 
			
		||||
			found_a_match = 1;
 | 
			
		||||
 | 
			
		||||
		if (match_bits && match)
 | 
			
		||||
			*match_bits |= lvt_enum_to_bit(lvt_enum);
 | 
			
		||||
 | 
			
		||||
		if (unmatch_bits && !match)
 | 
			
		||||
			*unmatch_bits |= lvt_enum_to_bit(lvt_enum);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return found_a_match;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Call lv_is_<prop> for each <prop>_LVP bit set in lvp_bits.
 | 
			
		||||
 * If lv matches all of the specified lv properties, then return 1.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int _lv_props_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvp_bits,
 | 
			
		||||
			   uint64_t *match_bits, uint64_t *unmatch_bits)
 | 
			
		||||
{
 | 
			
		||||
	struct lv_props *prop;
 | 
			
		||||
	int lvp_enum;
 | 
			
		||||
	int found_a_mismatch = 0;
 | 
			
		||||
	int match;
 | 
			
		||||
 | 
			
		||||
	if (match_bits)
 | 
			
		||||
		*match_bits = 0;
 | 
			
		||||
	if (unmatch_bits)
 | 
			
		||||
		*unmatch_bits = 0;
 | 
			
		||||
 | 
			
		||||
	for (lvp_enum = 1; lvp_enum < LVP_COUNT; lvp_enum++) {
 | 
			
		||||
		if (!lvp_bit_is_set(lvp_bits, lvp_enum))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(prop = get_lv_prop(lvp_enum)))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!prop->fn)
 | 
			
		||||
			match = _lv_is_prop(cmd, lv, lvp_enum);
 | 
			
		||||
		else
 | 
			
		||||
			match = prop->fn(cmd, lv);
 | 
			
		||||
 | 
			
		||||
		if (!match)
 | 
			
		||||
			found_a_mismatch = 1;
 | 
			
		||||
 | 
			
		||||
		if (match_bits && match)
 | 
			
		||||
			*match_bits |= lvp_enum_to_bit(lvp_enum);
 | 
			
		||||
 | 
			
		||||
		if (unmatch_bits && !match)
 | 
			
		||||
			*unmatch_bits |= lvp_enum_to_bit(lvp_enum);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return !found_a_mismatch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _check_lv_types(struct cmd_context *cmd, struct logical_volume *lv, int pos)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 1;
 | 
			
		||||
 | 
			
		||||
	if (!pos)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (!cmd->command->required_pos_args[pos-1].def.lvt_bits)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (!val_bit_is_set(cmd->command->required_pos_args[pos-1].def.val_bits, lv_VAL)) {
 | 
			
		||||
		log_error(INTERNAL_ERROR "Command (%s %d) arg position %d does not permit an LV (%llx)",
 | 
			
		||||
			  cmd->command->command_line_id, cmd->command->command_line_enum,
 | 
			
		||||
			  pos, (unsigned long long)cmd->command->required_pos_args[pos-1].def.val_bits);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = _lv_types_match(cmd, lv, cmd->command->required_pos_args[pos-1].def.lvt_bits, NULL, NULL);
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
		int lvt_enum = get_lvt_enum(lv);
 | 
			
		||||
		struct lv_types *type = get_lv_type(lvt_enum);
 | 
			
		||||
		log_warn("Operation on LV %s which has invalid type %s.",
 | 
			
		||||
			 display_lvname(lv), type ? type->name : "unknown");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Check if LV passes each rule specified in command definition. */
 | 
			
		||||
 | 
			
		||||
static int _check_lv_rules(struct cmd_context *cmd, struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	char buf[64];
 | 
			
		||||
	struct cmd_rule *rule;
 | 
			
		||||
	struct lv_types *lvtype = NULL;
 | 
			
		||||
	uint64_t lv_props_match_bits, lv_props_unmatch_bits;
 | 
			
		||||
	uint64_t lv_types_match_bits, lv_types_unmatch_bits;
 | 
			
		||||
	int opts_match_count, opts_unmatch_count;
 | 
			
		||||
	int lvt_enum;
 | 
			
		||||
	int ret = 1;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	lvt_enum = get_lvt_enum(lv);
 | 
			
		||||
	if (lvt_enum)
 | 
			
		||||
		lvtype = get_lv_type(lvt_enum);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < cmd->command->rule_count; i++) {
 | 
			
		||||
		rule = &cmd->command->rules[i];
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * RULE: <conditions> INVALID|REQUIRE <checks>
 | 
			
		||||
		 *
 | 
			
		||||
		 * If all the conditions apply to the command+LV, then
 | 
			
		||||
		 * the checks are performed.  If all conditions are zero
 | 
			
		||||
		 * (!opts_count, !lvt_bits, !lvp_bits), then the check
 | 
			
		||||
		 * is always performed.
 | 
			
		||||
		 *
 | 
			
		||||
		 * Conditions:
 | 
			
		||||
		 *
 | 
			
		||||
		 * 1. options (opts): if any of the specified options are set,
 | 
			
		||||
		 *    then the checks may apply.
 | 
			
		||||
		 *
 | 
			
		||||
		 * 2. LV types (lvt_bits): if any of the specified LV types
 | 
			
		||||
		 *    match the LV, then the checks may apply.
 | 
			
		||||
		 *
 | 
			
		||||
		 * 3. LV properties (lvp_bits): if all of the specified
 | 
			
		||||
		 *    LV properties match the LV, then the checks may apply.
 | 
			
		||||
		 *
 | 
			
		||||
		 * If conditions 1, 2, 3 all pass, then the checks apply.
 | 
			
		||||
		 *
 | 
			
		||||
		 * Checks:
 | 
			
		||||
		 *
 | 
			
		||||
		 * 1. options (check_opts):
 | 
			
		||||
		 *    INVALID: if any of the specified options are set,
 | 
			
		||||
		 *    then the command fails.
 | 
			
		||||
		 *    REQUIRE: if any of the specified options are not set,
 | 
			
		||||
		 *    then the command fails.
 | 
			
		||||
		 *
 | 
			
		||||
		 * 2. LV types (check_lvt_bits):
 | 
			
		||||
		 *    INVALID: if any of the specified LV types match the LV,
 | 
			
		||||
		 *    then the command fails.
 | 
			
		||||
		 *    REQUIRE: if none of the specified LV types match the LV,
 | 
			
		||||
		 *    then the command fails.
 | 
			
		||||
		 *
 | 
			
		||||
		 * 3. LV properties (check_lvp_bits):
 | 
			
		||||
		 *    INVALID: if any of the specified LV properties match
 | 
			
		||||
		 *    the LV, then the command fails.
 | 
			
		||||
		 *    REQUIRE: if any of the specified LV properties do not match
 | 
			
		||||
		 *    the LV, then the command fails.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		if (rule->opts_count && !opt_in_list_is_set(cmd, rule->opts, rule->opts_count, NULL, NULL))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* If LV matches one type in lvt_bits, this returns 1. */
 | 
			
		||||
		if (rule->lvt_bits && !_lv_types_match(cmd, lv, rule->lvt_bits, NULL, NULL))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* If LV matches all properties in lvp_bits, this returns 1. */
 | 
			
		||||
		if (rule->lvp_bits && !_lv_props_match(cmd, lv, rule->lvp_bits, NULL, NULL))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Check the options, LV types, LV properties.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		if (rule->check_opts)
 | 
			
		||||
			opt_in_list_is_set(cmd, rule->check_opts, rule->check_opts_count,
 | 
			
		||||
					   &opts_match_count, &opts_unmatch_count);
 | 
			
		||||
 | 
			
		||||
		if (rule->check_lvt_bits)
 | 
			
		||||
			_lv_types_match(cmd, lv, rule->check_lvt_bits,
 | 
			
		||||
					&lv_types_match_bits, &lv_types_unmatch_bits);
 | 
			
		||||
 | 
			
		||||
		if (rule->check_lvp_bits)
 | 
			
		||||
			_lv_props_match(cmd, lv, rule->check_lvp_bits,
 | 
			
		||||
					&lv_props_match_bits, &lv_props_unmatch_bits);
 | 
			
		||||
		
 | 
			
		||||
		/*
 | 
			
		||||
		 * Evaluate if the check results pass based on the rule.
 | 
			
		||||
		 * The options are checked again here because the previous
 | 
			
		||||
		 * option validation (during command matching) does not cover
 | 
			
		||||
		 * cases where the option is combined with conditions of LV types
 | 
			
		||||
		 * or properties.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		/* Fail if any invalid options are set. */
 | 
			
		||||
 | 
			
		||||
		if (rule->check_opts && (rule->rule == RULE_INVALID) && opts_match_count) {
 | 
			
		||||
			memset(buf, 0, sizeof(buf));
 | 
			
		||||
			opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
 | 
			
		||||
			log_warn("An invalid option is set: %s", buf);
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Fail if any required options are not set. */
 | 
			
		||||
 | 
			
		||||
		if (rule->check_opts && (rule->rule == RULE_REQUIRE) && opts_unmatch_count)  {
 | 
			
		||||
			memset(buf, 0, sizeof(buf));
 | 
			
		||||
			opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
 | 
			
		||||
			log_warn("A required option is not set: %s", buf);
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Fail if the LV matches any of the invalid LV types. */
 | 
			
		||||
 | 
			
		||||
		if (rule->check_lvt_bits && (rule->rule == RULE_INVALID) && lv_types_match_bits) {
 | 
			
		||||
			log_warn("Command on LV %s with invalid type: %s",
 | 
			
		||||
				 display_lvname(lv), lvtype ? lvtype->name : "unknown");
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Fail if the LV does not match any of the required LV types. */
 | 
			
		||||
 | 
			
		||||
		if (rule->check_lvt_bits && (rule->rule == RULE_REQUIRE) && !lv_types_match_bits) {
 | 
			
		||||
			memset(buf, 0, sizeof(buf));
 | 
			
		||||
			lvt_bits_to_str(rule->check_lvt_bits, buf, sizeof(buf));
 | 
			
		||||
			log_warn("Command on LV %s with type %s does not match required type: %s",
 | 
			
		||||
				 display_lvname(lv), lvtype ? lvtype->name : "unknown", buf);
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Fail if the LV matches any of the invalid LV properties. */
 | 
			
		||||
 | 
			
		||||
		if (rule->check_lvp_bits && (rule->rule == RULE_INVALID) && lv_props_match_bits) {
 | 
			
		||||
			memset(buf, 0, sizeof(buf));
 | 
			
		||||
			lvp_bits_to_str(lv_props_match_bits, buf, sizeof(buf));
 | 
			
		||||
			log_warn("Command on LV %s with invalid properties: %s",
 | 
			
		||||
				 display_lvname(lv), buf);
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Fail if the LV does not match any of the required LV properties. */
 | 
			
		||||
 | 
			
		||||
		if (rule->check_lvp_bits && (rule->rule == RULE_REQUIRE) && lv_props_unmatch_bits) {
 | 
			
		||||
			memset(buf, 0, sizeof(buf));
 | 
			
		||||
			lvp_bits_to_str(lv_props_unmatch_bits, buf, sizeof(buf));
 | 
			
		||||
			log_warn("Command on LV %s requires properties: %s",
 | 
			
		||||
				 display_lvname(lv), buf);
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Return which arg position the given LV is at,
 | 
			
		||||
 * where 1 represents the first position arg.
 | 
			
		||||
 * When the first position arg is repeatable,
 | 
			
		||||
 * return 1 for all.
 | 
			
		||||
 *
 | 
			
		||||
 * Return 0 when the command has no required
 | 
			
		||||
 * position args. (optional position args are
 | 
			
		||||
 * not considered.)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int _find_lv_arg_position(struct cmd_context *cmd, struct logical_volume *lv)
 | 
			
		||||
{
 | 
			
		||||
	const char *sep, *lvname;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (cmd->command->rp_count == 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (cmd->command->rp_count == 1)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < cmd->position_argc; i++) {
 | 
			
		||||
		if (i == cmd->command->rp_count)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (!val_bit_is_set(cmd->command->required_pos_args[i].def.val_bits, lv_VAL))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if ((sep = strstr(cmd->position_argv[i], "/")))
 | 
			
		||||
			lvname = sep + 1;
 | 
			
		||||
		else
 | 
			
		||||
			lvname = cmd->position_argv[i];
 | 
			
		||||
 | 
			
		||||
		if (!strcmp(lvname, lv->name))
 | 
			
		||||
			return i + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If the last position arg is an LV and this
 | 
			
		||||
	 * arg is beyond that position, then the last
 | 
			
		||||
	 * LV position arg is repeatable, so return
 | 
			
		||||
	 * that position.
 | 
			
		||||
	 */
 | 
			
		||||
	if (i == cmd->command->rp_count) {
 | 
			
		||||
		int last_pos = cmd->command->rp_count;
 | 
			
		||||
		if (val_bit_is_set(cmd->command->required_pos_args[last_pos-1].def.val_bits, lv_VAL))
 | 
			
		||||
			return last_pos;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
			  struct dm_list *arg_lvnames, const struct dm_list *tags_in,
 | 
			
		||||
			  int stop_on_error,
 | 
			
		||||
			  struct processing_handle *handle,
 | 
			
		||||
			  check_single_lv_fn_t check_single_lv,
 | 
			
		||||
			  process_single_lv_fn_t process_single_lv)
 | 
			
		||||
{
 | 
			
		||||
	log_report_t saved_log_report_state = log_get_report_state();
 | 
			
		||||
@@ -2345,10 +2938,13 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
	unsigned process_all = 0;
 | 
			
		||||
	unsigned tags_supplied = 0;
 | 
			
		||||
	unsigned lvargs_supplied = 0;
 | 
			
		||||
	int lv_is_named_arg;
 | 
			
		||||
	int lv_arg_pos;
 | 
			
		||||
	struct lv_list *lvl;
 | 
			
		||||
	struct dm_str_list *sl;
 | 
			
		||||
	struct dm_list final_lvs;
 | 
			
		||||
	struct lv_list *final_lvl;
 | 
			
		||||
	struct dm_list found_arg_lvnames;
 | 
			
		||||
	struct glv_list *glvl, *tglvl;
 | 
			
		||||
	int do_report_ret_code = 1;
 | 
			
		||||
 | 
			
		||||
@@ -2359,6 +2955,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
		stack;
 | 
			
		||||
 | 
			
		||||
	dm_list_init(&final_lvs);
 | 
			
		||||
	dm_list_init(&found_arg_lvnames);
 | 
			
		||||
 | 
			
		||||
	if (!vg_check_status(vg, EXPORTED_VG)) {
 | 
			
		||||
		ret_max = ECMD_FAILED;
 | 
			
		||||
@@ -2452,6 +3049,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
		if (lvargs_supplied && str_list_match_item(arg_lvnames, lvl->lv->name)) {
 | 
			
		||||
			/* Remove LV from list of unprocessed LV names */
 | 
			
		||||
			str_list_del(arg_lvnames, lvl->lv->name);
 | 
			
		||||
			str_list_add(cmd->mem, &found_arg_lvnames, lvl->lv->name);
 | 
			
		||||
			process_lv = 1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -2499,6 +3097,43 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
		if (lv_is_removed(lvl->lv))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		lv_is_named_arg = str_list_match_item(&found_arg_lvnames, lvl->lv->name);
 | 
			
		||||
 | 
			
		||||
		lv_arg_pos = _find_lv_arg_position(cmd, lvl->lv);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * The command definition may include restrictions on the
 | 
			
		||||
		 * types and properties of LVs that can be processed.
 | 
			
		||||
		 */
 | 
			
		||||
 | 
			
		||||
		if (!_check_lv_types(cmd, lvl->lv, lv_arg_pos)) {
 | 
			
		||||
			/* FIXME: include this result in report log? */
 | 
			
		||||
			if (lv_is_named_arg) {
 | 
			
		||||
				log_error("Operation not permitted (%s %d) on LV %s.",
 | 
			
		||||
					  cmd->command->command_line_id, cmd->command->command_line_enum,
 | 
			
		||||
					  display_lvname(lvl->lv));
 | 
			
		||||
				ret_max = ECMD_FAILED;
 | 
			
		||||
			}
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!_check_lv_rules(cmd, lvl->lv)) {
 | 
			
		||||
			/* FIXME: include this result in report log? */
 | 
			
		||||
			if (lv_is_named_arg) {
 | 
			
		||||
				log_error("Operation not permitted (%s %d) on LV %s.",
 | 
			
		||||
					  cmd->command->command_line_id, cmd->command->command_line_enum,
 | 
			
		||||
					  display_lvname(lvl->lv));
 | 
			
		||||
				ret_max = ECMD_FAILED;
 | 
			
		||||
			} 
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (check_single_lv && !check_single_lv(cmd, lvl->lv, handle, lv_is_named_arg)) {
 | 
			
		||||
			if (lv_is_named_arg)
 | 
			
		||||
				ret_max = ECMD_FAILED;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);
 | 
			
		||||
 | 
			
		||||
		ret = process_single_lv(cmd, lvl->lv, handle);
 | 
			
		||||
@@ -2729,12 +3364,164 @@ static int _get_arg_lvnames(struct cmd_context *cmd,
 | 
			
		||||
	return ret_max;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is a non-standard way of finding vgname/lvname to process.  It exists
 | 
			
		||||
 * because an earlier form of lvconvert did not follow the standard form, and
 | 
			
		||||
 * came up with its own inconsistent approach.
 | 
			
		||||
 *
 | 
			
		||||
 * In this case, when the position arg is a single name, it is treated as an LV
 | 
			
		||||
 * name (not a VG name).  This leaves the VG unknown.  So, other option values
 | 
			
		||||
 * must be searched for a VG name.  If one of those option values contains a
 | 
			
		||||
 * vgname/lvname value, then the VG name is extracted and used for the LV
 | 
			
		||||
 * position arg.
 | 
			
		||||
 *
 | 
			
		||||
 * Other option values that are searched for a VG name are:
 | 
			
		||||
 * --thinpool, --cachepool.
 | 
			
		||||
 *
 | 
			
		||||
 *  . command vg/lv1
 | 
			
		||||
 *  . add vg to arg_vgnames
 | 
			
		||||
 *  . add vg/lv1 to arg_lvnames
 | 
			
		||||
 *
 | 
			
		||||
 *  command lv1
 | 
			
		||||
 *  . error: no vg name
 | 
			
		||||
 *
 | 
			
		||||
 *  command --option vg/lv1 vg/lv2
 | 
			
		||||
 *  . verify both vg names match
 | 
			
		||||
 *  . add vg to arg_vgnames
 | 
			
		||||
 *  . add vg/lv2 to arg_lvnames
 | 
			
		||||
 *
 | 
			
		||||
 *  command --option lv1 lv2
 | 
			
		||||
 *  . error: no vg name
 | 
			
		||||
 *
 | 
			
		||||
 *  command --option vg/lv1 lv2
 | 
			
		||||
 *  . add vg to arg_vgnames
 | 
			
		||||
 *  . add vg/lv2 to arg_lvnames
 | 
			
		||||
 *
 | 
			
		||||
 *  command --option lv1 vg/lv2
 | 
			
		||||
 *  . add vg to arg_vgnames
 | 
			
		||||
 *  . add vg/lv2 to arg_lvnames
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int _get_arg_lvnames_using_options(struct cmd_context *cmd,
 | 
			
		||||
			    		  int argc, char **argv,
 | 
			
		||||
					  struct dm_list *arg_vgnames,
 | 
			
		||||
					  struct dm_list *arg_lvnames,
 | 
			
		||||
					  struct dm_list *arg_tags)
 | 
			
		||||
{
 | 
			
		||||
	const char *pos_name = NULL;
 | 
			
		||||
	const char *arg_name = NULL;
 | 
			
		||||
	const char *pos_vgname = NULL;
 | 
			
		||||
	const char *opt_vgname = NULL;
 | 
			
		||||
	const char *pos_lvname = NULL;
 | 
			
		||||
	const char *use_vgname = NULL;
 | 
			
		||||
	char *tmp_name;
 | 
			
		||||
	char *split;
 | 
			
		||||
	char *vglv;
 | 
			
		||||
	size_t vglv_sz;
 | 
			
		||||
 | 
			
		||||
	if (argc != 1) {
 | 
			
		||||
		log_error("One LV position arg is required.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(pos_name = dm_pool_strdup(cmd->mem, argv[0]))) {
 | 
			
		||||
		log_error("string alloc failed.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (*pos_name == '@') {
 | 
			
		||||
		if (!validate_tag(pos_name + 1)) {
 | 
			
		||||
			log_error("Skipping invalid tag %s.", pos_name);
 | 
			
		||||
			return ECMD_FAILED;
 | 
			
		||||
		}
 | 
			
		||||
		if (!str_list_add(cmd->mem, arg_tags,
 | 
			
		||||
				  dm_pool_strdup(cmd->mem, pos_name + 1))) {
 | 
			
		||||
			log_error("strlist allocation failed.");
 | 
			
		||||
			return ECMD_FAILED;
 | 
			
		||||
		}
 | 
			
		||||
		return ECMD_PROCESSED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((split = strchr(pos_name, '/'))) {
 | 
			
		||||
		pos_vgname = pos_name;
 | 
			
		||||
		pos_lvname = split + 1;
 | 
			
		||||
		*split = '\0';
 | 
			
		||||
	} else {
 | 
			
		||||
		pos_lvname = pos_name;
 | 
			
		||||
		pos_vgname = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (arg_is_set(cmd, thinpool_ARG))
 | 
			
		||||
		arg_name = arg_str_value(cmd, thinpool_ARG, NULL);
 | 
			
		||||
	else if (arg_is_set(cmd, cachepool_ARG))
 | 
			
		||||
		arg_name = arg_str_value(cmd, cachepool_ARG, NULL);
 | 
			
		||||
 | 
			
		||||
	if (!pos_vgname && !arg_name) {
 | 
			
		||||
		log_error("Cannot find VG name for LV %s.", pos_lvname);
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (arg_name && (split = strchr(arg_name, '/'))) {
 | 
			
		||||
		/* combined VG/LV */
 | 
			
		||||
 | 
			
		||||
		if (!(tmp_name = dm_pool_strdup(cmd->mem, arg_name))) {
 | 
			
		||||
			log_error("string alloc failed.");
 | 
			
		||||
			return ECMD_FAILED;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!(split = strchr(tmp_name, '/')))
 | 
			
		||||
			return ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
		opt_vgname = tmp_name;
 | 
			
		||||
		/* Don't care about opt lvname. */
 | 
			
		||||
		/* opt_lvname = split + 1; */
 | 
			
		||||
		*split = '\0';
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Don't care about opt lvname. */
 | 
			
		||||
		/* opt_lvname = arg_name; */
 | 
			
		||||
		opt_vgname = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!pos_vgname && !opt_vgname) {
 | 
			
		||||
		log_error("Cannot find VG name for LV %s.", pos_lvname);
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pos_vgname && opt_vgname && strcmp(pos_vgname, opt_vgname)) {
 | 
			
		||||
		log_error("VG name mismatch from position arg (%s) and option arg (%s).",
 | 
			
		||||
			  pos_vgname, opt_vgname);
 | 
			
		||||
		return ECMD_FAILED; 
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	use_vgname = pos_vgname ? pos_vgname : opt_vgname;
 | 
			
		||||
 | 
			
		||||
	if (!str_list_add(cmd->mem, arg_vgnames, dm_pool_strdup(cmd->mem, use_vgname))) {
 | 
			
		||||
		log_error("strlist allocation failed.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vglv_sz = strlen(use_vgname) + strlen(pos_lvname) + 2;
 | 
			
		||||
 | 
			
		||||
	if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
 | 
			
		||||
	    dm_snprintf(vglv, vglv_sz, "%s/%s", use_vgname, pos_lvname) < 0) {
 | 
			
		||||
		log_error("vg/lv string alloc failed.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
	if (!str_list_add(cmd->mem, arg_lvnames, vglv)) {
 | 
			
		||||
		log_error("strlist allocation failed.");
 | 
			
		||||
		return ECMD_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ECMD_PROCESSED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int _process_lv_vgnameid_list(struct cmd_context *cmd, uint32_t read_flags,
 | 
			
		||||
				     struct dm_list *vgnameids_to_process,
 | 
			
		||||
				     struct dm_list *arg_vgnames,
 | 
			
		||||
				     struct dm_list *arg_lvnames,
 | 
			
		||||
				     struct dm_list *arg_tags,
 | 
			
		||||
				     struct processing_handle *handle,
 | 
			
		||||
				     check_single_lv_fn_t check_single_lv,
 | 
			
		||||
				     process_single_lv_fn_t process_single_lv)
 | 
			
		||||
{
 | 
			
		||||
	log_report_t saved_log_report_state = log_get_report_state();
 | 
			
		||||
@@ -2827,7 +3614,7 @@ static int _process_lv_vgnameid_list(struct cmd_context *cmd, uint32_t read_flag
 | 
			
		||||
			goto endvg;
 | 
			
		||||
 | 
			
		||||
		ret = process_each_lv_in_vg(cmd, vg, &lvnames, tags_arg, 0,
 | 
			
		||||
					    handle, process_single_lv);
 | 
			
		||||
					    handle, check_single_lv, process_single_lv);
 | 
			
		||||
		if (ret != ECMD_PROCESSED)
 | 
			
		||||
			stack;
 | 
			
		||||
		report_log_ret_code(ret);
 | 
			
		||||
@@ -2858,6 +3645,7 @@ int process_each_lv(struct cmd_context *cmd,
 | 
			
		||||
		    const char *one_vgname, const char *one_lvname,
 | 
			
		||||
		    uint32_t read_flags,
 | 
			
		||||
		    struct processing_handle *handle,
 | 
			
		||||
		    check_single_lv_fn_t check_single_lv,
 | 
			
		||||
		    process_single_lv_fn_t process_single_lv)
 | 
			
		||||
{
 | 
			
		||||
	log_report_t saved_log_report_state = log_get_report_state();
 | 
			
		||||
@@ -2886,7 +3674,12 @@ int process_each_lv(struct cmd_context *cmd,
 | 
			
		||||
	/*
 | 
			
		||||
	 * Find any LVs, VGs or tags explicitly provided on the command line.
 | 
			
		||||
	 */
 | 
			
		||||
	if ((ret = _get_arg_lvnames(cmd, argc, argv, one_vgname, one_lvname, &arg_vgnames, &arg_lvnames, &arg_tags) != ECMD_PROCESSED)) {
 | 
			
		||||
	if (cmd->command->flags & GET_VGNAME_FROM_OPTIONS)
 | 
			
		||||
		ret = _get_arg_lvnames_using_options(cmd, argc, argv, &arg_vgnames, &arg_lvnames, &arg_tags);
 | 
			
		||||
	else
 | 
			
		||||
		ret = _get_arg_lvnames(cmd, argc, argv, one_vgname, one_lvname, &arg_vgnames, &arg_lvnames, &arg_tags);
 | 
			
		||||
 | 
			
		||||
	if (ret != ECMD_PROCESSED) {
 | 
			
		||||
		ret_max = ret;
 | 
			
		||||
		goto_out;
 | 
			
		||||
	}
 | 
			
		||||
@@ -2973,7 +3766,7 @@ int process_each_lv(struct cmd_context *cmd,
 | 
			
		||||
		_choose_vgs_to_process(cmd, &arg_vgnames, &vgnameids_on_system, &vgnameids_to_process);
 | 
			
		||||
 | 
			
		||||
	ret = _process_lv_vgnameid_list(cmd, read_flags, &vgnameids_to_process, &arg_vgnames, &arg_lvnames,
 | 
			
		||||
					&arg_tags, handle, process_single_lv);
 | 
			
		||||
					&arg_tags, handle, check_single_lv, process_single_lv);
 | 
			
		||||
 | 
			
		||||
	if (ret > ret_max)
 | 
			
		||||
		ret_max = ret;
 | 
			
		||||
@@ -3935,11 +4728,6 @@ int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *p
 | 
			
		||||
	if (pp->pva.pvmetadatacopies < 0)
 | 
			
		||||
		pp->pva.pvmetadatacopies = find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL);
 | 
			
		||||
 | 
			
		||||
	if (pp->pva.pvmetadatacopies > 2) {
 | 
			
		||||
		log_error("Metadatacopies may only be 0, 1 or 2");
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pp->pva.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, pp->pva.ba_size);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
@@ -4958,3 +5746,40 @@ out:
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dm_list *failed_pv_list(struct volume_group *vg)
 | 
			
		||||
{
 | 
			
		||||
	struct dm_list *failed_pvs;
 | 
			
		||||
	struct pv_list *pvl, *new_pvl;
 | 
			
		||||
 | 
			
		||||
	if (!(failed_pvs = dm_pool_alloc(vg->vgmem, sizeof(*failed_pvs)))) {
 | 
			
		||||
		log_error("Allocation of list of failed_pvs failed.");
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dm_list_init(failed_pvs);
 | 
			
		||||
 | 
			
		||||
	dm_list_iterate_items(pvl, &vg->pvs) {
 | 
			
		||||
		if (!is_missing_pv(pvl->pv))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Finally, --repair will remove empty PVs.
 | 
			
		||||
		 * But we only want remove these which are output of repair,
 | 
			
		||||
		 * Do not count these which are already empty here.
 | 
			
		||||
		 * FIXME: code should traverse PV in LV not in whole VG.
 | 
			
		||||
		 * FIXME: layer violation? should it depend on vgreduce --removemising?
 | 
			
		||||
		 */
 | 
			
		||||
		if (pvl->pv->pe_alloc_count == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (!(new_pvl = dm_pool_alloc(vg->vgmem, sizeof(*new_pvl)))) {
 | 
			
		||||
			log_error("Allocation of failed_pvs list entry failed.");
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
		new_pvl->pv = pvl->pv;
 | 
			
		||||
		dm_list_add(failed_pvs, &new_pvl->list);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return failed_pvs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -98,6 +98,18 @@ typedef int (*process_single_pvseg_fn_t) (struct cmd_context * cmd,
 | 
			
		||||
					  struct pv_segment * pvseg,
 | 
			
		||||
					  struct processing_handle *handle);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Called prior to process_single_lv() to decide if the LV should be
 | 
			
		||||
 * processed.  If this returns 0, the LV is not processed.
 | 
			
		||||
 *
 | 
			
		||||
 * This can evaluate the combination of command definition and
 | 
			
		||||
 * the LV object to decide if the combination is allowed.
 | 
			
		||||
 */
 | 
			
		||||
typedef int (*check_single_lv_fn_t) (struct cmd_context *cmd,
 | 
			
		||||
				     struct logical_volume *lv,
 | 
			
		||||
				     struct processing_handle *handle,
 | 
			
		||||
				     int lv_is_named_arg);
 | 
			
		||||
 | 
			
		||||
int process_each_vg(struct cmd_context *cmd,
 | 
			
		||||
	            int argc, char **argv,
 | 
			
		||||
		    const char *one_vgname,
 | 
			
		||||
@@ -125,6 +137,7 @@ int process_each_segment_in_pv(struct cmd_context *cmd,
 | 
			
		||||
int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
 | 
			
		||||
		    const char *one_vgname, const char *one_lvname,
 | 
			
		||||
		    uint32_t flags, struct processing_handle *handle,
 | 
			
		||||
		    check_single_lv_fn_t check_single_lv,
 | 
			
		||||
		    process_single_lv_fn_t process_single_lv);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -141,6 +154,7 @@ int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
			  struct dm_list *arg_lvnames, const struct dm_list *tagsl,
 | 
			
		||||
			  int stop_on_error, struct processing_handle *handle,
 | 
			
		||||
			  check_single_lv_fn_t check_single_lv,
 | 
			
		||||
			  process_single_lv_fn_t process_single_lv);
 | 
			
		||||
 | 
			
		||||
struct processing_handle *init_processing_handle(struct cmd_context *cmd, struct processing_handle *parent_handle);
 | 
			
		||||
@@ -159,6 +173,12 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name);
 | 
			
		||||
const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
 | 
			
		||||
			 unsigned *dev_dir_found);
 | 
			
		||||
 | 
			
		||||
int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count,
 | 
			
		||||
		       int *match_count, int *unmatch_count);
 | 
			
		||||
 | 
			
		||||
void opt_array_to_str(struct cmd_context *cmd, int *opts, int count,
 | 
			
		||||
		      char *buf, int len);
 | 
			
		||||
 | 
			
		||||
int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *pp);
 | 
			
		||||
int pvcreate_each_device(struct cmd_context *cmd, struct processing_handle *handle, struct pvcreate_params *pp);
 | 
			
		||||
 | 
			
		||||
@@ -220,4 +240,8 @@ int validate_restricted_lvname_param(struct cmd_context *cmd, const char **vg_na
 | 
			
		||||
int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
                    struct processing_handle *handle __attribute__((unused)));
 | 
			
		||||
 | 
			
		||||
int get_lvt_enum(struct logical_volume *lv);
 | 
			
		||||
 | 
			
		||||
struct dm_list *failed_pv_list(struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										148
									
								
								tools/tools.h
									
									
									
									
									
								
							
							
						
						
									
										148
									
								
								tools/tools.h
									
									
									
									
									
								
							@@ -50,20 +50,41 @@
 | 
			
		||||
#define CMD_LEN 256
 | 
			
		||||
#define MAX_ARGS 64
 | 
			
		||||
 | 
			
		||||
/* command functions */
 | 
			
		||||
typedef int (*command_fn) (struct cmd_context * cmd, int argc, char **argv);
 | 
			
		||||
/* define the enums for the values accepted by command line --options, foo_VAL */
 | 
			
		||||
enum {
 | 
			
		||||
#define val(a, b, c, d) a ,
 | 
			
		||||
#include "vals.h"
 | 
			
		||||
#undef val
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
#include "commands.h"
 | 
			
		||||
#undef xx
 | 
			
		||||
 | 
			
		||||
/* define the enums for the command line switches */
 | 
			
		||||
/* define the enums for the command line --options, foo_ARG */
 | 
			
		||||
enum {
 | 
			
		||||
#define arg(a, b, c, d, e, f) a ,
 | 
			
		||||
#include "args.h"
 | 
			
		||||
#undef arg
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* command functions */
 | 
			
		||||
#define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
#include "commands.h"
 | 
			
		||||
#undef xx
 | 
			
		||||
 | 
			
		||||
/* define enums for LV properties, foo_LVP */
 | 
			
		||||
enum {
 | 
			
		||||
#define lvp(a, b, c) a ,
 | 
			
		||||
#include "lv_props.h"
 | 
			
		||||
#undef lvp
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* define enums for LV types, foo_LVT */
 | 
			
		||||
enum {
 | 
			
		||||
#define lvt(a, b, c) a ,
 | 
			
		||||
#include "lv_types.h"
 | 
			
		||||
#undef lvt
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#include "command.h"
 | 
			
		||||
 | 
			
		||||
#define ARG_COUNTABLE 0x00000001	/* E.g. -vvvv */
 | 
			
		||||
#define ARG_GROUPABLE 0x00000002	/* E.g. --addtag */
 | 
			
		||||
 | 
			
		||||
@@ -79,13 +100,13 @@ struct arg_values {
 | 
			
		||||
/*	void *ptr; // Currently not used. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* a global table of possible arguments */
 | 
			
		||||
/* a global table of possible --option's */
 | 
			
		||||
struct arg_props {
 | 
			
		||||
	int arg_enum; /* foo_ARG from args.h */
 | 
			
		||||
	const char short_arg;
 | 
			
		||||
	char _padding[7];
 | 
			
		||||
	const char *long_arg;
 | 
			
		||||
 | 
			
		||||
	int (*fn) (struct cmd_context *cmd, struct arg_values *av);
 | 
			
		||||
	int val_enum; /* foo_VAL from vals.h */
 | 
			
		||||
	uint32_t flags;
 | 
			
		||||
	uint32_t prio;
 | 
			
		||||
};
 | 
			
		||||
@@ -96,6 +117,29 @@ struct arg_value_group_list {
 | 
			
		||||
	uint32_t prio;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* a global table of possible --option values */
 | 
			
		||||
struct val_props {
 | 
			
		||||
	int val_enum; /* foo_VAL from vals.h */
 | 
			
		||||
	int (*fn) (struct cmd_context *cmd, struct arg_values *av);
 | 
			
		||||
	const char *name;
 | 
			
		||||
	const char *usage;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* a global table of possible LV properties */
 | 
			
		||||
struct lv_props {
 | 
			
		||||
	int lvp_enum; /* is_foo_LVP from lv_props.h */
 | 
			
		||||
	const char *name; /* "lv_is_foo" used in command-lines.in */
 | 
			
		||||
	int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* a global table of possible LV types */
 | 
			
		||||
/* (as exposed externally in command line interface, not exactly as internal segtype is used) */
 | 
			
		||||
struct lv_types {
 | 
			
		||||
	int lvt_enum; /* is_foo_LVT from lv_types.h */
 | 
			
		||||
	const char *name; /* "foo" used in command-lines.in, i.e. LV_foo */
 | 
			
		||||
	int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define CACHE_VGMETADATA	0x00000001
 | 
			
		||||
#define PERMITTED_READ_ONLY 	0x00000002
 | 
			
		||||
/* Process all VGs if none specified on the command line. */
 | 
			
		||||
@@ -118,19 +162,8 @@ struct arg_value_group_list {
 | 
			
		||||
#define ENABLE_DUPLICATE_DEVS    0x00000400
 | 
			
		||||
/* Command does not accept tags as args. */
 | 
			
		||||
#define DISALLOW_TAG_ARGS        0x00000800
 | 
			
		||||
 
 | 
			
		||||
/* a register of the lvm commands */
 | 
			
		||||
struct command {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	const char *desc;
 | 
			
		||||
	const char *usage;
 | 
			
		||||
	command_fn fn;
 | 
			
		||||
 | 
			
		||||
	unsigned flags;
 | 
			
		||||
 | 
			
		||||
	int num_args;
 | 
			
		||||
	int *valid_args;
 | 
			
		||||
};
 | 
			
		||||
/* Command may need to find VG name in an option value. */
 | 
			
		||||
#define GET_VGNAME_FROM_OPTIONS  0x00001000
 | 
			
		||||
 | 
			
		||||
void usage(const char *name);
 | 
			
		||||
 | 
			
		||||
@@ -157,7 +190,15 @@ int segtype_arg(struct cmd_context *cmd, struct arg_values *av);
 | 
			
		||||
int alloc_arg(struct cmd_context *cmd, struct arg_values *av);
 | 
			
		||||
int locktype_arg(struct cmd_context *cmd, struct arg_values *av);
 | 
			
		||||
int readahead_arg(struct cmd_context *cmd, struct arg_values *av);
 | 
			
		||||
int vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
 | 
			
		||||
int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
 | 
			
		||||
int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
 | 
			
		||||
int polloperation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
 | 
			
		||||
int writemostly_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
 | 
			
		||||
int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
 | 
			
		||||
int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
 | 
			
		||||
int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
 | 
			
		||||
int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
 | 
			
		||||
 | 
			
		||||
/* we use the enums to access the switches */
 | 
			
		||||
unsigned arg_count(const struct cmd_context *cmd, int a);
 | 
			
		||||
@@ -190,6 +231,7 @@ int pvmove_poll(struct cmd_context *cmd, const char *pv_name, const char *uuid,
 | 
			
		||||
		const char *vg_name, const char *lv_name, 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);
 | 
			
		||||
 | 
			
		||||
@@ -199,4 +241,64 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
 | 
			
		||||
 | 
			
		||||
int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg);
 | 
			
		||||
 | 
			
		||||
struct lv_props *get_lv_prop(int lvp_enum);
 | 
			
		||||
struct lv_types *get_lv_type(int lvt_enum);
 | 
			
		||||
struct command *get_command(int cmd_enum);
 | 
			
		||||
 | 
			
		||||
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvchange_resync_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvchange_syncaction_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvchange_rebuild_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvchange_monitor_poll_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvchange_persistent_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
int lvconvert_repair_pvs_or_thinpool_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_replace_pv_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
int lvconvert_merge_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_combine_split_snapshot_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
int lvconvert_start_poll_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_to_pool_noarg_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_to_cache_vol_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_to_thin_with_external_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_swap_pool_metadata_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_merge_thin_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_split_cachepool_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
int lvconvert_raid_types_cmd(struct cmd_context * cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_split_mirror_images_cmd(struct cmd_context * cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_merge_mirror_images_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
int lvconvert_change_mirrorlog_cmd(struct cmd_context * cmd, int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
int lvconvert_merge_cmd(struct cmd_context *cmd, int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
int lvconvert_generic_check(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
                        struct processing_handle *handle,
 | 
			
		||||
                        int lv_is_named_arg);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int lvconvert_repair_pvs_mirror(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
                        struct processing_handle *handle,
 | 
			
		||||
                        struct dm_list *use_pvh);
 | 
			
		||||
int lvconvert_repair_pvs_raid(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
                        struct processing_handle *handle,
 | 
			
		||||
                        struct dm_list *use_pvh);
 | 
			
		||||
int lvconvert_repair_thinpool(struct cmd_context *cmd, struct logical_volume *lv,
 | 
			
		||||
                        struct processing_handle *handle);
 | 
			
		||||
int lvconvert_merge_snapshot_single(struct cmd_context *cmd,
 | 
			
		||||
                                       struct logical_volume *lv,
 | 
			
		||||
                                       struct processing_handle *handle);
 | 
			
		||||
int lvconvert_merge_thin_single(struct cmd_context *cmd,
 | 
			
		||||
                                         struct logical_volume *lv,
 | 
			
		||||
                                         struct processing_handle *handle);
 | 
			
		||||
int lvconvert_merge_mirror_images_single(struct cmd_context *cmd,
 | 
			
		||||
                                          struct logical_volume *lv,
 | 
			
		||||
                                          struct processing_handle *handle);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										136
									
								
								tools/vals.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								tools/vals.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Define value types which describe values accepted
 | 
			
		||||
 * by the --option's in args.h, and can also describe
 | 
			
		||||
 * the values accepted as positional args.
 | 
			
		||||
 *
 | 
			
		||||
 * Previously, accepted values were only "described"
 | 
			
		||||
 * by identifying the parsing function to use.
 | 
			
		||||
 *
 | 
			
		||||
 * Some standard val types are used by many options,
 | 
			
		||||
 * e.g. many options (aa_ARG, bb_ARG, cc_ARG) all
 | 
			
		||||
 * accept a number_VAL.
 | 
			
		||||
 *
 | 
			
		||||
 * Other special val types are used by only one option,
 | 
			
		||||
 * e.g. only mirrorlog_ARG accepts a mirrorlog_VAL.
 | 
			
		||||
 * This typically means that there are some specific
 | 
			
		||||
 * words that are recognized after the option.
 | 
			
		||||
 *
 | 
			
		||||
 * Some options currently take a standard val type,
 | 
			
		||||
 * (esp string_VAL), but they could be given their
 | 
			
		||||
 * own custom val type.  The advantage of using a
 | 
			
		||||
 * custom val type is the possibility of validating
 | 
			
		||||
 * the value when parsing it with a custom parsing
 | 
			
		||||
 * function, and the possibility of displaying the
 | 
			
		||||
 * actual accepted values in the command usage.
 | 
			
		||||
 * Without a custom val type, the code must do ad hoc
 | 
			
		||||
 * validation of the string values, and the usage
 | 
			
		||||
 * output for the option will only say "String"
 | 
			
		||||
 * rather than giving the accepted string values.
 | 
			
		||||
 * Even without a custom parsing function, there is
 | 
			
		||||
 * reason to define a custom x_VAL enum so that a
 | 
			
		||||
 * more descriptive usage string can be specified
 | 
			
		||||
 * as opposed to just "String".
 | 
			
		||||
 *
 | 
			
		||||
 * Most of the val types defined here are used after
 | 
			
		||||
 * --option's, and are referenced in foo_ARG entries
 | 
			
		||||
 * in args.h.  But, some val types are only used to
 | 
			
		||||
 * represent positional values in command definitions,
 | 
			
		||||
 * e.g. vg_VAL.
 | 
			
		||||
 *
 | 
			
		||||
 * val(a, b, c, d)
 | 
			
		||||
 *
 | 
			
		||||
 * a:  foo_VAL enums
 | 
			
		||||
 * b:  the function to parse and set the value
 | 
			
		||||
 * c:  the name used to reference this value in command defs
 | 
			
		||||
 * d:  what to display in usage output for this value
 | 
			
		||||
 *
 | 
			
		||||
 * command defintions will use --option NAME, where NAME
 | 
			
		||||
 * is shown in val() field c.  NAME will be translated to
 | 
			
		||||
 * foo_VAL enum in field a, which is used in commands[]
 | 
			
		||||
 * structs.
 | 
			
		||||
 *
 | 
			
		||||
 * option definitions (arg.h) will reference foo_VAL enum
 | 
			
		||||
 * in field a.
 | 
			
		||||
 *
 | 
			
		||||
 * FIXME: for specialized val types, the set of recognized
 | 
			
		||||
 * words is not defined or stored in a consistent way,
 | 
			
		||||
 * but is just whatever the parsing function happens to look
 | 
			
		||||
 * for, so adding a new accepted value for the val type is
 | 
			
		||||
 * generally making the parsing function recognize a new
 | 
			
		||||
 * word, and making the implementation code also recognize
 | 
			
		||||
 * that word to do something different.  This new word should
 | 
			
		||||
 * then also be added to the usage string for the val type here.
 | 
			
		||||
 * It would be nice if the accepted values could be defined in a
 | 
			
		||||
 * more consistent way, and perhaps in a single place, perhaps in
 | 
			
		||||
 * struct val_props.
 | 
			
		||||
 *
 | 
			
		||||
 * The usage text for an option is not always the full
 | 
			
		||||
 * set of words accepted for an option, but may be a
 | 
			
		||||
 * subset.  i.e. an outdated word that no longer does
 | 
			
		||||
 * anything may not be shown, but may still be recognized
 | 
			
		||||
 * and ignored, or an option that shouldn't be used in
 | 
			
		||||
 * general isn't shown to avoid suggesting it.
 | 
			
		||||
 * e.g. for --activate we show the most common "y|n|ay"
 | 
			
		||||
 * without showing the lvmlockd variations "ey|sy" which
 | 
			
		||||
 * are not applicable in general.
 | 
			
		||||
 *
 | 
			
		||||
 * FIXME: are there some specialized or irrelevant
 | 
			
		||||
 * options included in the usage text below that should
 | 
			
		||||
 * be removed?  Should "lvm1" be removed?
 | 
			
		||||
 *
 | 
			
		||||
 * For Number args that take optional units, a full usage
 | 
			
		||||
 * could be "Number[bBsSkKmMgGtTpPeE]" (with implied |),
 | 
			
		||||
 * but repeating this full specification produces cluttered
 | 
			
		||||
 * output, and doesn't indicate which unit is the default.
 | 
			
		||||
 * "Number[units]" would be cleaner, as would a subset of
 | 
			
		||||
 * common units, e.g. "Number[kmg...]", but neither helps
 | 
			
		||||
 * with default.  "Number[k|unit]" and "Number[m|unit]" show
 | 
			
		||||
 * the default, and "unit" indicates that other units
 | 
			
		||||
 * are possible without listing them all.  This also
 | 
			
		||||
 * suggests using the preferred lower case letters, because
 | 
			
		||||
 * --size and other option args treat upper/lower letters
 | 
			
		||||
 * the same, all as 1024 SI base.  For this reason, we
 | 
			
		||||
 * should avoid suggesting the upper case letters.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
val(none_VAL, NULL, "None", "ERR")             /* unused, for enum value 0 */
 | 
			
		||||
val(conststr_VAL, NULL, "ConstString", "ERR")  /* used only for command defs */
 | 
			
		||||
val(constnum_VAL, NULL, "ConstNumber", "ERR")  /* used only for command defs */
 | 
			
		||||
val(bool_VAL, yes_no_arg, "Bool", "y|n")
 | 
			
		||||
val(number_VAL, int_arg, "Number", NULL)
 | 
			
		||||
val(string_VAL, string_arg, "String", NULL)
 | 
			
		||||
val(vg_VAL, string_arg, "VG", NULL)
 | 
			
		||||
val(lv_VAL, string_arg, "LV", NULL)
 | 
			
		||||
val(pv_VAL, string_arg, "PV", NULL)
 | 
			
		||||
val(tag_VAL, tag_arg, "Tag", NULL)
 | 
			
		||||
val(select_VAL, NULL, "Select", NULL)       /* used only for command defs */
 | 
			
		||||
val(activationmode_VAL, string_arg, "ActivationMode", "partial|degraded|complete")
 | 
			
		||||
val(activation_VAL, activation_arg, "Active", "y|n|ay")
 | 
			
		||||
val(cachemode_VAL, cachemode_arg, "CacheMode", "writethrough|writeback")
 | 
			
		||||
val(discards_VAL, discards_arg, "Discards", "passdown|nopassdown|ignore")
 | 
			
		||||
val(mirrorlog_VAL, mirrorlog_arg, "MirrorLog", "core|disk")
 | 
			
		||||
val(sizekb_VAL, size_kb_arg, "SizeKB", "Number[k|unit]")
 | 
			
		||||
val(sizemb_VAL, size_mb_arg, "SizeMB", "Number[m|unit]")
 | 
			
		||||
val(numsigned_VAL, int_arg_with_sign, "SNumber", "[+|-]Number")
 | 
			
		||||
val(numsignedper_VAL, int_arg_with_sign_and_percent, "SNumberP", "[+|-]Number[%VG|%PVS|%FREE]")
 | 
			
		||||
val(permission_VAL, permission_arg, "Permission", "rw|r")
 | 
			
		||||
val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1")
 | 
			
		||||
val(units_VAL, string_arg, "Units", "hHbBsSkKmMgGtTpPeE")
 | 
			
		||||
val(segtype_VAL, segtype_arg, "SegType", "linear|striped|snapshot|mirror|raid*|thin|cache|thin-pool|cache-pool")
 | 
			
		||||
val(alloc_VAL, alloc_arg, "Alloc", "contiguous|cling|cling_by_tags|normal|anywhere|inherit")
 | 
			
		||||
val(locktype_VAL, locktype_arg, "LockType", "sanlock|dlm|none")
 | 
			
		||||
val(readahead_VAL, readahead_arg, "Readahead", "auto|none|NumberSectors")
 | 
			
		||||
val(vgmetadatacopies_VAL, vgmetadatacopies_arg, "MetadataCopiesVG", "all|unmanaged|Number")
 | 
			
		||||
val(pvmetadatacopies_VAL, pvmetadatacopies_arg, "MetadataCopiesPV", "0|1|2")
 | 
			
		||||
val(metadatacopies_VAL, metadatacopies_arg, "unused", "unused")
 | 
			
		||||
val(polloperation_VAL, polloperation_arg, "PollOp", "pvmove|convert|merge|merge_thin")
 | 
			
		||||
val(writemostly_VAL, writemostly_arg, "WriteMostlyPV", "PV[:t|n|y]")
 | 
			
		||||
val(syncaction_VAL, syncaction_arg, "SyncAction", "check|repair")
 | 
			
		||||
val(reportformat_VAL, reportformat_arg, "ReportFmt", "basic|json")
 | 
			
		||||
val(configreport_VAL, configreport_arg, "ConfigReport", "log|vg|lv|pv|pvseg|seg")
 | 
			
		||||
val(configtype_VAL, configtype_arg, "ConfigType", "current|default|diff|full|list|missing|new|profilable|profilable-command|profilable-metadata")
 | 
			
		||||
 | 
			
		||||
/* this should always be last */
 | 
			
		||||
val(VAL_COUNT, NULL, NULL, NULL)
 | 
			
		||||
 | 
			
		||||
@@ -482,6 +482,9 @@ static int _vgchange_metadata_copies(struct cmd_context *cmd,
 | 
			
		||||
{
 | 
			
		||||
	uint32_t mda_copies = arg_uint_value(cmd, vgmetadatacopies_ARG, DEFAULT_VGMETADATACOPIES);
 | 
			
		||||
 | 
			
		||||
	log_warn("vgchange_metadata_copies new %u vg_mda_copies %u D %u",
 | 
			
		||||
		 mda_copies, vg_mda_copies(vg), DEFAULT_VGMETADATACOPIES);
 | 
			
		||||
 | 
			
		||||
	if (mda_copies == vg_mda_copies(vg)) {
 | 
			
		||||
		if (vg_mda_copies(vg) == VGMETADATACOPIES_UNMANAGED)
 | 
			
		||||
			log_warn("Number of metadata copies for VG %s is already unmanaged.",
 | 
			
		||||
 
 | 
			
		||||
@@ -157,24 +157,12 @@ int vgconvert(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
		return EINVALID_CMD_LINE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (arg_is_set(cmd, metadatacopies_ARG)) {
 | 
			
		||||
		log_error("Invalid option --metadatacopies, "
 | 
			
		||||
			  "use --pvmetadatacopies instead.");
 | 
			
		||||
		return EINVALID_CMD_LINE;
 | 
			
		||||
	}
 | 
			
		||||
	if (!(cmd->fmt->features & FMT_MDAS) &&
 | 
			
		||||
	    (arg_is_set(cmd, pvmetadatacopies_ARG) ||
 | 
			
		||||
	     arg_is_set(cmd, metadatasize_ARG))) {
 | 
			
		||||
	    arg_is_set(cmd, pvmetadatacopies_ARG)) {
 | 
			
		||||
		log_error("Metadata parameters only apply to text format");
 | 
			
		||||
		return EINVALID_CMD_LINE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (arg_is_set(cmd, pvmetadatacopies_ARG) &&
 | 
			
		||||
	    arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) {
 | 
			
		||||
		log_error("Metadatacopies may only be 0, 1 or 2");
 | 
			
		||||
		return EINVALID_CMD_LINE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(cmd->fmt->features & FMT_BAS) &&
 | 
			
		||||
		arg_is_set(cmd, bootloaderareasize_ARG)) {
 | 
			
		||||
		log_error("Bootloader area parameters only apply to text format");
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name,
 | 
			
		||||
		vgdisplay_extents(vg);
 | 
			
		||||
 | 
			
		||||
		process_each_lv_in_vg(cmd, vg, NULL, NULL, 0, NULL,
 | 
			
		||||
				      (process_single_lv_fn_t)lvdisplay_full);
 | 
			
		||||
				      NULL, (process_single_lv_fn_t)lvdisplay_full);
 | 
			
		||||
 | 
			
		||||
		log_print("--- Physical volumes ---");
 | 
			
		||||
		process_each_pv_in_vg(cmd, vg, NULL,
 | 
			
		||||
 
 | 
			
		||||
@@ -136,12 +136,6 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
		return EINVALID_CMD_LINE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (arg_is_set(cmd, metadatacopies_ARG)) {
 | 
			
		||||
		log_error("Invalid option --metadatacopies, "
 | 
			
		||||
			  "use --pvmetadatacopies instead.");
 | 
			
		||||
		return EINVALID_CMD_LINE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vg_name = skip_dev_dir(cmd, argv[0], NULL);
 | 
			
		||||
	argc--;
 | 
			
		||||
	argv++;
 | 
			
		||||
 
 | 
			
		||||
@@ -33,5 +33,5 @@ int vgmknodes(struct cmd_context *cmd, int argc, char **argv)
 | 
			
		||||
	if (!lv_mknodes(cmd, NULL))
 | 
			
		||||
		return_ECMD_FAILED;
 | 
			
		||||
 | 
			
		||||
	return process_each_lv(cmd, argc, argv, NULL, NULL, LCK_VG_READ, NULL, &_vgmknodes_single);
 | 
			
		||||
	return process_each_lv(cmd, argc, argv, NULL, NULL, LCK_VG_READ, NULL, NULL, &_vgmknodes_single);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ((ret = process_each_lv_in_vg(cmd, vg, NULL, NULL, 1, &void_handle,
 | 
			
		||||
						 (process_single_lv_fn_t)lvremove_single)) != ECMD_PROCESSED) {
 | 
			
		||||
						 NULL, (process_single_lv_fn_t)lvremove_single)) != ECMD_PROCESSED) {
 | 
			
		||||
			stack;
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user