Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
4 : : *
5 : : * This file is part of LVM2.
6 : : *
7 : : * This copyrighted material is made available to anyone wishing to use,
8 : : * modify, copy, or redistribute it subject to the terms and conditions
9 : : * of the GNU Lesser General Public License v.2.1.
10 : : *
11 : : * You should have received a copy of the GNU Lesser General Public License
12 : : * along with this program; if not, write to the Free Software Foundation,
13 : : * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 : : */
15 : :
16 : : #include "lib.h"
17 : : #include "label.h"
18 : : #include "metadata.h"
19 : : #include "lvmcache.h"
20 : : #include "filter.h"
21 : : #include "xlate.h"
22 : : #include "disk_rep.h"
23 : :
24 : : #include <assert.h>
25 : :
26 : : /* FIXME: memcpy might not be portable */
27 : : #define CPIN_8(x, y, z) {memcpy((x), (y), (z));}
28 : : #define CPOUT_8(x, y, z) {memcpy((y), (x), (z));}
29 : : #define CPIN_16(x, y) {(x) = xlate16_be((y));}
30 : : #define CPOUT_16(x, y) {(y) = xlate16_be((x));}
31 : : #define CPIN_32(x, y) {(x) = xlate32_be((y));}
32 : : #define CPOUT_32(x, y) {(y) = xlate32_be((x));}
33 : : #define CPIN_64(x, y) {(x) = xlate64_be((y));}
34 : : #define CPOUT_64(x, y) {(y) = xlate64_be((x));}
35 : :
36 : 0 : static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
37 : : struct dm_pool *mem __attribute((unused)), struct pool_list *pl,
38 : : const char *vg_name __attribute((unused)))
39 : : {
40 : : char buf[512] __attribute((aligned(8)));
41 : :
42 : : /* FIXME: Need to check the cache here first */
43 [ # # ]: 0 : if (!dev_read(dev, UINT64_C(0), 512, buf)) {
44 : 0 : log_very_verbose("Failed to read PV data from %s",
45 : : dev_name(dev));
46 : 0 : return 0;
47 : : }
48 : :
49 [ # # ]: 0 : if (!read_pool_label(pl, fmt->labeller, dev, buf, NULL))
50 : 0 : return_0;
51 : :
52 : 0 : return 1;
53 : : }
54 : :
55 : 0 : static void _add_pl_to_list(struct dm_list *head, struct pool_list *data)
56 : : {
57 : : struct pool_list *pl;
58 : :
59 [ # # ]: 0 : dm_list_iterate_items(pl, head) {
60 [ # # ]: 0 : if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
61 : : char uuid[ID_LEN + 7] __attribute((aligned(8)));
62 : :
63 : 0 : id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7);
64 : :
65 [ # # ]: 0 : if (!dev_subsystem_part_major(data->dev)) {
66 : 0 : log_very_verbose("Ignoring duplicate PV %s on "
67 : : "%s", uuid,
68 : : dev_name(data->dev));
69 : 0 : return;
70 : : }
71 : 0 : log_very_verbose("Duplicate PV %s - using %s %s",
72 : : uuid, dev_subsystem_name(data->dev),
73 : : dev_name(data->dev));
74 : 0 : dm_list_del(&pl->list);
75 : 0 : break;
76 : : }
77 : : }
78 : 0 : dm_list_add(head, &data->list);
79 : : }
80 : :
81 : 0 : int read_pool_label(struct pool_list *pl, struct labeller *l,
82 : : struct device *dev, char *buf, struct label **label)
83 : : {
84 : : struct lvmcache_info *info;
85 : : struct id pvid;
86 : : struct id vgid;
87 : : char uuid[ID_LEN + 7] __attribute((aligned(8)));
88 : 0 : struct pool_disk *pd = &pl->pd;
89 : :
90 : 0 : pool_label_in(pd, buf);
91 : :
92 : 0 : get_pool_pv_uuid(&pvid, pd);
93 : 0 : id_write_format(&pvid, uuid, ID_LEN + 7);
94 : 0 : log_debug("Calculated uuid %s for %s", uuid, dev_name(dev));
95 : :
96 : 0 : get_pool_vg_uuid(&vgid, pd);
97 : 0 : id_write_format(&vgid, uuid, ID_LEN + 7);
98 : 0 : log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name);
99 : :
100 [ # # ]: 0 : if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name,
101 : : (char *) &vgid, 0)))
102 : 0 : return_0;
103 [ # # ]: 0 : if (label)
104 : 0 : *label = info->label;
105 : :
106 : 0 : info->device_size = xlate32_be(pd->pl_blocks) << SECTOR_SHIFT;
107 : 0 : dm_list_init(&info->mdas);
108 : :
109 : 0 : info->status &= ~CACHE_INVALID;
110 : :
111 : 0 : pl->dev = dev;
112 : 0 : pl->pv = NULL;
113 : 0 : memcpy(&pl->pv_uuid, &pvid, sizeof(pvid));
114 : :
115 : 0 : return 1;
116 : : }
117 : :
118 : : /**
119 : : * pool_label_out - copies a pool_label_t into a char buffer
120 : : * @pl: ptr to a pool_label_t struct
121 : : * @buf: ptr to raw space where label info will be copied
122 : : *
123 : : * This function is important because it takes care of all of
124 : : * the endian issues when copying to disk. This way, when
125 : : * machines of different architectures are used, they will
126 : : * be able to interpret ondisk labels correctly. Always use
127 : : * this function before writing to disk.
128 : : */
129 : 0 : void pool_label_out(struct pool_disk *pl, void *buf)
130 : : {
131 : 0 : struct pool_disk *bufpl = (struct pool_disk *) buf;
132 : :
133 : 0 : CPOUT_64(pl->pl_magic, bufpl->pl_magic);
134 : 0 : CPOUT_64(pl->pl_pool_id, bufpl->pl_pool_id);
135 : 0 : CPOUT_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
136 : 0 : CPOUT_32(pl->pl_version, bufpl->pl_version);
137 : 0 : CPOUT_32(pl->pl_subpools, bufpl->pl_subpools);
138 : 0 : CPOUT_32(pl->pl_sp_id, bufpl->pl_sp_id);
139 : 0 : CPOUT_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
140 : 0 : CPOUT_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
141 : 0 : CPOUT_32(pl->pl_sp_type, bufpl->pl_sp_type);
142 : 0 : CPOUT_64(pl->pl_blocks, bufpl->pl_blocks);
143 : 0 : CPOUT_32(pl->pl_striping, bufpl->pl_striping);
144 : 0 : CPOUT_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
145 : 0 : CPOUT_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
146 : 0 : CPOUT_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
147 : 0 : CPOUT_32(pl->pl_minor, bufpl->pl_minor);
148 : 0 : CPOUT_32(pl->pl_padding, bufpl->pl_padding);
149 : 0 : CPOUT_8(pl->pl_reserve, bufpl->pl_reserve, 184);
150 : 0 : }
151 : :
152 : : /**
153 : : * pool_label_in - copies a char buffer into a pool_label_t
154 : : * @pl: ptr to a pool_label_t struct
155 : : * @buf: ptr to raw space where label info is copied from
156 : : *
157 : : * This function is important because it takes care of all of
158 : : * the endian issues when information from disk is about to be
159 : : * used. This way, when machines of different architectures
160 : : * are used, they will be able to interpret ondisk labels
161 : : * correctly. Always use this function before using labels that
162 : : * were read from disk.
163 : : */
164 : 0 : void pool_label_in(struct pool_disk *pl, void *buf)
165 : : {
166 : 0 : struct pool_disk *bufpl = (struct pool_disk *) buf;
167 : :
168 : 0 : CPIN_64(pl->pl_magic, bufpl->pl_magic);
169 : 0 : CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id);
170 : 0 : CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
171 : 0 : CPIN_32(pl->pl_version, bufpl->pl_version);
172 : 0 : CPIN_32(pl->pl_subpools, bufpl->pl_subpools);
173 : 0 : CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id);
174 : 0 : CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
175 : 0 : CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
176 : 0 : CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type);
177 : 0 : CPIN_64(pl->pl_blocks, bufpl->pl_blocks);
178 : 0 : CPIN_32(pl->pl_striping, bufpl->pl_striping);
179 : 0 : CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
180 : 0 : CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
181 : 0 : CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
182 : 0 : CPIN_32(pl->pl_minor, bufpl->pl_minor);
183 : 0 : CPIN_32(pl->pl_padding, bufpl->pl_padding);
184 : 0 : CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184);
185 : 0 : }
186 : :
187 : 0 : static char _calc_char(unsigned int id)
188 : : {
189 : : /*
190 : : * [0-9A-Za-z!#] - 64 printable chars (6-bits)
191 : : */
192 : :
193 [ # # ]: 0 : if (id < 10)
194 : 0 : return id + 48;
195 [ # # ]: 0 : if (id < 36)
196 : 0 : return (id - 10) + 65;
197 [ # # ]: 0 : if (id < 62)
198 : 0 : return (id - 36) + 97;
199 [ # # ]: 0 : if (id == 62)
200 : 0 : return '!';
201 [ # # ]: 0 : if (id == 63)
202 : 0 : return '#';
203 : :
204 : 0 : return '%';
205 : : }
206 : :
207 : 0 : void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid)
208 : : {
209 : : int i;
210 : 0 : unsigned shifter = 0x003F;
211 : :
212 : : assert(ID_LEN == 32);
213 : 0 : memset(uuid, 0, ID_LEN);
214 : 0 : strcat(uuid, "POOL0000000000");
215 : :
216 : : /* We grab the entire 64 bits (+2 that get shifted in) */
217 [ # # ]: 0 : for (i = 13; i < 24; i++) {
218 : 0 : uuid[i] = _calc_char(((unsigned) poolid) & shifter);
219 : 0 : poolid = poolid >> 6;
220 : : }
221 : :
222 : : /* We grab the entire 32 bits (+4 that get shifted in) */
223 [ # # ]: 0 : for (i = 24; i < 30; i++) {
224 : 0 : uuid[i] = _calc_char((unsigned) (spid & shifter));
225 : 0 : spid = spid >> 6;
226 : : }
227 : :
228 : : /*
229 : : * Since we can only have 128 devices, we only worry about the
230 : : * last 12 bits
231 : : */
232 [ # # ]: 0 : for (i = 30; i < 32; i++) {
233 : 0 : uuid[i] = _calc_char((unsigned) (devid & shifter));
234 : 0 : devid = devid >> 6;
235 : : }
236 : :
237 : 0 : }
238 : :
239 : 0 : static int _read_vg_pds(const struct format_type *fmt, struct dm_pool *mem,
240 : : struct lvmcache_vginfo *vginfo, struct dm_list *head,
241 : : uint32_t *devcount)
242 : : {
243 : : struct lvmcache_info *info;
244 : 0 : struct pool_list *pl = NULL;
245 : : struct dm_pool *tmpmem;
246 : :
247 : 0 : uint32_t sp_count = 0;
248 : 0 : uint32_t *sp_devs = NULL;
249 : : uint32_t i;
250 : :
251 : : /* FIXME: maybe should return a different error in memory
252 : : * allocation failure */
253 [ # # ]: 0 : if (!(tmpmem = dm_pool_create("pool read_vg", 512)))
254 : 0 : return_0;
255 : :
256 [ # # ]: 0 : dm_list_iterate_items(info, &vginfo->infos) {
257 [ # # # # ]: 0 : if (info->dev &&
258 : 0 : !(pl = read_pool_disk(fmt, info->dev, mem, vginfo->vgname)))
259 : 0 : break;
260 : : /*
261 : : * We need to keep track of the total expected number
262 : : * of devices per subpool
263 : : */
264 [ # # ]: 0 : if (!sp_count) {
265 : : /* FIXME pl left uninitialised if !info->dev */
266 : 0 : sp_count = pl->pd.pl_subpools;
267 [ # # ]: 0 : if (!(sp_devs =
268 : 0 : dm_pool_zalloc(tmpmem,
269 : : sizeof(uint32_t) * sp_count))) {
270 : 0 : log_error("Unable to allocate %d 32-bit uints",
271 : : sp_count);
272 : 0 : dm_pool_destroy(tmpmem);
273 : 0 : return 0;
274 : : }
275 : : }
276 : : /*
277 : : * watch out for a pool label with a different subpool
278 : : * count than the original - give up if it does
279 : : */
280 [ # # ]: 0 : if (sp_count != pl->pd.pl_subpools)
281 : 0 : break;
282 : :
283 : 0 : _add_pl_to_list(head, pl);
284 : :
285 [ # # # # ]: 0 : if (sp_count > pl->pd.pl_sp_id && sp_devs[pl->pd.pl_sp_id] == 0)
286 : 0 : sp_devs[pl->pd.pl_sp_id] = pl->pd.pl_sp_devs;
287 : : }
288 : :
289 : 0 : *devcount = 0;
290 [ # # ]: 0 : for (i = 0; i < sp_count; i++)
291 : 0 : *devcount += sp_devs[i];
292 : :
293 : 0 : dm_pool_destroy(tmpmem);
294 : :
295 [ # # # # ]: 0 : if (pl && *pl->pd.pl_pool_name)
296 : 0 : return 1;
297 : :
298 : 0 : return 0;
299 : :
300 : : }
301 : :
302 : 0 : int read_pool_pds(const struct format_type *fmt, const char *vg_name,
303 : : struct dm_pool *mem, struct dm_list *pdhead)
304 : : {
305 : : struct lvmcache_vginfo *vginfo;
306 : : uint32_t totaldevs;
307 : 0 : int full_scan = -1;
308 : :
309 : : do {
310 : : /*
311 : : * If the cache scanning doesn't work, this will never work
312 : : */
313 [ # # ][ # # ]: 0 : if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
[ # # ]
314 : 0 : vginfo->infos.n) {
315 : :
316 [ # # ]: 0 : if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) {
317 : : /*
318 : : * If we found all the devices we were
319 : : * expecting, return success
320 : : */
321 [ # # ]: 0 : if (dm_list_size(pdhead) == totaldevs)
322 : 0 : return 1;
323 : :
324 : : /*
325 : : * accept partial pool if we've done a full
326 : : * rescan of the cache
327 : : */
328 [ # # ]: 0 : if (full_scan > 0)
329 : 0 : return 1;
330 : : }
331 : : }
332 : : /* Failed */
333 : 0 : dm_list_init(pdhead);
334 : :
335 : 0 : full_scan++;
336 [ # # ]: 0 : if (full_scan > 1) {
337 : 0 : log_debug("No devices for vg %s found in cache",
338 : : vg_name);
339 : 0 : return 0;
340 : : }
341 : 0 : lvmcache_label_scan(fmt->cmd, full_scan);
342 : :
343 : 0 : } while (1);
344 : :
345 : : }
346 : :
347 : 0 : struct pool_list *read_pool_disk(const struct format_type *fmt,
348 : : struct device *dev, struct dm_pool *mem,
349 : : const char *vg_name)
350 : : {
351 : : struct pool_list *pl;
352 : :
353 [ # # ]: 0 : if (!dev_open(dev))
354 : 0 : return_NULL;
355 : :
356 [ # # ]: 0 : if (!(pl = dm_pool_zalloc(mem, sizeof(*pl)))) {
357 : 0 : log_error("Unable to allocate pool list structure");
358 : 0 : return 0;
359 : : }
360 : :
361 [ # # ]: 0 : if (!__read_pool_disk(fmt, dev, mem, pl, vg_name))
362 : 0 : return_NULL;
363 : :
364 [ # # ]: 0 : if (!dev_close(dev))
365 : 0 : stack;
366 : :
367 : 0 : return pl;
368 : :
369 : : }
|