mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-30 20:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			29 Commits
		
	
	
		
			v2_02_159
			...
			dev-bmr-dm
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | d901468a27 | ||
|  | 7ebe630b69 | ||
|  | e104825916 | ||
|  | 12ecd95965 | ||
|  | ebc7fc67c8 | ||
|  | 005adb0a0a | ||
|  | cc4f036d36 | ||
|  | 059a383cf8 | ||
|  | 5e06b33c51 | ||
|  | 6233bcf52d | ||
|  | 589b752eeb | ||
|  | 0de56eeaad | ||
|  | 13cd3ff5a0 | ||
|  | 37d1b7b745 | ||
|  | 4d1c4e1f73 | ||
|  | 351bcf5f82 | ||
|  | f6b98ec7ca | ||
|  | 8ca874bc1f | ||
|  | bf1dfea393 | ||
|  | c1a66d4fc6 | ||
|  | a497b95db1 | ||
|  | 28658541da | ||
|  | 1faa208067 | ||
|  | 21b946dfb7 | ||
|  | 95ef0cdb46 | ||
|  | 03e03e9c11 | ||
|  | 5d3b136d38 | ||
|  | 69c721dd68 | ||
|  | fb0a671419 | 
| @@ -1 +1 @@ | ||||
| 1.02.129-git (2016-07-06) | ||||
| 1.02.131-git (2016-07-06) | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| Version 2.02.161 -  | ||||
| ================================ | ||||
|  | ||||
| Version 2.02.160 - 6th July 2016 | ||||
| ================================ | ||||
|   Minor fixes from coverity. | ||||
|  | ||||
| Version 2.02.159 - 6th July 2016 | ||||
| ================================ | ||||
|   Add raid0_meta segment type that provides metadata space for raid conversions. | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| Version 1.02.131 - | ||||
| ================================ | ||||
|  | ||||
| Version 1.02.130 - 6th July 2016 | ||||
| ================================ | ||||
|   Minor fixes from coverity. | ||||
|  | ||||
| Version 1.02.129 - 6th July 2016 | ||||
| ================================ | ||||
|   Update default dmstats field selections for groups. | ||||
|   | ||||
							
								
								
									
										5
									
								
								lib/cache/lvmetad.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								lib/cache/lvmetad.c
									
									
									
									
										vendored
									
									
								
							| @@ -879,7 +879,8 @@ static int _pv_populate_lvmcache(struct cmd_context *cmd, | ||||
| 		if (!id_read_format(&vgid, vgid_txt)) | ||||
| 			return_0; | ||||
| 	} else | ||||
| 		strcpy((char*)&vgid, fmt->orphan_vg_name); | ||||
| 		/* NB uuid is short and NUL-terminated. */ | ||||
| 		(void) dm_strncpy((char*)&vgid, fmt->orphan_vg_name, sizeof(vgid)); | ||||
|  | ||||
| 	if (!vgname) | ||||
| 		vgname = fmt->orphan_vg_name; | ||||
| @@ -1245,7 +1246,7 @@ int lvmetad_vg_update_finish(struct volume_group *vg) | ||||
| 		dm_hash_get_first(vg->fid->metadata_areas_index) : NULL; | ||||
| 	while (n) { | ||||
| 		mda = dm_hash_get_data(vg->fid->metadata_areas_index, n); | ||||
| 		strcpy(mda_id, dm_hash_get_key(vg->fid->metadata_areas_index, n)); | ||||
| 		(void) dm_strncpy(mda_id, dm_hash_get_key(vg->fid->metadata_areas_index, n), sizeof(mda_id)); | ||||
| 		if ((num = strchr(mda_id, '_'))) { | ||||
| 			*num = 0; | ||||
| 			++num; | ||||
|   | ||||
| @@ -1578,7 +1578,12 @@ static uint32_t _min_sublv_area_at_le(struct lv_segment *seg, uint32_t area_le) | ||||
|  | ||||
| 	/* Find smallest segment of each of the data image LVs at offset area_le */ | ||||
| 	for (s = 0; s < seg->area_count; s++) { | ||||
| 		seg1 = find_seg_by_le(seg_lv(seg, s), area_le); | ||||
| 		if (!(seg1 = find_seg_by_le(seg_lv(seg, s), area_le))) { | ||||
| 			log_error("Failed to find segment for %s extent %" PRIu32, | ||||
| 				  seg_lv(seg, s)->name, area_le); | ||||
| 			return 0; | ||||
| 		} | ||||
|  | ||||
| 		area_len = min(area_len, seg1->len); | ||||
| 	} | ||||
|  | ||||
| @@ -1734,7 +1739,8 @@ static int _raid0_to_striped_retrieve_segments_and_lvs(struct logical_volume *lv | ||||
| 	 */ | ||||
| 	area_le = le = 0; | ||||
| 	while (le < lv->le_count) { | ||||
| 		area_len = _min_sublv_area_at_le(seg, area_le); | ||||
| 		if (!(area_len = _min_sublv_area_at_le(seg, area_le))) | ||||
| 			return_0; | ||||
| 		area_le += area_len; | ||||
|  | ||||
| 		if (!_split_area_lvs_segments(seg, area_le) || | ||||
| @@ -1748,7 +1754,11 @@ static int _raid0_to_striped_retrieve_segments_and_lvs(struct logical_volume *lv | ||||
| 	area_le = 0; | ||||
| 	dm_list_iterate_items(seg_to, &new_segments) { | ||||
| 		for (s = 0; s < seg->area_count; s++) { | ||||
| 			data_seg = find_seg_by_le(seg_lv(seg, s), area_le); | ||||
| 			if (!(data_seg = find_seg_by_le(seg_lv(seg, s), area_le))) { | ||||
| 				log_error("Failed to find segment for %s extent %" PRIu32, | ||||
| 					  seg_lv(seg, s)->name, area_le); | ||||
| 				return 0; | ||||
| 			} | ||||
|  | ||||
| 			/* Move the respective area across to our new segments area */ | ||||
| 			if (!move_lv_segment_area(seg_to, s, data_seg, 0)) | ||||
| @@ -1816,10 +1826,14 @@ static int _eliminate_extracted_lvs_optional_write_vg(struct volume_group *vg, | ||||
| 	if (!_deactivate_and_remove_lvs(vg, removal_lvs)) | ||||
| 		return_0; | ||||
|  | ||||
| 	dm_list_init(removal_lvs); | ||||
|  | ||||
| 	/* Wait for events following any deactivation. */ | ||||
| 	sync_local_dev_names(vg->cmd); | ||||
| 	if (!sync_local_dev_names(vg->cmd)) { | ||||
| 		log_error("Failed to sync local devices after removing %u LVs in VG %s.", | ||||
| 			  dm_list_size(removal_lvs), vg->name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	dm_list_init(removal_lvs); | ||||
|  | ||||
| 	if (vg_write_requested && !_vg_write_commit_backup(vg)) | ||||
| 		return_0; | ||||
|   | ||||
							
								
								
									
										1
									
								
								libdm/.exported_symbols.DM_1_02_131
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								libdm/.exported_symbols.DM_1_02_131
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| dm_stats_create_regions_from_fd | ||||
| @@ -153,7 +153,7 @@ scan: | ||||
|  | ||||
| 			if (c == '-') { | ||||
| 				if (at_start || in_range) | ||||
| 					return_0; | ||||
| 					goto_bad; | ||||
| 				b = 0; | ||||
| 				in_range = 1; | ||||
| 				at_start = 1; | ||||
|   | ||||
| @@ -1146,15 +1146,17 @@ for (dm_stats_walk_init((dms), DM_STATS_WALK_GROUP),		\ | ||||
|  * empty. | ||||
|  */ | ||||
| #define dm_stats_walk_do(dms)					\ | ||||
| dm_stats_walk_start((dms));					\ | ||||
| do | ||||
| do {								\ | ||||
| 	dm_stats_walk_start((dms));				\ | ||||
| 	do | ||||
|  | ||||
| /* | ||||
|  * Start a 'while' style loop or end a 'do..while' loop iterating over the | ||||
|  * regions contained in dm_stats handle 'dms'. | ||||
|  */ | ||||
| #define dm_stats_walk_while(dms)				\ | ||||
| while(!dm_stats_walk_end((dms))) | ||||
| 	while(!dm_stats_walk_end((dms)));			\ | ||||
| } while (0) | ||||
|  | ||||
| /* | ||||
|  * Cursor relative property methods | ||||
| @@ -1283,6 +1285,35 @@ uint64_t dm_stats_get_group_id(const struct dm_stats *dms, uint64_t region_id); | ||||
| int dm_stats_get_group_descriptor(const struct dm_stats *dms, | ||||
| 				  uint64_t group_id, char **buf); | ||||
|  | ||||
| /* | ||||
|  * Create regions that correspond to the extents of a file in the | ||||
|  * filesystem and optionally place them into a group. | ||||
|  * | ||||
|  * File descriptor fd must reference a regular file, open for reading, | ||||
|  * in a local file system that supports the FIEMAP ioctl and that | ||||
|  * returns data describing the physical location of extents. | ||||
|  * | ||||
|  * The file descriptor can be closed by the caller following the call | ||||
|  * to dm_stats_create_regions_from_fd(). | ||||
|  * | ||||
|  * The function returns a pointer to an array of uint64_t containing | ||||
|  * the IDs of the newly created regions. The array is terminated by the | ||||
|  * value DM_STATS_REGIONS_ALL and should be freed using dm_free() when | ||||
|  * no longer required. | ||||
|  * | ||||
|  * Unless nogroup is non-zero the regions will be placed into a group | ||||
|  * and the group alias is set to the value supplied. | ||||
|  * | ||||
|  * The group_id for the new group is equal to the region_id value in | ||||
|  * the first array element. | ||||
|  * | ||||
|  * File mapped histograms will be supported in a future version. | ||||
|  */ | ||||
| uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd, | ||||
| 					  int group, int precise, | ||||
| 					  struct dm_histogram *bounds, | ||||
| 					  const char *alias); | ||||
|  | ||||
| /* | ||||
|  * Call this to actually run the ioctl. | ||||
|  */ | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| /* | ||||
|  * Copyright (C) 2015 Red Hat, Inc. All rights reserved. | ||||
|  * Copyright (C) 2016 Red Hat, Inc. All rights reserved. | ||||
|  * | ||||
|  * _stats_get_extents_for_file() based in part on filefrag_fiemap() from | ||||
|  * e2fsprogs/misc/filefrag.c. Copyright 2003 by Theodore Ts'o. | ||||
|  * | ||||
|  * This file is part of the device-mapper userspace tools. | ||||
|  * | ||||
| @@ -16,6 +19,12 @@ | ||||
|  | ||||
| #include "math.h" /* log10() */ | ||||
|  | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/vfs.h> /* fstatfs */ | ||||
| #include <linux/fs.h> /* FS_IOC_FIEMAP */ | ||||
| #include <linux/fiemap.h> /* fiemap */ | ||||
| #include <linux/magic.h> /* BTRFS_SUPER_MAGIC */ | ||||
|  | ||||
| #define DM_STATS_REGION_NOT_PRESENT UINT64_MAX | ||||
| #define DM_STATS_GROUP_NOT_PRESENT DM_STATS_GROUP_NONE | ||||
|  | ||||
| @@ -692,7 +701,7 @@ static int _parse_aux_data_group(struct dm_stats *dms, | ||||
| 	} | ||||
|  | ||||
| 	/* separate group tag from user aux_data */ | ||||
| 	if (strlen(end)) | ||||
| 	if ((strlen(end) > 1) || strncmp(end, "-", 1)) | ||||
| 		c = dm_strdup(end); | ||||
| 	else | ||||
| 		c = dm_strdup(""); | ||||
| @@ -1479,11 +1488,12 @@ static void _stats_walk_end_areas(const struct dm_stats *dms, uint64_t *flags, | ||||
| 		*cur_a = DM_STATS_WALK_REGION; | ||||
| 		*cur_r = DM_STATS_REGION_NOT_PRESENT; | ||||
| 		_stats_walk_next_present(dms, flags, cur_r, cur_a, cur_g); | ||||
| 		if (!_stats_walk_any_unskipped(dms, flags, cur_r, cur_a)) | ||||
| 		if (!_stats_walk_any_unskipped(dms, flags, cur_r, cur_a)) { | ||||
| 			/* no more regions */ | ||||
| 			*flags &= ~DM_STATS_WALK_REGION; | ||||
| 			if (!(*flags & DM_STATS_WALK_GROUP)) | ||||
| 				*cur_r = dms->max_region; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (*flags & DM_STATS_WALK_REGION) | ||||
| @@ -1979,7 +1989,6 @@ static int _stats_remove_region_id_from_group(struct dm_stats *dms, | ||||
|  | ||||
| 	/* removing group leader? */ | ||||
| 	if (region_id == group_id) { | ||||
| 		dms->groups[group_id].group_id = DM_STATS_GROUP_NOT_PRESENT; | ||||
| 		_stats_clear_group_regions(dms, group_id); | ||||
| 		_stats_group_destroy(&dms->groups[group_id]); | ||||
| 	} | ||||
| @@ -2599,11 +2608,15 @@ static int _average_rd_wait_time(const struct dm_stats *dms, double *await, | ||||
|  | ||||
| 	rd_io_ticks = dm_stats_get_counter(dms, DM_STATS_READ_NSECS, | ||||
| 					   region_id, area_id); | ||||
|  | ||||
| 	nr_rd_ios = dm_stats_get_counter(dms, DM_STATS_READS_COUNT, | ||||
| 					 region_id, area_id); | ||||
|  | ||||
| 	if (rd_io_ticks > 0) | ||||
| 	/* | ||||
| 	 * If rd_io_ticks is > 0 this should imply that nr_rd_ios is | ||||
| 	 * also > 0 (unless a kernel bug exists). Test for both here | ||||
| 	 * before using the IO count as a divisor (Coverity). | ||||
| 	 */ | ||||
| 	if (rd_io_ticks > 0 && nr_rd_ios > 0) | ||||
| 		*await = (double) rd_io_ticks / (double) nr_rd_ios; | ||||
| 	else | ||||
| 		*await = 0.0; | ||||
| @@ -2621,7 +2634,12 @@ static int _average_wr_wait_time(const struct dm_stats *dms, double *await, | ||||
| 	nr_wr_ios = dm_stats_get_counter(dms, DM_STATS_WRITES_COUNT, | ||||
| 					 region_id, area_id); | ||||
|  | ||||
| 	if (wr_io_ticks > 0) | ||||
| 	/* | ||||
| 	 * If wr_io_ticks is > 0 this should imply that nr_wr_ios is | ||||
| 	 * also > 0 (unless a kernel bug exists). Test for both here | ||||
| 	 * before using the IO count as a divisor (Coverity). | ||||
| 	 */ | ||||
| 	if (wr_io_ticks > 0 && nr_wr_ios > 0) | ||||
| 		*await = (double) wr_io_ticks / (double) nr_wr_ios; | ||||
| 	else | ||||
| 		*await = 0.0; | ||||
| @@ -2655,10 +2673,19 @@ static int _utilization(const struct dm_stats *dms, double *util, | ||||
| 	 * for the last interval; do not allow a value > 100% utilization | ||||
| 	 * to be passed to a dm_make_percent() call. We expect to see these | ||||
| 	 * at startup if counters have not been cleared before the first read. | ||||
| 	 * | ||||
| 	 * A zero interval_ns is also an error since metrics cannot be | ||||
| 	 * calculated without a defined interval - return zero and emit a | ||||
| 	 * backtrace in this case. | ||||
| 	 */ | ||||
| 	io_nsecs = dm_stats_get_counter(dms, DM_STATS_IO_NSECS, | ||||
| 					region_id, area_id); | ||||
|  | ||||
| 	if (!interval_ns) { | ||||
| 		*util = 0.0; | ||||
| 		return_0; | ||||
| 	} | ||||
|  | ||||
| 	io_nsecs = ((io_nsecs < interval_ns) ? io_nsecs : interval_ns); | ||||
|  | ||||
| 	*util = (double) io_nsecs / (double) interval_ns; | ||||
| @@ -3087,6 +3114,7 @@ int dm_stats_set_alias(struct dm_stats *dms, uint64_t group_id, const char *alia | ||||
| 	return 1; | ||||
|  | ||||
| bad: | ||||
| 	dm_free((char *) group->alias); | ||||
| 	group->alias = old_alias; | ||||
| 	return 0; | ||||
| } | ||||
| @@ -3160,7 +3188,7 @@ struct dm_histogram *dm_stats_get_histogram(const struct dm_stats *dms, | ||||
|  | ||||
| 	/* FIXME return histogram sum? Requires bounds check at group time */ | ||||
| 	if (region_id & DM_STATS_WALK_GROUP) { | ||||
| 		log_warn("Group histogram data is not supported"); | ||||
| 		log_err_once("Group histogram data is not supported"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| @@ -3666,6 +3694,7 @@ static int _stats_group_check_overlap(const struct dm_stats *dms, | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* build a table of extents in order of region_id */ | ||||
| 	for (id = dm_bit_get_first(regions); id >= 0; | ||||
| 	     id = dm_bit_get_next(regions, id)) { | ||||
| 		dm_list_init(&map[i].list); | ||||
| @@ -3675,6 +3704,7 @@ static int _stats_group_check_overlap(const struct dm_stats *dms, | ||||
| 		i++; | ||||
| 	} | ||||
|  | ||||
| 	/* sort by extent.start */ | ||||
| 	qsort(map, count, sizeof(*map), _extent_start_compare); | ||||
|  | ||||
| 	for (i = 0; i < count; i++) | ||||
| @@ -3704,6 +3734,7 @@ merge: | ||||
| 			overlap = merged = 1; | ||||
| 		} | ||||
| 	} | ||||
| 	/* continue until no merge candidates remain */ | ||||
| 	if (merged) | ||||
| 		goto merge; | ||||
|  | ||||
| @@ -3737,6 +3768,11 @@ int dm_stats_create_group(struct dm_stats *dms, const char *members, | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Check that each region_id in the bitmap meets the group | ||||
| 	 * constraints: present, not already grouped, and if any | ||||
| 	 * histogram is present that they all have the same bounds. | ||||
| 	 */ | ||||
| 	for (i = dm_bit_get_first(regions); i >= 0; | ||||
| 	     i = dm_bit_get_next(regions, i)) { | ||||
| 		if (!dm_stats_region_present(dms, i)) { | ||||
| @@ -3748,7 +3784,11 @@ int dm_stats_create_group(struct dm_stats *dms, const char *members, | ||||
| 				  FMTu64, i, dms->regions[i].group_id); | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| 		if (dms->regions[i].bounds) { | ||||
| 			log_error("Region ID %d: grouping regions with " | ||||
| 				  "histograms is not yet supported", i); | ||||
| 			goto bad; | ||||
| 		} | ||||
| 		if (dms->regions[i].timescale == 1) | ||||
| 			precise++; | ||||
|  | ||||
| @@ -3804,9 +3844,11 @@ int dm_stats_delete_group(struct dm_stats *dms, uint64_t group_id, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* clear group and mark as not present */ | ||||
| 	_stats_clear_group_regions(dms, group_id); | ||||
| 	_stats_group_destroy(&dms->groups[group_id]); | ||||
|  | ||||
| 	/* delete leader or clear aux_data */ | ||||
| 	if (remove_regions) | ||||
| 		return dm_stats_delete_region(dms, group_id); | ||||
| 	else if (!_stats_set_aux(dms, group_id, leader->aux_data)) | ||||
| @@ -3853,6 +3895,297 @@ int dm_stats_get_group_descriptor(const struct dm_stats *dms, | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Group a table of region_ids corresponding to the extents of a file. | ||||
|  */ | ||||
| static int _stats_group_file_regions(struct dm_stats *dms, uint64_t *region_ids, | ||||
| 				     uint64_t count, const char *alias) | ||||
| { | ||||
| 	dm_bitset_t regions = dm_bitset_create(NULL, dms->nr_regions); | ||||
| 	uint64_t i, group_id = DM_STATS_GROUP_NOT_PRESENT; | ||||
| 	char *members = NULL; | ||||
| 	int buflen; | ||||
|  | ||||
| 	if (!regions) { | ||||
| 		log_error("Cannot map file: failed to allocate group bitmap."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	for (i = 0; i < count; i++) | ||||
| 		dm_bit_set(regions, region_ids[i]); | ||||
|  | ||||
| 	buflen = _stats_group_tag_len(dms, regions); | ||||
| 	members = dm_malloc(buflen); | ||||
|  | ||||
| 	if (!members) { | ||||
| 		log_error("Cannot map file: failed to allocate group " | ||||
| 			  "descriptor."); | ||||
| 		dm_bitset_destroy(regions); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!_stats_group_tag_fill(dms, regions, members, buflen)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	/* | ||||
| 	 * overlaps should not be possible: overlapping file extents | ||||
| 	 * returned by FIEMAP imply a kernel bug or a corrupt fs. | ||||
| 	 */ | ||||
| 	if (!_stats_group_check_overlap(dms, regions, count)) | ||||
| 		log_info("Creating group with overlapping regions."); | ||||
|  | ||||
| 	if (!_stats_create_group(dms, regions, alias, &group_id)) | ||||
| 		goto bad; | ||||
|  | ||||
| 	dm_free(members); | ||||
| 	return 1; | ||||
| bad: | ||||
| 	dm_bitset_destroy(regions); | ||||
| 	dm_free(members); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext, | ||||
| 			     uint64_t id) | ||||
| { | ||||
| 	struct _extent extent; | ||||
|  | ||||
| 	/* final address of list is unknown */ | ||||
| 	memset(&extent.list, 0, sizeof(extent.list)); | ||||
|  | ||||
| 	/* convert bytes to dm (512b) sectors */ | ||||
| 	extent.start = fm_ext->fe_physical >> 9; | ||||
| 	extent.len = fm_ext->fe_length >> 9; | ||||
|  | ||||
| 	extent.id = id; | ||||
|  | ||||
| 	if (!dm_pool_grow_object(mem, &extent, | ||||
| 				 sizeof(extent))) { | ||||
| 		log_error("Cannot map file: failed to grow extent map."); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return 1; | ||||
|  | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Read the extents of an open file descriptor into a table of struct _extent. | ||||
|  * | ||||
|  * Based on e2fsprogs/misc/filefrag.c::filefrag_fiemap(). | ||||
|  * | ||||
|  * Copyright 2003 by Theodore Ts'o. | ||||
|  * | ||||
|  */ | ||||
| static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd, | ||||
| 						   uint64_t *count) | ||||
| { | ||||
| 	uint64_t buf[2048]; | ||||
| 	struct fiemap *fiemap = (struct fiemap *)buf; | ||||
| 	struct fiemap_extent *fm_ext = &fiemap->fm_extents[0]; | ||||
| 	struct fiemap_extent fm_last = {0}; | ||||
| 	struct _extent *extents; | ||||
| 	unsigned long long expected = 0; | ||||
| 	unsigned long long expected_dense = 0; | ||||
| 	unsigned long flags = 0; | ||||
| 	unsigned int i, num = 0; | ||||
| 	int tot_extents = 0, n = 0; | ||||
| 	int last = 0; | ||||
| 	int rc; | ||||
|  | ||||
| 	memset(buf, 0, sizeof(buf)); | ||||
|  | ||||
| 	/* space available per ioctl */ | ||||
| 	*count = (sizeof(buf) - sizeof(*fiemap)) | ||||
| 		  / sizeof(struct fiemap_extent); | ||||
|  | ||||
| 	/* grow temporary extent table in the pool */ | ||||
| 	if (!dm_pool_begin_object(mem, sizeof(*extents))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	flags |= FIEMAP_FLAG_SYNC; | ||||
|  | ||||
| 	do { | ||||
| 		/* start of ioctl loop - zero size and set count to bufsize */ | ||||
| 		fiemap->fm_length = ~0ULL; | ||||
| 		fiemap->fm_flags = flags; | ||||
| 		fiemap->fm_extent_count = *count; | ||||
|  | ||||
| 		/* get count-sized chunk of extents */ | ||||
| 		rc = ioctl(fd, FS_IOC_FIEMAP, (unsigned long) fiemap); | ||||
| 		if (rc < 0) { | ||||
| 			rc = -errno; | ||||
| 			if (rc == -EBADR) | ||||
| 				log_err_once("FIEMAP failed with unknown " | ||||
| 					     "flags %x.", fiemap->fm_flags); | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| 		/* If 0 extents are returned, then more ioctls are not needed */ | ||||
| 		if (fiemap->fm_mapped_extents == 0) | ||||
| 			break; | ||||
|  | ||||
| 		for (i = 0; i < fiemap->fm_mapped_extents; i++) { | ||||
| 			expected_dense = fm_last.fe_physical + | ||||
| 					 fm_last.fe_length; | ||||
| 			expected = fm_last.fe_physical + | ||||
| 				   fm_ext[i].fe_logical - fm_last.fe_logical; | ||||
| 			if ((fm_ext[i].fe_logical != 0) | ||||
| 			    && (fm_ext[i].fe_physical != expected) | ||||
| 			    && (fm_ext[i].fe_physical != expected_dense)) { | ||||
| 				tot_extents++; | ||||
| 				if (!_stats_add_extent(mem, fm_ext + i, | ||||
| 						       tot_extents - 1)) | ||||
| 					goto bad; | ||||
| 			} else { | ||||
| 				expected = 0; | ||||
| 				if (!tot_extents) | ||||
| 					tot_extents = 1; | ||||
| 				if (fm_ext[i].fe_logical == 0) | ||||
| 					if (!_stats_add_extent(mem, fm_ext + i, | ||||
| 							       tot_extents - 1)) | ||||
| 						goto bad; | ||||
| 			} | ||||
| 			num += tot_extents; | ||||
| 			if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST) | ||||
| 				last = 1; | ||||
| 			fm_last = fm_ext[i]; | ||||
| 			n++; | ||||
| 		} | ||||
|  | ||||
| 		fiemap->fm_start = (fm_ext[i - 1].fe_logical + | ||||
| 				    fm_ext[i - 1].fe_length); | ||||
| 	} while (last == 0); | ||||
|  | ||||
| 	if (!tot_extents) { | ||||
| 		log_error("Cannot map file: no allocated extents."); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	/* return total number of extents */ | ||||
| 	*count = tot_extents; | ||||
| 	return dm_pool_end_object(mem); | ||||
| bad: | ||||
| 	dm_pool_abandon_object(mem); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Create a set of regions representing the extents of a file and | ||||
|  * return a table of uint64_t region_id values. The number of regions | ||||
|  * created is returned in the memory pointed to by count (which must be | ||||
|  * non-NULL). | ||||
|  */ | ||||
| static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd, | ||||
| 					    struct dm_histogram *bounds, | ||||
| 					    int precise, uint64_t *count) | ||||
| { | ||||
| 	struct _extent *extents = NULL; | ||||
| 	uint64_t *regions = NULL, i; | ||||
| 	struct statfs fsbuf; | ||||
| 	struct stat buf; | ||||
|  | ||||
| 	if (fstatfs(fd, &fsbuf)) { | ||||
| 		log_error("fstatfs failed for fd %d", fd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (fsbuf.f_type == BTRFS_SUPER_MAGIC) { | ||||
| 		log_error("Cannot map file: btrfs does not provide " | ||||
| 			  "physical FIEMAP extent data."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (fstat(fd, &buf)) { | ||||
| 		log_error("fstat failed for fd %d", fd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(buf.st_mode & S_IFREG)) { | ||||
| 		log_error("Not a regular file"); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!dm_is_dm_major(major(buf.st_dev))) { | ||||
| 		log_error("Cannot map file: not a device-mapper device."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(extents = _stats_get_extents_for_file(dms->mem, fd, count))) | ||||
| 		return_0; | ||||
|  | ||||
| 	/* make space for end-of-table marker */ | ||||
| 	if (!(regions = dm_malloc((1 + *count) * sizeof(*regions)))) { | ||||
| 		log_error("Could not allocate memory for region IDs."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	for (i = 0; i < *count; i++) { | ||||
| 		if (!_stats_create_region(dms, regions + i, | ||||
| 					  extents[i].start, extents[i].len, -1, | ||||
| 					  precise, NULL, dms->program_id, "")) { | ||||
| 			log_error("Failed to create region " FMTu64 " of " | ||||
| 				  FMTu64 " at " FMTu64 ".", i, *count, | ||||
| 				  extents[i].start); | ||||
| 			goto out_remove; | ||||
| 		} | ||||
| 	} | ||||
| 	regions[*count] = DM_STATS_REGION_NOT_PRESENT; | ||||
|  | ||||
| 	dm_pool_free(dms->mem, extents); | ||||
| 	return regions; | ||||
|  | ||||
| out_remove: | ||||
| 	/* clean up regions after create failure */ | ||||
| 	for (--i; i != DM_STATS_REGION_NOT_PRESENT; i--) { | ||||
| 		if (!dm_stats_delete_region(dms, i)) | ||||
| 			log_error("Could not delete region " FMTu64 ".", i); | ||||
| 	} | ||||
|  | ||||
| out: | ||||
| 	dm_pool_free(dms->mem, extents); | ||||
| 	dm_free(regions); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd, | ||||
| 					  int group, int precise, | ||||
| 					  struct dm_histogram *bounds, | ||||
| 					  const char *alias) | ||||
| { | ||||
| 	uint64_t *regions, count = 0; | ||||
|  | ||||
| 	if (bounds) { | ||||
| 		log_error("File mapped groups with histograms are not " | ||||
| 			  "yet supported."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (alias && !group) { | ||||
| 		log_error("Cannot set alias without grouping regions."); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	regions = _stats_create_file_regions(dms, fd, bounds, precise, &count); | ||||
| 	if (!regions) | ||||
| 		return_0; | ||||
|  | ||||
| 	if (!group) | ||||
| 		return regions; | ||||
|  | ||||
| 	/* refresh handle */ | ||||
| 	if (!dm_stats_list(dms, NULL)) | ||||
| 		goto_out; | ||||
|  | ||||
| 	if (!_stats_group_file_regions(dms, regions, count, alias)) | ||||
| 		goto_out; | ||||
|  | ||||
| 	return regions; | ||||
| out: | ||||
| 	dm_free(regions); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Backward compatible dm_stats_create_region() implementations. | ||||
|  * | ||||
|   | ||||
| @@ -87,6 +87,9 @@ dmstats \(em device-mapper statistics management | ||||
| .  IR area_size ] | ||||
| .  RB [ \-\-bounds | ||||
| .  IR \%histogram_boundaries ] | ||||
| .  RB [ \-\-filemap | ||||
| .  IR path ] | ||||
| .  RB [ \-\-nogroup ] | ||||
| .  RB [ \-\-precise ] | ||||
| .  RB [ \-\-start | ||||
| .  IR start_sector | ||||
| @@ -299,6 +302,14 @@ When peforming a list or report, include objects of type group in the | ||||
| results. | ||||
| . | ||||
| .HP | ||||
| .BR \-\-filemap | ||||
| .IR path | ||||
| .br | ||||
| Instead of creating regions specified by command line options, open | ||||
| the file found at \fBpath\fP, and create regions corresponding to the | ||||
| locations of the on-disk extents allocated to the file. | ||||
| . | ||||
| .HP | ||||
| .BR \-\-groupid | ||||
| .IR id | ||||
| .br | ||||
| @@ -356,6 +367,12 @@ Specify the major number. | ||||
| Specify the minor number. | ||||
| . | ||||
| .HP | ||||
| .BR \-\-nogroup | ||||
| .br | ||||
| When creating regions mapping the extents of a file in the file | ||||
| system, do not create a group or set an alias. | ||||
| . | ||||
| .HP | ||||
| .BR \-\-nosuffix | ||||
| .br | ||||
| Suppress the suffix on output sizes.  Use with \fB\-\-units\fP | ||||
| @@ -538,8 +555,27 @@ device-mapper kernel statistics subsystem. | ||||
| By default dmstats creates regions with a \fBprogram_id\fP of | ||||
| "dmstats". | ||||
|  | ||||
| On success the \fBregion_id\fP of the newly created region is printed to | ||||
| stdout. | ||||
| On success the \fBregion_id\fP of the newly created region is printed | ||||
| to stdout. | ||||
|  | ||||
| If the \fB\-\-filemap\fP option is given with a regular file as the | ||||
| \fBpath\fP argument, instead of creating regions with parameters | ||||
| specified on the command line, \fBdmstats\fP will open the file located | ||||
| at \fBpath\fP and create regions corresponding to the physical extents | ||||
| allocated to the file. This can be used to monitor statistics for | ||||
| individual files in the file system, for example, virtual machine | ||||
| images, swap areas, or large database files. | ||||
|  | ||||
| To work with the \fB\-\-filemap\fP option, files must be located on a | ||||
| local file system, backed by a device-mapper device, that supports | ||||
| physical extent data using the FIEMAP ioctl (Ext4 and XFS for e.g.). | ||||
|  | ||||
| By default regions that map a file are placed into a group and the | ||||
| group alias is set to the basename of the file. This behaviour can be | ||||
| overridden with the \fB\-\-alias\fP and \fB\-\-nogroup\fP options. | ||||
|  | ||||
| To display only group information when listing and reporting, use the | ||||
| \fB\-\-statstype\fP option with the 'group' type. | ||||
| . | ||||
| .HP | ||||
| .CMD_DELETE | ||||
| @@ -1019,6 +1055,14 @@ vg00-lvol1: Created new region with 1 area(s) as region ID 1 | ||||
| .br | ||||
| vg00-lvol1: Created new region with 1 area(s) as region ID 2 | ||||
| .P | ||||
| Create regions mapping the file vm.img and place them into a group with | ||||
| the alias set to the same name as the file. | ||||
| .br | ||||
| # | ||||
| .B dmstats create --filemap vm.img | ||||
| .br | ||||
| vm.img: Created new group with 112 region(s) as group ID 3. | ||||
| .P | ||||
| Print raw counters for region 4 on device d0 | ||||
| .br | ||||
| # | ||||
|   | ||||
							
								
								
									
										1308
									
								
								man/lvconvert.8.in
									
									
									
									
									
								
							
							
						
						
									
										1308
									
								
								man/lvconvert.8.in
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -329,19 +329,20 @@ is specified. | ||||
| .IR LogicalExtentsNumber \c | ||||
| .RB [ % { VG | PVS | FREE | ORIGIN }] | ||||
| .br | ||||
| Gives the number of logical extents to allocate for the new | ||||
| logical volume.  The total number of physical extents allocated will be | ||||
| greater than this, for example, if the volume is mirrored. | ||||
| The number can also be expressed as a percentage of the total space | ||||
| in the Volume Group with the suffix \fB%VG\fP, as a percentage of the | ||||
| remaining free space in the Volume Group with the suffix \fB%FREE\fP, as a | ||||
| percentage of the remaining free space for the specified | ||||
| PhysicalVolume(s) with the suffix \fB%PVS\fP, or (for a snapshot) as a | ||||
| percentage of the total space in the Origin Logical Volume with the | ||||
| suffix \fB%ORIGIN\fP (i.e. \fB100%ORIGIN\fP provides space for the whole origin). | ||||
| When expressed as a percentage, the number is treated | ||||
| as an approximate upper limit for the number of physical extents | ||||
| to be allocated (including extents used by any mirrors, for example). | ||||
| Specifies the size of the new LV in logical extents.  The number of | ||||
| physical extents allocated may be different, and depends on the LV type. | ||||
| Certain LV types require more physical extents for data redundancy or | ||||
| metadata.  An alternate syntax allows the size to be determined indirectly | ||||
| as a percentage of the size of a related VG, LV, or set of PVs.  The | ||||
| suffix \fB%VG\fP denotes the total size of the VG, the suffix \fB%FREE\fP | ||||
| the remaining free space in the VG, and the suffix \fB%PVS\fP the free | ||||
| space in the specified Physical Volumes.  For a snapshot, the size | ||||
| can be expressed as a percentage of the total size of the Origin Logical | ||||
| Volume with the suffix \fB%ORIGIN\fP (\fB100%ORIGIN\fP provides space for | ||||
| the whole origin). | ||||
| When expressed as a percentage, the size defines an upper limit for the | ||||
| number of logical extents in the new LV. The precise number of logical | ||||
| extents in the new LV is not determined until the command has completed. | ||||
| . | ||||
| .HP | ||||
| .BR \-j | \-\-major | ||||
|   | ||||
							
								
								
									
										230
									
								
								tools/dmsetup.c
									
									
									
									
									
								
							
							
						
						
									
										230
									
								
								tools/dmsetup.c
									
									
									
									
									
								
							| @@ -171,6 +171,7 @@ enum { | ||||
| 	DEFERRED_ARG, | ||||
| 	SELECT_ARG, | ||||
| 	EXEC_ARG, | ||||
| 	FILEMAP_ARG, | ||||
| 	FORCE_ARG, | ||||
| 	GID_ARG, | ||||
| 	GROUP_ARG, | ||||
| @@ -187,6 +188,7 @@ enum { | ||||
| 	MODE_ARG, | ||||
| 	NAMEPREFIXES_ARG, | ||||
| 	NOFLUSH_ARG, | ||||
| 	NOGROUP_ARG, | ||||
| 	NOHEADINGS_ARG, | ||||
| 	NOLOCKFS_ARG, | ||||
| 	NOOPENCOUNT_ARG, | ||||
| @@ -4286,7 +4288,7 @@ FIELD_F(STATS_META, STR, "#Bins", 9, dm_stats_hist_bins, "hist_bins", "The numbe | ||||
| FIELD_F(STATS_META, STR, "Histogram Bounds", 16, dm_stats_hist_bounds, "hist_bounds", "Latency histogram bin boundaries.") | ||||
| FIELD_F(STATS_META, STR, "Histogram Ranges", 16, dm_stats_hist_ranges, "hist_ranges", "Latency histogram bin ranges.") | ||||
| FIELD_F(STATS_META, STR, "Name", 16, dm_stats_name, "stats_name", "Stats name of current object.") | ||||
| FIELD_F(STATS_META, STR, "ObjType", 11, dm_stats_object_type, "obj_type", "Type of stats object being reported.") | ||||
| FIELD_F(STATS_META, STR, "ObjType", 7, dm_stats_object_type, "obj_type", "Type of stats object being reported.") | ||||
| {0, 0, 0, 0, "", "", NULL, NULL}, | ||||
| /* *INDENT-ON* */ | ||||
| }; | ||||
| @@ -4611,6 +4613,24 @@ static int _bind_stats_device(struct dm_stats *dms, const char *name) | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _bind_stats_from_fd(struct dm_stats *dms, int fd) | ||||
| { | ||||
| 	int major, minor; | ||||
| 	struct stat buf; | ||||
|  | ||||
| 	if (fstat(fd, &buf)) { | ||||
| 		log_error("fstat failed for fd %d.", fd); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	major = (int) MAJOR(buf.st_dev); | ||||
| 	minor = (int) MINOR(buf.st_dev); | ||||
|  | ||||
| 	if (!dm_stats_bind_devno(dms, major, minor)) | ||||
| 		return_0; | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static int _stats_clear_one_region(struct dm_stats *dms, uint64_t region_id) | ||||
| { | ||||
|  | ||||
| @@ -4745,7 +4765,7 @@ static uint64_t _nr_areas_from_step(uint64_t len, int64_t step) | ||||
| 		return (uint64_t)(-step); | ||||
|  | ||||
| 	/* --areasize - cast step to unsigned as it cannot be -ve here. */ | ||||
| 	return (len / (step ? : len)) + !!(len % (uint64_t) step); | ||||
| 	return (len / step) + !!(len % (uint64_t) step); | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -4841,6 +4861,176 @@ out: | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns the full absolute path, or NULL if the path could | ||||
|  * not be resolved. | ||||
|  */ | ||||
| static char *_get_abspath(const char *path) | ||||
| { | ||||
| 	char *_path; | ||||
|  | ||||
| #ifdef HAVE_CANONICALIZE_FILE_NAME | ||||
| 	_path = canonicalize_file_name(path); | ||||
| #else | ||||
| 	/* FIXME Provide alternative */ | ||||
| 	log_error(INTERNAL_ERROR "Unimplemented _get_abspath."); | ||||
| 	_path = NULL; | ||||
| #endif | ||||
| 	return _path; | ||||
| } | ||||
|  | ||||
| static int _stats_create_file(CMD_ARGS) | ||||
| { | ||||
| 	const char *alias, *program_id = DM_STATS_PROGRAM_ID; | ||||
| 	uint64_t *regions, *region, count = 0; | ||||
| 	char *path, *abspath = NULL; | ||||
| 	int group, fd, precise; | ||||
| 	struct dm_stats *dms; | ||||
|  | ||||
| 	if (_switches[AREAS_ARG] || _switches[AREA_SIZE_ARG]) { | ||||
| 		log_error("--filemap is incompatible with --areas and --area-size."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (_switches[START_ARG] || _switches[LENGTH_ARG]) { | ||||
| 		log_error("--filemap is incompatible with --start and --length."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (_switches[SEGMENTS_ARG]) { | ||||
| 		log_error("--filemap and --segments are incompatible."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (_switches[USER_DATA_ARG]) { | ||||
| 		log_error("--userdata is not yet supported with --filemap."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (_switches[BOUNDS_ARG]) { | ||||
| 		log_error("--bounds is not yet supported with --filemap."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	/* _stats_create_file does not use _process_all() */ | ||||
| 	if (names) { | ||||
| 		log_error("Device argument not compatible with --filemap."); | ||||
| 		return 0; | ||||
| 	} else { | ||||
| 		if (argc || _switches[UUID_ARG] || _switches[MAJOR_ARG]) { | ||||
| 			log_error("--uuid, --major, and device argument are " | ||||
| 				  "incompatible with --filemap."); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (_switches[ALL_DEVICES_ARG]) { | ||||
| 			log_error("--alldevices is incompatible with " | ||||
| 				  "--filemap."); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (_switches[PRECISE_ARG]) { | ||||
| 		if (!dm_stats_driver_supports_precise()) { | ||||
| 			log_error("Using --precise requires driver version " | ||||
| 				  "4.32.0 or later."); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (_switches[BOUNDS_ARG]) { | ||||
| 		if (!dm_stats_driver_supports_histogram()) { | ||||
| 			log_error("Using --bounds requires driver version " | ||||
| 				  "4.32.0 or later."); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (_switches[PROGRAM_ID_ARG]) | ||||
| 		program_id = _string_args[PROGRAM_ID_ARG]; | ||||
| 	if (!strlen(program_id) && !_switches[FORCE_ARG]) | ||||
| 		program_id = DM_STATS_PROGRAM_ID; | ||||
|  | ||||
| 	path = _string_args[FILEMAP_ARG]; | ||||
| 	precise = _int_args[PRECISE_ARG]; | ||||
| 	group = !_switches[NOGROUP_ARG]; | ||||
|  | ||||
| 	if (!(abspath = _get_abspath(path))) { | ||||
| 		log_error("Could not canonicalize file name: %s", path); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(dms = dm_stats_create(DM_STATS_PROGRAM_ID))) | ||||
| 		return_0; | ||||
|  | ||||
| 	fd = open(abspath, O_RDONLY); | ||||
|  | ||||
| 	if (fd < 0) { | ||||
| 		log_error("Could not open %s for reading", path); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	if (!_bind_stats_from_fd(dms, fd)) | ||||
| 		goto_bad; | ||||
|  | ||||
| 	if (!strlen(program_id)) | ||||
| 		/* force creation of a region with no id */ | ||||
| 		dm_stats_set_program_id(dms, 1, NULL); | ||||
|  | ||||
| 	if (group && !_switches[ALIAS_ARG]) | ||||
| 		alias = dm_basename(abspath); | ||||
| 	else if (group) | ||||
| 		alias = _string_args[ALIAS_ARG]; | ||||
| 	else if (!_switches[ALIAS_ARG]) | ||||
| 		alias = NULL; | ||||
| 	else { | ||||
| 		log_error("Cannot set alias with --nogroup."); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	regions = dm_stats_create_regions_from_fd(dms, fd, group, precise, | ||||
| 						  NULL, alias); | ||||
|  | ||||
| 	if (close(fd)) | ||||
| 		log_error("Error closing %s", path); | ||||
|  | ||||
| 	fd = -1; | ||||
|  | ||||
| 	if (!regions) { | ||||
| 		log_error("Could not create regions from file %s", path); | ||||
| 		goto bad; | ||||
| 	} | ||||
|  | ||||
| 	for (region = regions; *region != DM_STATS_REGIONS_ALL; region++) { | ||||
| 		count++; | ||||
| 	} | ||||
|  | ||||
| 	if (group) { | ||||
| 		printf("%s: Created new group with "FMTu64" region(s) as " | ||||
| 		       "group ID "FMTu64".\n", path, count, regions[0]); | ||||
| 	} else { | ||||
| 		region = regions; | ||||
| 		do | ||||
| 			printf("%s: Created new region with 1 area as " | ||||
| 			       "region ID "FMTu64".\n", path, *region); | ||||
| 		while (*(++region) != DM_STATS_REGIONS_ALL); | ||||
| 	} | ||||
|  | ||||
| 	dm_free(regions); | ||||
| 	dm_free(abspath); | ||||
| 	dm_stats_destroy(dms); | ||||
| 	return 1; | ||||
|  | ||||
| bad: | ||||
| 	if (abspath) | ||||
| 		dm_free(abspath); | ||||
|  | ||||
| 	if ((fd > -1) && close(fd)) | ||||
| 		log_error("Error closing %s", path); | ||||
|  | ||||
| 	dm_stats_destroy(dms); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int _stats_create(CMD_ARGS) | ||||
| { | ||||
| 	struct dm_stats *dms; | ||||
| @@ -4876,6 +5066,10 @@ static int _stats_create(CMD_ARGS) | ||||
| 			return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (_switches[FILEMAP_ARG]) | ||||
| 		return _stats_create_file(cmd, subcommand, argc, argv, | ||||
| 					  names, multiple_devices); | ||||
|  | ||||
| 	if (names) | ||||
| 		name = names->name; | ||||
| 	else { | ||||
| @@ -5030,6 +5224,7 @@ static int _stats_delete(CMD_ARGS) | ||||
| 			log_error("Could not delete statistics group."); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		printf("Deleted statistics group " FMTu64 ".\n", group_id); | ||||
| 	} else if (_switches[ALL_REGIONS_ARG]) { | ||||
| 		dm_stats_foreach_region(dms) { | ||||
| 			region_id = dm_stats_get_current_region(dms); | ||||
| @@ -5040,7 +5235,10 @@ static int _stats_delete(CMD_ARGS) | ||||
| 			log_info("Deleted statistics region %" PRIu64, region_id); | ||||
| 		} | ||||
| 	} else { | ||||
| 		dm_stats_delete_region(dms, region_id); | ||||
| 		if (!dm_stats_delete_region(dms, region_id)) { | ||||
| 			log_error("Could not delete statistics region"); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		log_info("Deleted statistics region " FMTu64 ".\n", region_id); | ||||
| 	} | ||||
|  | ||||
| @@ -5679,24 +5877,6 @@ static int _process_tree_options(const char *options) | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns the full absolute path, or NULL if the path could | ||||
|  * not be resolved. | ||||
|  */ | ||||
| static char *_get_abspath(const char *path) | ||||
| { | ||||
| 	char *_path; | ||||
|  | ||||
| #ifdef HAVE_CANONICALIZE_FILE_NAME | ||||
| 	_path = canonicalize_file_name(path); | ||||
| #else | ||||
| 	/* FIXME Provide alternative */ | ||||
| 	log_error(INTERNAL_ERROR "Unimplemented _get_abspath."); | ||||
| 	_path = NULL; | ||||
| #endif | ||||
| 	return _path; | ||||
| } | ||||
|  | ||||
| static char *parse_loop_device_name(const char *dev, const char *dev_dir) | ||||
| { | ||||
| 	char *buf; | ||||
| @@ -5981,6 +6161,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir) | ||||
| 		{"deferred", 0, &ind, DEFERRED_ARG}, | ||||
| 		{"select", 1, &ind, SELECT_ARG}, | ||||
| 		{"exec", 1, &ind, EXEC_ARG}, | ||||
| 		{"filemap", 1, &ind, FILEMAP_ARG}, | ||||
| 		{"force", 0, &ind, FORCE_ARG}, | ||||
| 		{"gid", 1, &ind, GID_ARG}, | ||||
| 		{"group", 0, &ind, GROUP_ARG}, | ||||
| @@ -5995,6 +6176,7 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir) | ||||
| 		{"minor", 1, &ind, MINOR_ARG}, | ||||
| 		{"mode", 1, &ind, MODE_ARG}, | ||||
| 		{"nameprefixes", 0, &ind, NAMEPREFIXES_ARG}, | ||||
| 		{"nogroup", 0, &ind, NOGROUP_ARG}, | ||||
| 		{"noflush", 0, &ind, NOFLUSH_ARG}, | ||||
| 		{"noheadings", 0, &ind, NOHEADINGS_ARG}, | ||||
| 		{"nolockfs", 0, &ind, NOLOCKFS_ARG}, | ||||
| @@ -6144,6 +6326,10 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir) | ||||
| 			_switches[CLEAR_ARG]++; | ||||
| 		if (c == 'c' || c == 'C' || ind == COLS_ARG) | ||||
| 			_switches[COLS_ARG]++; | ||||
| 		if (ind == FILEMAP_ARG) { | ||||
| 			_switches[FILEMAP_ARG]++; | ||||
| 			_string_args[FILEMAP_ARG] = optarg; | ||||
| 		} | ||||
| 		if (c == 'f' || ind == FORCE_ARG) | ||||
| 			_switches[FORCE_ARG]++; | ||||
| 		if (c == 'r' || ind == READ_ONLY) | ||||
| @@ -6303,6 +6489,8 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir) | ||||
| 			_switches[NAMEPREFIXES_ARG]++; | ||||
| 		if (ind == NOFLUSH_ARG) | ||||
| 			_switches[NOFLUSH_ARG]++; | ||||
| 		if (ind == NOGROUP_ARG) | ||||
| 			_switches[NOGROUP_ARG]++; | ||||
| 		if (ind == NOHEADINGS_ARG) | ||||
| 			_switches[NOHEADINGS_ARG]++; | ||||
| 		if (ind == NOLOCKFS_ARG) | ||||
|   | ||||
| @@ -1705,6 +1705,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, | ||||
| 			      struct logical_volume *lv, | ||||
| 			      struct lvconvert_params *lp) | ||||
| { | ||||
| 	const char *new_type; | ||||
| 	uint32_t old_mimage_count; | ||||
| 	uint32_t old_log_count; | ||||
| 	uint32_t new_mimage_count; | ||||
| @@ -1733,6 +1734,16 @@ static int _lvconvert_mirrors(struct cmd_context *cmd, | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if ((new_type = arg_str_value(cmd, type_ARG, NULL)) && | ||||
| 	    !strcmp(new_type, SEG_TYPE_NAME_LINEAR)) { | ||||
| 		if (arg_is_set(cmd, mirrors_ARG) && (arg_uint_value(cmd, mirrors_ARG, 0) != 0)) { | ||||
| 			log_error("Cannot specify mirrors with linear type."); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		lp->mirrors_supplied = 1; | ||||
| 		lp->mirrors = 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Adjust mimage and/or log count */ | ||||
| 	if (!_lvconvert_mirrors_parse_params(cmd, lv, lp, | ||||
| 					     &old_mimage_count, &old_log_count, | ||||
| @@ -1812,6 +1823,7 @@ static void _lvconvert_raid_repair_ask(struct cmd_context *cmd, | ||||
|  | ||||
| static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp) | ||||
| { | ||||
| 	const char *new_type; | ||||
| 	int replace = 0, image_count = 0; | ||||
| 	struct dm_list *failed_pvs; | ||||
| 	struct cmd_context *cmd = lv->vg->cmd; | ||||
| @@ -1821,6 +1833,16 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l | ||||
| 	if (!lp->segtype) | ||||
| 		lp->segtype = seg->segtype; | ||||
|  | ||||
| 	if ((new_type = arg_str_value(cmd, type_ARG, NULL)) && | ||||
| 	    !strcmp(new_type, SEG_TYPE_NAME_LINEAR)) { | ||||
| 		if (arg_is_set(cmd, mirrors_ARG) && (arg_uint_value(cmd, mirrors_ARG, 0) != 0)) { | ||||
| 			log_error("Cannot specify mirrors with linear type."); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		lp->mirrors_supplied = 1; | ||||
| 		lp->mirrors = 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Can only change image count for raid1 and linear */ | ||||
| 	if (lp->mirrors_supplied && !seg_is_mirrored(seg) && !seg_is_linear(seg)) { | ||||
| 		log_error("'--mirrors/-m' is not compatible with %s", | ||||
| @@ -3614,6 +3636,20 @@ static int _convert_mirror_repair(struct cmd_context *cmd, struct logical_volume | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Convert mirror LV to linear LV. | ||||
|  * lvconvert --type linear LV | ||||
|  * | ||||
|  * Alternate syntax: | ||||
|  * lvconvert --mirrors 0 LV | ||||
|  */ | ||||
|  | ||||
| static int _convert_mirror_linear(struct cmd_context *cmd, struct logical_volume *lv, | ||||
| 			          struct lvconvert_params *lp) | ||||
| { | ||||
| 	return _lvconvert_mirrors(cmd, lv, lp); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Convert mirror LV to raid1 LV. | ||||
|  * lvconvert --type raid1 LV | ||||
| @@ -4126,6 +4162,9 @@ static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv, | ||||
| 	if (arg_is_set(cmd, repair_ARG)) | ||||
| 		return _convert_mirror_repair(cmd, lv, lp); | ||||
|  | ||||
| 	if (new_type && !strcmp(new_type, SEG_TYPE_NAME_LINEAR)) | ||||
| 		return _convert_mirror_linear(cmd, lv, lp); | ||||
|  | ||||
| 	if (new_type && new_segtype && segtype_is_raid(new_segtype)) | ||||
| 		return _convert_mirror_raid(cmd, lv, lp); | ||||
|  | ||||
| @@ -4152,6 +4191,7 @@ static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv, | ||||
| 		  "  --splitmirrors\n" | ||||
| 		  "  --mirrorlog\n" | ||||
| 		  "  --repair\n" | ||||
| 		  "  --type linear\n" | ||||
| 		  "  --type raid*\n"); | ||||
| 	return 0; | ||||
| } | ||||
|   | ||||
| @@ -49,9 +49,6 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv) | ||||
| 	/* Don't create a new PV on top of an existing PV like pvcreate does. */ | ||||
| 	pp.preserve_existing = 1; | ||||
|  | ||||
| 	/* pvcreate within vgcreate cannot be forced. */ | ||||
| 	pp.force = 0; | ||||
|  | ||||
| 	if (!vgcreate_params_set_defaults(cmd, &vp_def, NULL)) | ||||
| 		return EINVALID_CMD_LINE; | ||||
| 	vp_def.vg_name = vg_name; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user