mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-30 20:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			16 Commits
		
	
	
		
			v2_03_24
			...
			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