xref: /dflybsd-src/contrib/lvm2/dist/tools/pvchange.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /*	$NetBSD: pvchange.c,v 1.1.1.2 2009/12/02 00:25:54 haad Exp $	*/
286d7f5d3SJohn Marino 
386d7f5d3SJohn Marino /*
486d7f5d3SJohn Marino  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
586d7f5d3SJohn Marino  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
686d7f5d3SJohn Marino  *
786d7f5d3SJohn Marino  * This file is part of LVM2.
886d7f5d3SJohn Marino  *
986d7f5d3SJohn Marino  * This copyrighted material is made available to anyone wishing to use,
1086d7f5d3SJohn Marino  * modify, copy, or redistribute it subject to the terms and conditions
1186d7f5d3SJohn Marino  * of the GNU Lesser General Public License v.2.1.
1286d7f5d3SJohn Marino  *
1386d7f5d3SJohn Marino  * You should have received a copy of the GNU Lesser General Public License
1486d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software Foundation,
1586d7f5d3SJohn Marino  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1686d7f5d3SJohn Marino  */
1786d7f5d3SJohn Marino 
1886d7f5d3SJohn Marino #include "tools.h"
1986d7f5d3SJohn Marino 
2086d7f5d3SJohn Marino /* FIXME Locking.  PVs in VG. */
2186d7f5d3SJohn Marino 
_pvchange_single(struct cmd_context * cmd,struct physical_volume * pv,void * handle __attribute ((unused)))2286d7f5d3SJohn Marino static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
2386d7f5d3SJohn Marino 			    void *handle __attribute((unused)))
2486d7f5d3SJohn Marino {
2586d7f5d3SJohn Marino 	struct volume_group *vg = NULL;
2686d7f5d3SJohn Marino 	const char *vg_name = NULL;
2786d7f5d3SJohn Marino 	struct pv_list *pvl;
2886d7f5d3SJohn Marino 	uint64_t sector;
2986d7f5d3SJohn Marino 	uint32_t orig_pe_alloc_count;
3086d7f5d3SJohn Marino 	/* FIXME Next three only required for format1. */
3186d7f5d3SJohn Marino 	uint32_t orig_pe_count, orig_pe_size;
3286d7f5d3SJohn Marino 	uint64_t orig_pe_start;
3386d7f5d3SJohn Marino 
3486d7f5d3SJohn Marino 	const char *pv_name = pv_dev_name(pv);
3586d7f5d3SJohn Marino 	const char *tag = NULL;
3686d7f5d3SJohn Marino 	const char *orig_vg_name;
3786d7f5d3SJohn Marino 	char uuid[64] __attribute((aligned(8)));
3886d7f5d3SJohn Marino 
3986d7f5d3SJohn Marino 	int allocatable = 0;
4086d7f5d3SJohn Marino 	int tagarg = 0;
4186d7f5d3SJohn Marino 	int r = 0;
4286d7f5d3SJohn Marino 
4386d7f5d3SJohn Marino 	if (arg_count(cmd, addtag_ARG))
4486d7f5d3SJohn Marino 		tagarg = addtag_ARG;
4586d7f5d3SJohn Marino 	else if (arg_count(cmd, deltag_ARG))
4686d7f5d3SJohn Marino 		tagarg = deltag_ARG;
4786d7f5d3SJohn Marino 
4886d7f5d3SJohn Marino 	if (arg_count(cmd, allocatable_ARG))
4986d7f5d3SJohn Marino 		allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"),
5086d7f5d3SJohn Marino 				      "y");
5186d7f5d3SJohn Marino 	else if (tagarg && !(tag = arg_str_value(cmd, tagarg, NULL))) {
5286d7f5d3SJohn Marino 		log_error("Failed to get tag");
5386d7f5d3SJohn Marino 		return 0;
5486d7f5d3SJohn Marino 	}
5586d7f5d3SJohn Marino 
5686d7f5d3SJohn Marino 	/* If in a VG, must change using volume group. */
5786d7f5d3SJohn Marino 	if (!is_orphan(pv)) {
5886d7f5d3SJohn Marino 		vg_name = pv_vg_name(pv);
5986d7f5d3SJohn Marino 
6086d7f5d3SJohn Marino 		log_verbose("Finding volume group %s of physical volume %s",
6186d7f5d3SJohn Marino 			    vg_name, pv_name);
6286d7f5d3SJohn Marino 		vg = vg_read_for_update(cmd, vg_name, NULL, 0);
6386d7f5d3SJohn Marino 		if (vg_read_error(vg)) {
6486d7f5d3SJohn Marino 			vg_release(vg);
6586d7f5d3SJohn Marino 			return_0;
6686d7f5d3SJohn Marino 		}
6786d7f5d3SJohn Marino 
6886d7f5d3SJohn Marino 		if (!(pvl = find_pv_in_vg(vg, pv_name))) {
6986d7f5d3SJohn Marino 			log_error("Unable to find \"%s\" in volume group \"%s\"",
7086d7f5d3SJohn Marino 				  pv_name, vg->name);
7186d7f5d3SJohn Marino 			goto out;
7286d7f5d3SJohn Marino 		}
7386d7f5d3SJohn Marino 		if (tagarg && !(vg->fid->fmt->features & FMT_TAGS)) {
7486d7f5d3SJohn Marino 			log_error("Volume group containing %s does not "
7586d7f5d3SJohn Marino 				  "support tags", pv_name);
7686d7f5d3SJohn Marino 			goto out;
7786d7f5d3SJohn Marino 		}
7886d7f5d3SJohn Marino 		if (arg_count(cmd, uuid_ARG) && lvs_in_vg_activated(vg)) {
7986d7f5d3SJohn Marino 			log_error("Volume group containing %s has active "
8086d7f5d3SJohn Marino 				  "logical volumes", pv_name);
8186d7f5d3SJohn Marino 			goto out;
8286d7f5d3SJohn Marino 		}
8386d7f5d3SJohn Marino 		pv = pvl->pv;
8486d7f5d3SJohn Marino 		if (!archive(vg))
8586d7f5d3SJohn Marino 			goto out;
8686d7f5d3SJohn Marino 	} else {
8786d7f5d3SJohn Marino 		if (tagarg) {
8886d7f5d3SJohn Marino 			log_error("Can't change tag on Physical Volume %s not "
8986d7f5d3SJohn Marino 				  "in volume group", pv_name);
9086d7f5d3SJohn Marino 			return 0;
9186d7f5d3SJohn Marino 		}
9286d7f5d3SJohn Marino 
9386d7f5d3SJohn Marino 		vg_name = VG_ORPHANS;
9486d7f5d3SJohn Marino 
9586d7f5d3SJohn Marino 		if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
9686d7f5d3SJohn Marino 			log_error("Can't get lock for orphans");
9786d7f5d3SJohn Marino 			return 0;
9886d7f5d3SJohn Marino 		}
9986d7f5d3SJohn Marino 
10086d7f5d3SJohn Marino 		if (!(pv = pv_read(cmd, pv_name, NULL, &sector, 1, 0))) {
10186d7f5d3SJohn Marino 			unlock_vg(cmd, vg_name);
10286d7f5d3SJohn Marino 			log_error("Unable to read PV \"%s\"", pv_name);
10386d7f5d3SJohn Marino 			return 0;
10486d7f5d3SJohn Marino 		}
10586d7f5d3SJohn Marino 	}
10686d7f5d3SJohn Marino 
10786d7f5d3SJohn Marino 	if (arg_count(cmd, allocatable_ARG)) {
10886d7f5d3SJohn Marino 		if (is_orphan(pv) &&
10986d7f5d3SJohn Marino 		    !(pv->fmt->features & FMT_ORPHAN_ALLOCATABLE)) {
11086d7f5d3SJohn Marino 			log_error("Allocatability not supported by orphan "
11186d7f5d3SJohn Marino 				  "%s format PV %s", pv->fmt->name, pv_name);
11286d7f5d3SJohn Marino 			goto out;
11386d7f5d3SJohn Marino 		}
11486d7f5d3SJohn Marino 
11586d7f5d3SJohn Marino 		/* change allocatability for a PV */
11686d7f5d3SJohn Marino 		if (allocatable && (pv_status(pv) & ALLOCATABLE_PV)) {
11786d7f5d3SJohn Marino 			log_error("Physical volume \"%s\" is already "
11886d7f5d3SJohn Marino 				  "allocatable", pv_name);
11986d7f5d3SJohn Marino 			r = 1;
12086d7f5d3SJohn Marino 			goto out;
12186d7f5d3SJohn Marino 		}
12286d7f5d3SJohn Marino 
12386d7f5d3SJohn Marino 		if (!allocatable && !(pv_status(pv) & ALLOCATABLE_PV)) {
12486d7f5d3SJohn Marino 			log_error("Physical volume \"%s\" is already "
12586d7f5d3SJohn Marino 				  "unallocatable", pv_name);
12686d7f5d3SJohn Marino 			r = 1;
12786d7f5d3SJohn Marino 			goto out;
12886d7f5d3SJohn Marino 		}
12986d7f5d3SJohn Marino 
13086d7f5d3SJohn Marino 		if (allocatable) {
13186d7f5d3SJohn Marino 			log_verbose("Setting physical volume \"%s\" "
13286d7f5d3SJohn Marino 				    "allocatable", pv_name);
13386d7f5d3SJohn Marino 			pv->status |= ALLOCATABLE_PV;
13486d7f5d3SJohn Marino 		} else {
13586d7f5d3SJohn Marino 			log_verbose("Setting physical volume \"%s\" NOT "
13686d7f5d3SJohn Marino 				    "allocatable", pv_name);
13786d7f5d3SJohn Marino 			pv->status &= ~ALLOCATABLE_PV;
13886d7f5d3SJohn Marino 		}
13986d7f5d3SJohn Marino 	} else if (tagarg) {
14086d7f5d3SJohn Marino 		/* tag or deltag */
14186d7f5d3SJohn Marino 		if ((tagarg == addtag_ARG)) {
14286d7f5d3SJohn Marino 			if (!str_list_add(cmd->mem, &pv->tags, tag)) {
14386d7f5d3SJohn Marino 				log_error("Failed to add tag %s to physical "
14486d7f5d3SJohn Marino 					  "volume %s", tag, pv_name);
14586d7f5d3SJohn Marino 				goto out;
14686d7f5d3SJohn Marino 			}
14786d7f5d3SJohn Marino 		} else {
14886d7f5d3SJohn Marino 			if (!str_list_del(&pv->tags, tag)) {
14986d7f5d3SJohn Marino 				log_error("Failed to remove tag %s from "
15086d7f5d3SJohn Marino 					  "physical volume" "%s", tag, pv_name);
15186d7f5d3SJohn Marino 				goto out;
15286d7f5d3SJohn Marino 			}
15386d7f5d3SJohn Marino 		}
15486d7f5d3SJohn Marino 	} else {
15586d7f5d3SJohn Marino 		/* --uuid: Change PV ID randomly */
15686d7f5d3SJohn Marino 		if (!id_create(&pv->id)) {
15786d7f5d3SJohn Marino 			log_error("Failed to generate new random UUID for %s.",
15886d7f5d3SJohn Marino 				  pv_name);
15986d7f5d3SJohn Marino 			goto out;
16086d7f5d3SJohn Marino 		}
16186d7f5d3SJohn Marino 		if (!id_write_format(&pv->id, uuid, sizeof(uuid)))
16286d7f5d3SJohn Marino 			goto_out;
16386d7f5d3SJohn Marino 		log_verbose("Changing uuid of %s to %s.", pv_name, uuid);
16486d7f5d3SJohn Marino 		if (!is_orphan(pv)) {
16586d7f5d3SJohn Marino 			orig_vg_name = pv_vg_name(pv);
16686d7f5d3SJohn Marino 			orig_pe_alloc_count = pv_pe_alloc_count(pv);
16786d7f5d3SJohn Marino 
16886d7f5d3SJohn Marino 			/* FIXME format1 pv_write doesn't preserve these. */
16986d7f5d3SJohn Marino 			orig_pe_size = pv_pe_size(pv);
17086d7f5d3SJohn Marino 			orig_pe_start = pv_pe_start(pv);
17186d7f5d3SJohn Marino 			orig_pe_count = pv_pe_count(pv);
17286d7f5d3SJohn Marino 
17386d7f5d3SJohn Marino 			pv->vg_name = pv->fmt->orphan_vg_name;
17486d7f5d3SJohn Marino 			pv->pe_alloc_count = 0;
17586d7f5d3SJohn Marino 			if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
17686d7f5d3SJohn Marino 				log_error("pv_write with new uuid failed "
17786d7f5d3SJohn Marino 					  "for %s.", pv_name);
17886d7f5d3SJohn Marino 				goto out;
17986d7f5d3SJohn Marino 			}
18086d7f5d3SJohn Marino 			pv->vg_name = orig_vg_name;
18186d7f5d3SJohn Marino 			pv->pe_alloc_count = orig_pe_alloc_count;
18286d7f5d3SJohn Marino 
18386d7f5d3SJohn Marino 			pv->pe_size = orig_pe_size;
18486d7f5d3SJohn Marino 			pv->pe_start = orig_pe_start;
18586d7f5d3SJohn Marino 			pv->pe_count = orig_pe_count;
18686d7f5d3SJohn Marino 		}
18786d7f5d3SJohn Marino 	}
18886d7f5d3SJohn Marino 
18986d7f5d3SJohn Marino 	log_verbose("Updating physical volume \"%s\"", pv_name);
19086d7f5d3SJohn Marino 	if (!is_orphan(pv)) {
19186d7f5d3SJohn Marino 		if (!vg_write(vg) || !vg_commit(vg)) {
19286d7f5d3SJohn Marino 			log_error("Failed to store physical volume \"%s\" in "
19386d7f5d3SJohn Marino 				  "volume group \"%s\"", pv_name, vg->name);
19486d7f5d3SJohn Marino 			goto out;
19586d7f5d3SJohn Marino 		}
19686d7f5d3SJohn Marino 		backup(vg);
19786d7f5d3SJohn Marino 	} else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
19886d7f5d3SJohn Marino 		log_error("Failed to store physical volume \"%s\"",
19986d7f5d3SJohn Marino 			  pv_name);
20086d7f5d3SJohn Marino 		goto out;
20186d7f5d3SJohn Marino 	}
20286d7f5d3SJohn Marino 
20386d7f5d3SJohn Marino 	log_print("Physical volume \"%s\" changed", pv_name);
20486d7f5d3SJohn Marino 	r = 1;
20586d7f5d3SJohn Marino out:
20686d7f5d3SJohn Marino 	unlock_and_release_vg(cmd, vg, vg_name);
20786d7f5d3SJohn Marino 	return r;
20886d7f5d3SJohn Marino 
20986d7f5d3SJohn Marino }
21086d7f5d3SJohn Marino 
pvchange(struct cmd_context * cmd,int argc,char ** argv)21186d7f5d3SJohn Marino int pvchange(struct cmd_context *cmd, int argc, char **argv)
21286d7f5d3SJohn Marino {
21386d7f5d3SJohn Marino 	int opt = 0;
21486d7f5d3SJohn Marino 	int done = 0;
21586d7f5d3SJohn Marino 	int total = 0;
21686d7f5d3SJohn Marino 
21786d7f5d3SJohn Marino 	struct physical_volume *pv;
21886d7f5d3SJohn Marino 	char *pv_name;
21986d7f5d3SJohn Marino 
22086d7f5d3SJohn Marino 	struct pv_list *pvl;
22186d7f5d3SJohn Marino 	struct dm_list *pvslist;
22286d7f5d3SJohn Marino 	struct dm_list mdas;
22386d7f5d3SJohn Marino 
22486d7f5d3SJohn Marino 	if (arg_count(cmd, allocatable_ARG) + arg_count(cmd, addtag_ARG) +
22586d7f5d3SJohn Marino 	    arg_count(cmd, deltag_ARG) + arg_count(cmd, uuid_ARG) != 1) {
22686d7f5d3SJohn Marino 		log_error("Please give exactly one option of -x, -uuid, "
22786d7f5d3SJohn Marino 			  "--addtag or --deltag");
22886d7f5d3SJohn Marino 		return EINVALID_CMD_LINE;
22986d7f5d3SJohn Marino 	}
23086d7f5d3SJohn Marino 
23186d7f5d3SJohn Marino 	if (!(arg_count(cmd, all_ARG)) && !argc) {
23286d7f5d3SJohn Marino 		log_error("Please give a physical volume path");
23386d7f5d3SJohn Marino 		return EINVALID_CMD_LINE;
23486d7f5d3SJohn Marino 	}
23586d7f5d3SJohn Marino 
23686d7f5d3SJohn Marino 	if (arg_count(cmd, all_ARG) && argc) {
23786d7f5d3SJohn Marino 		log_error("Option a and PhysicalVolumePath are exclusive");
23886d7f5d3SJohn Marino 		return EINVALID_CMD_LINE;
23986d7f5d3SJohn Marino 	}
24086d7f5d3SJohn Marino 
24186d7f5d3SJohn Marino 	if (argc) {
24286d7f5d3SJohn Marino 		log_verbose("Using physical volume(s) on command line");
24386d7f5d3SJohn Marino 		for (; opt < argc; opt++) {
24486d7f5d3SJohn Marino 			pv_name = argv[opt];
24586d7f5d3SJohn Marino 			dm_list_init(&mdas);
24686d7f5d3SJohn Marino 			if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) {
24786d7f5d3SJohn Marino 				log_error("Failed to read physical volume %s",
24886d7f5d3SJohn Marino 					  pv_name);
24986d7f5d3SJohn Marino 				continue;
25086d7f5d3SJohn Marino 			}
25186d7f5d3SJohn Marino 			/*
25286d7f5d3SJohn Marino 			 * If a PV has no MDAs it may appear to be an
25386d7f5d3SJohn Marino 			 * orphan until the metadata is read off
25486d7f5d3SJohn Marino 			 * another PV in the same VG.  Detecting this
25586d7f5d3SJohn Marino 			 * means checking every VG by scanning every
25686d7f5d3SJohn Marino 			 * PV on the system.
25786d7f5d3SJohn Marino 			 */
25886d7f5d3SJohn Marino 			if (is_orphan(pv) && !dm_list_size(&mdas)) {
25986d7f5d3SJohn Marino 				if (!scan_vgs_for_pvs(cmd)) {
26086d7f5d3SJohn Marino 					log_error("Rescan for PVs without "
26186d7f5d3SJohn Marino 						  "metadata areas failed.");
26286d7f5d3SJohn Marino 					continue;
26386d7f5d3SJohn Marino 				}
26486d7f5d3SJohn Marino 				if (!(pv = pv_read(cmd, pv_name,
26586d7f5d3SJohn Marino 						   NULL, NULL, 1, 0))) {
26686d7f5d3SJohn Marino 					log_error("Failed to read "
26786d7f5d3SJohn Marino 						  "physical volume %s",
26886d7f5d3SJohn Marino 						  pv_name);
26986d7f5d3SJohn Marino 					continue;
27086d7f5d3SJohn Marino 				}
27186d7f5d3SJohn Marino 			}
27286d7f5d3SJohn Marino 
27386d7f5d3SJohn Marino 			total++;
27486d7f5d3SJohn Marino 			done += _pvchange_single(cmd, pv, NULL);
27586d7f5d3SJohn Marino 		}
27686d7f5d3SJohn Marino 	} else {
27786d7f5d3SJohn Marino 		log_verbose("Scanning for physical volume names");
27886d7f5d3SJohn Marino 		if (!(pvslist = get_pvs(cmd))) {
27986d7f5d3SJohn Marino 			stack;
28086d7f5d3SJohn Marino 			return ECMD_FAILED;
28186d7f5d3SJohn Marino 		}
28286d7f5d3SJohn Marino 
28386d7f5d3SJohn Marino 		dm_list_iterate_items(pvl, pvslist) {
28486d7f5d3SJohn Marino 			total++;
28586d7f5d3SJohn Marino 			done += _pvchange_single(cmd, pvl->pv, NULL);
28686d7f5d3SJohn Marino 		}
28786d7f5d3SJohn Marino 	}
28886d7f5d3SJohn Marino 
28986d7f5d3SJohn Marino 	log_print("%d physical volume%s changed / %d physical volume%s "
29086d7f5d3SJohn Marino 		  "not changed",
29186d7f5d3SJohn Marino 		  done, done == 1 ? "" : "s",
29286d7f5d3SJohn Marino 		  total - done, (total - done) == 1 ? "" : "s");
29386d7f5d3SJohn Marino 
29486d7f5d3SJohn Marino 	return (total == done) ? ECMD_PROCESSED : ECMD_FAILED;
29586d7f5d3SJohn Marino }
296