Home | History | Annotate | Line # | Download | only in metadata
      1 /*	$NetBSD: pv_map.c,v 1.1.1.2 2009/12/02 00:26:41 haad Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2001-2004 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 "pv_map.h"
     20 #include "pv_alloc.h"
     21 
     22 #include <assert.h>
     23 
     24 /*
     25  * Areas are maintained in size order, largest first.
     26  *
     27  * FIXME Cope with overlap.
     28  */
     29 static void _insert_area(struct dm_list *head, struct pv_area *a)
     30 {
     31 	struct pv_area *pva;
     32 
     33 	dm_list_iterate_items(pva, head) {
     34 		if (a->count > pva->count)
     35 			break;
     36 	}
     37 
     38 	dm_list_add(&pva->list, &a->list);
     39 	a->map->pe_count += a->count;
     40 }
     41 
     42 static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm,
     43 			       uint32_t start, uint32_t length)
     44 {
     45 	struct pv_area *pva;
     46 
     47 	if (!(pva = dm_pool_zalloc(mem, sizeof(*pva))))
     48 		return_0;
     49 
     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);
     56 
     57 	return 1;
     58 }
     59 
     60 static int _create_alloc_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm,
     61 				      uint32_t start, uint32_t count)
     62 {
     63 	struct pv_segment *peg;
     64 	uint32_t pe, end, area_len;
     65 
     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;
     70 
     71 	pe = start;
     72 
     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 */
     76 
     77 		/* Beyond the range we're interested in? */
     78 		if (pe > end)
     79 			break;
     80 
     81 		/* Skip if we haven't reached the first seg we want yet */
     82 		if (pe > peg->pe + peg->len - 1)
     83 			continue;
     84 
     85 		/* Free? */
     86 		if (peg->lvseg)
     87 			goto next;
     88 
     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;
     92 
     93 		if (!_create_single_area(mem, pvm, pe, area_len))
     94 			return_0;
     95 
     96       next:
     97 		pe = peg->pe + peg->len;
     98 	}
     99 
    100 	return 1;
    101 }
    102 
    103 static int _create_all_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm,
    104 				    struct dm_list *pe_ranges)
    105 {
    106 	struct pe_range *aa;
    107 
    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;
    113 
    114 		return 1;
    115 	}
    116 
    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;
    121 	}
    122 
    123 	return 1;
    124 }
    125 
    126 static int _create_maps(struct dm_pool *mem, struct dm_list *pvs, struct dm_list *pvms)
    127 {
    128 	struct pv_map *pvm, *pvm2;
    129 	struct pv_list *pvl;
    130 
    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);
    137 
    138 		pvm = NULL;
    139 
    140 		dm_list_iterate_items(pvm2, pvms)
    141 			if (pvm2->pv->dev == pvl->pv->dev) {
    142 				pvm = pvm2;
    143 				break;
    144 			}
    145 
    146 		if (!pvm) {
    147 			if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm))))
    148 				return_0;
    149 
    150 			pvm->pv = pvl->pv;
    151 			dm_list_init(&pvm->areas);
    152 			dm_list_add(pvms, &pvm->list);
    153 		}
    154 
    155 		if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges))
    156 			return_0;
    157 	}
    158 
    159 	return 1;
    160 }
    161 
    162 /*
    163  * Create list of PV areas available for this particular allocation
    164  */
    165 struct dm_list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
    166 			    struct dm_list *allocatable_pvs)
    167 {
    168 	struct dm_list *pvms;
    169 
    170 	if (!(pvms = dm_pool_zalloc(mem, sizeof(*pvms)))) {
    171 		log_error("create_pv_maps alloc failed");
    172 		return NULL;
    173 	}
    174 
    175 	dm_list_init(pvms);
    176 
    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;
    182 	}
    183 
    184 	return pvms;
    185 }
    186 
    187 void consume_pv_area(struct pv_area *pva, uint32_t to_go)
    188 {
    189 	dm_list_del(&pva->list);
    190 	pva->map->pe_count -= pva->count;
    191 
    192 	assert(to_go <= pva->count);
    193 
    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);
    199 	}
    200 }
    201 
    202 uint32_t pv_maps_size(struct dm_list *pvms)
    203 {
    204 	struct pv_map *pvm;
    205 	uint32_t pe_count = 0;
    206 
    207 	dm_list_iterate_items(pvm, pvms)
    208 		pe_count += pvm->pe_count;
    209 
    210 	return pe_count;
    211 }
    212