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 */
_round_up(uint32_t n,uint32_t size)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 */
_next_base(struct data_area * area)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 */
_adjust_pe_on_disk(struct pv_disk * pvd)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
_calc_simple_layout(struct pv_disk * pvd)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
_check_vg_limits(struct disk_list * dl)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 */
calculate_layout(struct disk_list * dl)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 */
calculate_extent_count(struct physical_volume * pv,uint32_t extent_size,uint32_t max_extent_count,uint64_t pe_start)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