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 "limits.h"
19 : : #include "display.h"
20 : : #include "toolcontext.h"
21 : : #include "lvm1-label.h"
22 : : #include "format1.h"
23 : : #include "segtype.h"
24 : :
25 : : /* VG consistency checks */
26 : 0 : static int _check_vgs(struct dm_list *pvs)
27 : : {
28 : : struct dm_list *pvh, *t;
29 : 0 : struct disk_list *dl = NULL;
30 : 0 : struct disk_list *first = NULL;
31 : :
32 : 0 : uint32_t pv_count = 0;
33 : 0 : uint32_t exported = 0;
34 : 0 : int first_time = 1;
35 : :
36 : : /*
37 : : * If there are exported and unexported PVs, ignore exported ones.
38 : : * This means an active VG won't be affected if disks are inserted
39 : : * bearing an exported VG with the same name.
40 : : */
41 [ # # ]: 0 : dm_list_iterate_items(dl, pvs) {
42 [ # # ]: 0 : if (first_time) {
43 : 0 : exported = dl->pvd.pv_status & VG_EXPORTED;
44 : 0 : first_time = 0;
45 : 0 : continue;
46 : : }
47 : :
48 [ # # ]: 0 : if (exported != (dl->pvd.pv_status & VG_EXPORTED)) {
49 : : /* Remove exported PVs */
50 [ # # ]: 0 : dm_list_iterate_safe(pvh, t, pvs) {
51 : 0 : dl = dm_list_item(pvh, struct disk_list);
52 [ # # ]: 0 : if (dl->pvd.pv_status & VG_EXPORTED)
53 : 0 : dm_list_del(pvh);
54 : : }
55 : 0 : break;
56 : : }
57 : : }
58 : :
59 : : /* Remove any PVs with VG structs that differ from the first */
60 [ # # ]: 0 : dm_list_iterate_safe(pvh, t, pvs) {
61 : 0 : dl = dm_list_item(pvh, struct disk_list);
62 : :
63 [ # # ]: 0 : if (!first)
64 : 0 : first = dl;
65 : :
66 [ # # ]: 0 : else if (memcmp(&first->vgd, &dl->vgd, sizeof(first->vgd))) {
67 : 0 : log_error("VG data differs between PVs %s and %s",
68 : : dev_name(first->dev), dev_name(dl->dev));
69 : 0 : log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32
70 : : " %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
71 : : PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32
72 : : " %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
73 : : PRIu32 " %" PRIu32 " %" PRIu32,
74 : : dev_name(first->dev), first->vgd.vg_uuid,
75 : : first->vgd.vg_name_dummy,
76 : : first->vgd.vg_number, first->vgd.vg_access,
77 : : first->vgd.vg_status, first->vgd.lv_max,
78 : : first->vgd.lv_cur, first->vgd.lv_open,
79 : : first->vgd.pv_max, first->vgd.pv_cur,
80 : : first->vgd.pv_act, first->vgd.dummy,
81 : : first->vgd.vgda, first->vgd.pe_size,
82 : : first->vgd.pe_total, first->vgd.pe_allocated,
83 : : first->vgd.pvg_total);
84 : 0 : log_debug("VG data on %s: %s %s %" PRIu32 " %" PRIu32
85 : : " %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
86 : : PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32
87 : : " %" PRIu32 " %" PRIu32 " %" PRIu32 " %"
88 : : PRIu32 " %" PRIu32 " %" PRIu32,
89 : : dev_name(dl->dev), dl->vgd.vg_uuid,
90 : : dl->vgd.vg_name_dummy, dl->vgd.vg_number,
91 : : dl->vgd.vg_access, dl->vgd.vg_status,
92 : : dl->vgd.lv_max, dl->vgd.lv_cur,
93 : : dl->vgd.lv_open, dl->vgd.pv_max,
94 : : dl->vgd.pv_cur, dl->vgd.pv_act, dl->vgd.dummy,
95 : : dl->vgd.vgda, dl->vgd.pe_size,
96 : : dl->vgd.pe_total, dl->vgd.pe_allocated,
97 : : dl->vgd.pvg_total);
98 : 0 : dm_list_del(pvh);
99 : 0 : return 0;
100 : : }
101 : 0 : pv_count++;
102 : : }
103 : :
104 : : /* On entry to fn, list known to be non-empty */
105 [ # # ]: 0 : if (pv_count != first->vgd.pv_cur) {
106 : 0 : log_error("%d PV(s) found for VG %s: expected %d",
107 : : pv_count, first->pvd.vg_name, first->vgd.pv_cur);
108 : : }
109 : :
110 : 0 : return 1;
111 : : }
112 : :
113 : 0 : static struct volume_group *_build_vg(struct format_instance *fid,
114 : : struct dm_list *pvs,
115 : : struct dm_pool *mem)
116 : : {
117 : 0 : struct volume_group *vg = dm_pool_alloc(mem, sizeof(*vg));
118 : : struct disk_list *dl;
119 : :
120 [ # # ]: 0 : if (!vg)
121 : 0 : goto_bad;
122 : :
123 [ # # ]: 0 : if (dm_list_empty(pvs))
124 : 0 : goto_bad;
125 : :
126 : 0 : memset(vg, 0, sizeof(*vg));
127 : :
128 : 0 : vg->cmd = fid->fmt->cmd;
129 : 0 : vg->vgmem = mem;
130 : 0 : vg->fid = fid;
131 : 0 : vg->seqno = 0;
132 : 0 : dm_list_init(&vg->pvs);
133 : 0 : dm_list_init(&vg->lvs);
134 : 0 : dm_list_init(&vg->tags);
135 : 0 : dm_list_init(&vg->removed_pvs);
136 : :
137 [ # # ]: 0 : if (!_check_vgs(pvs))
138 : 0 : goto_bad;
139 : :
140 : 0 : dl = dm_list_item(pvs->n, struct disk_list);
141 : :
142 [ # # ]: 0 : if (!import_vg(mem, vg, dl))
143 : 0 : goto_bad;
144 : :
145 [ # # ]: 0 : if (!import_pvs(fid->fmt, mem, vg, pvs))
146 : 0 : goto_bad;
147 : :
148 [ # # ]: 0 : if (!import_lvs(mem, vg, pvs))
149 : 0 : goto_bad;
150 : :
151 [ # # ]: 0 : if (!import_extents(fid->fmt->cmd, vg, pvs))
152 : 0 : goto_bad;
153 : :
154 [ # # ]: 0 : if (!import_snapshots(mem, vg, pvs))
155 : 0 : goto_bad;
156 : :
157 : 0 : return vg;
158 : :
159 : : bad:
160 : 0 : dm_pool_free(mem, vg);
161 : 0 : return NULL;
162 : : }
163 : :
164 : 0 : static struct volume_group *_format1_vg_read(struct format_instance *fid,
165 : : const char *vg_name,
166 : : struct metadata_area *mda __attribute((unused)))
167 : : {
168 : 0 : struct dm_pool *mem = dm_pool_create("lvm1 vg_read", VG_MEMPOOL_CHUNK);
169 : : struct dm_list pvs;
170 : 0 : struct volume_group *vg = NULL;
171 : 0 : dm_list_init(&pvs);
172 : :
173 [ # # ]: 0 : if (!mem)
174 : 0 : return_NULL;
175 : :
176 : : /* Strip dev_dir if present */
177 : 0 : vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
178 : :
179 [ # # ]: 0 : if (!read_pvs_in_vg
180 : 0 : (fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs))
181 : 0 : goto_bad;
182 : :
183 [ # # ]: 0 : if (!(vg = _build_vg(fid, &pvs, mem)))
184 : 0 : goto_bad;
185 : :
186 : 0 : return vg;
187 : : bad:
188 : 0 : dm_pool_destroy(mem);
189 : 0 : return NULL;
190 : : }
191 : :
192 : 0 : static struct disk_list *_flatten_pv(struct format_instance *fid,
193 : : struct dm_pool *mem, struct volume_group *vg,
194 : : struct physical_volume *pv,
195 : : const char *dev_dir)
196 : : {
197 : 0 : struct disk_list *dl = dm_pool_alloc(mem, sizeof(*dl));
198 : :
199 [ # # ]: 0 : if (!dl)
200 : 0 : return_NULL;
201 : :
202 : 0 : dl->mem = mem;
203 : 0 : dl->dev = pv->dev;
204 : :
205 : 0 : dm_list_init(&dl->uuids);
206 : 0 : dm_list_init(&dl->lvds);
207 : :
208 [ # # # # # : 0 : if (!export_pv(fid->fmt->cmd, mem, vg, &dl->pvd, pv) ||
# # # # # ]
209 : 0 : !export_vg(&dl->vgd, vg) ||
210 : 0 : !export_uuids(dl, vg) ||
211 : 0 : !export_lvs(dl, vg, pv, dev_dir) || !calculate_layout(dl)) {
212 : 0 : dm_pool_free(mem, dl);
213 : 0 : return_NULL;
214 : : }
215 : :
216 : 0 : return dl;
217 : : }
218 : :
219 : 0 : static int _flatten_vg(struct format_instance *fid, struct dm_pool *mem,
220 : : struct volume_group *vg,
221 : : struct dm_list *pvds, const char *dev_dir,
222 : : struct dev_filter *filter)
223 : : {
224 : : struct pv_list *pvl;
225 : : struct disk_list *data;
226 : :
227 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
228 [ # # ]: 0 : if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir)))
229 : 0 : return_0;
230 : :
231 : 0 : dm_list_add(pvds, &data->list);
232 : : }
233 : :
234 : 0 : export_numbers(pvds, vg);
235 : 0 : export_pv_act(pvds);
236 : :
237 [ # # ]: 0 : if (!export_vg_number(fid, pvds, vg->name, filter))
238 : 0 : return_0;
239 : :
240 : 0 : return 1;
241 : : }
242 : :
243 : 0 : static int _format1_vg_write(struct format_instance *fid, struct volume_group *vg,
244 : : struct metadata_area *mda __attribute((unused)))
245 : : {
246 : 0 : struct dm_pool *mem = dm_pool_create("lvm1 vg_write", VG_MEMPOOL_CHUNK);
247 : : struct dm_list pvds;
248 : 0 : int r = 0;
249 : :
250 [ # # ]: 0 : if (!mem)
251 : 0 : return_0;
252 : :
253 : 0 : dm_list_init(&pvds);
254 : :
255 [ # # # # ]: 0 : r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
256 : 0 : fid->fmt->cmd->filter) &&
257 : 0 : write_disks(fid->fmt, &pvds));
258 : :
259 : 0 : lvmcache_update_vg(vg, 0);
260 : 0 : dm_pool_destroy(mem);
261 : 0 : return r;
262 : : }
263 : :
264 : 0 : static int _format1_pv_read(const struct format_type *fmt, const char *pv_name,
265 : : struct physical_volume *pv, struct dm_list *mdas __attribute((unused)),
266 : : int scan_label_only __attribute((unused)))
267 : : {
268 : 0 : struct dm_pool *mem = dm_pool_create("lvm1 pv_read", 1024);
269 : : struct disk_list *dl;
270 : : struct device *dev;
271 : 0 : int r = 0;
272 : :
273 : 0 : log_very_verbose("Reading physical volume data %s from disk", pv_name);
274 : :
275 [ # # ]: 0 : if (!mem)
276 : 0 : return_0;
277 : :
278 [ # # ]: 0 : if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter)))
279 : 0 : goto_out;
280 : :
281 [ # # ]: 0 : if (!(dl = read_disk(fmt, dev, mem, NULL)))
282 : 0 : goto_out;
283 : :
284 [ # # ]: 0 : if (!import_pv(fmt, fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd))
285 : 0 : goto_out;
286 : :
287 : 0 : pv->fmt = fmt;
288 : :
289 : 0 : r = 1;
290 : :
291 : : out:
292 : 0 : dm_pool_destroy(mem);
293 : 0 : return r;
294 : : }
295 : :
296 : 0 : static int _format1_pv_setup(const struct format_type *fmt,
297 : : uint64_t pe_start, uint32_t extent_count,
298 : : uint32_t extent_size,
299 : : unsigned long data_alignment __attribute((unused)),
300 : : unsigned long data_alignment_offset __attribute((unused)),
301 : : int pvmetadatacopies __attribute((unused)),
302 : : uint64_t pvmetadatasize __attribute((unused)), struct dm_list *mdas __attribute((unused)),
303 : : struct physical_volume *pv, struct volume_group *vg __attribute((unused)))
304 : : {
305 [ # # ]: 0 : if (pv->size > MAX_PV_SIZE)
306 : 0 : pv->size--;
307 [ # # ]: 0 : if (pv->size > MAX_PV_SIZE) {
308 : 0 : log_error("Physical volumes cannot be bigger than %s",
309 : : display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE));
310 : 0 : return 0;
311 : : }
312 : :
313 : : /* Nothing more to do if extent size isn't provided */
314 [ # # ]: 0 : if (!extent_size)
315 : 0 : return 1;
316 : :
317 : : /*
318 : : * This works out pe_start and pe_count.
319 : : */
320 [ # # ]: 0 : if (!calculate_extent_count(pv, extent_size, extent_count, pe_start))
321 : 0 : return_0;
322 : :
323 : : /* Retain existing extent locations exactly */
324 [ # # ][ # # ]: 0 : if (((pe_start || extent_count) && (pe_start != pv->pe_start)) ||
[ # # ][ # # ]
[ # # ]
325 : 0 : (extent_count && (extent_count != pv->pe_count))) {
326 : 0 : log_error("Metadata would overwrite physical extents");
327 : 0 : return 0;
328 : : }
329 : :
330 : 0 : return 1;
331 : : }
332 : :
333 : 0 : static int _format1_lv_setup(struct format_instance *fid, struct logical_volume *lv)
334 : : {
335 : 0 : uint64_t max_size = UINT_MAX;
336 : :
337 [ # # ]: 0 : if (!*lv->lvid.s)
338 : 0 : lvid_from_lvnum(&lv->lvid, &lv->vg->id, find_free_lvnum(lv));
339 : :
340 [ # # ]: 0 : if (lv->le_count > MAX_LE_TOTAL) {
341 : 0 : log_error("logical volumes cannot contain more than "
342 : : "%d extents.", MAX_LE_TOTAL);
343 : 0 : return 0;
344 : : }
345 [ # # ]: 0 : if (lv->size > max_size) {
346 : 0 : log_error("logical volumes cannot be larger than %s",
347 : : display_size(fid->fmt->cmd, max_size));
348 : 0 : return 0;
349 : : }
350 : :
351 : 0 : return 1;
352 : : }
353 : :
354 : 0 : static int _format1_pv_write(const struct format_type *fmt, struct physical_volume *pv,
355 : : struct dm_list *mdas __attribute((unused)), int64_t sector __attribute((unused)))
356 : : {
357 : : struct dm_pool *mem;
358 : : struct disk_list *dl;
359 : : struct dm_list pvs;
360 : : struct label *label;
361 : : struct lvmcache_info *info;
362 : :
363 [ # # ]: 0 : if (!(info = lvmcache_add(fmt->labeller, (char *) &pv->id, pv->dev,
364 : : pv->vg_name, NULL, 0)))
365 : 0 : return_0;
366 : 0 : label = info->label;
367 : 0 : info->device_size = pv->size << SECTOR_SHIFT;
368 : 0 : info->fmt = fmt;
369 : :
370 : 0 : dm_list_init(&info->mdas);
371 : :
372 : 0 : dm_list_init(&pvs);
373 : :
374 : : /* Ensure any residual PE structure is gone */
375 : 0 : pv->pe_size = pv->pe_count = 0;
376 : 0 : pv->pe_start = LVM1_PE_ALIGN;
377 : :
378 [ # # ]: 0 : if (!(mem = dm_pool_create("lvm1 pv_write", 1024)))
379 : 0 : return_0;
380 : :
381 [ # # ]: 0 : if (!(dl = dm_pool_alloc(mem, sizeof(*dl))))
382 : 0 : goto_bad;
383 : :
384 : 0 : dl->mem = mem;
385 : 0 : dl->dev = pv->dev;
386 : :
387 [ # # ]: 0 : if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv))
388 : 0 : goto_bad;
389 : :
390 : : /* must be set to be able to zero gap after PV structure in
391 : : dev_write in order to make other disk tools happy */
392 : 0 : dl->pvd.pv_on_disk.base = METADATA_BASE;
393 : 0 : dl->pvd.pv_on_disk.size = PV_SIZE;
394 : 0 : dl->pvd.pe_on_disk.base = LVM1_PE_ALIGN << SECTOR_SHIFT;
395 : :
396 : 0 : dm_list_add(&pvs, &dl->list);
397 [ # # ]: 0 : if (!write_disks(fmt, &pvs))
398 : 0 : goto_bad;
399 : :
400 : 0 : dm_pool_destroy(mem);
401 : 0 : return 1;
402 : :
403 : : bad:
404 : 0 : dm_pool_destroy(mem);
405 : 0 : return 0;
406 : : }
407 : :
408 : 0 : static int _format1_vg_setup(struct format_instance *fid, struct volume_group *vg)
409 : : {
410 : : /* just check max_pv and max_lv */
411 [ # # ][ # # ]: 0 : if (!vg->max_lv || vg->max_lv >= MAX_LV)
412 : 0 : vg->max_lv = MAX_LV - 1;
413 : :
414 [ # # ][ # # ]: 0 : if (!vg->max_pv || vg->max_pv >= MAX_PV)
415 : 0 : vg->max_pv = MAX_PV - 1;
416 : :
417 [ # # ][ # # ]: 0 : if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
418 : 0 : log_error("Extent size must be between %s and %s",
419 : : display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE),
420 : : display_size(fid->fmt->cmd, (uint64_t) MAX_PE_SIZE));
421 : :
422 : 0 : return 0;
423 : : }
424 : :
425 [ # # ]: 0 : if (vg->extent_size % MIN_PE_SIZE) {
426 : 0 : log_error("Extent size must be multiple of %s",
427 : : display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE));
428 : 0 : return 0;
429 : : }
430 : :
431 : : /* Redundant? */
432 [ # # ]: 0 : if (vg->extent_size & (vg->extent_size - 1)) {
433 : 0 : log_error("Extent size must be power of 2");
434 : 0 : return 0;
435 : : }
436 : :
437 : 0 : return 1;
438 : : }
439 : :
440 : 0 : static int _format1_segtype_supported(struct format_instance *fid __attribute((unused)),
441 : : const struct segment_type *segtype)
442 : : {
443 [ # # ]: 0 : if (!(segtype->flags & SEG_FORMAT1_SUPPORT))
444 : 0 : return_0;
445 : :
446 : 0 : return 1;
447 : : }
448 : :
449 : : static struct metadata_area_ops _metadata_format1_ops = {
450 : : .vg_read = _format1_vg_read,
451 : : .vg_write = _format1_vg_write,
452 : : };
453 : :
454 : 1 : static struct format_instance *_format1_create_instance(const struct format_type *fmt,
455 : : const char *vgname __attribute((unused)),
456 : : const char *vgid __attribute((unused)),
457 : : void *private __attribute((unused)))
458 : : {
459 : : struct format_instance *fid;
460 : : struct metadata_area *mda;
461 : :
462 [ - + ]: 1 : if (!(fid = dm_pool_alloc(fmt->cmd->mem, sizeof(*fid))))
463 : 0 : return_NULL;
464 : :
465 : 1 : fid->fmt = fmt;
466 : 1 : dm_list_init(&fid->metadata_areas);
467 : :
468 : : /* Define a NULL metadata area */
469 [ - + ]: 1 : if (!(mda = dm_pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
470 : 0 : dm_pool_free(fmt->cmd->mem, fid);
471 : 0 : return_NULL;
472 : : }
473 : :
474 : 1 : mda->ops = &_metadata_format1_ops;
475 : 1 : mda->metadata_locn = NULL;
476 : 1 : dm_list_add(&fid->metadata_areas, &mda->list);
477 : :
478 : 1 : return fid;
479 : : }
480 : :
481 : 0 : static void _format1_destroy_instance(struct format_instance *fid __attribute((unused)))
482 : : {
483 : 0 : }
484 : :
485 : 3 : static void _format1_destroy(const struct format_type *fmt)
486 : : {
487 : 3 : dm_free((void *) fmt);
488 : 3 : }
489 : :
490 : : static struct format_handler _format1_ops = {
491 : : .pv_read = _format1_pv_read,
492 : : .pv_setup = _format1_pv_setup,
493 : : .pv_write = _format1_pv_write,
494 : : .lv_setup = _format1_lv_setup,
495 : : .vg_setup = _format1_vg_setup,
496 : : .segtype_supported = _format1_segtype_supported,
497 : : .create_instance = _format1_create_instance,
498 : : .destroy_instance = _format1_destroy_instance,
499 : : .destroy = _format1_destroy,
500 : : };
501 : :
502 : : #ifdef LVM1_INTERNAL
503 : 3 : struct format_type *init_lvm1_format(struct cmd_context *cmd)
504 : : #else /* Shared */
505 : : struct format_type *init_format(struct cmd_context *cmd);
506 : : struct format_type *init_format(struct cmd_context *cmd)
507 : : #endif
508 : : {
509 : 3 : struct format_type *fmt = dm_malloc(sizeof(*fmt));
510 : :
511 [ - + ]: 3 : if (!fmt)
512 : 0 : return_NULL;
513 : :
514 : 3 : fmt->cmd = cmd;
515 : 3 : fmt->ops = &_format1_ops;
516 : 3 : fmt->name = FMT_LVM1_NAME;
517 : 3 : fmt->alias = NULL;
518 : 3 : fmt->orphan_vg_name = FMT_LVM1_ORPHAN_VG_NAME;
519 : 3 : fmt->features = FMT_RESTRICTED_LVIDS | FMT_ORPHAN_ALLOCATABLE |
520 : : FMT_RESTRICTED_READAHEAD;
521 : 3 : fmt->private = NULL;
522 : :
523 [ - + ]: 3 : if (!(fmt->labeller = lvm1_labeller_create(fmt))) {
524 : 0 : log_error("Couldn't create lvm1 label handler.");
525 : 0 : return NULL;
526 : : }
527 : :
528 [ - + ]: 3 : if (!(label_register_handler(FMT_LVM1_NAME, fmt->labeller))) {
529 : 0 : log_error("Couldn't register lvm1 label handler.");
530 : 0 : return NULL;
531 : : }
532 : :
533 : 3 : log_very_verbose("Initialised format: %s", fmt->name);
534 : :
535 : 3 : return fmt;
536 : : }
|