1 /* $NetBSD: pvchange.c,v 1.1.1.2 2009/12/02 00:25:54 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 /* FIXME Locking. PVs in VG. */ 21 22 static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv, 23 void *handle __attribute((unused))) 24 { 25 struct volume_group *vg = NULL; 26 const char *vg_name = NULL; 27 struct pv_list *pvl; 28 uint64_t sector; 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; 33 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))); 38 39 int allocatable = 0; 40 int tagarg = 0; 41 int r = 0; 42 43 if (arg_count(cmd, addtag_ARG)) 44 tagarg = addtag_ARG; 45 else if (arg_count(cmd, deltag_ARG)) 46 tagarg = deltag_ARG; 47 48 if (arg_count(cmd, allocatable_ARG)) 49 allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"), 50 "y"); 51 else if (tagarg && !(tag = arg_str_value(cmd, tagarg, NULL))) { 52 log_error("Failed to get tag"); 53 return 0; 54 } 55 56 /* If in a VG, must change using volume group. */ 57 if (!is_orphan(pv)) { 58 vg_name = pv_vg_name(pv); 59 60 log_verbose("Finding volume group %s of physical volume %s", 61 vg_name, pv_name); 62 vg = vg_read_for_update(cmd, vg_name, NULL, 0); 63 if (vg_read_error(vg)) { 64 vg_release(vg); 65 return_0; 66 } 67 68 if (!(pvl = find_pv_in_vg(vg, pv_name))) { 69 log_error("Unable to find \"%s\" in volume group \"%s\"", 70 pv_name, vg->name); 71 goto out; 72 } 73 if (tagarg && !(vg->fid->fmt->features & FMT_TAGS)) { 74 log_error("Volume group containing %s does not " 75 "support tags", pv_name); 76 goto out; 77 } 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); 81 goto out; 82 } 83 pv = pvl->pv; 84 if (!archive(vg)) 85 goto out; 86 } else { 87 if (tagarg) { 88 log_error("Can't change tag on Physical Volume %s not " 89 "in volume group", pv_name); 90 return 0; 91 } 92 93 vg_name = VG_ORPHANS; 94 95 if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { 96 log_error("Can't get lock for orphans"); 97 return 0; 98 } 99 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); 103 return 0; 104 } 105 } 106 107 if (arg_count(cmd, allocatable_ARG)) { 108 if (is_orphan(pv) && 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); 112 goto out; 113 } 114 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); 119 r = 1; 120 goto out; 121 } 122 123 if (!allocatable && !(pv_status(pv) & ALLOCATABLE_PV)) { 124 log_error("Physical volume \"%s\" is already " 125 "unallocatable", pv_name); 126 r = 1; 127 goto out; 128 } 129 130 if (allocatable) { 131 log_verbose("Setting physical volume \"%s\" " 132 "allocatable", pv_name); 133 pv->status |= ALLOCATABLE_PV; 134 } else { 135 log_verbose("Setting physical volume \"%s\" NOT " 136 "allocatable", pv_name); 137 pv->status &= ~ALLOCATABLE_PV; 138 } 139 } else if (tagarg) { 140 /* tag or deltag */ 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); 145 goto out; 146 } 147 } else { 148 if (!str_list_del(&pv->tags, tag)) { 149 log_error("Failed to remove tag %s from " 150 "physical volume" "%s", tag, pv_name); 151 goto out; 152 } 153 } 154 } else { 155 /* --uuid: Change PV ID randomly */ 156 if (!id_create(&pv->id)) { 157 log_error("Failed to generate new random UUID for %s.", 158 pv_name); 159 goto out; 160 } 161 if (!id_write_format(&pv->id, uuid, sizeof(uuid))) 162 goto_out; 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); 167 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); 172 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 " 177 "for %s.", pv_name); 178 goto out; 179 } 180 pv->vg_name = orig_vg_name; 181 pv->pe_alloc_count = orig_pe_alloc_count; 182 183 pv->pe_size = orig_pe_size; 184 pv->pe_start = orig_pe_start; 185 pv->pe_count = orig_pe_count; 186 } 187 } 188 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); 194 goto out; 195 } 196 backup(vg); 197 } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) { 198 log_error("Failed to store physical volume \"%s\"", 199 pv_name); 200 goto out; 201 } 202 203 log_print("Physical volume \"%s\" changed", pv_name); 204 r = 1; 205 out: 206 unlock_and_release_vg(cmd, vg, vg_name); 207 return r; 208 209 } 210 211 int pvchange(struct cmd_context *cmd, int argc, char **argv) 212 { 213 int opt = 0; 214 int done = 0; 215 int total = 0; 216 217 struct physical_volume *pv; 218 char *pv_name; 219 220 struct pv_list *pvl; 221 struct dm_list *pvslist; 222 struct dm_list mdas; 223 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; 229 } 230 231 if (!(arg_count(cmd, all_ARG)) && !argc) { 232 log_error("Please give a physical volume path"); 233 return EINVALID_CMD_LINE; 234 } 235 236 if (arg_count(cmd, all_ARG) && argc) { 237 log_error("Option a and PhysicalVolumePath are exclusive"); 238 return EINVALID_CMD_LINE; 239 } 240 241 if (argc) { 242 log_verbose("Using physical volume(s) on command line"); 243 for (; opt < argc; opt++) { 244 pv_name = argv[opt]; 245 dm_list_init(&mdas); 246 if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) { 247 log_error("Failed to read physical volume %s", 248 pv_name); 249 continue; 250 } 251 /* 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 256 * PV on the system. 257 */ 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."); 262 continue; 263 } 264 if (!(pv = pv_read(cmd, pv_name, 265 NULL, NULL, 1, 0))) { 266 log_error("Failed to read " 267 "physical volume %s", 268 pv_name); 269 continue; 270 } 271 } 272 273 total++; 274 done += _pvchange_single(cmd, pv, NULL); 275 } 276 } else { 277 log_verbose("Scanning for physical volume names"); 278 if (!(pvslist = get_pvs(cmd))) { 279 stack; 280 return ECMD_FAILED; 281 } 282 283 dm_list_iterate_items(pvl, pvslist) { 284 total++; 285 done += _pvchange_single(cmd, pvl->pv, NULL); 286 } 287 } 288 289 log_print("%d physical volume%s changed / %d physical volume%s " 290 "not changed", 291 done, done == 1 ? "" : "s", 292 total - done, (total - done) == 1 ? "" : "s"); 293 294 return (total == done) ? ECMD_PROCESSED : ECMD_FAILED; 295 } 296