disk-rep.c revision 1.1.1.2 1 1.1 haad /* $NetBSD: disk-rep.c,v 1.1.1.2 2009/12/02 00:26:48 haad Exp $ */
2 1.1 haad
3 1.1 haad /*
4 1.1 haad * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 1.1 haad * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6 1.1 haad *
7 1.1 haad * This file is part of LVM2.
8 1.1 haad *
9 1.1 haad * This copyrighted material is made available to anyone wishing to use,
10 1.1 haad * modify, copy, or redistribute it subject to the terms and conditions
11 1.1 haad * of the GNU Lesser General Public License v.2.1.
12 1.1 haad *
13 1.1 haad * You should have received a copy of the GNU Lesser General Public License
14 1.1 haad * along with this program; if not, write to the Free Software Foundation,
15 1.1 haad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 1.1 haad */
17 1.1 haad
18 1.1 haad #include "lib.h"
19 1.1 haad #include "disk-rep.h"
20 1.1 haad #include "xlate.h"
21 1.1 haad #include "filter.h"
22 1.1 haad #include "lvmcache.h"
23 1.1 haad
24 1.1 haad #include <fcntl.h>
25 1.1 haad
26 1.1 haad #define xx16(v) disk->v = xlate16(disk->v)
27 1.1 haad #define xx32(v) disk->v = xlate32(disk->v)
28 1.1 haad #define xx64(v) disk->v = xlate64(disk->v)
29 1.1 haad
30 1.1 haad /*
31 1.1 haad * Functions to perform the endian conversion
32 1.1 haad * between disk and core. The same code works
33 1.1 haad * both ways of course.
34 1.1 haad */
35 1.1 haad static void _xlate_pvd(struct pv_disk *disk)
36 1.1 haad {
37 1.1 haad xx16(version);
38 1.1 haad
39 1.1 haad xx32(pv_on_disk.base);
40 1.1 haad xx32(pv_on_disk.size);
41 1.1 haad xx32(vg_on_disk.base);
42 1.1 haad xx32(vg_on_disk.size);
43 1.1 haad xx32(pv_uuidlist_on_disk.base);
44 1.1 haad xx32(pv_uuidlist_on_disk.size);
45 1.1 haad xx32(lv_on_disk.base);
46 1.1 haad xx32(lv_on_disk.size);
47 1.1 haad xx32(pe_on_disk.base);
48 1.1 haad xx32(pe_on_disk.size);
49 1.1 haad
50 1.1 haad xx32(pv_major);
51 1.1 haad xx32(pv_number);
52 1.1 haad xx32(pv_status);
53 1.1 haad xx32(pv_allocatable);
54 1.1 haad xx32(pv_size);
55 1.1 haad xx32(lv_cur);
56 1.1 haad xx32(pe_size);
57 1.1 haad xx32(pe_total);
58 1.1 haad xx32(pe_allocated);
59 1.1 haad xx32(pe_start);
60 1.1 haad }
61 1.1 haad
62 1.1 haad static void _xlate_lvd(struct lv_disk *disk)
63 1.1 haad {
64 1.1 haad xx32(lv_access);
65 1.1 haad xx32(lv_status);
66 1.1 haad xx32(lv_open);
67 1.1 haad xx32(lv_dev);
68 1.1 haad xx32(lv_number);
69 1.1 haad xx32(lv_mirror_copies);
70 1.1 haad xx32(lv_recovery);
71 1.1 haad xx32(lv_schedule);
72 1.1 haad xx32(lv_size);
73 1.1 haad xx32(lv_snapshot_minor);
74 1.1 haad xx16(lv_chunk_size);
75 1.1 haad xx16(dummy);
76 1.1 haad xx32(lv_allocated_le);
77 1.1 haad xx32(lv_stripes);
78 1.1 haad xx32(lv_stripesize);
79 1.1 haad xx32(lv_badblock);
80 1.1 haad xx32(lv_allocation);
81 1.1 haad xx32(lv_io_timeout);
82 1.1 haad xx32(lv_read_ahead);
83 1.1 haad }
84 1.1 haad
85 1.1 haad static void _xlate_vgd(struct vg_disk *disk)
86 1.1 haad {
87 1.1 haad xx32(vg_number);
88 1.1 haad xx32(vg_access);
89 1.1 haad xx32(vg_status);
90 1.1 haad xx32(lv_max);
91 1.1 haad xx32(lv_cur);
92 1.1 haad xx32(lv_open);
93 1.1 haad xx32(pv_max);
94 1.1 haad xx32(pv_cur);
95 1.1 haad xx32(pv_act);
96 1.1 haad xx32(dummy);
97 1.1 haad xx32(vgda);
98 1.1 haad xx32(pe_size);
99 1.1 haad xx32(pe_total);
100 1.1 haad xx32(pe_allocated);
101 1.1 haad xx32(pvg_total);
102 1.1 haad }
103 1.1 haad
104 1.1 haad static void _xlate_extents(struct pe_disk *extents, uint32_t count)
105 1.1 haad {
106 1.1 haad unsigned i;
107 1.1 haad
108 1.1 haad for (i = 0; i < count; i++) {
109 1.1 haad extents[i].lv_num = xlate16(extents[i].lv_num);
110 1.1 haad extents[i].le_num = xlate16(extents[i].le_num);
111 1.1 haad }
112 1.1 haad }
113 1.1 haad
114 1.1 haad /*
115 1.1 haad * Handle both minor metadata formats.
116 1.1 haad */
117 1.1 haad static int _munge_formats(struct pv_disk *pvd)
118 1.1 haad {
119 1.1 haad uint32_t pe_start;
120 1.1 haad unsigned b, e;
121 1.1 haad
122 1.1 haad switch (pvd->version) {
123 1.1 haad case 1:
124 1.1 haad pvd->pe_start = ((pvd->pe_on_disk.base +
125 1.1 haad pvd->pe_on_disk.size) >> SECTOR_SHIFT);
126 1.1 haad break;
127 1.1 haad
128 1.1 haad case 2:
129 1.1 haad pvd->version = 1;
130 1.1 haad pe_start = pvd->pe_start << SECTOR_SHIFT;
131 1.1 haad pvd->pe_on_disk.size = pe_start - pvd->pe_on_disk.base;
132 1.1 haad break;
133 1.1 haad
134 1.1 haad default:
135 1.1 haad return 0;
136 1.1 haad }
137 1.1 haad
138 1.1 haad /* UUID too long? */
139 1.1 haad if (pvd->pv_uuid[ID_LEN]) {
140 1.1 haad /* Retain ID_LEN chars from end */
141 1.1 haad for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) {
142 1.1 haad if (!pvd->pv_uuid[e]) {
143 1.1 haad e--;
144 1.1 haad break;
145 1.1 haad }
146 1.1 haad }
147 1.1 haad for (b = 0; b < ID_LEN; b++) {
148 1.1 haad pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN];
149 1.1 haad /* FIXME Remove all invalid chars */
150 1.1 haad if (pvd->pv_uuid[b] == '/')
151 1.1 haad pvd->pv_uuid[b] = '#';
152 1.1 haad }
153 1.1 haad memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN);
154 1.1 haad }
155 1.1 haad
156 1.1 haad /* If UUID is missing, create one */
157 1.1 haad if (pvd->pv_uuid[0] == '\0') {
158 1.1 haad uuid_from_num((char *)pvd->pv_uuid, pvd->pv_number);
159 1.1 haad pvd->pv_uuid[ID_LEN] = '\0';
160 1.1 haad }
161 1.1 haad
162 1.1 haad return 1;
163 1.1 haad }
164 1.1 haad
165 1.1 haad /*
166 1.1 haad * If exported, remove "PV_EXP" from end of VG name
167 1.1 haad */
168 1.1 haad static void _munge_exported_vg(struct pv_disk *pvd)
169 1.1 haad {
170 1.1 haad int l;
171 1.1 haad size_t s;
172 1.1 haad
173 1.1 haad /* Return if PV not in a VG */
174 1.1 haad if ((!*pvd->vg_name))
175 1.1 haad return;
176 1.1 haad /* FIXME also check vgd->status & VG_EXPORTED? */
177 1.1 haad
178 1.1 haad l = strlen((char *)pvd->vg_name);
179 1.1 haad s = sizeof(EXPORTED_TAG);
180 1.1 haad if (!strncmp((char *)pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
181 1.1 haad pvd->vg_name[l - s + 1] = '\0';
182 1.1 haad pvd->pv_status |= VG_EXPORTED;
183 1.1 haad }
184 1.1 haad }
185 1.1 haad
186 1.1 haad int munge_pvd(struct device *dev, struct pv_disk *pvd)
187 1.1 haad {
188 1.1 haad _xlate_pvd(pvd);
189 1.1 haad
190 1.1 haad if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
191 1.1 haad log_very_verbose("%s does not have a valid LVM1 PV identifier",
192 1.1 haad dev_name(dev));
193 1.1 haad return 0;
194 1.1 haad }
195 1.1 haad
196 1.1 haad if (!_munge_formats(pvd)) {
197 1.1 haad log_very_verbose("format1: Unknown metadata version %d "
198 1.1 haad "found on %s", pvd->version, dev_name(dev));
199 1.1 haad return 0;
200 1.1 haad }
201 1.1 haad
202 1.1 haad /* If VG is exported, set VG name back to the real name */
203 1.1 haad _munge_exported_vg(pvd);
204 1.1 haad
205 1.1 haad return 1;
206 1.1 haad }
207 1.1 haad
208 1.1 haad static int _read_pvd(struct device *dev, struct pv_disk *pvd)
209 1.1 haad {
210 1.1 haad if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
211 1.1 haad log_very_verbose("Failed to read PV data from %s",
212 1.1 haad dev_name(dev));
213 1.1 haad return 0;
214 1.1 haad }
215 1.1 haad
216 1.1 haad return munge_pvd(dev, pvd);
217 1.1 haad }
218 1.1 haad
219 1.1 haad static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
220 1.1 haad {
221 1.1 haad if (!dev_read(dev, pos, sizeof(*disk), disk))
222 1.1 haad return_0;
223 1.1 haad
224 1.1 haad _xlate_lvd(disk);
225 1.1 haad
226 1.1 haad return 1;
227 1.1 haad }
228 1.1 haad
229 1.1 haad int read_vgd(struct device *dev, struct vg_disk *vgd, struct pv_disk *pvd)
230 1.1 haad {
231 1.1 haad uint64_t pos = pvd->vg_on_disk.base;
232 1.1 haad
233 1.1 haad if (!dev_read(dev, pos, sizeof(*vgd), vgd))
234 1.1 haad return_0;
235 1.1 haad
236 1.1 haad _xlate_vgd(vgd);
237 1.1 haad
238 1.1 haad if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV))
239 1.1 haad return_0;
240 1.1 haad
241 1.1 haad /* If UUID is missing, create one */
242 1.1 haad if (vgd->vg_uuid[0] == '\0')
243 1.1 haad uuid_from_num((char *)vgd->vg_uuid, vgd->vg_number);
244 1.1 haad
245 1.1 haad return 1;
246 1.1 haad }
247 1.1 haad
248 1.1 haad static int _read_uuids(struct disk_list *data)
249 1.1 haad {
250 1.1 haad unsigned num_read = 0;
251 1.1 haad struct uuid_list *ul;
252 1.1 haad char buffer[NAME_LEN] __attribute((aligned(8)));
253 1.1 haad uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
254 1.1 haad uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
255 1.1 haad
256 1.1 haad while (pos < end && num_read < data->vgd.pv_cur) {
257 1.1 haad if (!dev_read(data->dev, pos, sizeof(buffer), buffer))
258 1.1 haad return_0;
259 1.1 haad
260 1.1 haad if (!(ul = dm_pool_alloc(data->mem, sizeof(*ul))))
261 1.1 haad return_0;
262 1.1 haad
263 1.1 haad memcpy(ul->uuid, buffer, NAME_LEN);
264 1.1 haad ul->uuid[NAME_LEN - 1] = '\0';
265 1.1 haad
266 1.1 haad dm_list_add(&data->uuids, &ul->list);
267 1.1 haad
268 1.1 haad pos += NAME_LEN;
269 1.1 haad num_read++;
270 1.1 haad }
271 1.1 haad
272 1.1 haad return 1;
273 1.1 haad }
274 1.1 haad
275 1.1 haad static int _check_lvd(struct lv_disk *lvd)
276 1.1 haad {
277 1.1 haad return !(lvd->lv_name[0] == '\0');
278 1.1 haad }
279 1.1 haad
280 1.1 haad static int _read_lvs(struct disk_list *data)
281 1.1 haad {
282 1.1 haad unsigned int i, lvs_read = 0;
283 1.1 haad uint64_t pos;
284 1.1 haad struct lvd_list *ll;
285 1.1 haad struct vg_disk *vgd = &data->vgd;
286 1.1 haad
287 1.1 haad for (i = 0; (i < vgd->lv_max) && (lvs_read < vgd->lv_cur); i++) {
288 1.1 haad pos = data->pvd.lv_on_disk.base + (i * sizeof(struct lv_disk));
289 1.1 haad ll = dm_pool_alloc(data->mem, sizeof(*ll));
290 1.1 haad
291 1.1 haad if (!ll)
292 1.1 haad return_0;
293 1.1 haad
294 1.1 haad if (!_read_lvd(data->dev, pos, &ll->lvd))
295 1.1 haad return_0;
296 1.1 haad
297 1.1 haad if (!_check_lvd(&ll->lvd))
298 1.1 haad continue;
299 1.1 haad
300 1.1 haad lvs_read++;
301 1.1 haad dm_list_add(&data->lvds, &ll->list);
302 1.1 haad }
303 1.1 haad
304 1.1 haad return 1;
305 1.1 haad }
306 1.1 haad
307 1.1 haad static int _read_extents(struct disk_list *data)
308 1.1 haad {
309 1.1 haad size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
310 1.1 haad struct pe_disk *extents = dm_pool_alloc(data->mem, len);
311 1.1 haad uint64_t pos = data->pvd.pe_on_disk.base;
312 1.1 haad
313 1.1 haad if (!extents)
314 1.1 haad return_0;
315 1.1 haad
316 1.1 haad if (!dev_read(data->dev, pos, len, extents))
317 1.1 haad return_0;
318 1.1 haad
319 1.1 haad _xlate_extents(extents, data->pvd.pe_total);
320 1.1 haad data->extents = extents;
321 1.1 haad
322 1.1 haad return 1;
323 1.1 haad }
324 1.1 haad
325 1.1 haad static void __update_lvmcache(const struct format_type *fmt,
326 1.1 haad struct disk_list *dl,
327 1.1 haad struct device *dev, const char *vgid,
328 1.1 haad unsigned exported)
329 1.1 haad {
330 1.1 haad struct lvmcache_info *info;
331 1.1 haad const char *vgname = *((char *)dl->pvd.vg_name) ?
332 1.1 haad (char *)dl->pvd.vg_name : fmt->orphan_vg_name;
333 1.1 haad
334 1.1 haad if (!(info = lvmcache_add(fmt->labeller, (char *)dl->pvd.pv_uuid, dev,
335 1.1 haad vgname, vgid, exported ? EXPORTED_VG : 0))) {
336 1.1 haad stack;
337 1.1 haad return;
338 1.1 haad }
339 1.1 haad
340 1.1 haad info->device_size = xlate32(dl->pvd.pv_size) << SECTOR_SHIFT;
341 1.1 haad dm_list_init(&info->mdas);
342 1.1 haad info->status &= ~CACHE_INVALID;
343 1.1 haad }
344 1.1 haad
345 1.1 haad static struct disk_list *__read_disk(const struct format_type *fmt,
346 1.1 haad struct device *dev, struct dm_pool *mem,
347 1.1 haad const char *vg_name)
348 1.1 haad {
349 1.1 haad struct disk_list *dl = dm_pool_zalloc(mem, sizeof(*dl));
350 1.1 haad const char *name = dev_name(dev);
351 1.1 haad
352 1.1 haad if (!dl)
353 1.1 haad return_NULL;
354 1.1 haad
355 1.1 haad dl->dev = dev;
356 1.1 haad dl->mem = mem;
357 1.1 haad dm_list_init(&dl->uuids);
358 1.1 haad dm_list_init(&dl->lvds);
359 1.1 haad
360 1.1 haad if (!_read_pvd(dev, &dl->pvd))
361 1.1 haad goto_bad;
362 1.1 haad
363 1.1 haad /*
364 1.1 haad * is it an orphan ?
365 1.1 haad */
366 1.1 haad if (!*dl->pvd.vg_name) {
367 1.1 haad log_very_verbose("%s is not a member of any format1 VG", name);
368 1.1 haad
369 1.1 haad __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0);
370 1.1 haad return (vg_name) ? NULL : dl;
371 1.1 haad }
372 1.1 haad
373 1.1 haad if (!read_vgd(dl->dev, &dl->vgd, &dl->pvd)) {
374 1.1 haad log_error("Failed to read VG data from PV (%s)", name);
375 1.1 haad __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0);
376 1.1 haad goto bad;
377 1.1 haad }
378 1.1 haad
379 1.1 haad if (vg_name && strcmp(vg_name, (char *)dl->pvd.vg_name)) {
380 1.1 haad log_very_verbose("%s is not a member of the VG %s",
381 1.1 haad name, vg_name);
382 1.1 haad __update_lvmcache(fmt, dl, dev, fmt->orphan_vg_name, 0);
383 1.1 haad goto bad;
384 1.1 haad }
385 1.1 haad
386 1.1 haad __update_lvmcache(fmt, dl, dev, (char *)dl->vgd.vg_uuid,
387 1.1 haad dl->vgd.vg_status & VG_EXPORTED);
388 1.1 haad
389 1.1 haad if (!_read_uuids(dl)) {
390 1.1 haad log_error("Failed to read PV uuid list from %s", name);
391 1.1 haad goto bad;
392 1.1 haad }
393 1.1 haad
394 1.1 haad if (!_read_lvs(dl)) {
395 1.1 haad log_error("Failed to read LV's from %s", name);
396 1.1 haad goto bad;
397 1.1 haad }
398 1.1 haad
399 1.1 haad if (!_read_extents(dl)) {
400 1.1 haad log_error("Failed to read extents from %s", name);
401 1.1 haad goto bad;
402 1.1 haad }
403 1.1 haad
404 1.1 haad log_very_verbose("Found %s in %sVG %s", name,
405 1.1 haad (dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
406 1.1 haad dl->pvd.vg_name);
407 1.1 haad
408 1.1 haad return dl;
409 1.1 haad
410 1.1 haad bad:
411 1.1 haad dm_pool_free(dl->mem, dl);
412 1.1 haad return NULL;
413 1.1 haad }
414 1.1 haad
415 1.1 haad struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
416 1.1 haad struct dm_pool *mem, const char *vg_name)
417 1.1 haad {
418 1.1 haad struct disk_list *dl;
419 1.1 haad
420 1.1 haad if (!dev_open(dev))
421 1.1 haad return_NULL;
422 1.1 haad
423 1.1 haad dl = __read_disk(fmt, dev, mem, vg_name);
424 1.1 haad
425 1.1 haad if (!dev_close(dev))
426 1.1 haad stack;
427 1.1 haad
428 1.1 haad return dl;
429 1.1 haad }
430 1.1 haad
431 1.1 haad static void _add_pv_to_list(struct dm_list *head, struct disk_list *data)
432 1.1 haad {
433 1.1 haad struct pv_disk *pvd;
434 1.1 haad struct disk_list *diskl;
435 1.1 haad
436 1.1 haad dm_list_iterate_items(diskl, head) {
437 1.1 haad pvd = &diskl->pvd;
438 1.1 haad if (!strncmp((char *)data->pvd.pv_uuid, (char *)pvd->pv_uuid,
439 1.1 haad sizeof(pvd->pv_uuid))) {
440 1.1.1.2 haad if (!dev_subsystem_part_major(data->dev)) {
441 1.1 haad log_very_verbose("Ignoring duplicate PV %s on "
442 1.1 haad "%s", pvd->pv_uuid,
443 1.1 haad dev_name(data->dev));
444 1.1 haad return;
445 1.1 haad }
446 1.1.1.2 haad log_very_verbose("Duplicate PV %s - using %s %s",
447 1.1.1.2 haad pvd->pv_uuid, dev_subsystem_name(data->dev),
448 1.1.1.2 haad dev_name(data->dev));
449 1.1 haad dm_list_del(&diskl->list);
450 1.1 haad break;
451 1.1 haad }
452 1.1 haad }
453 1.1 haad dm_list_add(head, &data->list);
454 1.1 haad }
455 1.1 haad
456 1.1 haad /*
457 1.1 haad * Build a list of pv_d's structures, allocated from mem.
458 1.1 haad * We keep track of the first object allocated from the pool
459 1.1 haad * so we can free off all the memory if something goes wrong.
460 1.1 haad */
461 1.1 haad int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
462 1.1 haad struct dev_filter *filter, struct dm_pool *mem,
463 1.1 haad struct dm_list *head)
464 1.1 haad {
465 1.1 haad struct dev_iter *iter;
466 1.1 haad struct device *dev;
467 1.1 haad struct disk_list *data = NULL;
468 1.1 haad struct lvmcache_vginfo *vginfo;
469 1.1 haad struct lvmcache_info *info;
470 1.1 haad
471 1.1 haad /* Fast path if we already saw this VG and cached the list of PVs */
472 1.1 haad if (vg_name && (vginfo = vginfo_from_vgname(vg_name, NULL)) &&
473 1.1 haad vginfo->infos.n) {
474 1.1 haad dm_list_iterate_items(info, &vginfo->infos) {
475 1.1 haad dev = info->dev;
476 1.1 haad if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
477 1.1 haad break;
478 1.1 haad _add_pv_to_list(head, data);
479 1.1 haad }
480 1.1 haad
481 1.1 haad /* Did we find the whole VG? */
482 1.1 haad if (!vg_name || is_orphan_vg(vg_name) ||
483 1.1 haad (data && *data->pvd.vg_name &&
484 1.1 haad dm_list_size(head) == data->vgd.pv_cur))
485 1.1 haad return 1;
486 1.1 haad
487 1.1 haad /* Failed */
488 1.1 haad dm_list_init(head);
489 1.1 haad /* vgcache_del(vg_name); */
490 1.1 haad }
491 1.1 haad
492 1.1 haad if (!(iter = dev_iter_create(filter, 1))) {
493 1.1 haad log_error("read_pvs_in_vg: dev_iter_create failed");
494 1.1 haad return 0;
495 1.1 haad }
496 1.1 haad
497 1.1 haad /* Otherwise do a complete scan */
498 1.1 haad for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
499 1.1 haad if ((data = read_disk(fmt, dev, mem, vg_name))) {
500 1.1 haad _add_pv_to_list(head, data);
501 1.1 haad }
502 1.1 haad }
503 1.1 haad dev_iter_destroy(iter);
504 1.1 haad
505 1.1 haad if (dm_list_empty(head))
506 1.1 haad return 0;
507 1.1 haad
508 1.1 haad return 1;
509 1.1 haad }
510 1.1 haad
511 1.1 haad static int _write_vgd(struct disk_list *data)
512 1.1 haad {
513 1.1 haad struct vg_disk *vgd = &data->vgd;
514 1.1 haad uint64_t pos = data->pvd.vg_on_disk.base;
515 1.1 haad
516 1.1 haad log_debug("Writing %s VG metadata to %s at %" PRIu64 " len %" PRIsize_t,
517 1.1 haad data->pvd.vg_name, dev_name(data->dev), pos, sizeof(*vgd));
518 1.1 haad
519 1.1 haad _xlate_vgd(vgd);
520 1.1 haad if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
521 1.1 haad return_0;
522 1.1 haad
523 1.1 haad _xlate_vgd(vgd);
524 1.1 haad
525 1.1 haad return 1;
526 1.1 haad }
527 1.1 haad
528 1.1 haad static int _write_uuids(struct disk_list *data)
529 1.1 haad {
530 1.1 haad struct uuid_list *ul;
531 1.1 haad uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
532 1.1 haad uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
533 1.1 haad
534 1.1 haad dm_list_iterate_items(ul, &data->uuids) {
535 1.1 haad if (pos >= end) {
536 1.1 haad log_error("Too many uuids to fit on %s",
537 1.1 haad dev_name(data->dev));
538 1.1 haad return 0;
539 1.1 haad }
540 1.1 haad
541 1.1 haad log_debug("Writing %s uuidlist to %s at %" PRIu64 " len %d",
542 1.1 haad data->pvd.vg_name, dev_name(data->dev),
543 1.1 haad pos, NAME_LEN);
544 1.1 haad
545 1.1 haad if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
546 1.1 haad return_0;
547 1.1 haad
548 1.1 haad pos += NAME_LEN;
549 1.1 haad }
550 1.1 haad
551 1.1 haad return 1;
552 1.1 haad }
553 1.1 haad
554 1.1 haad static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
555 1.1 haad {
556 1.1 haad log_debug("Writing %s LV %s metadata to %s at %" PRIu64 " len %"
557 1.1 haad PRIsize_t, disk->vg_name, disk->lv_name, dev_name(dev),
558 1.1 haad pos, sizeof(*disk));
559 1.1 haad
560 1.1 haad _xlate_lvd(disk);
561 1.1 haad if (!dev_write(dev, pos, sizeof(*disk), disk))
562 1.1 haad return_0;
563 1.1 haad
564 1.1 haad _xlate_lvd(disk);
565 1.1 haad
566 1.1 haad return 1;
567 1.1 haad }
568 1.1 haad
569 1.1 haad static int _write_lvs(struct disk_list *data)
570 1.1 haad {
571 1.1 haad struct lvd_list *ll;
572 1.1 haad uint64_t pos, offset;
573 1.1 haad
574 1.1 haad pos = data->pvd.lv_on_disk.base;
575 1.1 haad
576 1.1 haad if (!dev_set(data->dev, pos, data->pvd.lv_on_disk.size, 0)) {
577 1.1 haad log_error("Couldn't zero lv area on device '%s'",
578 1.1 haad dev_name(data->dev));
579 1.1 haad return 0;
580 1.1 haad }
581 1.1 haad
582 1.1 haad dm_list_iterate_items(ll, &data->lvds) {
583 1.1 haad offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
584 1.1 haad if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
585 1.1 haad log_error("lv_number %d too large", ll->lvd.lv_number);
586 1.1 haad return 0;
587 1.1 haad }
588 1.1 haad
589 1.1 haad if (!_write_lvd(data->dev, pos + offset, &ll->lvd))
590 1.1 haad return_0;
591 1.1 haad }
592 1.1 haad
593 1.1 haad return 1;
594 1.1 haad }
595 1.1 haad
596 1.1 haad static int _write_extents(struct disk_list *data)
597 1.1 haad {
598 1.1 haad size_t len = sizeof(struct pe_disk) * data->pvd.pe_total;
599 1.1 haad struct pe_disk *extents = data->extents;
600 1.1 haad uint64_t pos = data->pvd.pe_on_disk.base;
601 1.1 haad
602 1.1 haad log_debug("Writing %s extents metadata to %s at %" PRIu64 " len %"
603 1.1 haad PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
604 1.1 haad pos, len);
605 1.1 haad
606 1.1 haad _xlate_extents(extents, data->pvd.pe_total);
607 1.1 haad if (!dev_write(data->dev, pos, len, extents))
608 1.1 haad return_0;
609 1.1 haad
610 1.1 haad _xlate_extents(extents, data->pvd.pe_total);
611 1.1 haad
612 1.1 haad return 1;
613 1.1 haad }
614 1.1 haad
615 1.1 haad static int _write_pvd(struct disk_list *data)
616 1.1 haad {
617 1.1 haad char *buf;
618 1.1 haad uint64_t pos = data->pvd.pv_on_disk.base;
619 1.1 haad size_t size = data->pvd.pv_on_disk.size;
620 1.1 haad
621 1.1 haad if (size < sizeof(struct pv_disk)) {
622 1.1 haad log_error("Invalid PV structure size.");
623 1.1 haad return 0;
624 1.1 haad }
625 1.1 haad
626 1.1 haad /* Make sure that the gap between the PV structure and
627 1.1 haad the next one is zeroed in order to make non LVM tools
628 1.1 haad happy (idea from AED) */
629 1.1 haad buf = dm_malloc(size);
630 1.1 haad if (!buf) {
631 1.1.1.2 haad log_error("Couldn't allocate temporary PV buffer.");
632 1.1 haad return 0;
633 1.1 haad }
634 1.1 haad
635 1.1 haad memset(buf, 0, size);
636 1.1 haad memcpy(buf, &data->pvd, sizeof(struct pv_disk));
637 1.1 haad
638 1.1 haad log_debug("Writing %s PV metadata to %s at %" PRIu64 " len %"
639 1.1 haad PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
640 1.1 haad pos, size);
641 1.1 haad
642 1.1 haad _xlate_pvd((struct pv_disk *) buf);
643 1.1 haad if (!dev_write(data->dev, pos, size, buf)) {
644 1.1 haad dm_free(buf);
645 1.1 haad return_0;
646 1.1 haad }
647 1.1 haad
648 1.1 haad dm_free(buf);
649 1.1 haad return 1;
650 1.1 haad }
651 1.1 haad
652 1.1 haad /*
653 1.1 haad * assumes the device has been opened.
654 1.1 haad */
655 1.1 haad static int __write_all_pvd(const struct format_type *fmt __attribute((unused)),
656 1.1 haad struct disk_list *data)
657 1.1 haad {
658 1.1 haad const char *pv_name = dev_name(data->dev);
659 1.1 haad
660 1.1 haad if (!_write_pvd(data)) {
661 1.1 haad log_error("Failed to write PV structure onto %s", pv_name);
662 1.1 haad return 0;
663 1.1 haad }
664 1.1 haad
665 1.1 haad /* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
666 1.1 haad /*
667 1.1 haad * Stop here for orphan pv's.
668 1.1 haad */
669 1.1 haad if (data->pvd.vg_name[0] == '\0') {
670 1.1 haad /* if (!test_mode())
671 1.1 haad vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt); */
672 1.1 haad return 1;
673 1.1 haad }
674 1.1 haad
675 1.1 haad /* if (!test_mode())
676 1.1 haad vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
677 1.1 haad fmt); */
678 1.1 haad
679 1.1 haad if (!_write_vgd(data)) {
680 1.1 haad log_error("Failed to write VG data to %s", pv_name);
681 1.1 haad return 0;
682 1.1 haad }
683 1.1 haad
684 1.1 haad if (!_write_uuids(data)) {
685 1.1 haad log_error("Failed to write PV uuid list to %s", pv_name);
686 1.1 haad return 0;
687 1.1 haad }
688 1.1 haad
689 1.1 haad if (!_write_lvs(data)) {
690 1.1 haad log_error("Failed to write LV's to %s", pv_name);
691 1.1 haad return 0;
692 1.1 haad }
693 1.1 haad
694 1.1 haad if (!_write_extents(data)) {
695 1.1 haad log_error("Failed to write extents to %s", pv_name);
696 1.1 haad return 0;
697 1.1 haad }
698 1.1 haad
699 1.1 haad return 1;
700 1.1 haad }
701 1.1 haad
702 1.1 haad /*
703 1.1 haad * opens the device and hands to the above fn.
704 1.1 haad */
705 1.1 haad static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
706 1.1 haad {
707 1.1 haad int r;
708 1.1 haad
709 1.1 haad if (!dev_open(data->dev))
710 1.1 haad return_0;
711 1.1 haad
712 1.1 haad r = __write_all_pvd(fmt, data);
713 1.1 haad
714 1.1 haad if (!dev_close(data->dev))
715 1.1 haad stack;
716 1.1 haad
717 1.1 haad return r;
718 1.1 haad }
719 1.1 haad
720 1.1 haad /*
721 1.1 haad * Writes all the given pv's to disk. Does very
722 1.1 haad * little sanity checking, so make sure correct
723 1.1 haad * data is passed to here.
724 1.1 haad */
725 1.1 haad int write_disks(const struct format_type *fmt, struct dm_list *pvs)
726 1.1 haad {
727 1.1 haad struct disk_list *dl;
728 1.1 haad
729 1.1 haad dm_list_iterate_items(dl, pvs) {
730 1.1 haad if (!(_write_all_pvd(fmt, dl)))
731 1.1 haad return_0;
732 1.1 haad
733 1.1 haad log_very_verbose("Successfully wrote data to %s",
734 1.1 haad dev_name(dl->dev));
735 1.1 haad }
736 1.1 haad
737 1.1 haad return 1;
738 1.1 haad }
739