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