4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
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.
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
20 /* FIXME Locking. PVs in VG. */
22 static int _pvchange_single(struct cmd_context
*cmd
, struct physical_volume
*pv
,
23 void *handle
__attribute((unused
)))
25 struct volume_group
*vg
= NULL
;
26 const char *vg_name
= NULL
;
29 uint32_t orig_pe_alloc_count
;
30 /* FIXME Next three only required for format1. */
31 uint32_t orig_pe_count
, orig_pe_size
;
32 uint64_t orig_pe_start
;
34 const char *pv_name
= pv_dev_name(pv
);
35 const char *tag
= NULL
;
36 const char *orig_vg_name
;
37 char uuid
[64] __attribute((aligned(8)));
43 if (arg_count(cmd
, addtag_ARG
))
45 else if (arg_count(cmd
, deltag_ARG
))
48 if (arg_count(cmd
, allocatable_ARG
))
49 allocatable
= !strcmp(arg_str_value(cmd
, allocatable_ARG
, "n"),
51 else if (tagarg
&& !(tag
= arg_str_value(cmd
, tagarg
, NULL
))) {
52 log_error("Failed to get tag");
56 /* If in a VG, must change using volume group. */
58 vg_name
= pv_vg_name(pv
);
60 log_verbose("Finding volume group %s of physical volume %s",
62 vg
= vg_read_for_update(cmd
, vg_name
, NULL
, 0);
63 if (vg_read_error(vg
)) {
68 if (!(pvl
= find_pv_in_vg(vg
, pv_name
))) {
69 log_error("Unable to find \"%s\" in volume group \"%s\"",
73 if (tagarg
&& !(vg
->fid
->fmt
->features
& FMT_TAGS
)) {
74 log_error("Volume group containing %s does not "
75 "support tags", pv_name
);
78 if (arg_count(cmd
, uuid_ARG
) && lvs_in_vg_activated(vg
)) {
79 log_error("Volume group containing %s has active "
80 "logical volumes", pv_name
);
88 log_error("Can't change tag on Physical Volume %s not "
89 "in volume group", pv_name
);
95 if (!lock_vol(cmd
, vg_name
, LCK_VG_WRITE
)) {
96 log_error("Can't get lock for orphans");
100 if (!(pv
= pv_read(cmd
, pv_name
, NULL
, §or
, 1, 0))) {
101 unlock_vg(cmd
, vg_name
);
102 log_error("Unable to read PV \"%s\"", pv_name
);
107 if (arg_count(cmd
, allocatable_ARG
)) {
109 !(pv
->fmt
->features
& FMT_ORPHAN_ALLOCATABLE
)) {
110 log_error("Allocatability not supported by orphan "
111 "%s format PV %s", pv
->fmt
->name
, pv_name
);
115 /* change allocatability for a PV */
116 if (allocatable
&& (pv_status(pv
) & ALLOCATABLE_PV
)) {
117 log_error("Physical volume \"%s\" is already "
118 "allocatable", pv_name
);
123 if (!allocatable
&& !(pv_status(pv
) & ALLOCATABLE_PV
)) {
124 log_error("Physical volume \"%s\" is already "
125 "unallocatable", pv_name
);
131 log_verbose("Setting physical volume \"%s\" "
132 "allocatable", pv_name
);
133 pv
->status
|= ALLOCATABLE_PV
;
135 log_verbose("Setting physical volume \"%s\" NOT "
136 "allocatable", pv_name
);
137 pv
->status
&= ~ALLOCATABLE_PV
;
141 if ((tagarg
== addtag_ARG
)) {
142 if (!str_list_add(cmd
->mem
, &pv
->tags
, tag
)) {
143 log_error("Failed to add tag %s to physical "
144 "volume %s", tag
, pv_name
);
148 if (!str_list_del(&pv
->tags
, tag
)) {
149 log_error("Failed to remove tag %s from "
150 "physical volume" "%s", tag
, pv_name
);
155 /* --uuid: Change PV ID randomly */
156 if (!id_create(&pv
->id
)) {
157 log_error("Failed to generate new random UUID for %s.",
161 if (!id_write_format(&pv
->id
, uuid
, sizeof(uuid
)))
163 log_verbose("Changing uuid of %s to %s.", pv_name
, uuid
);
164 if (!is_orphan(pv
)) {
165 orig_vg_name
= pv_vg_name(pv
);
166 orig_pe_alloc_count
= pv_pe_alloc_count(pv
);
168 /* FIXME format1 pv_write doesn't preserve these. */
169 orig_pe_size
= pv_pe_size(pv
);
170 orig_pe_start
= pv_pe_start(pv
);
171 orig_pe_count
= pv_pe_count(pv
);
173 pv
->vg_name
= pv
->fmt
->orphan_vg_name
;
174 pv
->pe_alloc_count
= 0;
175 if (!(pv_write(cmd
, pv
, NULL
, INT64_C(-1)))) {
176 log_error("pv_write with new uuid failed "
180 pv
->vg_name
= orig_vg_name
;
181 pv
->pe_alloc_count
= orig_pe_alloc_count
;
183 pv
->pe_size
= orig_pe_size
;
184 pv
->pe_start
= orig_pe_start
;
185 pv
->pe_count
= orig_pe_count
;
189 log_verbose("Updating physical volume \"%s\"", pv_name
);
190 if (!is_orphan(pv
)) {
191 if (!vg_write(vg
) || !vg_commit(vg
)) {
192 log_error("Failed to store physical volume \"%s\" in "
193 "volume group \"%s\"", pv_name
, vg
->name
);
197 } else if (!(pv_write(cmd
, pv
, NULL
, INT64_C(-1)))) {
198 log_error("Failed to store physical volume \"%s\"",
203 log_print("Physical volume \"%s\" changed", pv_name
);
206 unlock_and_release_vg(cmd
, vg
, vg_name
);
211 int pvchange(struct cmd_context
*cmd
, int argc
, char **argv
)
217 struct physical_volume
*pv
;
221 struct dm_list
*pvslist
;
224 if (arg_count(cmd
, allocatable_ARG
) + arg_count(cmd
, addtag_ARG
) +
225 arg_count(cmd
, deltag_ARG
) + arg_count(cmd
, uuid_ARG
) != 1) {
226 log_error("Please give exactly one option of -x, -uuid, "
227 "--addtag or --deltag");
228 return EINVALID_CMD_LINE
;
231 if (!(arg_count(cmd
, all_ARG
)) && !argc
) {
232 log_error("Please give a physical volume path");
233 return EINVALID_CMD_LINE
;
236 if (arg_count(cmd
, all_ARG
) && argc
) {
237 log_error("Option a and PhysicalVolumePath are exclusive");
238 return EINVALID_CMD_LINE
;
242 log_verbose("Using physical volume(s) on command line");
243 for (; opt
< argc
; opt
++) {
246 if (!(pv
= pv_read(cmd
, pv_name
, &mdas
, NULL
, 1, 0))) {
247 log_error("Failed to read physical volume %s",
252 * If a PV has no MDAs it may appear to be an
253 * orphan until the metadata is read off
254 * another PV in the same VG. Detecting this
255 * means checking every VG by scanning every
258 if (is_orphan(pv
) && !dm_list_size(&mdas
)) {
259 if (!scan_vgs_for_pvs(cmd
)) {
260 log_error("Rescan for PVs without "
261 "metadata areas failed.");
264 if (!(pv
= pv_read(cmd
, pv_name
,
265 NULL
, NULL
, 1, 0))) {
266 log_error("Failed to read "
267 "physical volume %s",
274 done
+= _pvchange_single(cmd
, pv
, NULL
);
277 log_verbose("Scanning for physical volume names");
278 if (!(pvslist
= get_pvs(cmd
))) {
283 dm_list_iterate_items(pvl
, pvslist
) {
285 done
+= _pvchange_single(cmd
, pvl
->pv
, NULL
);
289 log_print("%d physical volume%s changed / %d physical volume%s "
291 done
, done
== 1 ? "" : "s",
292 total
- done
, (total
- done
) == 1 ? "" : "s");
294 return (total
== done
) ? ECMD_PROCESSED
: ECMD_FAILED
;