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, §or, 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