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