xref: /dflybsd-src/contrib/lvm2/dist/lib/format1/layout.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*	$NetBSD: layout.c,v 1.1.1.1 2008/12/22 00:18:00 haad Exp $	*/
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * This file is part of LVM2.
8*86d7f5d3SJohn Marino  *
9*86d7f5d3SJohn Marino  * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino  * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino  * of the GNU Lesser General Public License v.2.1.
12*86d7f5d3SJohn Marino  *
13*86d7f5d3SJohn Marino  * You should have received a copy of the GNU Lesser General Public License
14*86d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16*86d7f5d3SJohn Marino  */
17*86d7f5d3SJohn Marino 
18*86d7f5d3SJohn Marino #include "lib.h"
19*86d7f5d3SJohn Marino #include "disk-rep.h"
20*86d7f5d3SJohn Marino 
21*86d7f5d3SJohn Marino /*
22*86d7f5d3SJohn Marino  * Only works with powers of 2.
23*86d7f5d3SJohn Marino  */
_round_up(uint32_t n,uint32_t size)24*86d7f5d3SJohn Marino static uint32_t _round_up(uint32_t n, uint32_t size)
25*86d7f5d3SJohn Marino {
26*86d7f5d3SJohn Marino 	size--;
27*86d7f5d3SJohn Marino 	return (n + size) & ~size;
28*86d7f5d3SJohn Marino }
29*86d7f5d3SJohn Marino 
30*86d7f5d3SJohn Marino /* Unused.
31*86d7f5d3SJohn Marino static uint32_t _div_up(uint32_t n, uint32_t size)
32*86d7f5d3SJohn Marino {
33*86d7f5d3SJohn Marino 	return _round_up(n, size) / size;
34*86d7f5d3SJohn Marino }
35*86d7f5d3SJohn Marino */
36*86d7f5d3SJohn Marino 
37*86d7f5d3SJohn Marino /*
38*86d7f5d3SJohn Marino  * Each chunk of metadata should be aligned to
39*86d7f5d3SJohn Marino  * METADATA_ALIGN.
40*86d7f5d3SJohn Marino  */
_next_base(struct data_area * area)41*86d7f5d3SJohn Marino static uint32_t _next_base(struct data_area *area)
42*86d7f5d3SJohn Marino {
43*86d7f5d3SJohn Marino 	return _round_up(area->base + area->size, METADATA_ALIGN);
44*86d7f5d3SJohn Marino }
45*86d7f5d3SJohn Marino 
46*86d7f5d3SJohn Marino /*
47*86d7f5d3SJohn Marino  * Quick calculation based on pe_start.
48*86d7f5d3SJohn Marino  */
_adjust_pe_on_disk(struct pv_disk * pvd)49*86d7f5d3SJohn Marino static int _adjust_pe_on_disk(struct pv_disk *pvd)
50*86d7f5d3SJohn Marino {
51*86d7f5d3SJohn Marino 	uint32_t pe_start = pvd->pe_start << SECTOR_SHIFT;
52*86d7f5d3SJohn Marino 
53*86d7f5d3SJohn Marino 	if (pe_start < pvd->pe_on_disk.base + pvd->pe_on_disk.size)
54*86d7f5d3SJohn Marino 		return 0;
55*86d7f5d3SJohn Marino 
56*86d7f5d3SJohn Marino 	pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
57*86d7f5d3SJohn Marino 	return 1;
58*86d7f5d3SJohn Marino }
59*86d7f5d3SJohn Marino 
_calc_simple_layout(struct pv_disk * pvd)60*86d7f5d3SJohn Marino static void _calc_simple_layout(struct pv_disk *pvd)
61*86d7f5d3SJohn Marino {
62*86d7f5d3SJohn Marino 	pvd->pv_on_disk.base = METADATA_BASE;
63*86d7f5d3SJohn Marino 	pvd->pv_on_disk.size = PV_SIZE;
64*86d7f5d3SJohn Marino 
65*86d7f5d3SJohn Marino 	pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
66*86d7f5d3SJohn Marino 	pvd->vg_on_disk.size = VG_SIZE;
67*86d7f5d3SJohn Marino 
68*86d7f5d3SJohn Marino 	pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
69*86d7f5d3SJohn Marino 	pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
70*86d7f5d3SJohn Marino 
71*86d7f5d3SJohn Marino 	pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
72*86d7f5d3SJohn Marino 	pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
73*86d7f5d3SJohn Marino 
74*86d7f5d3SJohn Marino 	pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
75*86d7f5d3SJohn Marino 	pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
76*86d7f5d3SJohn Marino }
77*86d7f5d3SJohn Marino 
_check_vg_limits(struct disk_list * dl)78*86d7f5d3SJohn Marino static int _check_vg_limits(struct disk_list *dl)
79*86d7f5d3SJohn Marino {
80*86d7f5d3SJohn Marino 	if (dl->vgd.lv_max > MAX_LV) {
81*86d7f5d3SJohn Marino 		log_error("MaxLogicalVolumes of %d exceeds format limit of %d "
82*86d7f5d3SJohn Marino 			  "for VG '%s'", dl->vgd.lv_max, MAX_LV - 1,
83*86d7f5d3SJohn Marino 			  dl->pvd.vg_name);
84*86d7f5d3SJohn Marino 		return 0;
85*86d7f5d3SJohn Marino 	}
86*86d7f5d3SJohn Marino 
87*86d7f5d3SJohn Marino 	if (dl->vgd.pv_max > MAX_PV) {
88*86d7f5d3SJohn Marino 		log_error("MaxPhysicalVolumes of %d exceeds format limit of %d "
89*86d7f5d3SJohn Marino 			  "for VG '%s'", dl->vgd.pv_max, MAX_PV - 1,
90*86d7f5d3SJohn Marino 			  dl->pvd.vg_name);
91*86d7f5d3SJohn Marino 		return 0;
92*86d7f5d3SJohn Marino 	}
93*86d7f5d3SJohn Marino 
94*86d7f5d3SJohn Marino 	return 1;
95*86d7f5d3SJohn Marino }
96*86d7f5d3SJohn Marino 
97*86d7f5d3SJohn Marino /*
98*86d7f5d3SJohn Marino  * This assumes pe_count and pe_start have already
99*86d7f5d3SJohn Marino  * been calculated correctly.
100*86d7f5d3SJohn Marino  */
calculate_layout(struct disk_list * dl)101*86d7f5d3SJohn Marino int calculate_layout(struct disk_list *dl)
102*86d7f5d3SJohn Marino {
103*86d7f5d3SJohn Marino 	struct pv_disk *pvd = &dl->pvd;
104*86d7f5d3SJohn Marino 
105*86d7f5d3SJohn Marino 	_calc_simple_layout(pvd);
106*86d7f5d3SJohn Marino 	if (!_adjust_pe_on_disk(pvd)) {
107*86d7f5d3SJohn Marino 		log_error("Insufficient space for metadata and PE's.");
108*86d7f5d3SJohn Marino 		return 0;
109*86d7f5d3SJohn Marino 	}
110*86d7f5d3SJohn Marino 
111*86d7f5d3SJohn Marino 	if (!_check_vg_limits(dl))
112*86d7f5d3SJohn Marino 		return 0;
113*86d7f5d3SJohn Marino 
114*86d7f5d3SJohn Marino 	return 1;
115*86d7f5d3SJohn Marino }
116*86d7f5d3SJohn Marino 
117*86d7f5d3SJohn Marino /*
118*86d7f5d3SJohn Marino  * The number of extents that can fit on a disk is metadata format dependant.
119*86d7f5d3SJohn Marino  * pe_start is any existing value for pe_start
120*86d7f5d3SJohn Marino  */
calculate_extent_count(struct physical_volume * pv,uint32_t extent_size,uint32_t max_extent_count,uint64_t pe_start)121*86d7f5d3SJohn Marino int calculate_extent_count(struct physical_volume *pv, uint32_t extent_size,
122*86d7f5d3SJohn Marino 			   uint32_t max_extent_count, uint64_t pe_start)
123*86d7f5d3SJohn Marino {
124*86d7f5d3SJohn Marino 	struct pv_disk *pvd = dm_malloc(sizeof(*pvd));
125*86d7f5d3SJohn Marino 	uint32_t end;
126*86d7f5d3SJohn Marino 
127*86d7f5d3SJohn Marino 	if (!pvd)
128*86d7f5d3SJohn Marino 		return_0;
129*86d7f5d3SJohn Marino 
130*86d7f5d3SJohn Marino 	/*
131*86d7f5d3SJohn Marino 	 * Guess how many extents will fit, bearing in mind that
132*86d7f5d3SJohn Marino 	 * one is going to be knocked off at the start of the
133*86d7f5d3SJohn Marino 	 * next loop.
134*86d7f5d3SJohn Marino 	 */
135*86d7f5d3SJohn Marino 	if (max_extent_count)
136*86d7f5d3SJohn Marino 		pvd->pe_total = max_extent_count + 1;
137*86d7f5d3SJohn Marino 	else
138*86d7f5d3SJohn Marino 		pvd->pe_total = (pv->size / extent_size);
139*86d7f5d3SJohn Marino 
140*86d7f5d3SJohn Marino 	if (pvd->pe_total < PE_SIZE_PV_SIZE_REL) {
141*86d7f5d3SJohn Marino 		log_error("Too few extents on %s.  Try smaller extent size.",
142*86d7f5d3SJohn Marino 			  pv_dev_name(pv));
143*86d7f5d3SJohn Marino 		dm_free(pvd);
144*86d7f5d3SJohn Marino 		return 0;
145*86d7f5d3SJohn Marino 	}
146*86d7f5d3SJohn Marino 
147*86d7f5d3SJohn Marino 	do {
148*86d7f5d3SJohn Marino 		pvd->pe_total--;
149*86d7f5d3SJohn Marino 		_calc_simple_layout(pvd);
150*86d7f5d3SJohn Marino 		end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
151*86d7f5d3SJohn Marino 			SECTOR_SIZE - 1) >> SECTOR_SHIFT);
152*86d7f5d3SJohn Marino 
153*86d7f5d3SJohn Marino 		if (pe_start && end < pe_start)
154*86d7f5d3SJohn Marino 			end = pe_start;
155*86d7f5d3SJohn Marino 
156*86d7f5d3SJohn Marino 		pvd->pe_start = _round_up(end, LVM1_PE_ALIGN);
157*86d7f5d3SJohn Marino 
158*86d7f5d3SJohn Marino 	} while ((pvd->pe_start + (pvd->pe_total * extent_size))
159*86d7f5d3SJohn Marino 		 > pv->size);
160*86d7f5d3SJohn Marino 
161*86d7f5d3SJohn Marino 	if (pvd->pe_total > MAX_PE_TOTAL) {
162*86d7f5d3SJohn Marino 		log_error("Metadata extent limit (%u) exceeded for %s - "
163*86d7f5d3SJohn Marino 			  "%u required", MAX_PE_TOTAL, pv_dev_name(pv),
164*86d7f5d3SJohn Marino 			  pvd->pe_total);
165*86d7f5d3SJohn Marino 		dm_free(pvd);
166*86d7f5d3SJohn Marino 		return 0;
167*86d7f5d3SJohn Marino 	}
168*86d7f5d3SJohn Marino 
169*86d7f5d3SJohn Marino 	pv->pe_count = pvd->pe_total;
170*86d7f5d3SJohn Marino 	pv->pe_start = pvd->pe_start;
171*86d7f5d3SJohn Marino 	/* We can't set pe_size here without breaking LVM1 compatibility */
172*86d7f5d3SJohn Marino 	dm_free(pvd);
173*86d7f5d3SJohn Marino 	return 1;
174*86d7f5d3SJohn Marino }
175