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 
_alloc_pv_segment(struct dm_pool * mem,struct physical_volume * pv,uint32_t pe,uint32_t len,struct lv_segment * lvseg,uint32_t lv_area)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 
alloc_pv_segment_whole_pv(struct dm_pool * mem,struct physical_volume * pv)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 
peg_dup(struct dm_pool * mem,struct dm_list * peg_new,struct dm_list * peg_old)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  */
_pv_split_segment(struct physical_volume * pv,struct pv_segment * peg,uint32_t pe)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  */
pv_split_segment(struct physical_volume * pv,uint32_t pe)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 
assign_peg_to_lvseg(struct physical_volume * pv,uint32_t pe,uint32_t area_len,struct lv_segment * seg,uint32_t area_num)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 
release_pv_segment(struct pv_segment * peg,uint32_t area_reduction)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  */
merge_pv_segments(struct pv_segment * peg1,struct pv_segment * peg2)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  */
_overlap_pe(const struct pv_segment * pvseg,const struct pe_range * per)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  */
pv_list_extents_free(const struct dm_list * pvh)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  */
check_pv_segments(struct volume_group * vg)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 
_reduce_pv(struct physical_volume * pv,struct volume_group * vg,uint32_t new_pe_count)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 
_extend_pv(struct physical_volume * pv,struct volume_group * vg,uint32_t new_pe_count)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  */
pv_resize(struct physical_volume * pv,struct volume_group * vg,uint32_t new_pe_count)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