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