xref: /dragonfly/contrib/lvm2/dist/tools/vgchange.c (revision 9348a738)
1 /*	$NetBSD: vgchange.c,v 1.1.1.3 2009/12/02 00:25:51 haad Exp $	*/
2 
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
9  * This copyrighted material is made available to anyone wishing to use,
10  * modify, copy, or redistribute it subject to the terms and conditions
11  * of the GNU Lesser General Public License v.2.1.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 
18 #include "tools.h"
19 
20 static int _monitor_lvs_in_vg(struct cmd_context *cmd,
21 			       struct volume_group *vg, int reg)
22 {
23 	struct lv_list *lvl;
24 	struct logical_volume *lv;
25 	struct lvinfo info;
26 	int lv_active;
27 	int count = 0;
28 
29 	dm_list_iterate_items(lvl, &vg->lvs) {
30 		lv = lvl->lv;
31 
32 		if (!lv_info(cmd, lv, &info, 0, 0))
33 			lv_active = 0;
34 		else
35 			lv_active = info.exists;
36 
37 		/*
38 		 * FIXME: Need to consider all cases... PVMOVE, etc
39 		 */
40 		if ((lv->status & PVMOVE) || !lv_active)
41 			continue;
42 
43 		if (!monitor_dev_for_events(cmd, lv, reg)) {
44 			continue;
45 		} else
46 			count++;
47 	}
48 
49 	/*
50 	 * returns the number of _new_ monitored devices
51 	 */
52 
53 	return count;
54 }
55 
56 static int _activate_lvs_in_vg(struct cmd_context *cmd,
57 			       struct volume_group *vg, int activate)
58 {
59 	struct lv_list *lvl;
60 	struct logical_volume *lv;
61 	int count = 0, expected_count = 0;
62 
63 	dm_list_iterate_items(lvl, &vg->lvs) {
64 		lv = lvl->lv;
65 
66 		if (!lv_is_visible(lv))
67 			continue;
68 
69 		/* Only request activation of snapshot origin devices */
70 		if ((lv->status & SNAPSHOT) || lv_is_cow(lv))
71 			continue;
72 
73 		/* Only request activation of mirror LV */
74 		if ((lv->status & MIRROR_IMAGE) || (lv->status & MIRROR_LOG))
75 			continue;
76 
77 		/* Can't deactivate a pvmove LV */
78 		/* FIXME There needs to be a controlled way of doing this */
79 		if (((activate == CHANGE_AN) || (activate == CHANGE_ALN)) &&
80 		    ((lv->status & PVMOVE) ))
81 			continue;
82 
83 		expected_count++;
84 
85 		if (activate == CHANGE_AN) {
86 			if (!deactivate_lv(cmd, lv))
87 				continue;
88 		} else if (activate == CHANGE_ALN) {
89 			if (!deactivate_lv_local(cmd, lv))
90 				continue;
91 		} else if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
92 			if (!activate_lv_excl(cmd, lv))
93 				continue;
94 		} else if (activate == CHANGE_ALY) {
95 			if (!activate_lv_local(cmd, lv))
96 				continue;
97 		} else if (!activate_lv(cmd, lv))
98 			continue;
99 
100 		if (activate != CHANGE_AN && activate != CHANGE_ALN &&
101 		    (lv->status & (PVMOVE|CONVERTING)))
102 			lv_spawn_background_polling(cmd, lv);
103 
104 		count++;
105 	}
106 
107 	if (expected_count)
108 		log_verbose("%s %d logical volumes in volume group %s",
109 			    activate ? "Activated" : "Deactivated",
110 			    count, vg->name);
111 
112 	return (expected_count != count) ? ECMD_FAILED : ECMD_PROCESSED;
113 }
114 
115 static int _vgchange_monitoring(struct cmd_context *cmd, struct volume_group *vg)
116 {
117 	int active, monitored;
118 
119 	if ((active = lvs_in_vg_activated(vg)) &&
120 	    dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
121 		monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode());
122 		log_print("%d logical volume(s) in volume group "
123 			    "\"%s\" %smonitored",
124 			    monitored, vg->name, (dmeventd_monitor_mode()) ? "" : "un");
125 	}
126 
127 	return ECMD_PROCESSED;
128 }
129 
130 static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
131 {
132 	int lv_open, active, monitored;
133 	int available, ret;
134 	int activate = 1;
135 
136 	/*
137 	 * Safe, since we never write out new metadata here. Required for
138 	 * partial activation to work.
139 	 */
140 	cmd->handles_missing_pvs = 1;
141 
142 	available = arg_uint_value(cmd, available_ARG, 0);
143 
144 	if ((available == CHANGE_AN) || (available == CHANGE_ALN))
145 		activate = 0;
146 
147 	/* FIXME: Force argument to deactivate them? */
148 	if (!activate && (lv_open = lvs_in_vg_opened(vg))) {
149 		log_error("Can't deactivate volume group \"%s\" with %d open "
150 			  "logical volume(s)", vg->name, lv_open);
151 		return ECMD_FAILED;
152 	}
153 
154 	/* FIXME Move into library where clvmd can use it */
155 	if (activate)
156 		check_current_backup(vg);
157 
158 	if (activate && (active = lvs_in_vg_activated(vg))) {
159 		log_verbose("%d logical volume(s) in volume group \"%s\" "
160 			    "already active", active, vg->name);
161 		if (dmeventd_monitor_mode() != DMEVENTD_MONITOR_IGNORE) {
162 			monitored = _monitor_lvs_in_vg(cmd, vg, dmeventd_monitor_mode());
163 			log_verbose("%d existing logical volume(s) in volume "
164 				    "group \"%s\" %smonitored",
165 				    monitored, vg->name,
166 				    dmeventd_monitor_mode() ? "" : "un");
167 		}
168 	}
169 
170 	ret = _activate_lvs_in_vg(cmd, vg, available);
171 
172 	log_print("%d logical volume(s) in volume group \"%s\" now active",
173 		  lvs_in_vg_activated(vg), vg->name);
174 	return ret;
175 }
176 
177 static int _vgchange_alloc(struct cmd_context *cmd, struct volume_group *vg)
178 {
179 	alloc_policy_t alloc;
180 
181 	alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL);
182 
183 	if (!archive(vg)) {
184 		stack;
185 		return ECMD_FAILED;
186 	}
187 
188 	/* FIXME: make consistent with vg_set_alloc_policy() */
189 	if (alloc == vg->alloc) {
190 		log_error("Volume group allocation policy is already %s",
191 			  get_alloc_string(vg->alloc));
192 		return ECMD_FAILED;
193 	}
194 	if (!vg_set_alloc_policy(vg, alloc)) {
195 		stack;
196 		return ECMD_FAILED;
197 	}
198 
199 	if (!vg_write(vg) || !vg_commit(vg)) {
200 		stack;
201 		return ECMD_FAILED;
202 	}
203 
204 	backup(vg);
205 
206 	log_print("Volume group \"%s\" successfully changed", vg->name);
207 
208 	return ECMD_PROCESSED;
209 }
210 
211 static int _vgchange_resizeable(struct cmd_context *cmd,
212 				struct volume_group *vg)
213 {
214 	int resizeable = !strcmp(arg_str_value(cmd, resizeable_ARG, "n"), "y");
215 
216 	if (resizeable && vg_is_resizeable(vg)) {
217 		log_error("Volume group \"%s\" is already resizeable",
218 			  vg->name);
219 		return ECMD_FAILED;
220 	}
221 
222 	if (!resizeable && !vg_is_resizeable(vg)) {
223 		log_error("Volume group \"%s\" is already not resizeable",
224 			  vg->name);
225 		return ECMD_FAILED;
226 	}
227 
228 	if (!archive(vg)) {
229 		stack;
230 		return ECMD_FAILED;
231 	}
232 
233 	if (resizeable)
234 		vg->status |= RESIZEABLE_VG;
235 	else
236 		vg->status &= ~RESIZEABLE_VG;
237 
238 	if (!vg_write(vg) || !vg_commit(vg)) {
239 		stack;
240 		return ECMD_FAILED;
241 	}
242 
243 	backup(vg);
244 
245 	log_print("Volume group \"%s\" successfully changed", vg->name);
246 
247 	return ECMD_PROCESSED;
248 }
249 
250 static int _vgchange_clustered(struct cmd_context *cmd,
251 			       struct volume_group *vg)
252 {
253 	int clustered = !strcmp(arg_str_value(cmd, clustered_ARG, "n"), "y");
254 
255 	if (clustered && (vg_is_clustered(vg))) {
256 		log_error("Volume group \"%s\" is already clustered",
257 			  vg->name);
258 		return ECMD_FAILED;
259 	}
260 
261 	if (!clustered && !(vg_is_clustered(vg))) {
262 		log_error("Volume group \"%s\" is already not clustered",
263 			  vg->name);
264 		return ECMD_FAILED;
265 	}
266 
267 	if (!archive(vg)) {
268 		stack;
269 		return ECMD_FAILED;
270 	}
271 
272 	if (!vg_set_clustered(vg, clustered))
273 		return ECMD_FAILED;
274 
275 	if (!vg_write(vg) || !vg_commit(vg)) {
276 		stack;
277 		return ECMD_FAILED;
278 	}
279 
280 	backup(vg);
281 
282 	log_print("Volume group \"%s\" successfully changed", vg->name);
283 
284 	return ECMD_PROCESSED;
285 }
286 
287 static int _vgchange_logicalvolume(struct cmd_context *cmd,
288 				   struct volume_group *vg)
289 {
290 	uint32_t max_lv = arg_uint_value(cmd, logicalvolume_ARG, 0);
291 
292 	if (!archive(vg)) {
293 		stack;
294 		return ECMD_FAILED;
295 	}
296 
297 	if (!vg_set_max_lv(vg, max_lv)) {
298 		stack;
299 		return ECMD_FAILED;
300 	}
301 
302 	if (!vg_write(vg) || !vg_commit(vg)) {
303 		stack;
304 		return ECMD_FAILED;
305 	}
306 
307 	backup(vg);
308 
309 	log_print("Volume group \"%s\" successfully changed", vg->name);
310 
311 	return ECMD_PROCESSED;
312 }
313 
314 static int _vgchange_physicalvolumes(struct cmd_context *cmd,
315 				     struct volume_group *vg)
316 {
317 	uint32_t max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, 0);
318 
319 	if (arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) {
320 		log_error("MaxPhysicalVolumes may not be negative");
321 		return EINVALID_CMD_LINE;
322 	}
323 
324 	if (!archive(vg)) {
325 		stack;
326 		return ECMD_FAILED;
327 	}
328 
329 	if (!vg_set_max_pv(vg, max_pv)) {
330 		stack;
331 		return ECMD_FAILED;
332 	}
333 
334 	if (!vg_write(vg) || !vg_commit(vg)) {
335 		stack;
336 		return ECMD_FAILED;
337 	}
338 
339 	backup(vg);
340 
341 	log_print("Volume group \"%s\" successfully changed", vg->name);
342 
343 	return ECMD_PROCESSED;
344 }
345 
346 static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
347 {
348 	uint32_t extent_size;
349 
350 	if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
351 		log_error("Physical extent size may not be negative");
352 		return EINVALID_CMD_LINE;
353 	}
354 
355 	extent_size = arg_uint_value(cmd, physicalextentsize_ARG, 0);
356 	/* FIXME: remove check - redundant with vg_change_pesize */
357 	if (extent_size == vg->extent_size) {
358 		log_error("Physical extent size of VG %s is already %s",
359 			  vg->name, display_size(cmd, (uint64_t) extent_size));
360 		return ECMD_PROCESSED;
361 	}
362 
363 	if (!archive(vg)) {
364 		stack;
365 		return ECMD_FAILED;
366 	}
367 
368 	if (!vg_set_extent_size(vg, extent_size)) {
369 		stack;
370 		return EINVALID_CMD_LINE;
371 	}
372 
373 	if (!vg_write(vg) || !vg_commit(vg)) {
374 		stack;
375 		return ECMD_FAILED;
376 	}
377 
378 	backup(vg);
379 
380 	log_print("Volume group \"%s\" successfully changed", vg->name);
381 
382 	return ECMD_PROCESSED;
383 }
384 
385 static int _vgchange_tag(struct cmd_context *cmd, struct volume_group *vg,
386 			 int arg)
387 {
388 	const char *tag;
389 
390 	if (!(tag = arg_str_value(cmd, arg, NULL))) {
391 		log_error("Failed to get tag");
392 		return ECMD_FAILED;
393 	}
394 
395 	if (!(vg->fid->fmt->features & FMT_TAGS)) {
396 		log_error("Volume group %s does not support tags", vg->name);
397 		return ECMD_FAILED;
398 	}
399 
400 	if (!archive(vg)) {
401 		stack;
402 		return ECMD_FAILED;
403 	}
404 
405 	if ((arg == addtag_ARG)) {
406 		if (!str_list_add(cmd->mem, &vg->tags, tag)) {
407 			log_error("Failed to add tag %s to volume group %s",
408 				  tag, vg->name);
409 			return ECMD_FAILED;
410 		}
411 	} else {
412 		if (!str_list_del(&vg->tags, tag)) {
413 			log_error("Failed to remove tag %s from volume group "
414 				  "%s", tag, vg->name);
415 			return ECMD_FAILED;
416 		}
417 	}
418 
419 	if (!vg_write(vg) || !vg_commit(vg)) {
420 		stack;
421 		return ECMD_FAILED;
422 	}
423 
424 	backup(vg);
425 
426 	log_print("Volume group \"%s\" successfully changed", vg->name);
427 
428 	return ECMD_PROCESSED;
429 }
430 
431 static int _vgchange_uuid(struct cmd_context *cmd __attribute((unused)),
432 			  struct volume_group *vg)
433 {
434 	struct lv_list *lvl;
435 
436 	if (lvs_in_vg_activated(vg)) {
437 		log_error("Volume group has active logical volumes");
438 		return ECMD_FAILED;
439 	}
440 
441 	if (!archive(vg)) {
442 		stack;
443 		return ECMD_FAILED;
444 	}
445 
446 	if (!id_create(&vg->id)) {
447 		log_error("Failed to generate new random UUID for VG %s.",
448 			  vg->name);
449 		return ECMD_FAILED;
450 	}
451 
452 	dm_list_iterate_items(lvl, &vg->lvs) {
453 		memcpy(&lvl->lv->lvid, &vg->id, sizeof(vg->id));
454 	}
455 
456 	if (!vg_write(vg) || !vg_commit(vg)) {
457 		stack;
458 		return ECMD_FAILED;
459 	}
460 
461 	backup(vg);
462 
463 	log_print("Volume group \"%s\" successfully changed", vg->name);
464 
465 	return ECMD_PROCESSED;
466 }
467 
468 static int _vgchange_refresh(struct cmd_context *cmd, struct volume_group *vg)
469 {
470 	log_verbose("Refreshing volume group \"%s\"", vg->name);
471 
472 	if (!vg_refresh_visible(cmd, vg)) {
473 		stack;
474 		return ECMD_FAILED;
475 	}
476 
477 	return ECMD_PROCESSED;
478 }
479 
480 static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
481 			   struct volume_group *vg,
482 			   void *handle __attribute((unused)))
483 {
484 	int r = ECMD_FAILED;
485 
486 	if (vg_is_exported(vg)) {
487 		log_error("Volume group \"%s\" is exported", vg_name);
488 		return ECMD_FAILED;
489 	}
490 
491 	init_dmeventd_monitor(arg_int_value(cmd, monitor_ARG,
492 					    (is_static() || arg_count(cmd, ignoremonitoring_ARG)) ?
493 					    DMEVENTD_MONITOR_IGNORE : DEFAULT_DMEVENTD_MONITOR));
494 
495 	if (arg_count(cmd, available_ARG))
496 		r = _vgchange_available(cmd, vg);
497 
498 	else if (arg_count(cmd, monitor_ARG))
499 		r = _vgchange_monitoring(cmd, vg);
500 
501 	else if (arg_count(cmd, resizeable_ARG))
502 		r = _vgchange_resizeable(cmd, vg);
503 
504 	else if (arg_count(cmd, logicalvolume_ARG))
505 		r = _vgchange_logicalvolume(cmd, vg);
506 
507 	else if (arg_count(cmd, maxphysicalvolumes_ARG))
508 		r = _vgchange_physicalvolumes(cmd, vg);
509 
510 	else if (arg_count(cmd, addtag_ARG))
511 		r = _vgchange_tag(cmd, vg, addtag_ARG);
512 
513 	else if (arg_count(cmd, deltag_ARG))
514 		r = _vgchange_tag(cmd, vg, deltag_ARG);
515 
516 	else if (arg_count(cmd, physicalextentsize_ARG))
517 		r = _vgchange_pesize(cmd, vg);
518 
519 	else if (arg_count(cmd, uuid_ARG))
520 		r = _vgchange_uuid(cmd, vg);
521 
522 	else if (arg_count(cmd, alloc_ARG))
523 		r = _vgchange_alloc(cmd, vg);
524 
525 	else if (arg_count(cmd, clustered_ARG))
526 		r = _vgchange_clustered(cmd, vg);
527 
528 	else if (arg_count(cmd, refresh_ARG))
529 		r = _vgchange_refresh(cmd, vg);
530 
531 	return r;
532 }
533 
534 int vgchange(struct cmd_context *cmd, int argc, char **argv)
535 {
536 	if (!
537 	    (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
538 	     arg_count(cmd, maxphysicalvolumes_ARG) +
539 	     arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
540 	     arg_count(cmd, addtag_ARG) + arg_count(cmd, uuid_ARG) +
541 	     arg_count(cmd, physicalextentsize_ARG) +
542 	     arg_count(cmd, clustered_ARG) + arg_count(cmd, alloc_ARG) +
543 	     arg_count(cmd, monitor_ARG) + arg_count(cmd, refresh_ARG))) {
544 		log_error("One of -a, -c, -l, -p, -s, -x, --refresh, "
545 				"--uuid, --alloc, --addtag or --deltag required");
546 		return EINVALID_CMD_LINE;
547 	}
548 
549 	/* FIXME Cope with several changes at once! */
550 	if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
551 	    arg_count(cmd, maxphysicalvolumes_ARG) +
552 	    arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
553 	    arg_count(cmd, addtag_ARG) + arg_count(cmd, alloc_ARG) +
554 	    arg_count(cmd, uuid_ARG) + arg_count(cmd, clustered_ARG) +
555 	    arg_count(cmd, physicalextentsize_ARG) > 1) {
556 		log_error("Only one of -a, -c, -l, -p, -s, -x, --uuid, "
557 			  "--alloc, --addtag or --deltag allowed");
558 		return EINVALID_CMD_LINE;
559 	}
560 
561 	if (arg_count(cmd, ignorelockingfailure_ARG) &&
562 	    !arg_count(cmd, available_ARG)) {
563 		log_error("--ignorelockingfailure only available with -a");
564 		return EINVALID_CMD_LINE;
565 	}
566 
567 	if (arg_count(cmd, available_ARG) == 1
568 	    && arg_count(cmd, autobackup_ARG)) {
569 		log_error("-A option not necessary with -a option");
570 		return EINVALID_CMD_LINE;
571 	}
572 
573 	return process_each_vg(cmd, argc, argv,
574 			       (arg_count(cmd, available_ARG)) ?
575 			       0 : READ_FOR_UPDATE,
576 			       NULL,
577 			       &vgchange_single);
578 }
579