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