mirror of
				git://sourceware.org/git/lvm2.git
				synced 2025-10-30 20:23:49 +03:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
			v2_03_36
			...
			dev-dct-pv
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 1ce2c03d9b | ||
|  | 2ed8f23ae3 | ||
|  | 84607d93b6 | ||
|  | e719522e29 | ||
|  | 27a19e46f4 | 
| @@ -1935,6 +1935,7 @@ libdm/libdevmapper.pc | ||||
| man/Makefile | ||||
| po/Makefile | ||||
| scripts/lvm2-pvscan.service | ||||
| scripts/lvm-vgchange.service | ||||
| scripts/blkdeactivate.sh | ||||
| scripts/blk_availability_init_red_hat | ||||
| scripts/blk_availability_systemd_red_hat.service | ||||
|   | ||||
| @@ -320,6 +320,33 @@ static int _parse_debug_classes(struct cmd_context *cmd) | ||||
| 	return debug_classes; | ||||
| } | ||||
|  | ||||
| static uint32_t _parse_log_journal(struct cmd_context *cmd, int cfg, const char *cfgname) | ||||
| { | ||||
| 	const struct dm_config_node *cn; | ||||
| 	const struct dm_config_value *cv; | ||||
| 	uint32_t fields = 0; | ||||
| 	uint32_t val; | ||||
|  | ||||
| 	if (!(cn = find_config_tree_array(cmd, cfg, NULL))) { | ||||
| 		log_debug("Unable to find configuration for log/%s.", cfgname); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	for (cv = cn->v; cv; cv = cv->next) { | ||||
| 		if (cv->type != DM_CFG_STRING) { | ||||
| 			log_verbose("log/%s contains a value which is not a string.  Ignoring.", cfgname); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if ((val = log_journal_str_to_val(cv->v.str))) | ||||
| 			fields |= val; | ||||
| 		else | ||||
| 			log_verbose("Unrecognised value for log/%s: %s", cfgname, cv->v.str); | ||||
| 	} | ||||
|  | ||||
| 	return fields; | ||||
| } | ||||
|  | ||||
| static void _init_logging(struct cmd_context *cmd) | ||||
| { | ||||
| 	int append = 1; | ||||
| @@ -388,6 +415,9 @@ static void _init_logging(struct cmd_context *cmd) | ||||
| 	init_debug_file_fields(_parse_debug_fields(cmd, log_debug_file_fields_CFG, "debug_file_fields")); | ||||
| 	init_debug_output_fields(_parse_debug_fields(cmd, log_debug_output_fields_CFG, "debug_output_fields")); | ||||
|  | ||||
| 	cmd->default_settings.journal = _parse_log_journal(cmd, log_journal_CFG, "journal"); | ||||
| 	init_log_journal(cmd->default_settings.journal); | ||||
|  | ||||
| 	t = time(NULL); | ||||
| 	ctime_r(&t, &timebuf[0]); | ||||
| 	timebuf[24] = '\0'; | ||||
|   | ||||
| @@ -29,6 +29,7 @@ struct config_info { | ||||
| 	int debug_classes; | ||||
| 	int verbose; | ||||
| 	int silent; | ||||
| 	int suppress; | ||||
| 	int test; | ||||
| 	int syslog; | ||||
| 	int activation; | ||||
| @@ -40,6 +41,7 @@ struct config_info { | ||||
| 	int udev_sync; | ||||
| 	int udev_fallback; | ||||
| 	int issue_discards; | ||||
| 	uint32_t journal; | ||||
| 	const char *msg_prefix; | ||||
| 	const char *fmt_name; | ||||
| 	const char *dmeventd_executable; | ||||
|   | ||||
| @@ -876,6 +876,12 @@ cfg(log_syslog_CFG, "syslog", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_SYSLOG, | ||||
| cfg(log_file_CFG, "file", log_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, | ||||
| 	"Write error and debug log messages to a file specified here.\n") | ||||
|  | ||||
| cfg_array(log_journal_CFG, "journal", log_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, NULL, vsn(2, 3, 12), NULL, 0, NULL, | ||||
| 	  "Record lvm information in the systemd journal.\n" | ||||
| 	  "command: record commands that are run.\n" | ||||
| 	  "output: record default output from commands.\n" | ||||
| 	  "debug: record debug messages from commands.\n") | ||||
|  | ||||
| cfg(log_overwrite_CFG, "overwrite", log_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_OVERWRITE, vsn(1, 0, 0), NULL, 0, NULL, | ||||
| 	"Overwrite the log file each time the program is run.\n") | ||||
|  | ||||
|   | ||||
| @@ -25,6 +25,7 @@ | ||||
| #include <syslog.h> | ||||
| #include <ctype.h> | ||||
| #include <time.h> | ||||
| #include <systemd/sd-journal.h> | ||||
|  | ||||
| static FILE *_log_file; | ||||
| static char _log_file_path[PATH_MAX]; | ||||
| @@ -40,6 +41,7 @@ static char _msg_prefix[30] = "  "; | ||||
| static int _abort_on_internal_errors_config = 0; | ||||
| static uint32_t _debug_file_fields; | ||||
| static uint32_t _debug_output_fields; | ||||
| static uint32_t _log_journal = 0; | ||||
|  | ||||
| static lvm2_log_fn_t _lvm2_log_fn = NULL; | ||||
|  | ||||
| @@ -455,6 +457,11 @@ void init_debug_output_fields(uint32_t debug_fields) | ||||
| 	_debug_output_fields = debug_fields; | ||||
| } | ||||
|  | ||||
| void init_log_journal(uint32_t fields) | ||||
| { | ||||
| 	_log_journal = fields; | ||||
| } | ||||
|  | ||||
| static void _set_time_prefix(char *prefix, int buflen) | ||||
| { | ||||
|  | ||||
| @@ -609,6 +616,33 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c | ||||
| 	} | ||||
|  | ||||
|       log_it: | ||||
|  | ||||
| 	if (_log_journal) { | ||||
| 		int to_journal = 0; | ||||
|  | ||||
| 		/* By default the visible command output is _LOG_WARN or less. */ | ||||
|  | ||||
| 		if (_log_journal & LOG_JOURNAL_DEBUG) | ||||
| 			to_journal = 1; | ||||
| 		if ((_log_journal & LOG_JOURNAL_OUTPUT) && (log_level(level) <= _LOG_WARN)) | ||||
| 			to_journal = 1; | ||||
|  | ||||
| 		if (to_journal) { | ||||
| 			int prio; | ||||
| 			switch (log_level(level)) { | ||||
| 			case _LOG_ERR:    prio = LOG_ERR; break; | ||||
| 			case _LOG_WARN:   prio = LOG_WARNING; break; | ||||
| 			case _LOG_INFO:   prio = LOG_INFO; break; | ||||
| 			case _LOG_NOTICE: prio = LOG_NOTICE; break; | ||||
| 			case _LOG_DEBUG:  prio = LOG_DEBUG; break; | ||||
| 			default:          prio = LOG_INFO; | ||||
| 			} | ||||
| 			va_copy(ap, orig_ap); | ||||
| 			sd_journal_printv(prio, trformat, ap); | ||||
| 			va_end(ap); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!logged_via_report && ((verbose_level() >= level) && !_log_suppress)) { | ||||
| 		if (verbose_level() > _LOG_DEBUG) { | ||||
| 			memset(buf, 0, sizeof(buf)); | ||||
| @@ -792,3 +826,60 @@ void log_set_report_object_name_and_id(const char *name, const char *id) | ||||
| 	_log_report.object_name = name; | ||||
| 	_log_report.object_id = id; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * TODO: log/journal=["daemon_command"] | ||||
|  *       daemon_command: record commands that are run by an lvm daemon. | ||||
|  *       (i.e. not commands run directly by a user.) | ||||
|  *       For this we need to be able to clearly identify when a command is | ||||
|  *       being run by dmeventd/lvmpolld/lvmdbusd. | ||||
|  * | ||||
|  * TODO: log/journal_commmand_names=["lvcreate","lvconvert"] | ||||
|  * This would restrict log/journal=["command"] to the listed command names. | ||||
|  * Also allow "!command" to exclude a command, e.g. ["!pvs"] | ||||
|  * | ||||
|  * TODO: log/journal_daemon_command_names=["lvcreate","lvconvert"] | ||||
|  * This would restrict log/journal=["dameon_command"] to the listed command names. | ||||
|  * | ||||
|  * TODO: log/journal_daemon_names=["dmeventd"] | ||||
|  * This would restrict log/journal=["daemon_command"] to commands run by | ||||
|  * the named daemon. | ||||
|  * | ||||
|  * TODO: log/command_to_file=<path> would write this info to the file. | ||||
|  * | ||||
|  * TODO: log/debug_to_file=<path> would write full debugging to the file. | ||||
|  *       (the same effect as log/file=<path> log/level=7) | ||||
|  */ | ||||
|  | ||||
| void log_command(const char *cmd_line, const char *cmd_name, const char *cmd_id) | ||||
| { | ||||
| 	if (_log_journal & LOG_JOURNAL_COMMAND) { | ||||
|  | ||||
| 		/* | ||||
| 		 * TODO: DAEMON=dmeventd|lvmpolld|lvmdbusd, | ||||
| 		 * Could we include caller info such as libblkid, udev rule, etc? | ||||
| 		 * Does systemd already record the caller for us? | ||||
| 		 */ | ||||
|  | ||||
| 		/* The command line, pid, and other things are automatically included. */ | ||||
|  | ||||
| 		sd_journal_send("MESSAGE=lvm command %s", cmd_name, | ||||
| 				"MESSAGE_ID=3ca432788c374e4ba684b834188eca36", | ||||
| 				"LVM_CMD_NAME=%s", cmd_name, | ||||
| 				"LVM_CMD_ID=%s", cmd_id, | ||||
| 				"PRIORITY=%i", LOG_INFO, | ||||
| 				NULL); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| uint32_t log_journal_str_to_val(const char *str) | ||||
| { | ||||
| 	if (!strcasecmp(str, "command")) | ||||
| 		return LOG_JOURNAL_COMMAND; | ||||
| 	if (!strcasecmp(str, "output")) | ||||
| 		return LOG_JOURNAL_OUTPUT; | ||||
| 	if (!strcasecmp(str, "debug")) | ||||
| 		return LOG_JOURNAL_DEBUG; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -63,6 +63,10 @@ | ||||
| #define LOG_DEBUG_FIELD_FILELINE	0x0004 | ||||
| #define LOG_DEBUG_FIELD_MESSAGE		0x0008 | ||||
|  | ||||
| #define LOG_JOURNAL_COMMAND             0x0001 | ||||
| #define LOG_JOURNAL_OUTPUT              0x0002 | ||||
| #define LOG_JOURNAL_DEBUG               0x0004 | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Classes available for debug log messages. | ||||
|   | ||||
| @@ -62,6 +62,12 @@ void reset_log_duplicated(void); | ||||
| void init_syslog(int facility); | ||||
| void fin_syslog(void); | ||||
|  | ||||
| void init_log_journal(uint32_t fields); | ||||
| uint32_t log_journal_str_to_val(const char *str); | ||||
|  | ||||
| void log_command(const char *cmd_line, const char *cmd_name, const char *cmd_id); | ||||
|  | ||||
|  | ||||
| int error_message_produced(void); | ||||
| void reset_lvm_errno(int store_errmsg); | ||||
| int stored_errno(void); | ||||
|   | ||||
| @@ -5264,3 +5264,36 @@ struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_ | ||||
|  | ||||
| 	return vg; | ||||
| } | ||||
|  | ||||
| int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, struct device *dev, | ||||
| 			     struct dm_list *lvs_list) | ||||
| { | ||||
| 	struct pv_list *pvl; | ||||
| 	struct lv_list *lvl, *lvl2; | ||||
| 	struct physical_volume *pv = NULL; | ||||
|  | ||||
| 	dm_list_iterate_items(pvl, &vg->pvs) { | ||||
| 		if (pvl->pv->dev == dev) { | ||||
| 			pv = pvl->pv; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (!pv) | ||||
| 		return_0; | ||||
|  | ||||
| 	dm_list_iterate_items(lvl, &vg->lvs) { | ||||
| 		if (!lv_is_visible(lvl->lv)) | ||||
| 			continue; | ||||
| 		if (!lv_is_on_pv(lvl->lv, pv)) | ||||
| 			continue; | ||||
|  | ||||
| 		if (!(lvl2 = dm_pool_zalloc(cmd->mem, sizeof(*lvl2)))) | ||||
| 			return_0; | ||||
| 		lvl2->lv = lvl->lv; | ||||
| 		dm_list_add(lvs_list, &lvl2->list); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -539,4 +539,8 @@ char *tags_format_and_copy(struct dm_pool *mem, const struct dm_list *tagsl); | ||||
|  | ||||
| void set_pv_devices(struct format_instance *fid, struct volume_group *vg); | ||||
|  | ||||
| int get_visible_lvs_using_pv(struct cmd_context *cmd, struct volume_group *vg, struct device *dev, | ||||
|                             struct dm_list *lvs_list); | ||||
|  | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -88,7 +88,7 @@ install_systemd_generators: | ||||
| install_systemd_units:	install_dbus_service | ||||
| 	@echo "    [INSTALL] systemd_units" | ||||
| 	$(Q) $(INSTALL_DIR) $(systemd_unit_dir) | ||||
| 	$(Q) $(INSTALL_DATA) lvm2-pvscan.service $(systemd_unit_dir)/lvm2-pvscan@.service | ||||
| 	$(Q) $(INSTALL_DATA) lvm-vgchange.service $(systemd_unit_dir)/lvm-vgchange@.service | ||||
| ifeq ("@BUILD_DMEVENTD@", "yes") | ||||
| 	$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.socket $(systemd_unit_dir)/dm-event.socket | ||||
| 	$(Q) $(INSTALL_DATA) dm_event_systemd_red_hat.service $(systemd_unit_dir)/dm-event.service | ||||
| @@ -139,6 +139,7 @@ DISTCLEAN_TARGETS += \ | ||||
| 	dm_event_systemd_red_hat.socket \ | ||||
| 	lvmdump.sh \ | ||||
| 	lvm2-pvscan.service \ | ||||
| 	lvm-vgchange.service \ | ||||
| 	lvm2_cluster_activation_red_hat.sh \ | ||||
| 	lvm2_cluster_activation_systemd_red_hat.service \ | ||||
| 	lvm2_clvmd_systemd_red_hat.service \ | ||||
|   | ||||
							
								
								
									
										12
									
								
								scripts/lvm-vgchange.service.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								scripts/lvm-vgchange.service.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| [Unit] | ||||
| Description=LVM event activation of VG %i | ||||
| Documentation=man:vgchange(8) | ||||
| DefaultDependencies=no | ||||
| StartLimitIntervalSec=0 | ||||
| Before=shutdown.target | ||||
| Conflicts=shutdown.target | ||||
|  | ||||
| [Service] | ||||
| Type=oneshot | ||||
| RemainAfterExit=no | ||||
| ExecStart=@SBINDIR@/lvm vgchange -aay --config log/prefix=\"\" %i | ||||
| @@ -300,6 +300,9 @@ if (( sysreport )); then | ||||
| 		for unit in $("$GREP" lvm2-pvscan "$sysreport_dir/systemd_unit_list" | cut -d " " -f 1); do | ||||
| 			log "$SYSTEMCTL status -l --no-pager -n $log_lines -o short-precise $unit >> \"$sysreport_dir/systemd_lvm2_pvscan_service_status\"" | ||||
| 		done | ||||
| 		for unit in $("$GREP" lvm-vgchange "$sysreport_dir/systemd_unit_list" | cut -d " " -f 1); do | ||||
| 			log "$SYSTEMCTL status -l --no-pager -n $log_lines -o short-precise $unit >> \"$sysreport_dir/systemd_lvm_vgchange_service_status\"" | ||||
| 		done | ||||
| 	fi | ||||
| fi | ||||
|  | ||||
|   | ||||
							
								
								
									
										380
									
								
								test/shell/udev-pvscan-vgchange.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								test/shell/udev-pvscan-vgchange.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,380 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| # Copyright (C) 2021 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # 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 General Public License v.2. | ||||
| # | ||||
| # You should have received a copy of the GNU 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 | ||||
|  | ||||
| test_description='udev rule and systemd unit run vgchange' | ||||
|  | ||||
| SKIP_WITH_LVMPOLLD=1 | ||||
| SKIP_WITH_LVMLOCKD=1 | ||||
|  | ||||
| . lib/inittest | ||||
|  | ||||
| # | ||||
| # $ cat /tmp/devs | ||||
| # /dev/sdb | ||||
| # /dev/sdc | ||||
| # /dev/sdd | ||||
| # | ||||
| # Specify this file as LVM_TEST_DEVICE_LIST=/tmp/devs | ||||
| # when running the test. | ||||
| # | ||||
| # This test will wipe these devices. | ||||
| # | ||||
|  | ||||
| if [ -z ${LVM_TEST_DEVICE_LIST+x} ]; then echo "LVM_TEST_DEVICE_LIST is unset" && skip; else echo "LVM_TEST_DEVICE_LIST is set to '$LVM_TEST_DEVICE_LIST'"; fi | ||||
|  | ||||
| test -e "$LVM_TEST_DEVICE_LIST" || skip | ||||
|  | ||||
| num_devs=$(cat $LVM_TEST_DEVICE_LIST | wc -l) | ||||
|  | ||||
| RUNDIR="/run" | ||||
| test -d "$RUNDIR" || RUNDIR="/var/run" | ||||
| PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online" | ||||
| VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online" | ||||
| PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup" | ||||
|  | ||||
| _clear_online_files() { | ||||
| 	# wait till udev is finished | ||||
| 	aux udev_wait | ||||
| 	rm -f "$PVS_ONLINE_DIR"/* | ||||
| 	rm -f "$VGS_ONLINE_DIR"/* | ||||
| 	rm -f "$PVS_LOOKUP_DIR"/* | ||||
| } | ||||
|  | ||||
| test -d "$PVS_ONLINE_DIR" || mkdir -p "$PVS_ONLINE_DIR" | ||||
| test -d "$VGS_ONLINE_DIR" || mkdir -p "$VGS_ONLINE_DIR" | ||||
| test -d "$PVS_LOOKUP_DIR" || mkdir -p "$PVS_LOOKUP_DIR" | ||||
| _clear_online_files | ||||
|  | ||||
| aux prepare_real_devs | ||||
|  | ||||
| aux lvmconf 'devices/dir = "/dev"' | ||||
| aux lvmconf 'devices/use_devicesfile = 1' | ||||
| DFDIR="$LVM_SYSTEM_DIR/devices" | ||||
| DF="$DFDIR/system.devices" | ||||
| mkdir $DFDIR || true | ||||
| not ls $DF | ||||
|  | ||||
| get_real_devs | ||||
|  | ||||
| wipe_all() { | ||||
| 	for dev in "${REAL_DEVICES[@]}"; do | ||||
| 		wipefs -a $dev | ||||
| 	done | ||||
| } | ||||
|  | ||||
| # Test requires 3 devs | ||||
| test $num_devs -gt 2 || skip | ||||
| BDEV1=$(basename "$dev1") | ||||
| BDEV2=$(basename "$dev2") | ||||
| BDEV3=$(basename "$dev3") | ||||
|  | ||||
| wipe_all | ||||
| touch $DF | ||||
| for dev in "${REAL_DEVICES[@]}"; do | ||||
| 	pvcreate $dev | ||||
| done | ||||
|  | ||||
| # 1 dev, 1 vg, 1 lv | ||||
|  | ||||
| vgcreate $vg1 "$dev1" | ||||
| lvcreate -l1 -an -n $lv1 $vg1 "$dev1" | ||||
|  | ||||
| PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}') | ||||
|  | ||||
| _clear_online_files | ||||
| udevadm trigger --settle -c add /sys/block/$BDEV1 | ||||
|  | ||||
| ls "$RUNDIR/lvm/pvs_online/$PVID1" | ||||
| ls "$RUNDIR/lvm/vgs_online/$vg1" | ||||
| systemctl status lvm-vgchange@$vg1 | tee out || true | ||||
| grep Started out | ||||
| check lv_field $vg1/$lv1 lv_active "active" | ||||
|  | ||||
| vgchange -an $vg1 | ||||
| vgremove -y $vg1 | ||||
|  | ||||
|  | ||||
| # 2 devs, 1 vg, 2 lvs | ||||
|  | ||||
| vgcreate $vg2 "$dev1" "$dev2" | ||||
| lvcreate -l1 -an -n $lv1 $vg2 "$dev1" | ||||
| lvcreate -l1 -an -n $lv2 $vg2 "$dev2" | ||||
|  | ||||
| PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}') | ||||
| PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}') | ||||
|  | ||||
| _clear_online_files | ||||
|  | ||||
| udevadm trigger --settle -c add /sys/block/$BDEV1 | ||||
| ls "$RUNDIR/lvm/pvs_online/$PVID1" | ||||
| not ls "$RUNDIR/lvm/vgs_online/$vg2" | ||||
| systemctl status lvm-vgchange@$vg2 | tee out || true | ||||
| not grep Started out | ||||
| check lv_field $vg2/$lv1 lv_active "" | ||||
| check lv_field $vg2/$lv2 lv_active "" | ||||
|  | ||||
| udevadm trigger --settle -c add /sys/block/$BDEV2 | ||||
| ls "$RUNDIR/lvm/pvs_online/$PVID2" | ||||
| ls "$RUNDIR/lvm/vgs_online/$vg2" | ||||
| systemctl status lvm-vgchange@$vg2 | tee out || true | ||||
| grep Started out | ||||
| check lv_field $vg2/$lv1 lv_active "active" | ||||
| check lv_field $vg2/$lv2 lv_active "active" | ||||
|  | ||||
| vgchange -an $vg2 | ||||
| vgremove -y $vg2 | ||||
|  | ||||
|  | ||||
| # 3 devs, 1 vg, 4 lvs, concurrent pvscans | ||||
| # (attempting to have the pvscans run concurrently and race | ||||
| # to activate the VG) | ||||
|  | ||||
| vgcreate $vg3 "$dev1" "$dev2" "$dev3" | ||||
| lvcreate -l1 -an -n $lv1 $vg3 "$dev1" | ||||
| lvcreate -l1 -an -n $lv2 $vg3 "$dev2" | ||||
| lvcreate -l1 -an -n $lv3 $vg3 "$dev3" | ||||
| lvcreate -l8 -an -n $lv4 -i 2 $vg3 "$dev1" "$dev2" | ||||
|  | ||||
| PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}') | ||||
| PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}') | ||||
| PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}') | ||||
|  | ||||
| _clear_online_files | ||||
|  | ||||
| udevadm trigger -c add /sys/block/$BDEV1 & | ||||
| udevadm trigger -c add /sys/block/$BDEV2 & | ||||
| udevadm trigger -c add /sys/block/$BDEV3 | ||||
|  | ||||
| sleep 5 | ||||
| aux udev_wait | ||||
|  | ||||
| ls "$RUNDIR/lvm/pvs_online/$PVID1" | ||||
| ls "$RUNDIR/lvm/pvs_online/$PVID2" | ||||
| ls "$RUNDIR/lvm/pvs_online/$PVID3" | ||||
| ls "$RUNDIR/lvm/vgs_online/$vg3" | ||||
| systemctl status lvm-vgchange@$vg3 | tee out || true | ||||
| grep Started out | ||||
| check lv_field $vg3/$lv1 lv_active "active" | ||||
| check lv_field $vg3/$lv2 lv_active "active" | ||||
| check lv_field $vg3/$lv3 lv_active "active" | ||||
| check lv_field $vg3/$lv4 lv_active "active" | ||||
|  | ||||
| vgchange -an $vg3 | ||||
| vgremove -y $vg3 | ||||
|  | ||||
|  | ||||
| # 3 devs, 1 vg, 4 lvs, concurrent pvscans, metadata on only 1 PV | ||||
|  | ||||
| wipe_all | ||||
| rm $DF | ||||
| touch $DF | ||||
| pvcreate --metadatacopies 0 "$dev1" | ||||
| pvcreate --metadatacopies 0 "$dev2" | ||||
| pvcreate "$dev3" | ||||
|  | ||||
| vgcreate $vg4 "$dev1" "$dev2" "$dev3" | ||||
| lvcreate -l1 -an -n $lv1 $vg4 "$dev1" | ||||
| lvcreate -l1 -an -n $lv2 $vg4 "$dev2" | ||||
| lvcreate -l1 -an -n $lv3 $vg4 "$dev3" | ||||
| lvcreate -l8 -an -n $lv4 -i 2 $vg4 "$dev1" "$dev2" | ||||
|  | ||||
| PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}') | ||||
| PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}') | ||||
| PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}') | ||||
|  | ||||
| _clear_online_files | ||||
|  | ||||
| udevadm trigger -c add /sys/block/$BDEV1 & | ||||
| udevadm trigger -c add /sys/block/$BDEV2 & | ||||
| udevadm trigger -c add /sys/block/$BDEV3 | ||||
|  | ||||
| sleep 5 | ||||
| aux udev_wait | ||||
|  | ||||
| ls "$RUNDIR/lvm/pvs_online/$PVID1" | ||||
| ls "$RUNDIR/lvm/pvs_online/$PVID2" | ||||
| ls "$RUNDIR/lvm/pvs_online/$PVID3" | ||||
| ls "$RUNDIR/lvm/vgs_online/$vg4" | ||||
| systemctl status lvm-vgchange@$vg4 | tee out || true | ||||
| grep Started out | ||||
| check lv_field $vg4/$lv1 lv_active "active" | ||||
| check lv_field $vg4/$lv2 lv_active "active" | ||||
| check lv_field $vg4/$lv3 lv_active "active" | ||||
| check lv_field $vg4/$lv4 lv_active "active" | ||||
|  | ||||
| vgchange -an $vg4 | ||||
| vgremove -y $vg4 | ||||
|  | ||||
|  | ||||
| # 3 devs, 3 vgs, 2 lvs in each vg, concurrent pvscans | ||||
|  | ||||
| wipe_all | ||||
| rm $DF | ||||
| touch $DF | ||||
|  | ||||
| vgcreate $vg5 "$dev1" | ||||
| vgcreate $vg6 "$dev2" | ||||
| vgcreate $vg7 "$dev3" | ||||
| lvcreate -l1 -an -n $lv1 $vg5 | ||||
| lvcreate -l1 -an -n $lv2 $vg5 | ||||
| lvcreate -l1 -an -n $lv1 $vg6 | ||||
| lvcreate -l1 -an -n $lv2 $vg6 | ||||
| lvcreate -l1 -an -n $lv1 $vg7 | ||||
| lvcreate -l1 -an -n $lv2 $vg7 | ||||
|  | ||||
| _clear_online_files | ||||
|  | ||||
| udevadm trigger -c add /sys/block/$BDEV1 & | ||||
| udevadm trigger -c add /sys/block/$BDEV2 & | ||||
| udevadm trigger -c add /sys/block/$BDEV3 | ||||
|  | ||||
| sleep 5 | ||||
| aux udev_wait | ||||
|  | ||||
| ls "$RUNDIR/lvm/vgs_online/$vg5" | ||||
| ls "$RUNDIR/lvm/vgs_online/$vg6" | ||||
| ls "$RUNDIR/lvm/vgs_online/$vg7" | ||||
| systemctl status lvm-vgchange@$vg5 | tee out || true | ||||
| grep Started out | ||||
| systemctl status lvm-vgchange@$vg6 | tee out || true | ||||
| grep Started out | ||||
| systemctl status lvm-vgchange@$vg7 | tee out || true | ||||
| grep Started out | ||||
| check lv_field $vg5/$lv1 lv_active "active" | ||||
| check lv_field $vg5/$lv2 lv_active "active" | ||||
| check lv_field $vg6/$lv1 lv_active "active" | ||||
| check lv_field $vg6/$lv2 lv_active "active" | ||||
| check lv_field $vg7/$lv1 lv_active "active" | ||||
| check lv_field $vg7/$lv2 lv_active "active" | ||||
|  | ||||
| vgchange -an $vg5 | ||||
| vgremove -y $vg5 | ||||
| vgchange -an $vg6 | ||||
| vgremove -y $vg6 | ||||
| vgchange -an $vg7 | ||||
| vgremove -y $vg7 | ||||
|  | ||||
| # 3 devs, 1 vg, 1000 LVs | ||||
|  | ||||
| wipe_all | ||||
| rm $DF | ||||
| touch $DF | ||||
| pvcreate --metadatacopies 0 "$dev1" | ||||
| pvcreate "$dev2" | ||||
| pvcreate "$dev3" | ||||
| vgcreate -s 128K $vg8 "$dev1" "$dev2" "$dev3" | ||||
|  | ||||
| # Number of LVs to create | ||||
| TEST_DEVS=1000 | ||||
| # On low-memory boxes let's not stress too much | ||||
| test "$(aux total_mem)" -gt 524288 || TEST_DEVS=256 | ||||
|  | ||||
| vgcfgbackup -f data $vg8 | ||||
|  | ||||
| # Generate a lot of devices (size of 1 extent) | ||||
| awk -v TEST_DEVS=$TEST_DEVS '/^\t\}/ { | ||||
|     printf("\t}\n\tlogical_volumes {\n"); | ||||
|     cnt=0; | ||||
|     for (i = 0; i < TEST_DEVS; i++) { | ||||
|         printf("\t\tlvol%06d  {\n", i); | ||||
|         printf("\t\t\tid = \"%06d-1111-2222-3333-2222-1111-%06d\"\n", i, i); | ||||
|         print "\t\t\tstatus = [\"READ\", \"WRITE\", \"VISIBLE\"]"; | ||||
|         print "\t\t\tsegment_count = 1"; | ||||
|         print "\t\t\tsegment1 {"; | ||||
|         print "\t\t\t\tstart_extent = 0"; | ||||
|         print "\t\t\t\textent_count = 1"; | ||||
|         print "\t\t\t\ttype = \"striped\""; | ||||
|         print "\t\t\t\tstripe_count = 1"; | ||||
|         print "\t\t\t\tstripes = ["; | ||||
|         print "\t\t\t\t\t\"pv0\", " cnt++; | ||||
|         printf("\t\t\t\t]\n\t\t\t}\n\t\t}\n"); | ||||
|       } | ||||
|   } | ||||
|   {print} | ||||
| ' data >data_new | ||||
|  | ||||
| vgcfgrestore -f data_new $vg8 | ||||
|  | ||||
| _clear_online_files | ||||
|  | ||||
| udevadm trigger -c add /sys/block/$BDEV1 & | ||||
| udevadm trigger -c add /sys/block/$BDEV2 & | ||||
| udevadm trigger -c add /sys/block/$BDEV3 | ||||
|  | ||||
| sleep 5 | ||||
| aux udev_wait | ||||
|  | ||||
| ls "$RUNDIR/lvm/vgs_online/$vg8" | ||||
| systemctl status lvm-vgchange@$vg8 | tee out || true | ||||
| grep Started out | ||||
|  | ||||
| num_active=$(lvs $vg8 --noheading -o active | grep active | wc -l) | ||||
|  | ||||
| test $num_active -eq $TEST_DEVS | ||||
|  | ||||
| vgchange -an $vg8 | ||||
| vgremove -y $vg8 | ||||
|  | ||||
| # 1 pv on an md dev, 1 vg | ||||
|  | ||||
| wait_md_create() { | ||||
| 	local md=$1 | ||||
|  | ||||
| 	while :; do | ||||
| 		if ! grep "$(basename $md)" /proc/mdstat; then | ||||
| 			echo "$md not ready" | ||||
| 			cat /proc/mdstat | ||||
| 			sleep 2 | ||||
| 		else | ||||
| 			break | ||||
| 		fi | ||||
| 	done | ||||
| 	echo "$md" > WAIT_MD_DEV | ||||
| } | ||||
|  | ||||
| test -f /proc/mdstat && grep -q raid1 /proc/mdstat || \ | ||||
|        modprobe raid1 || skip | ||||
|  | ||||
| mddev="/dev/md33" | ||||
| not grep $mddev /proc/mdstat || skip | ||||
|  | ||||
| wipe_all | ||||
| rm $DF | ||||
| touch $DF | ||||
|  | ||||
| mdadm --create --metadata=1.0 "$mddev" --level 1 --chunk=64 --raid-devices=2 "$dev1" "$dev2" | ||||
| wait_md_create "$mddev" | ||||
| vgcreate $vg9 "$mddev" | ||||
|  | ||||
| PVIDMD=`pvs $mddev --noheading -o uuid | tr -d - | awk '{print $1}'` | ||||
| BDEVMD=$(basename "$mddev") | ||||
|  | ||||
| lvcreate -l1 -an -n $lv1 $vg9 | ||||
| lvcreate -l1 -an -n $lv2 $vg9 | ||||
|  | ||||
| _clear_online_files | ||||
|  | ||||
| udevadm trigger --settle -c add /sys/block/$BDEVMD | ||||
|  | ||||
| ls "$RUNDIR/lvm/vgs_online/$vg9" | ||||
| systemctl status lvm-vgchange@$vg9 | tee out || true | ||||
| grep Started out | ||||
| check lv_field $vg9/$lv1 lv_active "active" | ||||
| check lv_field $vg9/$lv2 lv_active "active" | ||||
|  | ||||
| vgchange -an $vg9 | ||||
| vgremove -y $vg9 | ||||
|  | ||||
| mdadm --stop "$mddev" | ||||
| udev_wait | ||||
| wipe_all | ||||
|  | ||||
							
								
								
									
										28
									
								
								tools/args.h
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								tools/args.h
									
									
									
									
									
								
							| @@ -307,12 +307,33 @@ arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0, | ||||
| arg(importdevices_ARG, '\0', "importdevices", 0, 0, 0, | ||||
|     "Add devices to the devices file.\n") | ||||
|  | ||||
| arg(journal_ARG, '\0', "journal", string_VAL, 0, 0, | ||||
|     "Record information in the systemd journal.\n" | ||||
|     "This information is in addition to information\n" | ||||
|     "enabled by the lvm.conf log/journal setting.\n" | ||||
|     "command: record information about the command.\n" | ||||
|     "output: record the default command output.\n" | ||||
|     "debug: record full command debugging.\n") | ||||
|  | ||||
| arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0, | ||||
|     "By default the PV is labelled with an LVM2 identifier in its second\n" | ||||
|     "sector (sector 1). This lets you use a different sector near the\n" | ||||
|     "start of the disk (between 0 and 3 inclusive - see LABEL_SCAN_SECTORS\n" | ||||
|     "in the source). Use with care.\n") | ||||
|  | ||||
| arg(listlvs_ARG, '\0', "listlvs", 0, 0, 0, | ||||
|     "Print a list of LVs that use the device.\n") | ||||
|  | ||||
| arg(listvg_ARG, '\0', "listvg", 0, 0, 0, | ||||
|     "Print the VG that uses the device.\n") | ||||
|  | ||||
| arg(checkcomplete_ARG, '\0', "checkcomplete", 0, 0, 0, | ||||
|     "Check if all the devices used by a VG or LV are present,\n" | ||||
|     "and print \"complete\" or \"incomplete\" for each listed\n" | ||||
|     "VG or LV.  This option is used as a part of event-based\n" | ||||
|     "autoactivation, so pvscan will do nothing if this option\n" | ||||
|     "is set and event_activation=0 in the config settings.\n") | ||||
|  | ||||
| arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0, | ||||
|     "Used to pass options for special cases to lvmlockd.\n" | ||||
|     "See \\fBlvmlockd\\fP(8) for more information.\n") | ||||
| @@ -795,6 +816,9 @@ arg(type_ARG, '\0', "type", segtype_VAL, 0, 0, | ||||
|     "(e.g. --stripes, --mirrors, --snapshot, --virtualsize, --thin, --cache, --vdo).\n" | ||||
|     "Use inferred types with care because it can lead to unexpected results.\n") | ||||
|  | ||||
| arg(udevoutput_ARG, '\0', "udevoutput", 0, 0, 0, | ||||
|     "Command output is modified to be imported from a udev rule.\n") | ||||
|  | ||||
| arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0, | ||||
|     "Produce output immediately without sorting or aligning the columns properly.\n") | ||||
|  | ||||
| @@ -871,6 +895,10 @@ arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", vgmetadatacopies_VAL, 0, 0, | ||||
|     "\\fBall\\fP causes LVM to first clear the metadataignore flags on\n" | ||||
|     "all PVs, and then to become unmanaged.\n") | ||||
|  | ||||
| arg(vgonline_ARG, '\0', "vgonline", 0, 0, 0, | ||||
|     "The first command to see a complete VG will report it uniquely.\n" | ||||
|     "Other commands to see the complete VG will report it differently.\n") | ||||
|  | ||||
| arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0, | ||||
|     "Display a one line comment for each configuration node.\n") | ||||
|  | ||||
|   | ||||
| @@ -188,7 +188,7 @@ | ||||
| # | ||||
| OO_ALL: --commandprofile String, --config String, --debug, | ||||
| --driverloaded Bool, --help, --nolocking, --lockopt String, --longhelp, --profile String, --quiet, | ||||
| --verbose, --version, --yes, --test, --devicesfile String, --devices PV | ||||
| --verbose, --version, --yes, --test, --devicesfile String, --devices PV, --journal String | ||||
|  | ||||
| # | ||||
| # options for pvs, lvs, vgs, fullreport | ||||
| @@ -1603,11 +1603,37 @@ DESC: Display PV information. | ||||
|  | ||||
| pvscan --cache_long | ||||
| OO: --ignorelockingfailure, --reportformat ReportFmt, | ||||
| --activate ay, --major Number, --minor Number, --noudevsync | ||||
| --major Number, --minor Number, --noudevsync | ||||
| OP: PV|String ... | ||||
| IO: --background | ||||
| ID: pvscan_cache | ||||
| DESC: Autoactivate a VG when all PVs are online. | ||||
| DESC: Record that a PV is online or offline. | ||||
|  | ||||
| pvscan --cache_long --activate ay | ||||
| OO: --ignorelockingfailure, --reportformat ReportFmt, | ||||
| --major Number, --minor Number, --noudevsync | ||||
| OP: PV|String ... | ||||
| IO: --background | ||||
| ID: pvscan_cache | ||||
| DESC: Record that a PV is online and autoactivate the VG if complete. | ||||
|  | ||||
| pvscan --cache_long --listvg PV | ||||
| OO: --ignorelockingfailure, --checkcomplete, --vgonline, --udevoutput | ||||
| ID: pvscan_cache | ||||
| DESC: Record that a PV is online and list the VG using the PV. | ||||
|  | ||||
| pvscan --cache_long --listlvs PV | ||||
| OO: --ignorelockingfailure, --checkcomplete, --vgonline | ||||
| ID: pvscan_cache | ||||
| DESC: Record that a PV is online and list LVs using the PV. | ||||
|  | ||||
| pvscan --listlvs PV | ||||
| ID: pvscan_cache | ||||
| DESC: List LVs using the PV. | ||||
|  | ||||
| pvscan --listvg PV | ||||
| ID: pvscan_cache | ||||
| DESC: List the VG using the PV. | ||||
|  | ||||
| --- | ||||
|  | ||||
|   | ||||
| @@ -2007,6 +2007,8 @@ out: | ||||
| 	log_debug("Recognised command %s (id %d / enum %d).", | ||||
| 		  commands[best_i].command_id, best_i, commands[best_i].command_enum); | ||||
|  | ||||
| 	log_command(cmd->cmd_line, commands[best_i].name, commands[best_i].command_id); | ||||
|  | ||||
| 	return &commands[best_i]; | ||||
| } | ||||
|  | ||||
| @@ -2381,6 +2383,9 @@ static void _reset_current_settings_to_default(struct cmd_context *cmd) | ||||
|  | ||||
| static void _get_current_output_settings_from_args(struct cmd_context *cmd) | ||||
| { | ||||
| 	if (arg_is_set(cmd, udevoutput_ARG)) | ||||
| 		cmd->current_settings.suppress = 1; | ||||
|  | ||||
| 	if (arg_is_set(cmd, debug_ARG)) | ||||
| 		cmd->current_settings.debug = _LOG_FATAL + (arg_count(cmd, debug_ARG) - 1); | ||||
|  | ||||
| @@ -2392,14 +2397,25 @@ static void _get_current_output_settings_from_args(struct cmd_context *cmd) | ||||
| 		cmd->current_settings.verbose = 0; | ||||
| 		cmd->current_settings.silent = (arg_count(cmd, quiet_ARG) > 1) ? 1 : 0; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * default_settings.journal is already set from config and has already been | ||||
| 	 * applied using init_log_journal(). | ||||
| 	 * current_settings have been set to default_settings. | ||||
| 	 * now --journal value adds to current_settings. | ||||
| 	 */ | ||||
| 	if (arg_is_set(cmd, journal_ARG)) | ||||
| 		cmd->current_settings.journal |= log_journal_str_to_val(arg_str_value(cmd, journal_ARG, "")); | ||||
| } | ||||
|  | ||||
| static void _apply_current_output_settings(struct cmd_context *cmd) | ||||
| { | ||||
| 	log_suppress(cmd->current_settings.suppress); | ||||
| 	init_debug(cmd->current_settings.debug); | ||||
| 	init_debug_classes_logged(cmd->default_settings.debug_classes); | ||||
| 	init_verbose(cmd->current_settings.verbose + VERBOSE_BASE_LEVEL); | ||||
| 	init_silent(cmd->current_settings.silent); | ||||
| 	init_log_journal(cmd->current_settings.journal); | ||||
| } | ||||
|  | ||||
| static int _read_devices_list(struct cmd_context *cmd) | ||||
|   | ||||
							
								
								
									
										411
									
								
								tools/pvscan.c
									
									
									
									
									
								
							
							
						
						
									
										411
									
								
								tools/pvscan.c
									
									
									
									
									
								
							| @@ -179,6 +179,27 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Avoid a duplicate pvscan[%d] prefix when logging to the journal. | ||||
|  * FIXME: this should probably replace if (udevoutput) with | ||||
|  * if (log_journal & LOG_JOURNAL_OUTPUT) | ||||
|  */ | ||||
| #define log_print_pvscan(cmd, fmt, args...) \ | ||||
| do \ | ||||
| 	if (arg_is_set(cmd, udevoutput_ARG)) \ | ||||
| 		log_print(fmt, ##args); \ | ||||
| 	else \ | ||||
| 		log_print("pvscan[%d] " fmt, getpid(), ##args); \ | ||||
| while (0) | ||||
|  | ||||
| #define log_error_pvscan(cmd, fmt, args...) \ | ||||
| do \ | ||||
| 	if (arg_is_set(cmd, udevoutput_ARG)) \ | ||||
| 		log_error(fmt, ##args); \ | ||||
| 	else \ | ||||
| 		log_error("pvscan[%d] " fmt, getpid(), ##args); \ | ||||
| while (0) | ||||
|  | ||||
| static char *_vgname_in_pvid_file_buf(char *buf) | ||||
| { | ||||
| 	char *p, *n; | ||||
| @@ -259,7 +280,7 @@ static void _lookup_file_remove(char *vgname) | ||||
|  * that the vg will be activated again when it becomes complete. | ||||
|  */ | ||||
|  | ||||
| static void _online_vg_file_remove(const char *vgname) | ||||
| void online_vg_file_remove(const char *vgname) | ||||
| { | ||||
| 	char path[PATH_MAX]; | ||||
|  | ||||
| @@ -314,7 +335,7 @@ static void _online_pvid_file_remove_devno(int major, int minor) | ||||
| 				log_sys_debug("unlink", path); | ||||
|  | ||||
| 			if (file_vgname[0]) { | ||||
| 				_online_vg_file_remove(file_vgname); | ||||
| 				online_vg_file_remove(file_vgname); | ||||
| 				_lookup_file_remove(file_vgname); | ||||
| 			} | ||||
| 		} | ||||
| @@ -345,7 +366,7 @@ static void _online_files_remove(const char *dirpath) | ||||
| 		log_sys_debug("closedir", dirpath); | ||||
| } | ||||
|  | ||||
| static int _online_pvid_file_create(struct device *dev, const char *vgname) | ||||
| static int _online_pvid_file_create(struct cmd_context *cmd, struct device *dev, const char *vgname) | ||||
| { | ||||
| 	char path[PATH_MAX]; | ||||
| 	char buf[MAX_PVID_FILE_SIZE] = { 0 }; | ||||
| @@ -362,18 +383,18 @@ static int _online_pvid_file_create(struct device *dev, const char *vgname) | ||||
| 	minor = (int)MINOR(dev->dev); | ||||
|  | ||||
| 	if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, dev->pvid) < 0) { | ||||
| 		log_error("Path %s/%s is too long.", _pvs_online_dir, dev->pvid); | ||||
| 		log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_online_dir, dev->pvid); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if ((len1 = dm_snprintf(buf, sizeof(buf), "%d:%d\n", major, minor)) < 0) { | ||||
| 		log_error("Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor); | ||||
| 		log_error_pvscan(cmd, "Cannot create online file path for %s %d:%d.", dev_name(dev), major, minor); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (vgname) { | ||||
| 		if ((len2 = dm_snprintf(buf + len1, sizeof(buf) - len1, "vg:%s\n", vgname)) < 0) { | ||||
| 			log_warn("Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname); | ||||
| 			log_print_pvscan(cmd, "Incomplete online file for %s %d:%d vg %s.", dev_name(dev), major, minor, vgname); | ||||
| 			/* can still continue without vgname */ | ||||
| 			len2 = 0; | ||||
| 		} | ||||
| @@ -387,7 +408,7 @@ static int _online_pvid_file_create(struct device *dev, const char *vgname) | ||||
| 	if (fd < 0) { | ||||
| 		if (errno == EEXIST) | ||||
| 			goto check_duplicate; | ||||
| 		log_error("Failed to create online file for %s path %s error %d", dev_name(dev), path, errno); | ||||
| 		log_error_pvscan(cmd, "Failed to create online file for %s path %s error %d", dev_name(dev), path, errno); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| @@ -435,12 +456,12 @@ check_duplicate: | ||||
| 	/* Don't know how vgname might not match, but it's not good so fail. */ | ||||
|  | ||||
| 	if ((file_major != major) || (file_minor != minor)) | ||||
| 		log_error("pvscan[%d] PV %s is duplicate for PVID %s on %d:%d and %d:%d.", | ||||
| 			  getpid(), dev_name(dev), dev->pvid, major, minor, file_major, file_minor); | ||||
| 		log_error_pvscan(cmd, "PV %s is duplicate for PVID %s on %d:%d and %d:%d.", | ||||
| 			         dev_name(dev), dev->pvid, major, minor, file_major, file_minor); | ||||
|  | ||||
| 	if (file_vgname[0] && vgname && strcmp(file_vgname, vgname)) | ||||
| 		log_error("pvscan[%d] PV %s has unexpected VG %s vs %s.", | ||||
| 			  getpid(), dev_name(dev), vgname, file_vgname); | ||||
| 		log_error_pvscan(cmd, "PV %s has unexpected VG %s vs %s.", | ||||
| 			         dev_name(dev), vgname, file_vgname); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -475,7 +496,7 @@ static int _write_lookup_file(struct cmd_context *cmd, struct volume_group *vg) | ||||
| 	int fd; | ||||
|  | ||||
| 	if (dm_snprintf(path, sizeof(path), "%s/%s", _pvs_lookup_dir, vg->name) < 0) { | ||||
| 		log_error("Path %s/%s is too long.", _pvs_lookup_dir, vg->name); | ||||
| 		log_error_pvscan(cmd, "Path %s/%s is too long.", _pvs_lookup_dir, vg->name); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| @@ -638,7 +659,7 @@ static int _count_pvid_files_from_lookup_file(struct cmd_context *cmd, struct de | ||||
| 	return (vgname) ? 1 : 0; | ||||
| } | ||||
|  | ||||
| static void _online_dir_setup(void) | ||||
| static void _online_dir_setup(struct cmd_context *cmd) | ||||
| { | ||||
| 	struct stat st; | ||||
| 	int rv; | ||||
| @@ -652,7 +673,7 @@ static void _online_dir_setup(void) | ||||
| 	dm_prepare_selinux_context(NULL, 0); | ||||
|  | ||||
| 	if ((rv < 0) && stat(DEFAULT_RUN_DIR, &st)) | ||||
| 		log_error("Failed to create %s %d", DEFAULT_RUN_DIR, errno); | ||||
| 		log_error_pvscan(cmd, "Failed to create %s %d", DEFAULT_RUN_DIR, errno); | ||||
|  | ||||
| do_pvs: | ||||
| 	if (!stat(_pvs_online_dir, &st)) | ||||
| @@ -664,7 +685,7 @@ do_pvs: | ||||
| 	dm_prepare_selinux_context(NULL, 0); | ||||
|  | ||||
| 	if ((rv < 0) && stat(_pvs_online_dir, &st)) | ||||
| 		log_error("Failed to create %s %d", _pvs_online_dir, errno); | ||||
| 		log_error_pvscan(cmd, "Failed to create %s %d", _pvs_online_dir, errno); | ||||
|  | ||||
| do_vgs: | ||||
| 	if (!stat(_vgs_online_dir, &st)) | ||||
| @@ -676,7 +697,7 @@ do_vgs: | ||||
| 	dm_prepare_selinux_context(NULL, 0); | ||||
|  | ||||
| 	if ((rv < 0) && stat(_vgs_online_dir, &st)) | ||||
| 		log_error("Failed to create %s %d", _vgs_online_dir, errno); | ||||
| 		log_error_pvscan(cmd, "Failed to create %s %d", _vgs_online_dir, errno); | ||||
|  | ||||
| do_lookup: | ||||
| 	if (!stat(_pvs_lookup_dir, &st)) | ||||
| @@ -688,7 +709,7 @@ do_lookup: | ||||
| 	dm_prepare_selinux_context(NULL, 0); | ||||
|  | ||||
| 	if ((rv < 0) && stat(_pvs_lookup_dir, &st)) | ||||
| 		log_error("Failed to create %s %d", _pvs_lookup_dir, errno); | ||||
| 		log_error_pvscan(cmd, "Failed to create %s %d", _pvs_lookup_dir, errno); | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -725,7 +746,7 @@ static int _pvscan_aa_single(struct cmd_context *cmd, const char *vg_name, | ||||
| 	log_debug("pvscan autoactivating VG %s.", vg_name); | ||||
|  | ||||
| 	if (!vgchange_activate(cmd, vg, CHANGE_AAY)) { | ||||
| 		log_error("%s: autoactivation failed.", vg->name); | ||||
| 		log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name); | ||||
| 		pp->activate_errors++; | ||||
| 	} | ||||
|  | ||||
| @@ -738,7 +759,7 @@ static int _online_vg_file_create(struct cmd_context *cmd, const char *vgname) | ||||
| 	int fd; | ||||
|  | ||||
| 	if (dm_snprintf(path, sizeof(path), "%s/%s", _vgs_online_dir, vgname) < 0) { | ||||
| 		log_error("Path %s/%s is too long.", _vgs_online_dir, vgname); | ||||
| 		log_error_pvscan(cmd, "Path %s/%s is too long.", _vgs_online_dir, vgname); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| @@ -826,15 +847,15 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname, | ||||
| 		_online_pvid_file_read(path, &file_major, &file_minor, file_vgname); | ||||
|  | ||||
| 		if (file_vgname[0] && strcmp(vgname, file_vgname)) { | ||||
| 			log_error("Wrong VG found for %d:%d PVID %s: %s vs %s", | ||||
| 				  file_major, file_minor, pvid, vgname, file_vgname); | ||||
| 			log_error_pvscan(cmd, "Wrong VG found for %d:%d PVID %s: %s vs %s", | ||||
| 				         file_major, file_minor, pvid, vgname, file_vgname); | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| 		devno = MKDEV(file_major, file_minor); | ||||
|  | ||||
| 		if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) { | ||||
| 			log_error("No device found for %d:%d PVID %s", file_major, file_minor, pvid); | ||||
| 			log_error_pvscan(cmd, "No device found for %d:%d PVID %s", file_major, file_minor, pvid); | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| @@ -844,7 +865,7 @@ static int _get_devs_from_saved_vg(struct cmd_context *cmd, const char *vgname, | ||||
| 		if (strcmp(name1, name2)) { | ||||
| 			if (!id_write_format((const struct id *)pvid, uuidstr, sizeof(uuidstr))) | ||||
| 				uuidstr[0] = '\0'; | ||||
| 			log_print("PVID %s read from %s last written to %s.", uuidstr, name1, name2); | ||||
| 			log_print_pvscan(cmd, "PVID %s read from %s last written to %s.", uuidstr, name1, name2); | ||||
| 			goto bad; | ||||
| 		} | ||||
|  | ||||
| @@ -921,7 +942,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp | ||||
| 	 * The dev_cache gives us struct devices from the devnums. | ||||
| 	 */ | ||||
| 	if (!_get_devs_from_saved_vg(cmd, vgname, &devs)) { | ||||
| 		log_print("pvscan[%d] VG %s not using quick activation.", getpid(), vgname); | ||||
| 		log_print_pvscan(cmd, "VG %s not using quick activation.", vgname); | ||||
| 		*no_quick = 1; | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
| @@ -932,7 +953,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp | ||||
| 	 * label rescan are then disabled in vg_read.) | ||||
| 	 */ | ||||
| 	if (!lock_vol(cmd, vgname, LCK_VG_WRITE, NULL)) { | ||||
| 		log_error("pvscan activation for VG %s failed to lock VG.", vgname); | ||||
| 		log_error_pvscan(cmd, "activation for VG %s failed to lock VG.", vgname); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
|  | ||||
| @@ -945,7 +966,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp | ||||
| 	label_scan_devs(cmd, NULL, &devs); | ||||
|  | ||||
| 	if (!(vgid = lvmcache_vgid_from_vgname(cmd, vgname))) { | ||||
| 		log_error("pvscan activation for VG %s failed to find vgid.", vgname); | ||||
| 		log_error_pvscan(cmd, "activation for VG %s failed to find vgid.", vgname); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
|  | ||||
| @@ -965,7 +986,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp | ||||
| 		 * original device arg scan.  There will be very few and unusual | ||||
| 		 * cases that would be caught here. | ||||
| 		 */ | ||||
| 		log_error("pvscan activation for VG %s cannot read (%x).", vgname, error_flags); | ||||
| 		log_error_pvscan(cmd, "activation for VG %s cannot read (%x).", vgname, error_flags); | ||||
| 		return ECMD_FAILED; | ||||
| 	} | ||||
|  | ||||
| @@ -987,7 +1008,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp | ||||
| 	dm_list_iterate_items(pvl, &vg->pvs) { | ||||
| 		if (dev_in_device_list(pvl->pv->dev, &devs)) | ||||
| 			continue; | ||||
| 		log_error("pvscan activation for VG %s found different devices.", vgname); | ||||
| 		log_error_pvscan(cmd, "activation for VG %s found different devices.", vgname); | ||||
| 		ret = ECMD_FAILED; | ||||
| 		goto out; | ||||
| 	} | ||||
| @@ -995,7 +1016,7 @@ static int _pvscan_aa_quick(struct cmd_context *cmd, struct pvscan_aa_params *pp | ||||
| 	log_debug("pvscan autoactivating VG %s.", vgname); | ||||
|  | ||||
| 	if (!vgchange_activate(cmd, vg, CHANGE_AAY)) { | ||||
| 		log_error("%s: autoactivation failed.", vg->name); | ||||
| 		log_error_pvscan(cmd, "%s: autoactivation failed.", vg->name); | ||||
| 		pp->activate_errors++; | ||||
| 	} | ||||
|  | ||||
| @@ -1014,7 +1035,7 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp, | ||||
| 	int ret = ECMD_FAILED; | ||||
|  | ||||
| 	if (!(handle = init_processing_handle(cmd, NULL))) { | ||||
| 		log_error("Failed to initialize processing handle."); | ||||
| 		log_error_pvscan(cmd, "Failed to initialize processing handle."); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| @@ -1029,11 +1050,11 @@ static int _pvscan_aa(struct cmd_context *cmd, struct pvscan_aa_params *pp, | ||||
| 	 */ | ||||
| 	dm_list_iterate_items_safe(sl, sl2, vgnames) { | ||||
| 		if (!_online_vg_file_create(cmd, sl->str)) { | ||||
| 			log_print("pvscan[%d] VG %s skip autoactivation.", getpid(), sl->str); | ||||
| 			log_print_pvscan(cmd, "VG %s skip autoactivation.", sl->str); | ||||
| 			str_list_del(vgnames, sl->str); | ||||
| 			continue; | ||||
| 		} | ||||
| 		log_print("pvscan[%d] VG %s run autoactivation.", getpid(), sl->str); | ||||
| 		log_print_pvscan(cmd, "VG %s run autoactivation.", sl->str); | ||||
| 	} | ||||
|  | ||||
| 	if (dm_list_empty(vgnames)) { | ||||
| @@ -1165,6 +1186,64 @@ static int _get_args_devs(struct cmd_context *cmd, struct dm_list *pvscan_args, | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void _set_pv_devices_online(struct cmd_context *cmd, struct volume_group *vg) | ||||
| { | ||||
| 	char path[PATH_MAX]; | ||||
| 	char file_vgname[NAME_LEN]; | ||||
| 	char pvid[ID_LEN+1] = { 0 }; | ||||
| 	struct pv_list *pvl; | ||||
| 	struct device *dev; | ||||
| 	int major, minor; | ||||
| 	dev_t devno; | ||||
|  | ||||
| 	dm_list_iterate_items(pvl, &vg->pvs) { | ||||
| 		memcpy(&pvid, &pvl->pv->id.uuid, ID_LEN); | ||||
|  | ||||
| 		if (pvl->pv->status & MISSING_PV) { | ||||
| 			log_debug("set_pv_devices_online vg %s pv %s missing flag already set", | ||||
| 				  vg->name, pvid); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!_online_pvid_file_exists(pvid)) { | ||||
| 			log_debug("set_pv_devices_online vg %s pv %s no online file", | ||||
| 				  vg->name, pvid); | ||||
| 			pvl->pv->status |= MISSING_PV; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		memset(path, 0, sizeof(path)); | ||||
| 		snprintf(path, sizeof(path), "%s/%s", _pvs_online_dir, pvid); | ||||
|  | ||||
| 		major = 0; | ||||
| 		minor = 0; | ||||
| 		file_vgname[0] = '\0'; | ||||
|  | ||||
| 		_online_pvid_file_read(path, &major, &minor, file_vgname); | ||||
|  | ||||
| 		if (file_vgname[0] && strcmp(vg->name, file_vgname)) { | ||||
| 			log_warn("WARNING: VG %s PV %s wrong vgname in online file %s", | ||||
| 				  vg->name, pvid, file_vgname); | ||||
| 			pvl->pv->status |= MISSING_PV; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		devno = MKDEV(major, minor); | ||||
|  | ||||
| 		if (!(dev = dev_cache_get_by_devt(cmd, devno, NULL, NULL))) { | ||||
| 			log_print_pvscan(cmd, "VG %s PV %s no device found for %d:%d", | ||||
| 					 vg->name, pvid, major, minor); | ||||
| 			pvl->pv->status |= MISSING_PV; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		log_debug("set_pv_devices_online vg %s pv %s is online %s", | ||||
| 			  vg->name, pvid, dev_name(dev)); | ||||
|  | ||||
| 		pvl->pv->dev = dev; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvscan_devs, | ||||
| 			int *pv_count, struct dm_list *complete_vgnames) | ||||
| { | ||||
| @@ -1177,15 +1256,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs | ||||
| 	struct metadata_area *mda1, *mda2; | ||||
| 	struct volume_group *vg; | ||||
| 	struct physical_volume *pv; | ||||
| 	const char *vgname; | ||||
| 	uint32_t ext_version, ext_flags; | ||||
| 	const char *vgname = NULL; | ||||
| 	uint64_t devsize; | ||||
| 	uint32_t ext_version, ext_flags; | ||||
| 	int do_cache = arg_is_set(cmd, cache_long_ARG); | ||||
| 	int do_activate = arg_is_set(cmd, activate_ARG); | ||||
| 	int do_full_check; | ||||
| 	int do_list_lvs = arg_is_set(cmd, listlvs_ARG); | ||||
| 	int do_list_vg = arg_is_set(cmd, listvg_ARG); | ||||
| 	int do_check_complete = arg_is_set(cmd, checkcomplete_ARG); | ||||
| 	int do_vgonline = arg_is_set(cmd, vgonline_ARG); | ||||
| 	int pvs_online; | ||||
| 	int pvs_offline; | ||||
| 	int pvs_unknown; | ||||
| 	int vg_complete; | ||||
| 	int do_full_check; | ||||
| 	int ret = 1; | ||||
|  | ||||
| 	dm_list_iterate_items_safe(devl, devl2, pvscan_devs) { | ||||
| @@ -1199,20 +1283,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs | ||||
| 		 * using udev and the native version didn't catch it. | ||||
| 		 */ | ||||
| 		if (udev_dev_is_mpath_component(dev)) { | ||||
| 			log_print("pvscan[%d] ignore multipath component %s.", getpid(), dev_name(dev)); | ||||
| 			log_print_pvscan(cmd, "ignore multipath component %s.", dev_name(dev)); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) { | ||||
| 			if (!do_all) | ||||
| 				log_print("pvscan[%d] ignore %s with no lvm info.", getpid(), dev_name(dev)); | ||||
| 				log_print_pvscan(cmd, "ignore %s with no lvm info.", dev_name(dev)); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		ext_version = lvmcache_ext_version(info); | ||||
| 		ext_flags = lvmcache_ext_flags(info); | ||||
| 		if ((ext_version >= 2) && !(ext_flags & PV_EXT_USED)) { | ||||
| 			log_print("pvscan[%d] PV %s not used.", getpid(), dev_name(dev)); | ||||
| 			log_print_pvscan(cmd, "PV %s not used.", dev_name(dev)); | ||||
| 			(*pv_count)++; | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -1231,7 +1315,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs | ||||
| 			vg = mda2->ops->vg_read(cmd, fid, "", mda2, NULL, NULL); | ||||
|  | ||||
| 		if (!vg) { | ||||
| 			log_print("pvscan[%d] PV %s has no VG metadata.", getpid(), dev_name(dev)); | ||||
| 			log_print_pvscan(cmd, "PV %s has no VG metadata.", dev_name(dev)); | ||||
| 			fmt->ops->destroy_instance(fid); | ||||
| 			goto online; | ||||
| 		} | ||||
| @@ -1239,7 +1323,7 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs | ||||
| 		set_pv_devices(fid, vg); | ||||
|  | ||||
| 		if (!(pv = find_pv(vg, dev))) { | ||||
| 			log_print("pvscan[%d] PV %s not found in VG %s.", getpid(), dev_name(dev), vg->name); | ||||
| 			log_print_pvscan(cmd, "PV %s not found in VG %s.", dev_name(dev), vg->name); | ||||
| 			release_vg(vg); | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -1257,13 +1341,13 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs | ||||
| 				do_full_check = 1; | ||||
| 		} | ||||
| 		if (do_full_check && dev_is_md_component(dev, NULL, 1)) { | ||||
| 			log_print("pvscan[%d] ignore md component %s.", getpid(), dev_name(dev)); | ||||
| 			log_print_pvscan(cmd, "ignore md component %s.", dev_name(dev)); | ||||
| 			release_vg(vg); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (vg_is_shared(vg)) { | ||||
| 			log_print("pvscan[%d] PV %s ignore shared VG.", getpid(), dev_name(dev)); | ||||
| 			log_print_pvscan(cmd, "PV %s ignore shared VG.", dev_name(dev)); | ||||
| 			release_vg(vg); | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -1273,7 +1357,13 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs | ||||
| 		    vg_is_foreign(vg)) { | ||||
| 			log_verbose("Ignore PV %s with VG system id %s with our system id %s", | ||||
| 				    dev_name(dev), vg->system_id, cmd->system_id); | ||||
| 			log_print("pvscan[%d] PV %s ignore foreign VG.", getpid(), dev_name(dev)); | ||||
| 			log_print_pvscan(cmd, "PV %s ignore foreign VG.", dev_name(dev)); | ||||
| 			release_vg(vg); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (vg_is_exported(vg)) { | ||||
| 			log_print_pvscan(cmd, "PV %s ignore exported VG.", dev_name(dev)); | ||||
| 			release_vg(vg); | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -1292,19 +1382,20 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs | ||||
|  | ||||
| 		/* | ||||
| 		 * Create file named for pvid to record this PV is online. | ||||
| 		 * The command creates/checks online files only when --cache is used. | ||||
| 		 */ | ||||
| 		if (!_online_pvid_file_create(dev, vg ? vg->name : NULL)) { | ||||
| 			log_error("pvscan[%d] PV %s failed to create online file.", getpid(), dev_name(dev)); | ||||
| 		if (do_cache && !_online_pvid_file_create(cmd, dev, vg ? vg->name : NULL)) { | ||||
| 			log_error_pvscan(cmd, "PV %s failed to create online file.", dev_name(dev)); | ||||
| 			release_vg(vg); | ||||
| 			ret = 0; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * When not activating we don't need to know about vg completeness. | ||||
| 		 * A plain pvscan --cache <dev> just creates the online file. | ||||
| 		 */ | ||||
| 		if (!do_activate) { | ||||
| 			log_print("pvscan[%d] PV %s online.", getpid(), dev_name(dev)); | ||||
| 		if (!do_activate && !do_list_lvs && !do_list_vg) { | ||||
| 			log_print_pvscan(cmd, "PV %s online.", dev_name(dev)); | ||||
| 			release_vg(vg); | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -1312,58 +1403,159 @@ static int _online_devs(struct cmd_context *cmd, int do_all, struct dm_list *pvs | ||||
| 		/* | ||||
| 		 * Check if all the PVs for this VG are online.  If the arrival | ||||
| 		 * of this dev completes the VG, then save the vgname in | ||||
| 		 * complete_vgnames so it will be activated. | ||||
| 		 * complete_vgnames (activation phase will want to know which | ||||
| 		 * VGs to activate.) | ||||
| 		 */ | ||||
| 		pvs_online = 0; | ||||
| 		pvs_offline = 0; | ||||
| 		pvs_unknown = 0; | ||||
| 		vg_complete = 0; | ||||
| 		if (do_activate || do_check_complete) { | ||||
| 			pvs_online = 0; | ||||
| 			pvs_offline = 0; | ||||
| 			pvs_unknown = 0; | ||||
| 			vg_complete = 0; | ||||
|  | ||||
| 		if (vg) { | ||||
| 			/* | ||||
| 			 * Use the VG metadata from this PV for a list of all | ||||
| 			 * PVIDs.  Write a lookup file of PVIDs in case another | ||||
| 			 * pvscan needs it.  After writing lookup file, recheck | ||||
| 			 * pvid files to resolve a possible race with another | ||||
| 			 * pvscan reading the lookup file that missed it. | ||||
| 			 */ | ||||
| 			log_debug("checking all pvid files from vg %s", vg->name); | ||||
| 			_count_pvid_files(vg, &pvs_online, &pvs_offline); | ||||
|  | ||||
| 			if (pvs_offline && _write_lookup_file(cmd, vg)) { | ||||
| 				log_debug("rechecking all pvid files from vg %s", vg->name); | ||||
| 			if (vg) { | ||||
| 				/* | ||||
| 				 * Use the VG metadata from this PV for a list of all | ||||
| 				 * PVIDs.  Write a lookup file of PVIDs in case another | ||||
| 				 * pvscan needs it.  After writing lookup file, recheck | ||||
| 				 * pvid files to resolve a possible race with another | ||||
| 				 * pvscan reading the lookup file that missed it. | ||||
| 				 */ | ||||
| 				log_debug("checking all pvid files from vg %s", vg->name); | ||||
| 				_count_pvid_files(vg, &pvs_online, &pvs_offline); | ||||
| 				if (!pvs_offline) | ||||
| 					log_print("pvscan[%d] VG %s complete after recheck.", getpid(), vg->name); | ||||
| 	 | ||||
| 				if (pvs_offline && _write_lookup_file(cmd, vg)) { | ||||
| 					log_debug("rechecking all pvid files from vg %s", vg->name); | ||||
| 					_count_pvid_files(vg, &pvs_online, &pvs_offline); | ||||
| 					if (!pvs_offline) | ||||
| 						log_print_pvscan(cmd, "VG %s complete after recheck.", vg->name); | ||||
| 				} | ||||
| 	 | ||||
| 				vgname = vg->name; | ||||
| 			} else { | ||||
| 				/* | ||||
| 				 * No VG metadata on this PV, so try to use a lookup | ||||
| 				 * file written by a prior pvscan for a list of all | ||||
| 				 * PVIDs.  A lookup file may not exist for this PV if | ||||
| 				 * it's the first to appear from the VG. | ||||
| 				 */ | ||||
| 				log_debug("checking all pvid files from lookup file"); | ||||
| 				if (!_count_pvid_files_from_lookup_file(cmd, dev, &pvs_online, &pvs_offline, &vgname)) | ||||
| 					pvs_unknown = 1; | ||||
| 			} | ||||
| 	 | ||||
| 			if (pvs_unknown) { | ||||
| 				log_print_pvscan(cmd, "PV %s online, VG unknown.", dev_name(dev)); | ||||
| 				vg_complete = 0; | ||||
| 	 | ||||
| 			} else if (pvs_offline) { | ||||
| 				log_print_pvscan(cmd, "PV %s online, VG %s incomplete (need %d).", | ||||
| 						 dev_name(dev), vgname, pvs_offline); | ||||
| 				vg_complete = 0; | ||||
| 	 | ||||
| 			} else { | ||||
| 				log_print_pvscan(cmd, "PV %s online, VG %s is complete.", dev_name(dev), vgname); | ||||
| 				if (!str_list_add(cmd->mem, complete_vgnames, dm_pool_strdup(cmd->mem, vgname))) | ||||
| 					stack; | ||||
| 				vg_complete = 1; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (!vgname && vg) | ||||
| 			vgname = vg->name; | ||||
|  | ||||
| 		if (do_list_vg || do_list_lvs) { | ||||
| 			if (!vgname) { | ||||
| 				log_print("VG unknown"); | ||||
| 			} else if (!do_check_complete) { | ||||
| 				log_print("VG %s", vgname); | ||||
| 			} else if (vg_complete) { | ||||
| 				if (do_vgonline && !_online_vg_file_create(cmd, vgname)) { | ||||
| 					log_print("VG %s finished", vgname); | ||||
| 				} else { | ||||
| 					/* | ||||
| 					 * A udev rule imports KEY=val from a program's stdout. | ||||
| 					 * Other output causes udev to ignore everything. | ||||
| 					 * Run pvscan from udev rule using --udevoutput to | ||||
| 					 * enable this printf, and suppress all log output | ||||
| 					 */ | ||||
| 					if (arg_is_set(cmd, udevoutput_ARG)) | ||||
| 						printf("LVM_VG_NAME_COMPLETE='%s'\n", vgname); | ||||
| 					else | ||||
| 						log_print("VG %s complete", vgname); | ||||
| 				} | ||||
| 			} else { | ||||
| 				if (arg_is_set(cmd, udevoutput_ARG)) | ||||
| 					printf("LVM_VG_NAME_INCOMPLETE='%s'\n", vgname); | ||||
| 				else | ||||
| 					log_print("VG %s incomplete", vgname); | ||||
| 			} | ||||
|  | ||||
| 			vgname = vg->name; | ||||
| 		} else { | ||||
| 			/* | ||||
| 			 * No VG metadata on this PV, so try to use a lookup | ||||
| 			 * file written by a prior pvscan for a list of all | ||||
| 			 * PVIDs.  A lookup file may not exist for this PV if | ||||
| 			 * it's the first to appear from the VG. | ||||
| 			 * When the VG is complete|finished, we could print | ||||
| 			 * a list of devices in the VG, by reading the pvid files | ||||
| 			 * that were counted, which provides major:minor of each | ||||
| 			 * device and using that to get the struct dev and dev_name. | ||||
| 			 * The user could pass this list of devices to --devices | ||||
| 			 * to optimize a subsequent command (activation) on the VG. | ||||
| 			 * Just call set_pv_devices_online (if not done othewise) | ||||
| 			 * since that finds the devs. | ||||
| 			 */ | ||||
| 			log_debug("checking all pvid files from lookup file"); | ||||
| 			if (!_count_pvid_files_from_lookup_file(cmd, dev, &pvs_online, &pvs_offline, &vgname)) | ||||
| 				pvs_unknown = 1; | ||||
| 		} | ||||
|  | ||||
| 		if (pvs_unknown) { | ||||
| 			log_print("pvscan[%d] PV %s online, VG unknown.", | ||||
| 				  getpid(), dev_name(dev)); | ||||
| 		} else if (pvs_offline) { | ||||
| 			log_print("pvscan[%d] PV %s online, VG %s incomplete (need %d).", | ||||
| 				  getpid(), dev_name(dev), vgname, pvs_offline); | ||||
| 		} else { | ||||
| 			log_print("pvscan[%d] PV %s online, VG %s is complete.", getpid(), dev_name(dev), vgname); | ||||
| 			if (!str_list_add(cmd->mem, complete_vgnames, dm_pool_strdup(cmd->mem, vgname))) | ||||
| 				stack; | ||||
| 			vg_complete = 1; | ||||
| 		if (do_list_lvs && !vg) { | ||||
| 			/* require all PVs used for booting have metadata */ | ||||
| 			log_print_pvscan(cmd, "Cannot list LVs from device without metadata."); | ||||
| 		} | ||||
|  | ||||
| 		if (!saved_vg && vg && vg_complete && !do_all && (dm_list_size(pvscan_devs) == 1)) | ||||
| 		if (do_list_lvs && vg) { | ||||
| 			struct dm_list lvs_list; | ||||
| 			struct lv_list *lvl; | ||||
|  | ||||
| 			dm_list_init(&lvs_list); | ||||
|  | ||||
| 			/* | ||||
| 			 * For each vg->pvs entry, get the dev based on the online file | ||||
| 			 * for the pvid and set pv->dev or pv->status MISSING_PV. | ||||
| 			 */ | ||||
| 			_set_pv_devices_online(cmd, vg); | ||||
|  | ||||
| 			/* | ||||
| 			 * lvs_list are LVs that use dev. | ||||
| 			 */ | ||||
| 			if (!get_visible_lvs_using_pv(cmd, vg, dev, &lvs_list)) | ||||
| 				log_print_pvscan(cmd, "Failed to find LVs using %s.", dev_name(dev)); | ||||
|  | ||||
| 			if (!do_check_complete) { | ||||
| 				dm_list_iterate_items(lvl, &lvs_list) | ||||
| 					log_print("LV %s", display_lvname(lvl->lv)); | ||||
| 			} else if (vg_complete) { | ||||
| 				/* | ||||
| 				 * A shortcut; the vg complete implies all lvs are complete. | ||||
| 				 */ | ||||
| 				dm_list_iterate_items(lvl, &lvs_list) | ||||
| 					log_print("LV %s complete", display_lvname(lvl->lv)); | ||||
| 			} else { | ||||
| 				/* | ||||
| 				 * For each LV in VG, check if all devs are present. | ||||
| 				 * Sets the PARTIAL flag on LVs that are not complete. | ||||
| 				 */ | ||||
| 				if (!vg_mark_partial_lvs(vg, 1)) | ||||
| 					log_print_pvscan(cmd, "Failed to check partial lvs."); | ||||
|  | ||||
| 				dm_list_iterate_items(lvl, &lvs_list) { | ||||
| 					if (!lv_is_partial(lvl->lv)) | ||||
| 						log_print("LV %s complete", display_lvname(lvl->lv)); | ||||
| 					else | ||||
| 						log_print("LV %s incomplete", display_lvname(lvl->lv)); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * When "pvscan --cache -aay <dev>" completes the vg, save the | ||||
| 		 * struct vg to use for quick activation function. | ||||
| 		 */ | ||||
| 		if (do_activate && !saved_vg && vg && vg_complete && !do_all && (dm_list_size(pvscan_devs) == 1)) | ||||
| 			saved_vg = vg; | ||||
| 		else | ||||
| 			release_vg(vg); | ||||
| @@ -1452,7 +1644,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv, | ||||
| 	cmd->pvscan_cache_single = 1; | ||||
|  | ||||
| 	if (!setup_devices(cmd)) { | ||||
| 		log_error("Failed to set up devices."); | ||||
| 		log_error_pvscan(cmd, "Failed to set up devices."); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| @@ -1518,8 +1710,8 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv, | ||||
|  | ||||
| 	dm_list_iterate_items_safe(devl, devl2, &pvscan_devs) { | ||||
| 		if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) { | ||||
| 			log_print("pvscan[%d] %s excluded by filters: %s.", getpid(), | ||||
| 				  dev_name(devl->dev), dev_filtered_reason(devl->dev)); | ||||
| 			log_print_pvscan(cmd, "%s excluded by filters: %s.", | ||||
| 					 dev_name(devl->dev), dev_filtered_reason(devl->dev)); | ||||
| 			dm_list_del(&devl->list); | ||||
| 		} | ||||
| 	} | ||||
| @@ -1547,7 +1739,7 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv, | ||||
| 	dm_list_iterate_items_safe(devl, devl2, &pvscan_devs) { | ||||
| 		if (!label_read_pvid(devl->dev)) { | ||||
| 			/* Not an lvm device */ | ||||
| 			log_print("pvscan[%d] %s not an lvm device.", getpid(), dev_name(devl->dev)); | ||||
| 			log_print_pvscan(cmd, "%s not an lvm device.", dev_name(devl->dev)); | ||||
| 			dm_list_del(&devl->list); | ||||
| 			continue; | ||||
| 		} | ||||
| @@ -1558,8 +1750,8 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv, | ||||
| 		 */ | ||||
| 		if (relax_deviceid_filter) { | ||||
| 			if (!get_du_for_pvid(cmd, devl->dev->pvid)) { | ||||
| 				log_print("pvscan[%d] %s excluded by devices file (checking PVID).", | ||||
| 					  getpid(), dev_name(devl->dev)); | ||||
| 				log_print_pvscan(cmd, "%s excluded by devices file (checking PVID).", | ||||
| 					         dev_name(devl->dev)); | ||||
| 				dm_list_del(&devl->list); | ||||
| 				continue; | ||||
| 			} | ||||
| @@ -1567,8 +1759,8 @@ static int _pvscan_cache_args(struct cmd_context *cmd, int argc, char **argv, | ||||
|  | ||||
| 		/* Applies all filters, including those that need data from dev. */ | ||||
| 		if (!cmd->filter->passes_filter(cmd, cmd->filter, devl->dev, NULL)) { | ||||
| 			log_print("pvscan[%d] %s excluded by filters: %s.", getpid(), | ||||
| 				  dev_name(devl->dev), dev_filtered_reason(devl->dev)); | ||||
| 			log_print_pvscan(cmd, "%s excluded by filters: %s.", | ||||
| 					 dev_name(devl->dev), dev_filtered_reason(devl->dev)); | ||||
| 			dm_list_del(&devl->list); | ||||
| 		} | ||||
| 	} | ||||
| @@ -1624,6 +1816,29 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv) | ||||
| 		return ECMD_PROCESSED; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * lvm udev rules call: | ||||
| 	 *   pvscan --cache --listvg|--listlvs --checkcomplete PV | ||||
| 	 * when PVs appear, even if event_activation=0 in lvm.conf. | ||||
| 	 * | ||||
| 	 * The udev rules will do autoactivation if they see complete | ||||
| 	 * VGs/LVs reported from the pvscan. | ||||
| 	 * | ||||
| 	 * When event_activation=0 we do not want to do autoactivation | ||||
| 	 * from udev events, so we need the pvscan to not report any | ||||
| 	 * complete VGs/LVs when event_activation=0 so that the udev | ||||
| 	 * rules do not attempt to autoactivate. | ||||
| 	 */ | ||||
|  | ||||
| 	if (arg_is_set(cmd, checkcomplete_ARG) && | ||||
| 	    !find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) { | ||||
| 		if (arg_is_set(cmd, udevoutput_ARG)) | ||||
| 			printf("LVM_EVENT_ACTIVATION=0\n"); | ||||
| 		else | ||||
| 			log_print_pvscan(cmd, "Ignoring pvscan with --checkcomplete because event_activation is disabled."); | ||||
| 		return ECMD_PROCESSED; | ||||
| 	} | ||||
|  | ||||
| 	if (arg_is_set(cmd, major_ARG) + arg_is_set(cmd, minor_ARG)) | ||||
| 		devno_args = 1; | ||||
|  | ||||
| @@ -1634,7 +1849,7 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv) | ||||
|  | ||||
| 	do_all = !argc && !devno_args; | ||||
|  | ||||
| 	_online_dir_setup(); | ||||
| 	_online_dir_setup(cmd); | ||||
|  | ||||
| 	if (do_all) { | ||||
| 		if (!_pvscan_cache_all(cmd, argc, argv, &complete_vgnames)) | ||||
|   | ||||
| @@ -810,6 +810,24 @@ int lv_change_activate(struct cmd_context *cmd, struct logical_volume *lv, | ||||
| 		lv_clear_integrity_recalculate_metadata(lv); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * When LVs are deactivated, then autoactivation of the VG is | ||||
| 	 * "re-armed" by removing the vg online file.  So, after deactivation | ||||
| 	 * of LVs, if PVs are disconnected and reconnected again, event | ||||
| 	 * activation will trigger autoactivation again.  This secondary | ||||
| 	 * autoactivation is somewhat different from, and not as important as | ||||
| 	 * the initial autoactivation during system startup.  The secondary | ||||
| 	 * autoactivation will happen to a VG on a running system and may be | ||||
| 	 * mixing with user commands, so the end result is unpredictable. | ||||
| 	 * | ||||
| 	 * It's possible that we might want a config setting for usersto   | ||||
| 	 * disable secondary autoactivations.  Once a system is up, the | ||||
| 	 * user may want to take charge of activation changes to the VG | ||||
| 	 * and not have the system autoactivation interfere. | ||||
| 	 */ | ||||
| 	if (!is_change_activating(activate) && find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) | ||||
| 		online_vg_file_remove(lv->vg->name); | ||||
|  | ||||
| 	set_lv_notify(lv->vg->cmd); | ||||
|  | ||||
| 	return r; | ||||
|   | ||||
| @@ -291,4 +291,6 @@ int lvconvert_cachevol_attach_single(struct cmd_context *cmd, | ||||
|                                      struct logical_volume *lv, | ||||
|                                      struct processing_handle *handle); | ||||
|  | ||||
| void online_vg_file_remove(const char *vgname); | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										80
									
								
								udev/69-dm-lvm.rules.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								udev/69-dm-lvm.rules.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| # Copyright (C) 2012,2021 Red Hat, Inc. All rights reserved. | ||||
| # | ||||
| # This file is part of LVM. | ||||
| # | ||||
| # This rule requires blkid to be called on block devices before so only devices | ||||
| # used as LVM PVs are processed (ID_FS_TYPE="LVM2_member"). | ||||
|  | ||||
| SUBSYSTEM!="block", GOTO="lvm_end" | ||||
| (LVM_EXEC_RULE) | ||||
|  | ||||
| ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="lvm_end" | ||||
|  | ||||
| # Only process devices already marked as a PV - this requires blkid to be called before. | ||||
| ENV{ID_FS_TYPE}!="LVM2_member", GOTO="lvm_end" | ||||
| ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end" | ||||
| ACTION=="remove", GOTO="lvm_end" | ||||
|  | ||||
| # Create /dev/disk/by-id/lvm-pv-uuid-<PV_UUID> symlink for each PV | ||||
| ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-id/lvm-pv-uuid-$env{ID_FS_UUID_ENC}" | ||||
|  | ||||
| # If the PV is a special device listed below, scan only if the device is | ||||
| # properly activated. These devices are not usable after an ADD event, | ||||
| # but they require an extra setup and they are ready after a CHANGE event. | ||||
| # Also support coldplugging with ADD event but only if the device is already | ||||
| # properly activated. | ||||
| # This logic should be eventually moved to rules where those particular | ||||
| # devices are processed primarily (MD and loop). | ||||
|  | ||||
| # DM device: | ||||
| KERNEL!="dm-[0-9]*", GOTO="next" | ||||
| ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", ENV{DM_ACTIVATION}=="1", GOTO="lvm_scan" | ||||
| GOTO="lvm_end" | ||||
|  | ||||
| # MD device: | ||||
| LABEL="next" | ||||
| KERNEL!="md[0-9]*", GOTO="next" | ||||
| IMPORT{db}="LVM_MD_PV_ACTIVATED" | ||||
| ACTION=="add", ENV{LVM_MD_PV_ACTIVATED}=="1", GOTO="lvm_scan" | ||||
| ACTION=="change", ENV{LVM_MD_PV_ACTIVATED}!="1", TEST=="md/array_state", ENV{LVM_MD_PV_ACTIVATED}="1", GOTO="lvm_scan" | ||||
| ACTION=="add", KERNEL=="md[0-9]*p[0-9]*", GOTO="lvm_scan" | ||||
| ENV{LVM_MD_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0" | ||||
| GOTO="lvm_end" | ||||
|  | ||||
| # Loop device: | ||||
| LABEL="next" | ||||
| KERNEL!="loop[0-9]*", GOTO="next" | ||||
| ACTION=="add", ENV{LVM_LOOP_PV_ACTIVATED}=="1", GOTO="lvm_scan" | ||||
| ACTION=="change", ENV{LVM_LOOP_PV_ACTIVATED}!="1", TEST=="loop/backing_file", ENV{LVM_LOOP_PV_ACTIVATED}="1", GOTO="lvm_scan" | ||||
| ENV{LVM_LOOP_PV_ACTIVATED}!="1", ENV{SYSTEMD_READY}="0" | ||||
| GOTO="lvm_end" | ||||
|  | ||||
| LABEL="next" | ||||
| ACTION!="add", GOTO="lvm_end" | ||||
|  | ||||
| LABEL="lvm_scan" | ||||
|  | ||||
| ENV{SYSTEMD_READY}="1" | ||||
|  | ||||
| # pvscan will check if this device completes a VG, | ||||
| # i.e. all PVs in the VG are now present with the | ||||
| # arrival of this PV.  If so, it prints to stdout: | ||||
| # LVM_VG_NAME_COMPLETE='foo' | ||||
| # | ||||
| # When the VG is complete it can be activated, so | ||||
| # the lvm-vgchange service is started which runs | ||||
| # vgchange -aay <vgname>. | ||||
| # | ||||
| # pvscan only reads the single device specified, | ||||
| # and uses temp files under /run/lvm to check if | ||||
| # other PVs in the VG are present. | ||||
| # | ||||
| # If event_activation=0 in lvm.conf, this pvscan | ||||
| # (using checkcomplete) will do nothing, so that | ||||
| # no event-based autoactivation will be happen. | ||||
|  | ||||
| IMPORT{program}="(LVM_EXEC)/lvm pvscan --cache --listvg --checkcomplete --vgonline --udevoutput --journal=output $env{DEVNAME}" | ||||
| ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemctl start lvm-vgchange@$env{LVM_VG_NAME_COMPLETE}.service" | ||||
| GOTO="lvm_end" | ||||
|  | ||||
| LABEL="lvm_end" | ||||
| @@ -18,7 +18,7 @@ top_builddir = @top_builddir@ | ||||
| include $(top_builddir)/make.tmpl | ||||
|  | ||||
| DM_RULES=10-dm.rules 13-dm-disk.rules 95-dm-notify.rules | ||||
| LVM_RULES=11-dm-lvm.rules 69-dm-lvm-metad.rules | ||||
| LVM_RULES=11-dm-lvm.rules 69-dm-lvm.rules | ||||
|  | ||||
| DM_DIR=$(shell $(GREP) "\#define DM_DIR" $(top_srcdir)/libdm/misc/dm-ioctl.h | $(AWK) '{print $$3}') | ||||
|  | ||||
|   | ||||
							
								
								
									
										57
									
								
								udev/pvscan-udev-initrd.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								udev/pvscan-udev-initrd.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| # pvscan wrapper called by initrd lvm udev rule to find the | ||||
| # intersection of complete VGs/LVs found by pvscan and the | ||||
| # requested VGs/LVs from the cmdline. | ||||
| # | ||||
| # Used in 64-lvm.rules as: | ||||
| # IMPORT{program}="pvscan-udev-initrd.sh $env{DEVNAME}" | ||||
| # | ||||
| # See /usr/lib/dracut/modules.d/90lvm/64-lvm.rules | ||||
|  | ||||
| #!/bin/sh | ||||
|  | ||||
| dev=$1 | ||||
|  | ||||
| type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh | ||||
|  | ||||
|  | ||||
| VGS=$(getargs rd.lvm.vg -d rd_LVM_VG=) | ||||
| LVS=$(getargs rd.lvm.lv -d rd_LVM_LV=) | ||||
|  | ||||
| IFS=' ' | ||||
|  | ||||
| # pvscan will produce a single VG line, and one or more LV lines. | ||||
| # VG <name> complete | ||||
| # VG <name> incomplete | ||||
| # LV <name> complete | ||||
| # LV <name> incomplete | ||||
| # | ||||
| # LV names are printed as vgname/lvname. | ||||
| # We only care about the complete items. | ||||
| # Each pvscan will produce a single VG line, | ||||
| # and may produce zero, one or more LV lines. | ||||
|  | ||||
| PVSCAN=$(/usr/sbin/lvm pvscan --cache --listlvs --checkcomplete --journal output --config 'global/event_activation=1' $dev) | ||||
|  | ||||
| read -r -a VGSARRAY <<< "$VGS" | ||||
|  | ||||
| for VG in "${VGSARRAY[@]}" | ||||
| do | ||||
|     if strstr "$PVSCAN" "VG $VG complete" ; then | ||||
|         echo LVM_VG_NAME_COMPLETE=\'"$VG"\' | ||||
|     fi | ||||
| done | ||||
|  | ||||
| # Combine all matching LVs into a single print containing them all, | ||||
| # e.g. LVM_LV_NAMES_COMPLETE='vg/lv1 vg/lv2' | ||||
|  | ||||
| read -r -a LVSARRAY <<< "$LVS" | ||||
|  | ||||
| echo -n LVM_LV_NAMES_COMPLETE=\' | ||||
| for LV in "${LVSARRAY[@]}" | ||||
| do | ||||
|     if strstr "$PVSCAN" "LV $LV complete" ; then | ||||
|         echo -n "$LV " | ||||
|     fi | ||||
| done | ||||
| echo \' | ||||
|  | ||||
		Reference in New Issue
	
	Block a user