4 * Copyright (C) 2003 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2006 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
21 #include "toolcontext.h"
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
,
32 struct pv_segment
*peg
;
34 if (!(peg
= dm_pool_zalloc(mem
, sizeof(*peg
)))) {
35 log_error("pv_segment allocation failed");
43 peg
->lv_area
= lv_area
;
45 dm_list_init(&peg
->list
);
50 int alloc_pv_segment_whole_pv(struct dm_pool
*mem
, struct physical_volume
*pv
)
52 struct pv_segment
*peg
;
57 /* FIXME Cope with holes in PVs */
58 if (!(peg
= _alloc_pv_segment(mem
, pv
, 0, pv
->pe_count
, NULL
, 0)))
61 dm_list_add(&pv
->segments
, &peg
->list
);
66 int peg_dup(struct dm_pool
*mem
, struct dm_list
*peg_new
, struct dm_list
*peg_old
)
68 struct pv_segment
*peg
, *pego
;
70 dm_list_init(peg_new
);
72 dm_list_iterate_items(pego
, peg_old
) {
73 if (!(peg
= _alloc_pv_segment(mem
, pego
->pv
, pego
->pe
,
74 pego
->len
, pego
->lvseg
,
77 dm_list_add(peg_new
, &peg
->list
);
84 * Split peg at given extent.
85 * Second part is always deallocated.
87 static int _pv_split_segment(struct physical_volume
*pv
, struct pv_segment
*peg
,
90 struct pv_segment
*peg_new
;
92 if (!(peg_new
= _alloc_pv_segment(pv
->fmt
->cmd
->mem
, peg
->pv
, pe
,
93 peg
->len
+ peg
->pe
- pe
,
97 peg
->len
= peg
->len
- peg_new
->len
;
99 dm_list_add_h(&peg
->list
, &peg_new
->list
);
102 peg
->pv
->pe_alloc_count
-= peg_new
->len
;
103 peg
->lvseg
->lv
->vg
->free_count
+= peg_new
->len
;
110 * Ensure there is a PV segment boundary at the given extent.
112 int pv_split_segment(struct physical_volume
*pv
, uint32_t pe
)
114 struct pv_segment
*peg
;
116 if (pe
== pv
->pe_count
)
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
));
125 /* This is a peg start already */
129 if (!_pv_split_segment(pv
, peg
, pe
))
135 static struct pv_segment null_pv_segment
= {
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
,
145 struct pv_segment
*peg
;
147 /* Missing format1 PV */
149 return &null_pv_segment
;
151 if (!pv_split_segment(pv
, pe
) ||
152 !pv_split_segment(pv
, pe
+ area_len
))
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
);
162 peg
->lv_area
= area_num
;
164 peg
->pv
->pe_alloc_count
+= area_len
;
165 peg
->lvseg
->lv
->vg
->free_count
-= area_len
;
170 int release_pv_segment(struct pv_segment
*peg
, uint32_t area_reduction
)
173 log_error("release_pv_segment with unallocated segment: "
174 "%s PE %" PRIu32
, pv_dev_name(peg
->pv
), peg
->pe
);
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
;
185 /* FIXME merge free space */
190 if (!pv_split_segment(peg
->pv
, peg
->pe
+ peg
->lvseg
->area_len
-
198 * Only for use by lv_segment merging routines.
200 void merge_pv_segments(struct pv_segment
*peg1
, struct pv_segment
*peg2
)
202 peg1
->len
+= peg2
->len
;
204 dm_list_del(&peg2
->list
);
208 * Calculate the overlap, in extents, between a struct pv_segment and
211 static uint32_t _overlap_pe(const struct pv_segment
*pvseg
,
212 const struct pe_range
*per
)
217 start
= max(pvseg
->pe
, per
->start
);
218 end
= min(pvseg
->pe
+ pvseg
->len
, per
->start
+ per
->count
);
226 * Returns: number of free PEs in a struct pv_list
228 uint32_t pv_list_extents_free(const struct dm_list
*pvh
)
231 struct pe_range
*per
;
232 uint32_t extents
= 0;
233 struct pv_segment
*pvseg
;
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
);
248 * Check all pv_segments in VG for consistency
250 int check_pv_segments(struct volume_group
*vg
)
252 struct physical_volume
*pv
;
254 struct pv_segment
*peg
;
256 uint32_t start_pe
, alloced
;
257 uint32_t pv_count
= 0, free_count
= 0, extent_count
= 0;
260 dm_list_iterate_items(pvl
, &vg
->pvs
) {
267 dm_list_iterate_items(peg
, &pv
->segments
) {
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",
282 if (seg_type(peg
->lvseg
, s
) != AREA_PV
) {
283 log_error("Wrong lvseg area type");
286 if (seg_pvseg(peg
->lvseg
, s
) != peg
) {
287 log_error("Inconsistent pvseg pointers");
290 if (peg
->lvseg
->area_len
!= peg
->len
) {
291 log_error("Inconsistent length: %u %u",
293 peg
->lvseg
->area_len
);
298 start_pe
+= peg
->len
;
301 if (start_pe
!= pv
->pe_count
) {
302 log_error("PV segment pe_count mismatch: %u != %u",
303 start_pe
, pv
->pe_count
);
307 if (alloced
!= pv
->pe_alloc_count
) {
308 log_error("PV segment pe_alloc_count mismatch: "
309 "%u != %u", alloced
, pv
->pe_alloc_count
);
313 extent_count
+= start_pe
;
314 free_count
+= (start_pe
- alloced
);
317 if (pv_count
!= vg
->pv_count
) {
318 log_error("PV segment VG pv_count mismatch: %u != %u",
319 pv_count
, vg
->pv_count
);
323 if (free_count
!= vg
->free_count
) {
324 log_error("PV segment VG free_count mismatch: %u != %u",
325 free_count
, vg
->free_count
);
329 if (extent_count
!= vg
->extent_count
) {
330 log_error("PV segment VG extent_count mismatch: %u != %u",
331 extent_count
, vg
->extent_count
);
338 static int _reduce_pv(struct physical_volume
*pv
, struct volume_group
*vg
, uint32_t new_pe_count
)
340 struct pv_segment
*peg
, *pegt
;
341 uint32_t old_pe_count
= pv
->pe_count
;
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
,
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
)
357 log_error("%s: cannot resize to %" PRIu32
" extents as "
358 "later ones are allocated.",
359 pv_dev_name(pv
), new_pe_count
);
364 if (!pv_split_segment(pv
, new_pe_count
))
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
);
372 pv
->pe_count
= new_pe_count
;
374 vg
->extent_count
-= (old_pe_count
- new_pe_count
);
375 vg
->free_count
-= (old_pe_count
- new_pe_count
);
380 static int _extend_pv(struct physical_volume
*pv
, struct volume_group
*vg
,
381 uint32_t new_pe_count
)
383 struct pv_segment
*peg
;
384 uint32_t old_pe_count
= pv
->pe_count
;
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
);
393 peg
= _alloc_pv_segment(pv
->fmt
->cmd
->mem
, pv
,
395 new_pe_count
- old_pe_count
,
397 dm_list_add(&pv
->segments
, &peg
->list
);
399 pv
->pe_count
= new_pe_count
;
401 vg
->extent_count
+= (new_pe_count
- old_pe_count
);
402 vg
->free_count
+= (new_pe_count
- old_pe_count
);
408 * Resize a PV in a VG, adding or removing segments as needed.
409 * New size must fit within pv->size.
411 int pv_resize(struct physical_volume
*pv
,
412 struct volume_group
*vg
,
413 uint32_t new_pe_count
)
415 if ((new_pe_count
== pv
->pe_count
)) {
416 log_verbose("No change to size of physical volume %s.",
421 log_verbose("Resizing physical volume %s from %" PRIu32
422 " to %" PRIu32
" extents.",
423 pv_dev_name(pv
), pv
->pe_count
, new_pe_count
);
425 if (new_pe_count
> pv
->pe_count
)
426 return _extend_pv(pv
, vg
, new_pe_count
);
428 return _reduce_pv(pv
, vg
, new_pe_count
);