1 1.1 haad /* $NetBSD: pv_manip.c,v 1.1.1.1 2008/12/22 00:18:09 haad Exp $ */ 2 1.1 haad 3 1.1 haad /* 4 1.1 haad * Copyright (C) 2003 Sistina Software, Inc. All rights reserved. 5 1.1 haad * Copyright (C) 2004-2006 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 "lib.h" 19 1.1 haad #include "metadata.h" 20 1.1 haad #include "pv_alloc.h" 21 1.1 haad #include "toolcontext.h" 22 1.1 haad #include "archiver.h" 23 1.1 haad #include "locking.h" 24 1.1 haad #include "lvmcache.h" 25 1.1 haad 26 1.1 haad static struct pv_segment *_alloc_pv_segment(struct dm_pool *mem, 27 1.1 haad struct physical_volume *pv, 28 1.1 haad uint32_t pe, uint32_t len, 29 1.1 haad struct lv_segment *lvseg, 30 1.1 haad uint32_t lv_area) 31 1.1 haad { 32 1.1 haad struct pv_segment *peg; 33 1.1 haad 34 1.1 haad if (!(peg = dm_pool_zalloc(mem, sizeof(*peg)))) { 35 1.1 haad log_error("pv_segment allocation failed"); 36 1.1 haad return NULL; 37 1.1 haad } 38 1.1 haad 39 1.1 haad peg->pv = pv; 40 1.1 haad peg->pe = pe; 41 1.1 haad peg->len = len; 42 1.1 haad peg->lvseg = lvseg; 43 1.1 haad peg->lv_area = lv_area; 44 1.1 haad 45 1.1 haad dm_list_init(&peg->list); 46 1.1 haad 47 1.1 haad return peg; 48 1.1 haad } 49 1.1 haad 50 1.1 haad int alloc_pv_segment_whole_pv(struct dm_pool *mem, struct physical_volume *pv) 51 1.1 haad { 52 1.1 haad struct pv_segment *peg; 53 1.1 haad 54 1.1 haad if (!pv->pe_count) 55 1.1 haad return 1; 56 1.1 haad 57 1.1 haad /* FIXME Cope with holes in PVs */ 58 1.1 haad if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count, NULL, 0))) 59 1.1 haad return_0; 60 1.1 haad 61 1.1 haad dm_list_add(&pv->segments, &peg->list); 62 1.1 haad 63 1.1 haad return 1; 64 1.1 haad } 65 1.1 haad 66 1.1 haad int peg_dup(struct dm_pool *mem, struct dm_list *peg_new, struct dm_list *peg_old) 67 1.1 haad { 68 1.1 haad struct pv_segment *peg, *pego; 69 1.1 haad 70 1.1 haad dm_list_init(peg_new); 71 1.1 haad 72 1.1 haad dm_list_iterate_items(pego, peg_old) { 73 1.1 haad if (!(peg = _alloc_pv_segment(mem, pego->pv, pego->pe, 74 1.1 haad pego->len, pego->lvseg, 75 1.1 haad pego->lv_area))) 76 1.1 haad return_0; 77 1.1 haad dm_list_add(peg_new, &peg->list); 78 1.1 haad } 79 1.1 haad 80 1.1 haad return 1; 81 1.1 haad } 82 1.1 haad 83 1.1 haad /* 84 1.1 haad * Split peg at given extent. 85 1.1 haad * Second part is always deallocated. 86 1.1 haad */ 87 1.1 haad static int _pv_split_segment(struct physical_volume *pv, struct pv_segment *peg, 88 1.1 haad uint32_t pe) 89 1.1 haad { 90 1.1 haad struct pv_segment *peg_new; 91 1.1 haad 92 1.1 haad if (!(peg_new = _alloc_pv_segment(pv->fmt->cmd->mem, peg->pv, pe, 93 1.1 haad peg->len + peg->pe - pe, 94 1.1 haad NULL, 0))) 95 1.1 haad return_0; 96 1.1 haad 97 1.1 haad peg->len = peg->len - peg_new->len; 98 1.1 haad 99 1.1 haad dm_list_add_h(&peg->list, &peg_new->list); 100 1.1 haad 101 1.1 haad if (peg->lvseg) { 102 1.1 haad peg->pv->pe_alloc_count -= peg_new->len; 103 1.1 haad peg->lvseg->lv->vg->free_count += peg_new->len; 104 1.1 haad } 105 1.1 haad 106 1.1 haad return 1; 107 1.1 haad } 108 1.1 haad 109 1.1 haad /* 110 1.1 haad * Ensure there is a PV segment boundary at the given extent. 111 1.1 haad */ 112 1.1 haad int pv_split_segment(struct physical_volume *pv, uint32_t pe) 113 1.1 haad { 114 1.1 haad struct pv_segment *peg; 115 1.1 haad 116 1.1 haad if (pe == pv->pe_count) 117 1.1 haad return 1; 118 1.1 haad 119 1.1 haad if (!(peg = find_peg_by_pe(pv, pe))) { 120 1.1 haad log_error("Segment with extent %" PRIu32 " in PV %s not found", 121 1.1 haad pe, pv_dev_name(pv)); 122 1.1 haad return 0; 123 1.1 haad } 124 1.1 haad 125 1.1 haad /* This is a peg start already */ 126 1.1 haad if (pe == peg->pe) 127 1.1 haad return 1; 128 1.1 haad 129 1.1 haad if (!_pv_split_segment(pv, peg, pe)) 130 1.1 haad return_0; 131 1.1 haad 132 1.1 haad return 1; 133 1.1 haad } 134 1.1 haad 135 1.1 haad static struct pv_segment null_pv_segment = { 136 1.1 haad .pv = NULL, 137 1.1 haad .pe = 0, 138 1.1 haad }; 139 1.1 haad 140 1.1 haad struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, 141 1.1 haad uint32_t pe, uint32_t area_len, 142 1.1 haad struct lv_segment *seg, 143 1.1 haad uint32_t area_num) 144 1.1 haad { 145 1.1 haad struct pv_segment *peg; 146 1.1 haad 147 1.1 haad /* Missing format1 PV */ 148 1.1 haad if (!pv) 149 1.1 haad return &null_pv_segment; 150 1.1 haad 151 1.1 haad if (!pv_split_segment(pv, pe) || 152 1.1 haad !pv_split_segment(pv, pe + area_len)) 153 1.1 haad return_NULL; 154 1.1 haad 155 1.1 haad if (!(peg = find_peg_by_pe(pv, pe))) { 156 1.1 haad log_error("Missing PV segment on %s at %u.", 157 1.1 haad pv_dev_name(pv), pe); 158 1.1 haad return NULL; 159 1.1 haad } 160 1.1 haad 161 1.1 haad peg->lvseg = seg; 162 1.1 haad peg->lv_area = area_num; 163 1.1 haad 164 1.1 haad peg->pv->pe_alloc_count += area_len; 165 1.1 haad peg->lvseg->lv->vg->free_count -= area_len; 166 1.1 haad 167 1.1 haad return peg; 168 1.1 haad } 169 1.1 haad 170 1.1 haad int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction) 171 1.1 haad { 172 1.1 haad if (!peg->lvseg) { 173 1.1 haad log_error("release_pv_segment with unallocated segment: " 174 1.1 haad "%s PE %" PRIu32, pv_dev_name(peg->pv), peg->pe); 175 1.1 haad return 0; 176 1.1 haad } 177 1.1 haad 178 1.1 haad if (peg->lvseg->area_len == area_reduction) { 179 1.1 haad peg->pv->pe_alloc_count -= area_reduction; 180 1.1 haad peg->lvseg->lv->vg->free_count += area_reduction; 181 1.1 haad 182 1.1 haad peg->lvseg = NULL; 183 1.1 haad peg->lv_area = 0; 184 1.1 haad 185 1.1 haad /* FIXME merge free space */ 186 1.1 haad 187 1.1 haad return 1; 188 1.1 haad } 189 1.1 haad 190 1.1 haad if (!pv_split_segment(peg->pv, peg->pe + peg->lvseg->area_len - 191 1.1 haad area_reduction)) 192 1.1 haad return_0; 193 1.1 haad 194 1.1 haad return 1; 195 1.1 haad } 196 1.1 haad 197 1.1 haad /* 198 1.1 haad * Only for use by lv_segment merging routines. 199 1.1 haad */ 200 1.1 haad void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2) 201 1.1 haad { 202 1.1 haad peg1->len += peg2->len; 203 1.1 haad 204 1.1 haad dm_list_del(&peg2->list); 205 1.1 haad } 206 1.1 haad 207 1.1 haad /* 208 1.1 haad * Calculate the overlap, in extents, between a struct pv_segment and 209 1.1 haad * a struct pe_range. 210 1.1 haad */ 211 1.1 haad static uint32_t _overlap_pe(const struct pv_segment *pvseg, 212 1.1 haad const struct pe_range *per) 213 1.1 haad { 214 1.1 haad uint32_t start; 215 1.1 haad uint32_t end; 216 1.1 haad 217 1.1 haad start = max(pvseg->pe, per->start); 218 1.1 haad end = min(pvseg->pe + pvseg->len, per->start + per->count); 219 1.1 haad if (end < start) 220 1.1 haad return 0; 221 1.1 haad else 222 1.1 haad return end - start; 223 1.1 haad } 224 1.1 haad 225 1.1 haad /* 226 1.1 haad * Returns: number of free PEs in a struct pv_list 227 1.1 haad */ 228 1.1 haad uint32_t pv_list_extents_free(const struct dm_list *pvh) 229 1.1 haad { 230 1.1 haad struct pv_list *pvl; 231 1.1 haad struct pe_range *per; 232 1.1 haad uint32_t extents = 0; 233 1.1 haad struct pv_segment *pvseg; 234 1.1 haad 235 1.1 haad dm_list_iterate_items(pvl, pvh) { 236 1.1 haad dm_list_iterate_items(per, pvl->pe_ranges) { 237 1.1 haad dm_list_iterate_items(pvseg, &pvl->pv->segments) { 238 1.1 haad if (!pvseg_is_allocated(pvseg)) 239 1.1 haad extents += _overlap_pe(pvseg, per); 240 1.1 haad } 241 1.1 haad } 242 1.1 haad } 243 1.1 haad 244 1.1 haad return extents; 245 1.1 haad } 246 1.1 haad 247 1.1 haad /* 248 1.1 haad * Check all pv_segments in VG for consistency 249 1.1 haad */ 250 1.1 haad int check_pv_segments(struct volume_group *vg) 251 1.1 haad { 252 1.1 haad struct physical_volume *pv; 253 1.1 haad struct pv_list *pvl; 254 1.1 haad struct pv_segment *peg; 255 1.1 haad unsigned s, segno; 256 1.1 haad uint32_t start_pe, alloced; 257 1.1 haad uint32_t pv_count = 0, free_count = 0, extent_count = 0; 258 1.1 haad int ret = 1; 259 1.1 haad 260 1.1 haad dm_list_iterate_items(pvl, &vg->pvs) { 261 1.1 haad pv = pvl->pv; 262 1.1 haad segno = 0; 263 1.1 haad start_pe = 0; 264 1.1 haad alloced = 0; 265 1.1 haad pv_count++; 266 1.1 haad 267 1.1 haad dm_list_iterate_items(peg, &pv->segments) { 268 1.1 haad s = peg->lv_area; 269 1.1 haad 270 1.1 haad /* FIXME Remove this next line eventually */ 271 1.1 haad log_debug("%s %u: %6u %6u: %s(%u:%u)", 272 1.1 haad pv_dev_name(pv), segno++, peg->pe, peg->len, 273 1.1 haad peg->lvseg ? peg->lvseg->lv->name : "NULL", 274 1.1 haad peg->lvseg ? peg->lvseg->le : 0, s); 275 1.1 haad /* FIXME Add details here on failure instead */ 276 1.1 haad if (start_pe != peg->pe) { 277 1.1 haad log_error("Gap in pvsegs: %u, %u", 278 1.1 haad start_pe, peg->pe); 279 1.1 haad ret = 0; 280 1.1 haad } 281 1.1 haad if (peg->lvseg) { 282 1.1 haad if (seg_type(peg->lvseg, s) != AREA_PV) { 283 1.1 haad log_error("Wrong lvseg area type"); 284 1.1 haad ret = 0; 285 1.1 haad } 286 1.1 haad if (seg_pvseg(peg->lvseg, s) != peg) { 287 1.1 haad log_error("Inconsistent pvseg pointers"); 288 1.1 haad ret = 0; 289 1.1 haad } 290 1.1 haad if (peg->lvseg->area_len != peg->len) { 291 1.1 haad log_error("Inconsistent length: %u %u", 292 1.1 haad peg->len, 293 1.1 haad peg->lvseg->area_len); 294 1.1 haad ret = 0; 295 1.1 haad } 296 1.1 haad alloced += peg->len; 297 1.1 haad } 298 1.1 haad start_pe += peg->len; 299 1.1 haad } 300 1.1 haad 301 1.1 haad if (start_pe != pv->pe_count) { 302 1.1 haad log_error("PV segment pe_count mismatch: %u != %u", 303 1.1 haad start_pe, pv->pe_count); 304 1.1 haad ret = 0; 305 1.1 haad } 306 1.1 haad 307 1.1 haad if (alloced != pv->pe_alloc_count) { 308 1.1 haad log_error("PV segment pe_alloc_count mismatch: " 309 1.1 haad "%u != %u", alloced, pv->pe_alloc_count); 310 1.1 haad ret = 0; 311 1.1 haad } 312 1.1 haad 313 1.1 haad extent_count += start_pe; 314 1.1 haad free_count += (start_pe - alloced); 315 1.1 haad } 316 1.1 haad 317 1.1 haad if (pv_count != vg->pv_count) { 318 1.1 haad log_error("PV segment VG pv_count mismatch: %u != %u", 319 1.1 haad pv_count, vg->pv_count); 320 1.1 haad ret = 0; 321 1.1 haad } 322 1.1 haad 323 1.1 haad if (free_count != vg->free_count) { 324 1.1 haad log_error("PV segment VG free_count mismatch: %u != %u", 325 1.1 haad free_count, vg->free_count); 326 1.1 haad ret = 0; 327 1.1 haad } 328 1.1 haad 329 1.1 haad if (extent_count != vg->extent_count) { 330 1.1 haad log_error("PV segment VG extent_count mismatch: %u != %u", 331 1.1 haad extent_count, vg->extent_count); 332 1.1 haad ret = 0; 333 1.1 haad } 334 1.1 haad 335 1.1 haad return ret; 336 1.1 haad } 337 1.1 haad 338 1.1 haad static int _reduce_pv(struct physical_volume *pv, struct volume_group *vg, uint32_t new_pe_count) 339 1.1 haad { 340 1.1 haad struct pv_segment *peg, *pegt; 341 1.1 haad uint32_t old_pe_count = pv->pe_count; 342 1.1 haad 343 1.1 haad if (new_pe_count < pv->pe_alloc_count) { 344 1.1 haad log_error("%s: cannot resize to %" PRIu32 " extents " 345 1.1 haad "as %" PRIu32 " are allocated.", 346 1.1 haad pv_dev_name(pv), new_pe_count, 347 1.1 haad pv->pe_alloc_count); 348 1.1 haad return 0; 349 1.1 haad } 350 1.1 haad 351 1.1 haad /* Check PEs to be removed are not already allocated */ 352 1.1 haad dm_list_iterate_items(peg, &pv->segments) { 353 1.1 haad if (peg->pe + peg->len <= new_pe_count) 354 1.1 haad continue; 355 1.1 haad 356 1.1 haad if (peg->lvseg) { 357 1.1 haad log_error("%s: cannot resize to %" PRIu32 " extents as " 358 1.1 haad "later ones are allocated.", 359 1.1 haad pv_dev_name(pv), new_pe_count); 360 1.1 haad return 0; 361 1.1 haad } 362 1.1 haad } 363 1.1 haad 364 1.1 haad if (!pv_split_segment(pv, new_pe_count)) 365 1.1 haad return_0; 366 1.1 haad 367 1.1 haad dm_list_iterate_items_safe(peg, pegt, &pv->segments) { 368 1.1 haad if (peg->pe + peg->len > new_pe_count) 369 1.1 haad dm_list_del(&peg->list); 370 1.1 haad } 371 1.1 haad 372 1.1 haad pv->pe_count = new_pe_count; 373 1.1 haad 374 1.1 haad vg->extent_count -= (old_pe_count - new_pe_count); 375 1.1 haad vg->free_count -= (old_pe_count - new_pe_count); 376 1.1 haad 377 1.1 haad return 1; 378 1.1 haad } 379 1.1 haad 380 1.1 haad static int _extend_pv(struct physical_volume *pv, struct volume_group *vg, 381 1.1 haad uint32_t new_pe_count) 382 1.1 haad { 383 1.1 haad struct pv_segment *peg; 384 1.1 haad uint32_t old_pe_count = pv->pe_count; 385 1.1 haad 386 1.1 haad if ((uint64_t) new_pe_count * pv->pe_size > pv->size ) { 387 1.1 haad log_error("%s: cannot resize to %" PRIu32 " extents as there " 388 1.1 haad "is only room for %" PRIu64 ".", pv_dev_name(pv), 389 1.1 haad new_pe_count, pv->size / pv->pe_size); 390 1.1 haad return 0; 391 1.1 haad } 392 1.1 haad 393 1.1 haad peg = _alloc_pv_segment(pv->fmt->cmd->mem, pv, 394 1.1 haad old_pe_count, 395 1.1 haad new_pe_count - old_pe_count, 396 1.1 haad NULL, 0); 397 1.1 haad dm_list_add(&pv->segments, &peg->list); 398 1.1 haad 399 1.1 haad pv->pe_count = new_pe_count; 400 1.1 haad 401 1.1 haad vg->extent_count += (new_pe_count - old_pe_count); 402 1.1 haad vg->free_count += (new_pe_count - old_pe_count); 403 1.1 haad 404 1.1 haad return 1; 405 1.1 haad } 406 1.1 haad 407 1.1 haad /* 408 1.1 haad * Resize a PV in a VG, adding or removing segments as needed. 409 1.1 haad * New size must fit within pv->size. 410 1.1 haad */ 411 1.1 haad int pv_resize(struct physical_volume *pv, 412 1.1 haad struct volume_group *vg, 413 1.1 haad uint32_t new_pe_count) 414 1.1 haad { 415 1.1 haad if ((new_pe_count == pv->pe_count)) { 416 1.1 haad log_verbose("No change to size of physical volume %s.", 417 1.1 haad pv_dev_name(pv)); 418 1.1 haad return 1; 419 1.1 haad } 420 1.1 haad 421 1.1 haad log_verbose("Resizing physical volume %s from %" PRIu32 422 1.1 haad " to %" PRIu32 " extents.", 423 1.1 haad pv_dev_name(pv), pv->pe_count, new_pe_count); 424 1.1 haad 425 1.1 haad if (new_pe_count > pv->pe_count) 426 1.1 haad return _extend_pv(pv, vg, new_pe_count); 427 1.1 haad else 428 1.1 haad return _reduce_pv(pv, vg, new_pe_count); 429 1.1 haad } 430