1*7c604eeaShaad /* $NetBSD: pvchange.c,v 1.1.1.2 2009/12/02 00:25:54 haad Exp $ */
256a34939Shaad
356a34939Shaad /*
456a34939Shaad * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
556a34939Shaad * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
656a34939Shaad *
756a34939Shaad * This file is part of LVM2.
856a34939Shaad *
956a34939Shaad * This copyrighted material is made available to anyone wishing to use,
1056a34939Shaad * modify, copy, or redistribute it subject to the terms and conditions
1156a34939Shaad * of the GNU Lesser General Public License v.2.1.
1256a34939Shaad *
1356a34939Shaad * You should have received a copy of the GNU Lesser General Public License
1456a34939Shaad * along with this program; if not, write to the Free Software Foundation,
1556a34939Shaad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1656a34939Shaad */
1756a34939Shaad
1856a34939Shaad #include "tools.h"
1956a34939Shaad
2056a34939Shaad /* FIXME Locking. PVs in VG. */
2156a34939Shaad
_pvchange_single(struct cmd_context * cmd,struct physical_volume * pv,void * handle __attribute ((unused)))2256a34939Shaad static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
2356a34939Shaad void *handle __attribute((unused)))
2456a34939Shaad {
2556a34939Shaad struct volume_group *vg = NULL;
2656a34939Shaad const char *vg_name = NULL;
2756a34939Shaad struct pv_list *pvl;
2856a34939Shaad uint64_t sector;
2956a34939Shaad uint32_t orig_pe_alloc_count;
3056a34939Shaad /* FIXME Next three only required for format1. */
3156a34939Shaad uint32_t orig_pe_count, orig_pe_size;
3256a34939Shaad uint64_t orig_pe_start;
3356a34939Shaad
3456a34939Shaad const char *pv_name = pv_dev_name(pv);
3556a34939Shaad const char *tag = NULL;
3656a34939Shaad const char *orig_vg_name;
3756a34939Shaad char uuid[64] __attribute((aligned(8)));
3856a34939Shaad
3956a34939Shaad int allocatable = 0;
4056a34939Shaad int tagarg = 0;
41*7c604eeaShaad int r = 0;
4256a34939Shaad
4356a34939Shaad if (arg_count(cmd, addtag_ARG))
4456a34939Shaad tagarg = addtag_ARG;
4556a34939Shaad else if (arg_count(cmd, deltag_ARG))
4656a34939Shaad tagarg = deltag_ARG;
4756a34939Shaad
4856a34939Shaad if (arg_count(cmd, allocatable_ARG))
4956a34939Shaad allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"),
5056a34939Shaad "y");
5156a34939Shaad else if (tagarg && !(tag = arg_str_value(cmd, tagarg, NULL))) {
5256a34939Shaad log_error("Failed to get tag");
5356a34939Shaad return 0;
5456a34939Shaad }
5556a34939Shaad
5656a34939Shaad /* If in a VG, must change using volume group. */
5756a34939Shaad if (!is_orphan(pv)) {
5856a34939Shaad vg_name = pv_vg_name(pv);
5956a34939Shaad
6056a34939Shaad log_verbose("Finding volume group %s of physical volume %s",
6156a34939Shaad vg_name, pv_name);
62*7c604eeaShaad vg = vg_read_for_update(cmd, vg_name, NULL, 0);
63*7c604eeaShaad if (vg_read_error(vg)) {
64*7c604eeaShaad vg_release(vg);
6556a34939Shaad return_0;
66*7c604eeaShaad }
6756a34939Shaad
6856a34939Shaad if (!(pvl = find_pv_in_vg(vg, pv_name))) {
69*7c604eeaShaad log_error("Unable to find \"%s\" in volume group \"%s\"",
7056a34939Shaad pv_name, vg->name);
71*7c604eeaShaad goto out;
7256a34939Shaad }
7356a34939Shaad if (tagarg && !(vg->fid->fmt->features & FMT_TAGS)) {
7456a34939Shaad log_error("Volume group containing %s does not "
7556a34939Shaad "support tags", pv_name);
76*7c604eeaShaad goto out;
7756a34939Shaad }
7856a34939Shaad if (arg_count(cmd, uuid_ARG) && lvs_in_vg_activated(vg)) {
7956a34939Shaad log_error("Volume group containing %s has active "
8056a34939Shaad "logical volumes", pv_name);
81*7c604eeaShaad goto out;
8256a34939Shaad }
8356a34939Shaad pv = pvl->pv;
8456a34939Shaad if (!archive(vg))
85*7c604eeaShaad goto out;
8656a34939Shaad } else {
8756a34939Shaad if (tagarg) {
8856a34939Shaad log_error("Can't change tag on Physical Volume %s not "
8956a34939Shaad "in volume group", pv_name);
9056a34939Shaad return 0;
9156a34939Shaad }
9256a34939Shaad
9356a34939Shaad vg_name = VG_ORPHANS;
9456a34939Shaad
9556a34939Shaad if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
9656a34939Shaad log_error("Can't get lock for orphans");
9756a34939Shaad return 0;
9856a34939Shaad }
9956a34939Shaad
100*7c604eeaShaad if (!(pv = pv_read(cmd, pv_name, NULL, §or, 1, 0))) {
10156a34939Shaad unlock_vg(cmd, vg_name);
10256a34939Shaad log_error("Unable to read PV \"%s\"", pv_name);
10356a34939Shaad return 0;
10456a34939Shaad }
10556a34939Shaad }
10656a34939Shaad
10756a34939Shaad if (arg_count(cmd, allocatable_ARG)) {
10856a34939Shaad if (is_orphan(pv) &&
10956a34939Shaad !(pv->fmt->features & FMT_ORPHAN_ALLOCATABLE)) {
11056a34939Shaad log_error("Allocatability not supported by orphan "
11156a34939Shaad "%s format PV %s", pv->fmt->name, pv_name);
112*7c604eeaShaad goto out;
11356a34939Shaad }
11456a34939Shaad
11556a34939Shaad /* change allocatability for a PV */
11656a34939Shaad if (allocatable && (pv_status(pv) & ALLOCATABLE_PV)) {
11756a34939Shaad log_error("Physical volume \"%s\" is already "
11856a34939Shaad "allocatable", pv_name);
119*7c604eeaShaad r = 1;
120*7c604eeaShaad goto out;
12156a34939Shaad }
12256a34939Shaad
12356a34939Shaad if (!allocatable && !(pv_status(pv) & ALLOCATABLE_PV)) {
12456a34939Shaad log_error("Physical volume \"%s\" is already "
12556a34939Shaad "unallocatable", pv_name);
126*7c604eeaShaad r = 1;
127*7c604eeaShaad goto out;
12856a34939Shaad }
12956a34939Shaad
13056a34939Shaad if (allocatable) {
13156a34939Shaad log_verbose("Setting physical volume \"%s\" "
13256a34939Shaad "allocatable", pv_name);
13356a34939Shaad pv->status |= ALLOCATABLE_PV;
13456a34939Shaad } else {
13556a34939Shaad log_verbose("Setting physical volume \"%s\" NOT "
13656a34939Shaad "allocatable", pv_name);
13756a34939Shaad pv->status &= ~ALLOCATABLE_PV;
13856a34939Shaad }
13956a34939Shaad } else if (tagarg) {
14056a34939Shaad /* tag or deltag */
14156a34939Shaad if ((tagarg == addtag_ARG)) {
14256a34939Shaad if (!str_list_add(cmd->mem, &pv->tags, tag)) {
14356a34939Shaad log_error("Failed to add tag %s to physical "
14456a34939Shaad "volume %s", tag, pv_name);
145*7c604eeaShaad goto out;
14656a34939Shaad }
14756a34939Shaad } else {
14856a34939Shaad if (!str_list_del(&pv->tags, tag)) {
14956a34939Shaad log_error("Failed to remove tag %s from "
15056a34939Shaad "physical volume" "%s", tag, pv_name);
151*7c604eeaShaad goto out;
15256a34939Shaad }
15356a34939Shaad }
15456a34939Shaad } else {
15556a34939Shaad /* --uuid: Change PV ID randomly */
15656a34939Shaad if (!id_create(&pv->id)) {
15756a34939Shaad log_error("Failed to generate new random UUID for %s.",
15856a34939Shaad pv_name);
159*7c604eeaShaad goto out;
16056a34939Shaad }
161*7c604eeaShaad if (!id_write_format(&pv->id, uuid, sizeof(uuid)))
162*7c604eeaShaad goto_out;
16356a34939Shaad log_verbose("Changing uuid of %s to %s.", pv_name, uuid);
16456a34939Shaad if (!is_orphan(pv)) {
16556a34939Shaad orig_vg_name = pv_vg_name(pv);
16656a34939Shaad orig_pe_alloc_count = pv_pe_alloc_count(pv);
16756a34939Shaad
16856a34939Shaad /* FIXME format1 pv_write doesn't preserve these. */
16956a34939Shaad orig_pe_size = pv_pe_size(pv);
17056a34939Shaad orig_pe_start = pv_pe_start(pv);
17156a34939Shaad orig_pe_count = pv_pe_count(pv);
17256a34939Shaad
17356a34939Shaad pv->vg_name = pv->fmt->orphan_vg_name;
17456a34939Shaad pv->pe_alloc_count = 0;
17556a34939Shaad if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
17656a34939Shaad log_error("pv_write with new uuid failed "
17756a34939Shaad "for %s.", pv_name);
178*7c604eeaShaad goto out;
17956a34939Shaad }
18056a34939Shaad pv->vg_name = orig_vg_name;
18156a34939Shaad pv->pe_alloc_count = orig_pe_alloc_count;
18256a34939Shaad
18356a34939Shaad pv->pe_size = orig_pe_size;
18456a34939Shaad pv->pe_start = orig_pe_start;
18556a34939Shaad pv->pe_count = orig_pe_count;
18656a34939Shaad }
18756a34939Shaad }
18856a34939Shaad
18956a34939Shaad log_verbose("Updating physical volume \"%s\"", pv_name);
19056a34939Shaad if (!is_orphan(pv)) {
19156a34939Shaad if (!vg_write(vg) || !vg_commit(vg)) {
19256a34939Shaad log_error("Failed to store physical volume \"%s\" in "
19356a34939Shaad "volume group \"%s\"", pv_name, vg->name);
194*7c604eeaShaad goto out;
19556a34939Shaad }
19656a34939Shaad backup(vg);
19756a34939Shaad } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
19856a34939Shaad log_error("Failed to store physical volume \"%s\"",
19956a34939Shaad pv_name);
200*7c604eeaShaad goto out;
20156a34939Shaad }
20256a34939Shaad
20356a34939Shaad log_print("Physical volume \"%s\" changed", pv_name);
204*7c604eeaShaad r = 1;
205*7c604eeaShaad out:
206*7c604eeaShaad unlock_and_release_vg(cmd, vg, vg_name);
207*7c604eeaShaad return r;
20856a34939Shaad
20956a34939Shaad }
21056a34939Shaad
pvchange(struct cmd_context * cmd,int argc,char ** argv)21156a34939Shaad int pvchange(struct cmd_context *cmd, int argc, char **argv)
21256a34939Shaad {
21356a34939Shaad int opt = 0;
21456a34939Shaad int done = 0;
21556a34939Shaad int total = 0;
21656a34939Shaad
21756a34939Shaad struct physical_volume *pv;
21856a34939Shaad char *pv_name;
21956a34939Shaad
22056a34939Shaad struct pv_list *pvl;
22156a34939Shaad struct dm_list *pvslist;
22256a34939Shaad struct dm_list mdas;
22356a34939Shaad
22456a34939Shaad if (arg_count(cmd, allocatable_ARG) + arg_count(cmd, addtag_ARG) +
22556a34939Shaad arg_count(cmd, deltag_ARG) + arg_count(cmd, uuid_ARG) != 1) {
22656a34939Shaad log_error("Please give exactly one option of -x, -uuid, "
22756a34939Shaad "--addtag or --deltag");
22856a34939Shaad return EINVALID_CMD_LINE;
22956a34939Shaad }
23056a34939Shaad
23156a34939Shaad if (!(arg_count(cmd, all_ARG)) && !argc) {
23256a34939Shaad log_error("Please give a physical volume path");
23356a34939Shaad return EINVALID_CMD_LINE;
23456a34939Shaad }
23556a34939Shaad
23656a34939Shaad if (arg_count(cmd, all_ARG) && argc) {
23756a34939Shaad log_error("Option a and PhysicalVolumePath are exclusive");
23856a34939Shaad return EINVALID_CMD_LINE;
23956a34939Shaad }
24056a34939Shaad
24156a34939Shaad if (argc) {
24256a34939Shaad log_verbose("Using physical volume(s) on command line");
24356a34939Shaad for (; opt < argc; opt++) {
24456a34939Shaad pv_name = argv[opt];
24556a34939Shaad dm_list_init(&mdas);
246*7c604eeaShaad if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) {
24756a34939Shaad log_error("Failed to read physical volume %s",
24856a34939Shaad pv_name);
24956a34939Shaad continue;
25056a34939Shaad }
25156a34939Shaad /*
25256a34939Shaad * If a PV has no MDAs it may appear to be an
25356a34939Shaad * orphan until the metadata is read off
25456a34939Shaad * another PV in the same VG. Detecting this
25556a34939Shaad * means checking every VG by scanning every
25656a34939Shaad * PV on the system.
25756a34939Shaad */
25856a34939Shaad if (is_orphan(pv) && !dm_list_size(&mdas)) {
25956a34939Shaad if (!scan_vgs_for_pvs(cmd)) {
26056a34939Shaad log_error("Rescan for PVs without "
26156a34939Shaad "metadata areas failed.");
26256a34939Shaad continue;
26356a34939Shaad }
26456a34939Shaad if (!(pv = pv_read(cmd, pv_name,
265*7c604eeaShaad NULL, NULL, 1, 0))) {
26656a34939Shaad log_error("Failed to read "
26756a34939Shaad "physical volume %s",
26856a34939Shaad pv_name);
26956a34939Shaad continue;
27056a34939Shaad }
27156a34939Shaad }
27256a34939Shaad
27356a34939Shaad total++;
27456a34939Shaad done += _pvchange_single(cmd, pv, NULL);
27556a34939Shaad }
27656a34939Shaad } else {
27756a34939Shaad log_verbose("Scanning for physical volume names");
27856a34939Shaad if (!(pvslist = get_pvs(cmd))) {
279*7c604eeaShaad stack;
28056a34939Shaad return ECMD_FAILED;
28156a34939Shaad }
28256a34939Shaad
28356a34939Shaad dm_list_iterate_items(pvl, pvslist) {
28456a34939Shaad total++;
28556a34939Shaad done += _pvchange_single(cmd, pvl->pv, NULL);
28656a34939Shaad }
28756a34939Shaad }
28856a34939Shaad
28956a34939Shaad log_print("%d physical volume%s changed / %d physical volume%s "
29056a34939Shaad "not changed",
29156a34939Shaad done, done == 1 ? "" : "s",
29256a34939Shaad total - done, (total - done) == 1 ? "" : "s");
29356a34939Shaad
29456a34939Shaad return (total == done) ? ECMD_PROCESSED : ECMD_FAILED;
29556a34939Shaad }
296