Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / lib / metadata / pv_map.c
blobb0e7440a07720e2226a9ae0ba8f431ba10643c92
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2001-2004 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
18 #include "lib.h"
19 #include "pv_map.h"
20 #include "pv_alloc.h"
22 #include <assert.h>
25 * Areas are maintained in size order, largest first.
27 * FIXME Cope with overlap.
29 static void _insert_area(struct dm_list *head, struct pv_area *a)
31 struct pv_area *pva;
33 dm_list_iterate_items(pva, head) {
34 if (a->count > pva->count)
35 break;
38 dm_list_add(&pva->list, &a->list);
39 a->map->pe_count += a->count;
42 static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm,
43 uint32_t start, uint32_t length)
45 struct pv_area *pva;
47 if (!(pva = dm_pool_zalloc(mem, sizeof(*pva))))
48 return_0;
50 log_debug("Allowing allocation on %s start PE %" PRIu32 " length %"
51 PRIu32, pv_dev_name(pvm->pv), start, length);
52 pva->map = pvm;
53 pva->start = start;
54 pva->count = length;
55 _insert_area(&pvm->areas, pva);
57 return 1;
60 static int _create_alloc_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm,
61 uint32_t start, uint32_t count)
63 struct pv_segment *peg;
64 uint32_t pe, end, area_len;
66 /* Only select extents from start to end inclusive */
67 end = start + count - 1;
68 if (end > pvm->pv->pe_count - 1)
69 end = pvm->pv->pe_count - 1;
71 pe = start;
73 /* Walk through complete ordered list of device segments */
74 dm_list_iterate_items(peg, &pvm->pv->segments) {
75 /* pe holds the next extent we want to check */
77 /* Beyond the range we're interested in? */
78 if (pe > end)
79 break;
81 /* Skip if we haven't reached the first seg we want yet */
82 if (pe > peg->pe + peg->len - 1)
83 continue;
85 /* Free? */
86 if (peg->lvseg)
87 goto next;
89 /* How much of this peg do we need? */
90 area_len = (end >= peg->pe + peg->len - 1) ?
91 peg->len - (pe - peg->pe) : end - pe + 1;
93 if (!_create_single_area(mem, pvm, pe, area_len))
94 return_0;
96 next:
97 pe = peg->pe + peg->len;
100 return 1;
103 static int _create_all_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm,
104 struct dm_list *pe_ranges)
106 struct pe_range *aa;
108 if (!pe_ranges) {
109 /* Use whole PV */
110 if (!_create_alloc_areas_for_pv(mem, pvm, UINT32_C(0),
111 pvm->pv->pe_count))
112 return_0;
114 return 1;
117 dm_list_iterate_items(aa, pe_ranges) {
118 if (!_create_alloc_areas_for_pv(mem, pvm, aa->start,
119 aa->count))
120 return_0;
123 return 1;
126 static int _create_maps(struct dm_pool *mem, struct dm_list *pvs, struct dm_list *pvms)
128 struct pv_map *pvm, *pvm2;
129 struct pv_list *pvl;
131 dm_list_iterate_items(pvl, pvs) {
132 if (!(pvl->pv->status & ALLOCATABLE_PV))
133 continue;
134 if (pvl->pv->status & MISSING_PV)
135 continue;
136 assert(pvl->pv->dev);
138 pvm = NULL;
140 dm_list_iterate_items(pvm2, pvms)
141 if (pvm2->pv->dev == pvl->pv->dev) {
142 pvm = pvm2;
143 break;
146 if (!pvm) {
147 if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm))))
148 return_0;
150 pvm->pv = pvl->pv;
151 dm_list_init(&pvm->areas);
152 dm_list_add(pvms, &pvm->list);
155 if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges))
156 return_0;
159 return 1;
163 * Create list of PV areas available for this particular allocation
165 struct dm_list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
166 struct dm_list *allocatable_pvs)
168 struct dm_list *pvms;
170 if (!(pvms = dm_pool_zalloc(mem, sizeof(*pvms)))) {
171 log_error("create_pv_maps alloc failed");
172 return NULL;
175 dm_list_init(pvms);
177 if (!_create_maps(mem, allocatable_pvs, pvms)) {
178 log_error("Couldn't create physical volume maps in %s",
179 vg->name);
180 dm_pool_free(mem, pvms);
181 return NULL;
184 return pvms;
187 void consume_pv_area(struct pv_area *pva, uint32_t to_go)
189 dm_list_del(&pva->list);
190 pva->map->pe_count -= pva->count;
192 assert(to_go <= pva->count);
194 if (to_go < pva->count) {
195 /* split the area */
196 pva->start += to_go;
197 pva->count -= to_go;
198 _insert_area(&pva->map->areas, pva);
202 uint32_t pv_maps_size(struct dm_list *pvms)
204 struct pv_map *pvm;
205 uint32_t pe_count = 0;
207 dm_list_iterate_items(pvm, pvms)
208 pe_count += pvm->pe_count;
210 return pe_count;