1 1.1 haad /* $NetBSD: pvchange.c,v 1.1.1.2 2009/12/02 00:25:54 haad Exp $ */ 2 1.1 haad 3 1.1 haad /* 4 1.1 haad * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. 5 1.1 haad * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. 6 1.1 haad * 7 1.1 haad * This file is part of LVM2. 8 1.1 haad * 9 1.1 haad * This copyrighted material is made available to anyone wishing to use, 10 1.1 haad * modify, copy, or redistribute it subject to the terms and conditions 11 1.1 haad * of the GNU Lesser General Public License v.2.1. 12 1.1 haad * 13 1.1 haad * You should have received a copy of the GNU Lesser General Public License 14 1.1 haad * along with this program; if not, write to the Free Software Foundation, 15 1.1 haad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 1.1 haad */ 17 1.1 haad 18 1.1 haad #include "tools.h" 19 1.1 haad 20 1.1 haad /* FIXME Locking. PVs in VG. */ 21 1.1 haad 22 1.1 haad static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv, 23 1.1 haad void *handle __attribute((unused))) 24 1.1 haad { 25 1.1 haad struct volume_group *vg = NULL; 26 1.1 haad const char *vg_name = NULL; 27 1.1 haad struct pv_list *pvl; 28 1.1 haad uint64_t sector; 29 1.1 haad uint32_t orig_pe_alloc_count; 30 1.1 haad /* FIXME Next three only required for format1. */ 31 1.1 haad uint32_t orig_pe_count, orig_pe_size; 32 1.1 haad uint64_t orig_pe_start; 33 1.1 haad 34 1.1 haad const char *pv_name = pv_dev_name(pv); 35 1.1 haad const char *tag = NULL; 36 1.1 haad const char *orig_vg_name; 37 1.1 haad char uuid[64] __attribute((aligned(8))); 38 1.1 haad 39 1.1 haad int allocatable = 0; 40 1.1 haad int tagarg = 0; 41 1.1.1.2 haad int r = 0; 42 1.1 haad 43 1.1 haad if (arg_count(cmd, addtag_ARG)) 44 1.1 haad tagarg = addtag_ARG; 45 1.1 haad else if (arg_count(cmd, deltag_ARG)) 46 1.1 haad tagarg = deltag_ARG; 47 1.1 haad 48 1.1 haad if (arg_count(cmd, allocatable_ARG)) 49 1.1 haad allocatable = !strcmp(arg_str_value(cmd, allocatable_ARG, "n"), 50 1.1 haad "y"); 51 1.1 haad else if (tagarg && !(tag = arg_str_value(cmd, tagarg, NULL))) { 52 1.1 haad log_error("Failed to get tag"); 53 1.1 haad return 0; 54 1.1 haad } 55 1.1 haad 56 1.1 haad /* If in a VG, must change using volume group. */ 57 1.1 haad if (!is_orphan(pv)) { 58 1.1 haad vg_name = pv_vg_name(pv); 59 1.1 haad 60 1.1 haad log_verbose("Finding volume group %s of physical volume %s", 61 1.1 haad vg_name, pv_name); 62 1.1.1.2 haad vg = vg_read_for_update(cmd, vg_name, NULL, 0); 63 1.1.1.2 haad if (vg_read_error(vg)) { 64 1.1.1.2 haad vg_release(vg); 65 1.1 haad return_0; 66 1.1.1.2 haad } 67 1.1 haad 68 1.1 haad if (!(pvl = find_pv_in_vg(vg, pv_name))) { 69 1.1.1.2 haad log_error("Unable to find \"%s\" in volume group \"%s\"", 70 1.1.1.2 haad pv_name, vg->name); 71 1.1.1.2 haad goto out; 72 1.1 haad } 73 1.1 haad if (tagarg && !(vg->fid->fmt->features & FMT_TAGS)) { 74 1.1 haad log_error("Volume group containing %s does not " 75 1.1 haad "support tags", pv_name); 76 1.1.1.2 haad goto out; 77 1.1 haad } 78 1.1 haad if (arg_count(cmd, uuid_ARG) && lvs_in_vg_activated(vg)) { 79 1.1 haad log_error("Volume group containing %s has active " 80 1.1 haad "logical volumes", pv_name); 81 1.1.1.2 haad goto out; 82 1.1 haad } 83 1.1 haad pv = pvl->pv; 84 1.1 haad if (!archive(vg)) 85 1.1.1.2 haad goto out; 86 1.1 haad } else { 87 1.1 haad if (tagarg) { 88 1.1 haad log_error("Can't change tag on Physical Volume %s not " 89 1.1 haad "in volume group", pv_name); 90 1.1 haad return 0; 91 1.1 haad } 92 1.1 haad 93 1.1 haad vg_name = VG_ORPHANS; 94 1.1 haad 95 1.1 haad if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) { 96 1.1 haad log_error("Can't get lock for orphans"); 97 1.1 haad return 0; 98 1.1 haad } 99 1.1 haad 100 1.1.1.2 haad if (!(pv = pv_read(cmd, pv_name, NULL, §or, 1, 0))) { 101 1.1 haad unlock_vg(cmd, vg_name); 102 1.1 haad log_error("Unable to read PV \"%s\"", pv_name); 103 1.1 haad return 0; 104 1.1 haad } 105 1.1 haad } 106 1.1 haad 107 1.1 haad if (arg_count(cmd, allocatable_ARG)) { 108 1.1 haad if (is_orphan(pv) && 109 1.1 haad !(pv->fmt->features & FMT_ORPHAN_ALLOCATABLE)) { 110 1.1 haad log_error("Allocatability not supported by orphan " 111 1.1 haad "%s format PV %s", pv->fmt->name, pv_name); 112 1.1.1.2 haad goto out; 113 1.1 haad } 114 1.1 haad 115 1.1 haad /* change allocatability for a PV */ 116 1.1 haad if (allocatable && (pv_status(pv) & ALLOCATABLE_PV)) { 117 1.1 haad log_error("Physical volume \"%s\" is already " 118 1.1 haad "allocatable", pv_name); 119 1.1.1.2 haad r = 1; 120 1.1.1.2 haad goto out; 121 1.1 haad } 122 1.1 haad 123 1.1 haad if (!allocatable && !(pv_status(pv) & ALLOCATABLE_PV)) { 124 1.1 haad log_error("Physical volume \"%s\" is already " 125 1.1 haad "unallocatable", pv_name); 126 1.1.1.2 haad r = 1; 127 1.1.1.2 haad goto out; 128 1.1 haad } 129 1.1 haad 130 1.1 haad if (allocatable) { 131 1.1 haad log_verbose("Setting physical volume \"%s\" " 132 1.1 haad "allocatable", pv_name); 133 1.1 haad pv->status |= ALLOCATABLE_PV; 134 1.1 haad } else { 135 1.1 haad log_verbose("Setting physical volume \"%s\" NOT " 136 1.1 haad "allocatable", pv_name); 137 1.1 haad pv->status &= ~ALLOCATABLE_PV; 138 1.1 haad } 139 1.1 haad } else if (tagarg) { 140 1.1 haad /* tag or deltag */ 141 1.1 haad if ((tagarg == addtag_ARG)) { 142 1.1 haad if (!str_list_add(cmd->mem, &pv->tags, tag)) { 143 1.1 haad log_error("Failed to add tag %s to physical " 144 1.1 haad "volume %s", tag, pv_name); 145 1.1.1.2 haad goto out; 146 1.1 haad } 147 1.1 haad } else { 148 1.1 haad if (!str_list_del(&pv->tags, tag)) { 149 1.1 haad log_error("Failed to remove tag %s from " 150 1.1 haad "physical volume" "%s", tag, pv_name); 151 1.1.1.2 haad goto out; 152 1.1 haad } 153 1.1 haad } 154 1.1 haad } else { 155 1.1 haad /* --uuid: Change PV ID randomly */ 156 1.1 haad if (!id_create(&pv->id)) { 157 1.1 haad log_error("Failed to generate new random UUID for %s.", 158 1.1 haad pv_name); 159 1.1.1.2 haad goto out; 160 1.1 haad } 161 1.1.1.2 haad if (!id_write_format(&pv->id, uuid, sizeof(uuid))) 162 1.1.1.2 haad goto_out; 163 1.1 haad log_verbose("Changing uuid of %s to %s.", pv_name, uuid); 164 1.1 haad if (!is_orphan(pv)) { 165 1.1 haad orig_vg_name = pv_vg_name(pv); 166 1.1 haad orig_pe_alloc_count = pv_pe_alloc_count(pv); 167 1.1 haad 168 1.1 haad /* FIXME format1 pv_write doesn't preserve these. */ 169 1.1 haad orig_pe_size = pv_pe_size(pv); 170 1.1 haad orig_pe_start = pv_pe_start(pv); 171 1.1 haad orig_pe_count = pv_pe_count(pv); 172 1.1 haad 173 1.1 haad pv->vg_name = pv->fmt->orphan_vg_name; 174 1.1 haad pv->pe_alloc_count = 0; 175 1.1 haad if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) { 176 1.1 haad log_error("pv_write with new uuid failed " 177 1.1 haad "for %s.", pv_name); 178 1.1.1.2 haad goto out; 179 1.1 haad } 180 1.1 haad pv->vg_name = orig_vg_name; 181 1.1 haad pv->pe_alloc_count = orig_pe_alloc_count; 182 1.1 haad 183 1.1 haad pv->pe_size = orig_pe_size; 184 1.1 haad pv->pe_start = orig_pe_start; 185 1.1 haad pv->pe_count = orig_pe_count; 186 1.1 haad } 187 1.1 haad } 188 1.1 haad 189 1.1 haad log_verbose("Updating physical volume \"%s\"", pv_name); 190 1.1 haad if (!is_orphan(pv)) { 191 1.1 haad if (!vg_write(vg) || !vg_commit(vg)) { 192 1.1 haad log_error("Failed to store physical volume \"%s\" in " 193 1.1 haad "volume group \"%s\"", pv_name, vg->name); 194 1.1.1.2 haad goto out; 195 1.1 haad } 196 1.1 haad backup(vg); 197 1.1 haad } else if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) { 198 1.1 haad log_error("Failed to store physical volume \"%s\"", 199 1.1 haad pv_name); 200 1.1.1.2 haad goto out; 201 1.1 haad } 202 1.1 haad 203 1.1 haad log_print("Physical volume \"%s\" changed", pv_name); 204 1.1.1.2 haad r = 1; 205 1.1.1.2 haad out: 206 1.1.1.2 haad unlock_and_release_vg(cmd, vg, vg_name); 207 1.1.1.2 haad return r; 208 1.1 haad 209 1.1 haad } 210 1.1 haad 211 1.1 haad int pvchange(struct cmd_context *cmd, int argc, char **argv) 212 1.1 haad { 213 1.1 haad int opt = 0; 214 1.1 haad int done = 0; 215 1.1 haad int total = 0; 216 1.1 haad 217 1.1 haad struct physical_volume *pv; 218 1.1 haad char *pv_name; 219 1.1 haad 220 1.1 haad struct pv_list *pvl; 221 1.1 haad struct dm_list *pvslist; 222 1.1 haad struct dm_list mdas; 223 1.1 haad 224 1.1 haad if (arg_count(cmd, allocatable_ARG) + arg_count(cmd, addtag_ARG) + 225 1.1 haad arg_count(cmd, deltag_ARG) + arg_count(cmd, uuid_ARG) != 1) { 226 1.1 haad log_error("Please give exactly one option of -x, -uuid, " 227 1.1 haad "--addtag or --deltag"); 228 1.1 haad return EINVALID_CMD_LINE; 229 1.1 haad } 230 1.1 haad 231 1.1 haad if (!(arg_count(cmd, all_ARG)) && !argc) { 232 1.1 haad log_error("Please give a physical volume path"); 233 1.1 haad return EINVALID_CMD_LINE; 234 1.1 haad } 235 1.1 haad 236 1.1 haad if (arg_count(cmd, all_ARG) && argc) { 237 1.1 haad log_error("Option a and PhysicalVolumePath are exclusive"); 238 1.1 haad return EINVALID_CMD_LINE; 239 1.1 haad } 240 1.1 haad 241 1.1 haad if (argc) { 242 1.1 haad log_verbose("Using physical volume(s) on command line"); 243 1.1 haad for (; opt < argc; opt++) { 244 1.1 haad pv_name = argv[opt]; 245 1.1 haad dm_list_init(&mdas); 246 1.1.1.2 haad if (!(pv = pv_read(cmd, pv_name, &mdas, NULL, 1, 0))) { 247 1.1 haad log_error("Failed to read physical volume %s", 248 1.1 haad pv_name); 249 1.1 haad continue; 250 1.1 haad } 251 1.1 haad /* 252 1.1 haad * If a PV has no MDAs it may appear to be an 253 1.1 haad * orphan until the metadata is read off 254 1.1 haad * another PV in the same VG. Detecting this 255 1.1 haad * means checking every VG by scanning every 256 1.1 haad * PV on the system. 257 1.1 haad */ 258 1.1 haad if (is_orphan(pv) && !dm_list_size(&mdas)) { 259 1.1 haad if (!scan_vgs_for_pvs(cmd)) { 260 1.1 haad log_error("Rescan for PVs without " 261 1.1 haad "metadata areas failed."); 262 1.1 haad continue; 263 1.1 haad } 264 1.1 haad if (!(pv = pv_read(cmd, pv_name, 265 1.1.1.2 haad NULL, NULL, 1, 0))) { 266 1.1 haad log_error("Failed to read " 267 1.1 haad "physical volume %s", 268 1.1 haad pv_name); 269 1.1 haad continue; 270 1.1 haad } 271 1.1 haad } 272 1.1 haad 273 1.1 haad total++; 274 1.1 haad done += _pvchange_single(cmd, pv, NULL); 275 1.1 haad } 276 1.1 haad } else { 277 1.1 haad log_verbose("Scanning for physical volume names"); 278 1.1 haad if (!(pvslist = get_pvs(cmd))) { 279 1.1.1.2 haad stack; 280 1.1 haad return ECMD_FAILED; 281 1.1 haad } 282 1.1 haad 283 1.1 haad dm_list_iterate_items(pvl, pvslist) { 284 1.1 haad total++; 285 1.1 haad done += _pvchange_single(cmd, pvl->pv, NULL); 286 1.1 haad } 287 1.1 haad } 288 1.1 haad 289 1.1 haad log_print("%d physical volume%s changed / %d physical volume%s " 290 1.1 haad "not changed", 291 1.1 haad done, done == 1 ? "" : "s", 292 1.1 haad total - done, (total - done) == 1 ? "" : "s"); 293 1.1 haad 294 1.1 haad return (total == done) ? ECMD_PROCESSED : ECMD_FAILED; 295 1.1 haad } 296