Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
3 : : * Copyright (C) 2004-2009 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 "device.h"
18 : : #include "metadata.h"
19 : : #include "toolcontext.h"
20 : : #include "lvm-string.h"
21 : : #include "lvm-file.h"
22 : : #include "lvmcache.h"
23 : : #include "memlock.h"
24 : : #include "str_list.h"
25 : : #include "pv_alloc.h"
26 : : #include "segtype.h"
27 : : #include "activate.h"
28 : : #include "display.h"
29 : : #include "locking.h"
30 : : #include "archiver.h"
31 : : #include "defaults.h"
32 : : #include "filter-persistent.h"
33 : :
34 : : #include <sys/param.h>
35 : :
36 : : /*
37 : : * FIXME: Check for valid handle before dereferencing field or log error?
38 : : */
39 : : #define pv_field(handle, field) \
40 : : (((const struct physical_volume *)(handle))->field)
41 : :
42 : : static struct physical_volume *_pv_read(struct cmd_context *cmd,
43 : : struct dm_pool *pvmem,
44 : : const char *pv_name,
45 : : struct dm_list *mdas,
46 : : uint64_t *label_sector,
47 : : int warnings, int scan_label_only);
48 : :
49 : : static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd,
50 : : const char *pv_name);
51 : :
52 : : static struct pv_list *_find_pv_in_vg(const struct volume_group *vg,
53 : : const char *pv_name);
54 : :
55 : : static struct pv_list *_find_pv_in_vg_by_uuid(const struct volume_group *vg,
56 : : const struct id *id);
57 : :
58 : : static uint32_t _vg_bad_status_bits(const struct volume_group *vg,
59 : : uint64_t status);
60 : :
61 : : const char _really_init[] =
62 : : "Really INITIALIZE physical volume \"%s\" of volume group \"%s\" [y/n]? ";
63 : :
64 : 0 : unsigned long set_pe_align(struct physical_volume *pv, unsigned long data_alignment)
65 : : {
66 [ # # ]: 0 : if (pv->pe_align)
67 : 0 : goto out;
68 : :
69 [ # # ]: 0 : if (data_alignment)
70 : 0 : pv->pe_align = data_alignment;
71 : : else
72 [ # # ]: 0 : pv->pe_align = MAX(65536UL, lvm_getpagesize()) >> SECTOR_SHIFT;
73 : :
74 [ # # ]: 0 : if (!pv->dev)
75 : 0 : goto out;
76 : :
77 : : /*
78 : : * Align to stripe-width of underlying md device if present
79 : : */
80 [ # # ]: 0 : if (find_config_tree_bool(pv->fmt->cmd, "devices/md_chunk_alignment",
81 : : DEFAULT_MD_CHUNK_ALIGNMENT))
82 [ # # ]: 0 : pv->pe_align = MAX(pv->pe_align,
83 : : dev_md_stripe_width(pv->fmt->cmd->sysfs_dir,
84 : : pv->dev));
85 : :
86 : : /*
87 : : * Align to topology's minimum_io_size or optimal_io_size if present
88 : : * - minimum_io_size - the smallest request the device can perform
89 : : * w/o incurring a read-modify-write penalty (e.g. MD's chunk size)
90 : : * - optimal_io_size - the device's preferred unit of receiving I/O
91 : : * (e.g. MD's stripe width)
92 : : */
93 [ # # ]: 0 : if (find_config_tree_bool(pv->fmt->cmd,
94 : : "devices/data_alignment_detection",
95 : : DEFAULT_DATA_ALIGNMENT_DETECTION)) {
96 [ # # ]: 0 : pv->pe_align = MAX(pv->pe_align,
97 : : dev_minimum_io_size(pv->fmt->cmd->sysfs_dir,
98 : : pv->dev));
99 : :
100 [ # # ]: 0 : pv->pe_align = MAX(pv->pe_align,
101 : : dev_optimal_io_size(pv->fmt->cmd->sysfs_dir,
102 : : pv->dev));
103 : : }
104 : :
105 : 0 : log_very_verbose("%s: Setting PE alignment to %lu sectors.",
106 : : dev_name(pv->dev), pv->pe_align);
107 : :
108 : : out:
109 : 0 : return pv->pe_align;
110 : : }
111 : :
112 : 0 : unsigned long set_pe_align_offset(struct physical_volume *pv,
113 : : unsigned long data_alignment_offset)
114 : : {
115 [ # # ]: 0 : if (pv->pe_align_offset)
116 : 0 : goto out;
117 : :
118 [ # # ]: 0 : if (data_alignment_offset)
119 : 0 : pv->pe_align_offset = data_alignment_offset;
120 : :
121 [ # # ]: 0 : if (!pv->dev)
122 : 0 : goto out;
123 : :
124 [ # # ]: 0 : if (find_config_tree_bool(pv->fmt->cmd,
125 : : "devices/data_alignment_offset_detection",
126 : : DEFAULT_DATA_ALIGNMENT_OFFSET_DETECTION)) {
127 : 0 : int align_offset = dev_alignment_offset(pv->fmt->cmd->sysfs_dir,
128 : 0 : pv->dev);
129 : : /* must handle a -1 alignment_offset; means dev is misaligned */
130 [ # # ]: 0 : if (align_offset < 0)
131 : 0 : align_offset = 0;
132 : 0 : pv->pe_align_offset = MAX(pv->pe_align_offset, align_offset);
133 : : }
134 : :
135 : 0 : log_very_verbose("%s: Setting PE alignment offset to %lu sectors.",
136 : : dev_name(pv->dev), pv->pe_align_offset);
137 : :
138 : : out:
139 : 0 : return pv->pe_align_offset;
140 : : }
141 : :
142 : 0 : void add_pvl_to_vgs(struct volume_group *vg, struct pv_list *pvl)
143 : : {
144 : 0 : dm_list_add(&vg->pvs, &pvl->list);
145 : 0 : vg->pv_count++;
146 : 0 : }
147 : :
148 : :
149 : : /**
150 : : * add_pv_to_vg - Add a physical volume to a volume group
151 : : * @vg - volume group to add to
152 : : * @pv_name - name of the pv (to be removed)
153 : : * @pv - physical volume to add to volume group
154 : : *
155 : : * Returns:
156 : : * 0 - failure
157 : : * 1 - success
158 : : * FIXME: remove pv_name - obtain safely from pv
159 : : */
160 : 0 : int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
161 : : struct physical_volume *pv)
162 : : {
163 : : struct pv_list *pvl;
164 : 0 : struct format_instance *fid = vg->fid;
165 : 0 : struct dm_pool *mem = vg->vgmem;
166 : : char uuid[64] __attribute((aligned(8)));
167 : :
168 : 0 : log_verbose("Adding physical volume '%s' to volume group '%s'",
169 : : pv_name, vg->name);
170 : :
171 [ # # ]: 0 : if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) {
172 : 0 : log_error("pv_list allocation for '%s' failed", pv_name);
173 : 0 : return 0;
174 : : }
175 : :
176 [ # # ]: 0 : if (!is_orphan_vg(pv->vg_name)) {
177 : 0 : log_error("Physical volume '%s' is already in volume group "
178 : : "'%s'", pv_name, pv->vg_name);
179 : 0 : return 0;
180 : : }
181 : :
182 [ # # ]: 0 : if (pv->fmt != fid->fmt) {
183 : 0 : log_error("Physical volume %s is of different format type (%s)",
184 : : pv_name, pv->fmt->name);
185 : 0 : return 0;
186 : : }
187 : :
188 : : /* Ensure PV doesn't depend on another PV already in the VG */
189 [ # # ]: 0 : if (pv_uses_vg(pv, vg)) {
190 : 0 : log_error("Physical volume %s might be constructed from same "
191 : : "volume group %s", pv_name, vg->name);
192 : 0 : return 0;
193 : : }
194 : :
195 [ # # ]: 0 : if (!(pv->vg_name = dm_pool_strdup(mem, vg->name))) {
196 : 0 : log_error("vg->name allocation failed for '%s'", pv_name);
197 : 0 : return 0;
198 : : }
199 : :
200 : 0 : memcpy(&pv->vgid, &vg->id, sizeof(vg->id));
201 : :
202 : : /* Units of 512-byte sectors */
203 : 0 : pv->pe_size = vg->extent_size;
204 : :
205 : : /*
206 : : * pe_count must always be calculated by pv_setup
207 : : */
208 : 0 : pv->pe_alloc_count = 0;
209 : :
210 [ # # ]: 0 : if (!fid->fmt->ops->pv_setup(fid->fmt, UINT64_C(0), 0,
211 : : vg->extent_size, 0, 0, 0UL, UINT64_C(0),
212 : : &fid->metadata_areas, pv, vg)) {
213 : 0 : log_error("Format-specific setup of physical volume '%s' "
214 : : "failed.", pv_name);
215 : 0 : return 0;
216 : : }
217 : :
218 [ # # # # ]: 0 : if (_find_pv_in_vg(vg, pv_name) ||
219 : 0 : _find_pv_in_vg_by_uuid(vg, &pv->id)) {
220 [ # # ]: 0 : if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
221 : 0 : stack;
222 : 0 : uuid[0] = '\0';
223 : : }
224 : 0 : log_error("Physical volume '%s (%s)' listed more than once.",
225 : : pv_name, uuid);
226 : 0 : return 0;
227 : : }
228 : :
229 [ # # ][ # # ]: 0 : if (vg->pv_count && (vg->pv_count == vg->max_pv)) {
230 : 0 : log_error("No space for '%s' - volume group '%s' "
231 : : "holds max %d physical volume(s).", pv_name,
232 : : vg->name, vg->max_pv);
233 : 0 : return 0;
234 : : }
235 : :
236 [ # # ]: 0 : if (!alloc_pv_segment_whole_pv(mem, pv))
237 : 0 : return_0;
238 : :
239 [ # # ]: 0 : if ((uint64_t) vg->extent_count + pv->pe_count > UINT32_MAX) {
240 : 0 : log_error("Unable to add %s to %s: new extent count (%"
241 : : PRIu64 ") exceeds limit (%" PRIu32 ").",
242 : : pv_name, vg->name,
243 : : (uint64_t) vg->extent_count + pv->pe_count,
244 : : UINT32_MAX);
245 : 0 : return 0;
246 : : }
247 : :
248 : 0 : pvl->pv = pv;
249 : 0 : add_pvl_to_vgs(vg, pvl);
250 : 0 : vg->extent_count += pv->pe_count;
251 : 0 : vg->free_count += pv->pe_count;
252 : :
253 : 0 : return 1;
254 : : }
255 : :
256 : 0 : static int _copy_pv(struct dm_pool *pvmem,
257 : : struct physical_volume *pv_to,
258 : : struct physical_volume *pv_from)
259 : : {
260 : 0 : memcpy(pv_to, pv_from, sizeof(*pv_to));
261 : :
262 [ # # ]: 0 : if (!(pv_to->vg_name = dm_pool_strdup(pvmem, pv_from->vg_name)))
263 : 0 : return_0;
264 : :
265 [ # # ]: 0 : if (!str_list_dup(pvmem, &pv_to->tags, &pv_from->tags))
266 : 0 : return_0;
267 : :
268 [ # # ]: 0 : if (!peg_dup(pvmem, &pv_to->segments, &pv_from->segments))
269 : 0 : return_0;
270 : :
271 : 0 : return 1;
272 : : }
273 : :
274 : 0 : static struct pv_list *_copy_pvl(struct dm_pool *pvmem, struct pv_list *pvl_from)
275 : : {
276 : 0 : struct pv_list *pvl_to = NULL;
277 : :
278 [ # # ]: 0 : if (!(pvl_to = dm_pool_zalloc(pvmem, sizeof(*pvl_to))))
279 : 0 : return_NULL;
280 : :
281 [ # # ]: 0 : if (!(pvl_to->pv = dm_pool_alloc(pvmem, sizeof(*pvl_to->pv))))
282 : 0 : goto_bad;
283 : :
284 [ # # ]: 0 : if(!_copy_pv(pvmem, pvl_to->pv, pvl_from->pv))
285 : 0 : goto_bad;
286 : :
287 : 0 : return pvl_to;
288 : : bad:
289 : 0 : dm_pool_free(pvmem, pvl_to);
290 : 0 : return NULL;
291 : : }
292 : :
293 : 0 : int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
294 : : const char *vgid, const char *pvid,
295 : : struct physical_volume *pv)
296 : : {
297 : : struct volume_group *vg;
298 : : struct pv_list *pvl;
299 : 0 : int r = 0, consistent = 0;
300 : :
301 [ # # ]: 0 : if (!(vg = vg_read_internal(fmt->cmd, vg_name, vgid, &consistent))) {
302 : 0 : log_error("get_pv_from_vg_by_id: vg_read_internal failed to read VG %s",
303 : : vg_name);
304 : 0 : return 0;
305 : : }
306 : :
307 [ # # ]: 0 : if (!consistent)
308 : 0 : log_warn("WARNING: Volume group %s is not consistent",
309 : : vg_name);
310 : :
311 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
312 [ # # ]: 0 : if (id_equal(&pvl->pv->id, (const struct id *) pvid)) {
313 [ # # ]: 0 : if (!_copy_pv(fmt->cmd->mem, pv, pvl->pv)) {
314 : 0 : log_error("internal PV duplication failed");
315 : 0 : r = 0;
316 : 0 : goto out;
317 : : }
318 : 0 : r = 1;
319 : 0 : goto out;
320 : : }
321 : : }
322 : : out:
323 : 0 : vg_release(vg);
324 : 0 : return r;
325 : : }
326 : :
327 : 0 : int move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
328 : : const char *pv_name)
329 : : {
330 : : struct physical_volume *pv;
331 : : struct pv_list *pvl;
332 : :
333 : : /* FIXME: handle tags */
334 [ # # ]: 0 : if (!(pvl = find_pv_in_vg(vg_from, pv_name))) {
335 : 0 : log_error("Physical volume %s not in volume group %s",
336 : : pv_name, vg_from->name);
337 : 0 : return 0;
338 : : }
339 : :
340 [ # # # # ]: 0 : if (_vg_bad_status_bits(vg_from, RESIZEABLE_VG) ||
341 : 0 : _vg_bad_status_bits(vg_to, RESIZEABLE_VG))
342 : 0 : return 0;
343 : :
344 : 0 : dm_list_move(&vg_to->pvs, &pvl->list);
345 : :
346 : 0 : vg_from->pv_count--;
347 : 0 : vg_to->pv_count++;
348 : :
349 : 0 : pv = pvl->pv;
350 : :
351 : 0 : vg_from->extent_count -= pv_pe_count(pv);
352 : 0 : vg_to->extent_count += pv_pe_count(pv);
353 : :
354 : 0 : vg_from->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv);
355 : 0 : vg_to->free_count += pv_pe_count(pv) - pv_pe_alloc_count(pv);
356 : :
357 : 0 : return 1;
358 : : }
359 : :
360 : 0 : int move_pvs_used_by_lv(struct volume_group *vg_from,
361 : : struct volume_group *vg_to,
362 : : const char *lv_name)
363 : : {
364 : : struct lv_segment *lvseg;
365 : : unsigned s;
366 : : struct lv_list *lvl;
367 : : struct logical_volume *lv;
368 : :
369 : : /* FIXME: handle tags */
370 [ # # ]: 0 : if (!(lvl = find_lv_in_vg(vg_from, lv_name))) {
371 : 0 : log_error("Logical volume %s not in volume group %s",
372 : : lv_name, vg_from->name);
373 : 0 : return 0;
374 : : }
375 : :
376 [ # # # # ]: 0 : if (_vg_bad_status_bits(vg_from, RESIZEABLE_VG) ||
377 : 0 : _vg_bad_status_bits(vg_to, RESIZEABLE_VG))
378 : 0 : return 0;
379 : :
380 [ # # ]: 0 : dm_list_iterate_items(lvseg, &lvl->lv->segments) {
381 [ # # ]: 0 : if (lvseg->log_lv)
382 [ # # ]: 0 : if (!move_pvs_used_by_lv(vg_from, vg_to,
383 : 0 : lvseg->log_lv->name))
384 : 0 : return_0;
385 [ # # ]: 0 : for (s = 0; s < lvseg->area_count; s++) {
386 [ # # ]: 0 : if (seg_type(lvseg, s) == AREA_PV) {
387 [ # # ]: 0 : if (!move_pv(vg_from, vg_to,
388 : 0 : pv_dev_name(seg_pv(lvseg, s))))
389 : 0 : return_0;
390 [ # # ]: 0 : } else if (seg_type(lvseg, s) == AREA_LV) {
391 : 0 : lv = seg_lv(lvseg, s);
392 [ # # ]: 0 : if (!move_pvs_used_by_lv(vg_from, vg_to,
393 : 0 : lv->name))
394 : 0 : return_0;
395 : : }
396 : : }
397 : : }
398 : 0 : return 1;
399 : : }
400 : :
401 : 0 : static int validate_new_vg_name(struct cmd_context *cmd, const char *vg_name)
402 : : {
403 : : char vg_path[PATH_MAX];
404 : :
405 [ # # ]: 0 : if (!validate_name(vg_name))
406 : 0 : return_0;
407 : :
408 : 0 : snprintf(vg_path, PATH_MAX, "%s%s", cmd->dev_dir, vg_name);
409 [ # # ]: 0 : if (path_exists(vg_path)) {
410 : 0 : log_error("%s: already exists in filesystem", vg_path);
411 : 0 : return 0;
412 : : }
413 : :
414 : 0 : return 1;
415 : : }
416 : :
417 : 0 : int validate_vg_rename_params(struct cmd_context *cmd,
418 : : const char *vg_name_old,
419 : : const char *vg_name_new)
420 : : {
421 : : unsigned length;
422 : : char *dev_dir;
423 : :
424 : 0 : dev_dir = cmd->dev_dir;
425 : 0 : length = strlen(dev_dir);
426 : :
427 : : /* Check sanity of new name */
428 [ # # ]: 0 : if (strlen(vg_name_new) > NAME_LEN - length - 2) {
429 : 0 : log_error("New volume group path exceeds maximum length "
430 : : "of %d!", NAME_LEN - length - 2);
431 : 0 : return 0;
432 : : }
433 : :
434 [ # # ]: 0 : if (!validate_new_vg_name(cmd, vg_name_new)) {
435 : 0 : log_error("New volume group name \"%s\" is invalid",
436 : : vg_name_new);
437 : 0 : return 0;
438 : : }
439 : :
440 [ # # ]: 0 : if (!strcmp(vg_name_old, vg_name_new)) {
441 : 0 : log_error("Old and new volume group names must differ");
442 : 0 : return 0;
443 : : }
444 : :
445 : 0 : return 1;
446 : : }
447 : :
448 : 0 : int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
449 : : const char *new_name)
450 : : {
451 : 0 : struct dm_pool *mem = vg->vgmem;
452 : : struct pv_list *pvl;
453 : :
454 [ # # ]: 0 : if (!(vg->name = dm_pool_strdup(mem, new_name))) {
455 : 0 : log_error("vg->name allocation failed for '%s'", new_name);
456 : 0 : return 0;
457 : : }
458 : :
459 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
460 [ # # ]: 0 : if (!(pvl->pv->vg_name = dm_pool_strdup(mem, new_name))) {
461 : 0 : log_error("pv->vg_name allocation failed for '%s'",
462 : : pv_dev_name(pvl->pv));
463 : 0 : return 0;
464 : : }
465 : : }
466 : :
467 : 0 : return 1;
468 : : }
469 : :
470 : 0 : int remove_lvs_in_vg(struct cmd_context *cmd,
471 : : struct volume_group *vg,
472 : : force_t force)
473 : : {
474 : : struct dm_list *lst;
475 : : struct lv_list *lvl;
476 : :
477 [ # # ]: 0 : while ((lst = dm_list_first(&vg->lvs))) {
478 : 0 : lvl = dm_list_item(lst, struct lv_list);
479 [ # # ]: 0 : if (!lv_remove_with_dependencies(cmd, lvl->lv, force))
480 : 0 : return 0;
481 : : }
482 : :
483 : 0 : return 1;
484 : : }
485 : :
486 : 0 : int vg_remove_check(struct volume_group *vg)
487 : : {
488 : : unsigned lv_count;
489 : : struct pv_list *pvl, *tpvl;
490 : :
491 [ # # ][ # # ]: 0 : if (vg_read_error(vg) || vg_missing_pv_count(vg)) {
492 [ # # ]: 0 : log_error("Volume group \"%s\" not found, is inconsistent "
493 : : "or has PVs missing.", vg ? vg->name : "");
494 : 0 : log_error("Consider vgreduce --removemissing if metadata "
495 : : "is inconsistent.");
496 : 0 : return 0;
497 : : }
498 : :
499 [ # # ]: 0 : if (!vg_check_status(vg, EXPORTED_VG))
500 : 0 : return 0;
501 : :
502 : 0 : lv_count = vg_visible_lvs(vg);
503 : :
504 [ # # ]: 0 : if (lv_count) {
505 : 0 : log_error("Volume group \"%s\" still contains %u "
506 : : "logical volume(s)", vg->name, lv_count);
507 : 0 : return 0;
508 : : }
509 : :
510 [ # # ]: 0 : if (!archive(vg))
511 : 0 : return 0;
512 : :
513 [ # # ]: 0 : dm_list_iterate_items_safe(pvl, tpvl, &vg->pvs) {
514 : 0 : dm_list_del(&pvl->list);
515 : 0 : dm_list_add(&vg->removed_pvs, &pvl->list);
516 : : }
517 : 0 : return 1;
518 : : }
519 : :
520 : 0 : int vg_remove(struct volume_group *vg)
521 : : {
522 : : struct physical_volume *pv;
523 : : struct pv_list *pvl;
524 : 0 : int ret = 1;
525 : :
526 [ # # ]: 0 : if (!lock_vol(vg->cmd, VG_ORPHANS, LCK_VG_WRITE)) {
527 : 0 : log_error("Can't get lock for orphan PVs");
528 : 0 : return 0;
529 : : }
530 : :
531 [ # # ]: 0 : if (!vg_remove_mdas(vg)) {
532 : 0 : log_error("vg_remove_mdas %s failed", vg->name);
533 : 0 : unlock_vg(vg->cmd, VG_ORPHANS);
534 : 0 : return 0;
535 : : }
536 : :
537 : : /* init physical volumes */
538 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->removed_pvs) {
539 : 0 : pv = pvl->pv;
540 : 0 : log_verbose("Removing physical volume \"%s\" from "
541 : : "volume group \"%s\"", pv_dev_name(pv), vg->name);
542 : 0 : pv->vg_name = vg->fid->fmt->orphan_vg_name;
543 : 0 : pv->status = ALLOCATABLE_PV;
544 : :
545 [ # # ]: 0 : if (!dev_get_size(pv_dev(pv), &pv->size)) {
546 : 0 : log_error("%s: Couldn't get size.", pv_dev_name(pv));
547 : 0 : ret = 0;
548 : 0 : continue;
549 : : }
550 : :
551 : : /* FIXME Write to same sector label was read from */
552 [ # # ]: 0 : if (!pv_write(vg->cmd, pv, NULL, INT64_C(-1))) {
553 : 0 : log_error("Failed to remove physical volume \"%s\""
554 : : " from volume group \"%s\"",
555 : : pv_dev_name(pv), vg->name);
556 : 0 : ret = 0;
557 : : }
558 : : }
559 : :
560 : 0 : backup_remove(vg->cmd, vg->name);
561 : :
562 [ # # ]: 0 : if (ret)
563 : 0 : log_print("Volume group \"%s\" successfully removed", vg->name);
564 : : else
565 : 0 : log_error("Volume group \"%s\" not properly removed", vg->name);
566 : :
567 : 0 : unlock_vg(vg->cmd, VG_ORPHANS);
568 : 0 : return ret;
569 : : }
570 : :
571 : : /*
572 : : * Extend a VG by a single PV / device path
573 : : *
574 : : * Parameters:
575 : : * - vg: handle of volume group to extend by 'pv_name'
576 : : * - pv_name: device path of PV to add to VG
577 : : * - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate
578 : : *
579 : : */
580 : 0 : static int vg_extend_single_pv(struct volume_group *vg, char *pv_name,
581 : : struct pvcreate_params *pp)
582 : : {
583 : : struct physical_volume *pv;
584 : :
585 : 0 : pv = pv_by_path(vg->fid->fmt->cmd, pv_name);
586 [ # # # # ]: 0 : if (!pv && !pp) {
587 : 0 : log_error("%s not identified as an existing "
588 : : "physical volume", pv_name);
589 : 0 : return 0;
590 [ # # ][ # # ]: 0 : } else if (!pv && pp) {
591 : 0 : pv = pvcreate_single(vg->cmd, pv_name, pp);
592 [ # # ]: 0 : if (!pv)
593 : 0 : return 0;
594 : : }
595 [ # # ]: 0 : if (!add_pv_to_vg(vg, pv_name, pv))
596 : 0 : return 0;
597 : 0 : return 1;
598 : : }
599 : :
600 : : /*
601 : : * Extend a VG by a single PV / device path
602 : : *
603 : : * Parameters:
604 : : * - vg: handle of volume group to extend by 'pv_name'
605 : : * - pv_count: count of device paths of PVs
606 : : * - pv_names: device paths of PVs to add to VG
607 : : * - pp: parameters to pass to implicit pvcreate; if NULL, do not pvcreate
608 : : *
609 : : */
610 : 0 : int vg_extend(struct volume_group *vg, int pv_count, char **pv_names,
611 : : struct pvcreate_params *pp)
612 : : {
613 : : int i;
614 : :
615 [ # # ]: 0 : if (_vg_bad_status_bits(vg, RESIZEABLE_VG))
616 : 0 : return 0;
617 : :
618 : : /* attach each pv */
619 [ # # ]: 0 : for (i = 0; i < pv_count; i++) {
620 [ # # ]: 0 : if (!vg_extend_single_pv(vg, pv_names[i], pp))
621 : 0 : goto bad;
622 : : }
623 : :
624 : : /* FIXME Decide whether to initialise and add new mdahs to format instance */
625 : :
626 : 0 : return 1;
627 : :
628 : : bad:
629 : 0 : log_error("Unable to add physical volume '%s' to "
630 : : "volume group '%s'.", pv_names[i], vg->name);
631 : 0 : return 0;
632 : : }
633 : :
634 : : /* FIXME: use this inside vgreduce_single? */
635 : 0 : int vg_reduce(struct volume_group *vg, char *pv_name)
636 : : {
637 : : struct physical_volume *pv;
638 : : struct pv_list *pvl;
639 : :
640 [ # # ]: 0 : if (_vg_bad_status_bits(vg, RESIZEABLE_VG))
641 : 0 : return 0;
642 : :
643 [ # # ]: 0 : if (!archive(vg))
644 : 0 : goto bad;
645 : :
646 : : /* remove each pv */
647 [ # # ]: 0 : if (!(pvl = find_pv_in_vg(vg, pv_name))) {
648 : 0 : log_error("Physical volume %s not in volume group %s.",
649 : : pv_name, vg->name);
650 : 0 : goto bad;
651 : : }
652 : :
653 : 0 : pv = pvl->pv;
654 : :
655 [ # # ]: 0 : if (pv_pe_alloc_count(pv)) {
656 : 0 : log_error("Physical volume %s still in use.",
657 : : pv_name);
658 : 0 : goto bad;
659 : : }
660 : :
661 [ # # ]: 0 : if (!dev_get_size(pv_dev(pv), &pv->size)) {
662 : 0 : log_error("%s: Couldn't get size.", pv_name);
663 : 0 : goto bad;
664 : : }
665 : :
666 : 0 : vg->pv_count--;
667 : 0 : vg->free_count -= pv_pe_count(pv) - pv_pe_alloc_count(pv);
668 : 0 : vg->extent_count -= pv_pe_count(pv);
669 : :
670 : : /* add pv to the remove_pvs list */
671 : 0 : dm_list_del(&pvl->list);
672 : 0 : dm_list_add(&vg->removed_pvs, &pvl->list);
673 : :
674 : 0 : return 1;
675 : :
676 : : bad:
677 : 0 : log_error("Unable to remove physical volume '%s' from "
678 : : "volume group '%s'.", pv_name, vg->name);
679 : 0 : return 0;
680 : : }
681 : :
682 : 0 : int lv_change_tag(struct logical_volume *lv, const char *tag, int add_tag)
683 : : {
684 : : char *tag_new;
685 : :
686 [ # # ]: 0 : if (!(lv->vg->fid->fmt->features & FMT_TAGS)) {
687 : 0 : log_error("Logical volume %s/%s does not support tags",
688 : : lv->vg->name, lv->name);
689 : 0 : return 0;
690 : : }
691 : :
692 [ # # ]: 0 : if (add_tag) {
693 [ # # ]: 0 : if (!(tag_new = dm_pool_strdup(lv->vg->vgmem, tag))) {
694 : 0 : return_0;
695 : : }
696 [ # # ]: 0 : if (!str_list_add(lv->vg->vgmem, &lv->tags, tag_new)) {
697 : 0 : log_error("Failed to add tag %s to %s/%s",
698 : : tag, lv->vg->name, lv->name);
699 : 0 : return 0;
700 : : }
701 : : } else {
702 [ # # ]: 0 : if (!str_list_del(&lv->tags, tag)) {
703 : 0 : log_error("Failed to remove tag %s from %s/%s",
704 : : tag, lv->vg->name, lv->name);
705 : 0 : return 0;
706 : : }
707 : : }
708 : 0 : return 1;
709 : : }
710 : :
711 : 0 : int vg_change_tag(struct volume_group *vg, const char *tag, int add_tag)
712 : : {
713 : : char *tag_new;
714 : :
715 [ # # ]: 0 : if (!(vg->fid->fmt->features & FMT_TAGS)) {
716 : 0 : log_error("Volume group %s does not support tags", vg->name);
717 : 0 : return 0;
718 : : }
719 : :
720 [ # # ]: 0 : if (add_tag) {
721 [ # # ]: 0 : if (!(tag_new = dm_pool_strdup(vg->vgmem, tag))) {
722 : 0 : return_0;
723 : : }
724 [ # # ]: 0 : if (!str_list_add(vg->vgmem, &vg->tags, tag_new)) {
725 : 0 : log_error("Failed to add tag %s to volume group %s",
726 : : tag, vg->name);
727 : 0 : return 0;
728 : : }
729 : : } else {
730 [ # # ]: 0 : if (!str_list_del(&vg->tags, tag)) {
731 : 0 : log_error("Failed to remove tag %s from volume group "
732 : : "%s", tag, vg->name);
733 : 0 : return 0;
734 : : }
735 : : }
736 : 0 : return 1;
737 : : }
738 : :
739 : 0 : const char *strip_dir(const char *vg_name, const char *dev_dir)
740 : : {
741 : 0 : size_t len = strlen(dev_dir);
742 [ # # ]: 0 : if (!strncmp(vg_name, dev_dir, len))
743 : 0 : vg_name += len;
744 : :
745 : 0 : return vg_name;
746 : : }
747 : :
748 : : /*
749 : : * Validate parameters to vg_create() before calling.
750 : : * FIXME: Move inside vg_create library function.
751 : : * FIXME: Change vgcreate_params struct to individual gets/sets
752 : : */
753 : 0 : int vgcreate_params_validate(struct cmd_context *cmd,
754 : : struct vgcreate_params *vp)
755 : : {
756 [ # # ]: 0 : if (!validate_new_vg_name(cmd, vp->vg_name)) {
757 : 0 : log_error("New volume group name \"%s\" is invalid",
758 : : vp->vg_name);
759 : 0 : return 1;
760 : : }
761 : :
762 [ # # ]: 0 : if (vp->alloc == ALLOC_INHERIT) {
763 : 0 : log_error("Volume Group allocation policy cannot inherit "
764 : : "from anything");
765 : 0 : return 1;
766 : : }
767 : :
768 [ # # ]: 0 : if (!vp->extent_size) {
769 : 0 : log_error("Physical extent size may not be zero");
770 : 0 : return 1;
771 : : }
772 : :
773 [ # # ]: 0 : if (!(cmd->fmt->features & FMT_UNLIMITED_VOLS)) {
774 [ # # ]: 0 : if (!vp->max_lv)
775 : 0 : vp->max_lv = 255;
776 [ # # ]: 0 : if (!vp->max_pv)
777 : 0 : vp->max_pv = 255;
778 [ # # ][ # # ]: 0 : if (vp->max_lv > 255 || vp->max_pv > 255) {
779 : 0 : log_error("Number of volumes may not exceed 255");
780 : 0 : return 1;
781 : : }
782 : : }
783 : :
784 : 0 : return 0;
785 : : }
786 : :
787 : : /*
788 : : * Create a (struct volume_group) volume group handle from a struct volume_group pointer and a
789 : : * possible failure code or zero for success.
790 : : */
791 : 0 : static struct volume_group *_vg_make_handle(struct cmd_context *cmd,
792 : : struct volume_group *vg,
793 : : uint32_t failure)
794 : : {
795 : : struct dm_pool *vgmem;
796 : :
797 [ # # ]: 0 : if (!vg) {
798 [ # # # # ]: 0 : if (!(vgmem = dm_pool_create("lvm2 vg_handle", VG_MEMPOOL_CHUNK)) ||
799 : 0 : !(vg = dm_pool_zalloc(vgmem, sizeof(*vg)))) {
800 : 0 : log_error("Error allocating vg handle.");
801 [ # # ]: 0 : if (vgmem)
802 : 0 : dm_pool_destroy(vgmem);
803 : 0 : return_NULL;
804 : : }
805 : 0 : vg->vgmem = vgmem;
806 : : }
807 : :
808 : 0 : vg->read_status = failure;
809 : :
810 : 0 : return (struct volume_group *)vg;
811 : : }
812 : :
813 : 0 : int lv_has_unknown_segments(const struct logical_volume *lv)
814 : : {
815 : : struct lv_segment *seg;
816 : : /* foreach segment */
817 [ # # ]: 0 : dm_list_iterate_items(seg, &lv->segments)
818 [ # # ]: 0 : if (seg_unknown(seg))
819 : 0 : return 1;
820 : 0 : return 0;
821 : : }
822 : :
823 : 0 : int vg_has_unknown_segments(const struct volume_group *vg)
824 : : {
825 : : struct lv_list *lvl;
826 : :
827 : : /* foreach LV */
828 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs)
829 [ # # ]: 0 : if (lv_has_unknown_segments(lvl->lv))
830 : 0 : return 1;
831 : 0 : return 0;
832 : : }
833 : :
834 : : /*
835 : : * Create a VG with default parameters.
836 : : * Returns:
837 : : * - struct volume_group* with SUCCESS code: VG structure created
838 : : * - NULL or struct volume_group* with FAILED_* code: error creating VG structure
839 : : * Use vg_read_error() to determine success or failure.
840 : : * FIXME: cleanup usage of _vg_make_handle()
841 : : */
842 : 0 : struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name)
843 : : {
844 : : struct volume_group *vg;
845 : 0 : int consistent = 0;
846 : : struct dm_pool *mem;
847 : : uint32_t rc;
848 : :
849 [ # # ]: 0 : if (!validate_name(vg_name)) {
850 : 0 : log_error("Invalid vg name %s", vg_name);
851 : : /* FIXME: use _vg_make_handle() w/proper error code */
852 : 0 : return NULL;
853 : : }
854 : :
855 : 0 : rc = vg_lock_newname(cmd, vg_name);
856 [ # # ]: 0 : if (rc != SUCCESS)
857 : : /* NOTE: let caller decide - this may be check for existence */
858 : 0 : return _vg_make_handle(cmd, NULL, rc);
859 : :
860 : : /* FIXME: Is this vg_read_internal necessary? Move it inside
861 : : vg_lock_newname? */
862 : : /* is this vg name already in use ? */
863 [ # # ]: 0 : if ((vg = vg_read_internal(cmd, vg_name, NULL, &consistent))) {
864 : 0 : log_error("A volume group called '%s' already exists.", vg_name);
865 : 0 : unlock_and_release_vg(cmd, vg, vg_name);
866 : 0 : return _vg_make_handle(cmd, NULL, FAILED_EXIST);
867 : : }
868 : :
869 [ # # ]: 0 : if (!(mem = dm_pool_create("lvm2 vg_create", VG_MEMPOOL_CHUNK)))
870 : 0 : goto_bad;
871 : :
872 [ # # ]: 0 : if (!(vg = dm_pool_zalloc(mem, sizeof(*vg))))
873 : 0 : goto_bad;
874 : :
875 [ # # ]: 0 : if (!id_create(&vg->id)) {
876 : 0 : log_error("Couldn't create uuid for volume group '%s'.",
877 : : vg_name);
878 : 0 : goto bad;
879 : : }
880 : :
881 : : /* Strip dev_dir if present */
882 : 0 : vg_name = strip_dir(vg_name, cmd->dev_dir);
883 : :
884 : 0 : vg->vgmem = mem;
885 : 0 : vg->cmd = cmd;
886 : :
887 [ # # ]: 0 : if (!(vg->name = dm_pool_strdup(mem, vg_name)))
888 : 0 : goto_bad;
889 : :
890 : 0 : vg->seqno = 0;
891 : :
892 : 0 : vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
893 [ # # ]: 0 : if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN)))
894 : 0 : goto_bad;
895 : :
896 : 0 : *vg->system_id = '\0';
897 : :
898 : 0 : vg->extent_size = DEFAULT_EXTENT_SIZE * 2;
899 : 0 : vg->extent_count = 0;
900 : 0 : vg->free_count = 0;
901 : :
902 : 0 : vg->max_lv = DEFAULT_MAX_LV;
903 : 0 : vg->max_pv = DEFAULT_MAX_PV;
904 : :
905 : 0 : vg->alloc = DEFAULT_ALLOC_POLICY;
906 : :
907 : 0 : vg->pv_count = 0;
908 : 0 : dm_list_init(&vg->pvs);
909 : :
910 : 0 : dm_list_init(&vg->lvs);
911 : :
912 : 0 : dm_list_init(&vg->tags);
913 : :
914 : : /* initialize removed_pvs list */
915 : 0 : dm_list_init(&vg->removed_pvs);
916 : :
917 [ # # ]: 0 : if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg_name,
918 : : NULL, NULL))) {
919 : 0 : log_error("Failed to create format instance");
920 : 0 : goto bad;
921 : : }
922 : :
923 [ # # # # ]: 0 : if (vg->fid->fmt->ops->vg_setup &&
924 : 0 : !vg->fid->fmt->ops->vg_setup(vg->fid, vg)) {
925 : 0 : log_error("Format specific setup of volume group '%s' failed.",
926 : : vg_name);
927 : 0 : goto bad;
928 : : }
929 : 0 : return _vg_make_handle(cmd, vg, SUCCESS);
930 : :
931 : : bad:
932 : 0 : unlock_and_release_vg(cmd, vg, vg_name);
933 : : /* FIXME: use _vg_make_handle() w/proper error code */
934 : 0 : return NULL;
935 : : }
936 : :
937 : 0 : uint64_t extents_from_size(struct cmd_context *cmd, uint64_t size,
938 : : uint32_t extent_size)
939 : : {
940 [ # # ]: 0 : if (size % extent_size) {
941 : 0 : size += extent_size - size % extent_size;
942 : 0 : log_print("Rounding up size to full physical extent %s",
943 : : display_size(cmd, size));
944 : : }
945 : :
946 [ # # ]: 0 : if (size > (uint64_t) UINT32_MAX * extent_size) {
947 : 0 : log_error("Volume too large (%s) for extent size %s. "
948 : : "Upper limit is %s.",
949 : : display_size(cmd, size),
950 : : display_size(cmd, (uint64_t) extent_size),
951 : : display_size(cmd, (uint64_t) UINT32_MAX *
952 : : extent_size));
953 : 0 : return 0;
954 : : }
955 : :
956 : 0 : return (uint64_t) size / extent_size;
957 : : }
958 : :
959 : 0 : static int _recalc_extents(uint32_t *extents, const char *desc1,
960 : : const char *desc2, uint32_t old_size,
961 : : uint32_t new_size)
962 : : {
963 : 0 : uint64_t size = (uint64_t) old_size * (*extents);
964 : :
965 [ # # ]: 0 : if (size % new_size) {
966 : 0 : log_error("New size %" PRIu64 " for %s%s not an exact number "
967 : : "of new extents.", size, desc1, desc2);
968 : 0 : return 0;
969 : : }
970 : :
971 : 0 : size /= new_size;
972 : :
973 [ # # ]: 0 : if (size > UINT32_MAX) {
974 : 0 : log_error("New extent count %" PRIu64 " for %s%s exceeds "
975 : : "32 bits.", size, desc1, desc2);
976 : 0 : return 0;
977 : : }
978 : :
979 : 0 : *extents = (uint32_t) size;
980 : :
981 : 0 : return 1;
982 : : }
983 : :
984 : 0 : int vg_set_extent_size(struct volume_group *vg, uint32_t new_size)
985 : : {
986 : 0 : uint32_t old_size = vg->extent_size;
987 : : struct pv_list *pvl;
988 : : struct lv_list *lvl;
989 : : struct physical_volume *pv;
990 : : struct logical_volume *lv;
991 : : struct lv_segment *seg;
992 : : struct pv_segment *pvseg;
993 : : uint32_t s;
994 : :
995 [ # # ]: 0 : if (!vg_is_resizeable(vg)) {
996 : 0 : log_error("Volume group \"%s\" must be resizeable "
997 : : "to change PE size", vg->name);
998 : 0 : return 0;
999 : : }
1000 : :
1001 [ # # ]: 0 : if (!new_size) {
1002 : 0 : log_error("Physical extent size may not be zero");
1003 : 0 : return 0;
1004 : : }
1005 : :
1006 [ # # ]: 0 : if (new_size == vg->extent_size)
1007 : 0 : return 1;
1008 : :
1009 [ # # ]: 0 : if (new_size & (new_size - 1)) {
1010 : 0 : log_error("Physical extent size must be a power of 2.");
1011 : 0 : return 0;
1012 : : }
1013 : :
1014 [ # # ]: 0 : if (new_size > vg->extent_size) {
1015 [ # # ]: 0 : if ((uint64_t) vg_size(vg) % new_size) {
1016 : : /* FIXME Adjust used PV sizes instead */
1017 : 0 : log_error("New extent size is not a perfect fit");
1018 : 0 : return 0;
1019 : : }
1020 : : }
1021 : :
1022 : 0 : vg->extent_size = new_size;
1023 : :
1024 [ # # # # ]: 0 : if (vg->fid->fmt->ops->vg_setup &&
1025 : 0 : !vg->fid->fmt->ops->vg_setup(vg->fid, vg))
1026 : 0 : return_0;
1027 : :
1028 [ # # ]: 0 : if (!_recalc_extents(&vg->extent_count, vg->name, "", old_size,
1029 : : new_size))
1030 : 0 : return_0;
1031 : :
1032 [ # # ]: 0 : if (!_recalc_extents(&vg->free_count, vg->name, " free space",
1033 : : old_size, new_size))
1034 : 0 : return_0;
1035 : :
1036 : : /* foreach PV */
1037 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
1038 : 0 : pv = pvl->pv;
1039 : :
1040 : 0 : pv->pe_size = new_size;
1041 [ # # ]: 0 : if (!_recalc_extents(&pv->pe_count, pv_dev_name(pv), "",
1042 : : old_size, new_size))
1043 : 0 : return_0;
1044 : :
1045 [ # # ]: 0 : if (!_recalc_extents(&pv->pe_alloc_count, pv_dev_name(pv),
1046 : : " allocated space", old_size, new_size))
1047 : 0 : return_0;
1048 : :
1049 : : /* foreach free PV Segment */
1050 [ # # ]: 0 : dm_list_iterate_items(pvseg, &pv->segments) {
1051 [ # # ]: 0 : if (pvseg_is_allocated(pvseg))
1052 : 0 : continue;
1053 : :
1054 [ # # ]: 0 : if (!_recalc_extents(&pvseg->pe, pv_dev_name(pv),
1055 : : " PV segment start", old_size,
1056 : : new_size))
1057 : 0 : return_0;
1058 [ # # ]: 0 : if (!_recalc_extents(&pvseg->len, pv_dev_name(pv),
1059 : : " PV segment length", old_size,
1060 : : new_size))
1061 : 0 : return_0;
1062 : : }
1063 : : }
1064 : :
1065 : : /* foreach LV */
1066 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
1067 : 0 : lv = lvl->lv;
1068 : :
1069 [ # # ]: 0 : if (!_recalc_extents(&lv->le_count, lv->name, "", old_size,
1070 : : new_size))
1071 : 0 : return_0;
1072 : :
1073 [ # # ]: 0 : dm_list_iterate_items(seg, &lv->segments) {
1074 [ # # ]: 0 : if (!_recalc_extents(&seg->le, lv->name,
1075 : : " segment start", old_size,
1076 : : new_size))
1077 : 0 : return_0;
1078 : :
1079 [ # # ]: 0 : if (!_recalc_extents(&seg->len, lv->name,
1080 : : " segment length", old_size,
1081 : : new_size))
1082 : 0 : return_0;
1083 : :
1084 [ # # ]: 0 : if (!_recalc_extents(&seg->area_len, lv->name,
1085 : : " area length", old_size,
1086 : : new_size))
1087 : 0 : return_0;
1088 : :
1089 [ # # ]: 0 : if (!_recalc_extents(&seg->extents_copied, lv->name,
1090 : : " extents moved", old_size,
1091 : : new_size))
1092 : 0 : return_0;
1093 : :
1094 : : /* foreach area */
1095 [ # # ]: 0 : for (s = 0; s < seg->area_count; s++) {
1096 [ # # # # ]: 0 : switch (seg_type(seg, s)) {
1097 : : case AREA_PV:
1098 [ # # ]: 0 : if (!_recalc_extents
1099 : 0 : (&seg_pe(seg, s),
1100 : 0 : lv->name,
1101 : : " pvseg start", old_size,
1102 : : new_size))
1103 : 0 : return_0;
1104 [ # # ]: 0 : if (!_recalc_extents
1105 : 0 : (&seg_pvseg(seg, s)->len,
1106 : 0 : lv->name,
1107 : : " pvseg length", old_size,
1108 : : new_size))
1109 : 0 : return_0;
1110 : 0 : break;
1111 : : case AREA_LV:
1112 [ # # ]: 0 : if (!_recalc_extents
1113 : 0 : (&seg_le(seg, s), lv->name,
1114 : : " area start", old_size,
1115 : : new_size))
1116 : 0 : return_0;
1117 : 0 : break;
1118 : : case AREA_UNASSIGNED:
1119 : 0 : log_error("Unassigned area %u found in "
1120 : : "segment", s);
1121 : 0 : return 0;
1122 : : }
1123 : : }
1124 : : }
1125 : :
1126 : : }
1127 : :
1128 : 0 : return 1;
1129 : : }
1130 : :
1131 : 0 : int vg_set_max_lv(struct volume_group *vg, uint32_t max_lv)
1132 : : {
1133 [ # # ]: 0 : if (!vg_is_resizeable(vg)) {
1134 : 0 : log_error("Volume group \"%s\" must be resizeable "
1135 : : "to change MaxLogicalVolume", vg->name);
1136 : 0 : return 0;
1137 : : }
1138 : :
1139 [ # # ]: 0 : if (!(vg->fid->fmt->features & FMT_UNLIMITED_VOLS)) {
1140 [ # # ]: 0 : if (!max_lv)
1141 : 0 : max_lv = 255;
1142 [ # # ]: 0 : else if (max_lv > 255) {
1143 : 0 : log_error("MaxLogicalVolume limit is 255");
1144 : 0 : return 0;
1145 : : }
1146 : : }
1147 : :
1148 [ # # ][ # # ]: 0 : if (max_lv && max_lv < vg_visible_lvs(vg)) {
1149 : 0 : log_error("MaxLogicalVolume is less than the current number "
1150 : : "%d of LVs for %s", vg_visible_lvs(vg),
1151 : : vg->name);
1152 : 0 : return 0;
1153 : : }
1154 : 0 : vg->max_lv = max_lv;
1155 : :
1156 : 0 : return 1;
1157 : : }
1158 : :
1159 : 0 : int vg_set_max_pv(struct volume_group *vg, uint32_t max_pv)
1160 : : {
1161 [ # # ]: 0 : if (!vg_is_resizeable(vg)) {
1162 : 0 : log_error("Volume group \"%s\" must be resizeable "
1163 : : "to change MaxPhysicalVolumes", vg->name);
1164 : 0 : return 0;
1165 : : }
1166 : :
1167 [ # # ]: 0 : if (!(vg->fid->fmt->features & FMT_UNLIMITED_VOLS)) {
1168 [ # # ]: 0 : if (!max_pv)
1169 : 0 : max_pv = 255;
1170 [ # # ]: 0 : else if (max_pv > 255) {
1171 : 0 : log_error("MaxPhysicalVolume limit is 255");
1172 : 0 : return 0;
1173 : : }
1174 : : }
1175 : :
1176 [ # # ][ # # ]: 0 : if (max_pv && max_pv < vg->pv_count) {
1177 : 0 : log_error("MaxPhysicalVolumes is less than the current number "
1178 : : "%d of PVs for \"%s\"", vg->pv_count,
1179 : : vg->name);
1180 : 0 : return 0;
1181 : : }
1182 : 0 : vg->max_pv = max_pv;
1183 : 0 : return 1;
1184 : : }
1185 : :
1186 : 0 : int vg_set_alloc_policy(struct volume_group *vg, alloc_policy_t alloc)
1187 : : {
1188 [ # # ]: 0 : if (alloc == ALLOC_INHERIT) {
1189 : 0 : log_error("Volume Group allocation policy cannot inherit "
1190 : : "from anything");
1191 : 0 : return 0;
1192 : : }
1193 : :
1194 [ # # ]: 0 : if (alloc == vg->alloc)
1195 : 0 : return 1;
1196 : :
1197 : 0 : vg->alloc = alloc;
1198 : 0 : return 1;
1199 : : }
1200 : :
1201 : 0 : int vg_set_clustered(struct volume_group *vg, int clustered)
1202 : : {
1203 : : struct lv_list *lvl;
1204 [ # # ]: 0 : if (clustered) {
1205 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
1206 [ # # ][ # # ]: 0 : if (lv_is_origin(lvl->lv) || lv_is_cow(lvl->lv)) {
1207 : 0 : log_error("Volume group %s contains snapshots "
1208 : : "that are not yet supported.",
1209 : : vg->name);
1210 : 0 : return 0;
1211 : : }
1212 : : }
1213 : : }
1214 : :
1215 [ # # ]: 0 : if (clustered)
1216 : 0 : vg->status |= CLUSTERED;
1217 : : else
1218 : 0 : vg->status &= ~CLUSTERED;
1219 : 0 : return 1;
1220 : : }
1221 : :
1222 : : /*
1223 : : * Separate metadata areas after splitting a VG.
1224 : : * Also accepts orphan VG as destination (for vgreduce).
1225 : : */
1226 : 0 : int vg_split_mdas(struct cmd_context *cmd __attribute((unused)),
1227 : : struct volume_group *vg_from, struct volume_group *vg_to)
1228 : : {
1229 : : struct metadata_area *mda, *mda2;
1230 : : struct dm_list *mdas_from, *mdas_to;
1231 : 0 : int common_mda = 0;
1232 : :
1233 : 0 : mdas_from = &vg_from->fid->metadata_areas;
1234 : 0 : mdas_to = &vg_to->fid->metadata_areas;
1235 : :
1236 [ # # ]: 0 : dm_list_iterate_items_safe(mda, mda2, mdas_from) {
1237 [ # # ]: 0 : if (!mda->ops->mda_in_vg) {
1238 : 0 : common_mda = 1;
1239 : 0 : continue;
1240 : : }
1241 : :
1242 [ # # ]: 0 : if (!mda->ops->mda_in_vg(vg_from->fid, vg_from, mda)) {
1243 [ # # ]: 0 : if (is_orphan_vg(vg_to->name))
1244 : 0 : dm_list_del(&mda->list);
1245 : : else
1246 : 0 : dm_list_move(mdas_to, &mda->list);
1247 : : }
1248 : : }
1249 : :
1250 [ # # # # # : 0 : if (dm_list_empty(mdas_from) ||
# ]
1251 : 0 : (!is_orphan_vg(vg_to->name) && dm_list_empty(mdas_to)))
1252 : 0 : return common_mda;
1253 : :
1254 : 0 : return 1;
1255 : : }
1256 : :
1257 : : /*
1258 : : * See if we may pvcreate on this device.
1259 : : * 0 indicates we may not.
1260 : : */
1261 : 0 : static int pvcreate_check(struct cmd_context *cmd, const char *name,
1262 : : struct pvcreate_params *pp)
1263 : : {
1264 : : struct physical_volume *pv;
1265 : : struct device *dev;
1266 : : uint64_t md_superblock, swap_signature;
1267 : : int wipe_md, wipe_swap;
1268 : : struct dm_list mdas;
1269 : :
1270 : 0 : dm_list_init(&mdas);
1271 : :
1272 : : /* FIXME Check partition type is LVM unless --force is given */
1273 : :
1274 : : /* Is there a pv here already? */
1275 : 0 : pv = pv_read(cmd, name, &mdas, NULL, 0, 0);
1276 : :
1277 : : /*
1278 : : * If a PV has no MDAs it may appear to be an orphan until the
1279 : : * metadata is read off another PV in the same VG. Detecting
1280 : : * this means checking every VG by scanning every PV on the
1281 : : * system.
1282 : : */
1283 [ # # # # ]: 0 : if (pv && is_orphan(pv) && !dm_list_size(&mdas)) {
[ # # ]
1284 [ # # ]: 0 : if (!scan_vgs_for_pvs(cmd))
1285 : 0 : return_0;
1286 : 0 : pv = pv_read(cmd, name, NULL, NULL, 0, 0);
1287 : : }
1288 : :
1289 : : /* Allow partial & exported VGs to be destroyed. */
1290 : : /* We must have -ff to overwrite a non orphan */
1291 [ # # ][ # # ]: 0 : if (pv && !is_orphan(pv) && pp->force != DONT_PROMPT_OVERRIDE) {
[ # # ]
1292 : 0 : log_error("Can't initialize physical volume \"%s\" of "
1293 : : "volume group \"%s\" without -ff", name, pv_vg_name(pv));
1294 : 0 : return 0;
1295 : : }
1296 : :
1297 : : /* prompt */
1298 [ # # ][ # # ]: 0 : if (pv && !is_orphan(pv) && !pp->yes &&
[ # # # # ]
1299 : 0 : yes_no_prompt(_really_init, name, pv_vg_name(pv)) == 'n') {
1300 : 0 : log_error("%s: physical volume not initialized", name);
1301 : 0 : return 0;
1302 : : }
1303 : :
1304 [ # # ]: 0 : if (sigint_caught())
1305 : 0 : return 0;
1306 : :
1307 : 0 : dev = dev_cache_get(name, cmd->filter);
1308 : :
1309 : : /* Is there an md superblock here? */
1310 : : /* FIXME: still possible issues here - rescan cache? */
1311 [ # # # # ]: 0 : if (!dev && md_filtering()) {
1312 : 0 : refresh_filters(cmd);
1313 : 0 : init_md_filtering(0);
1314 : 0 : dev = dev_cache_get(name, cmd->filter);
1315 : 0 : init_md_filtering(1);
1316 : : }
1317 : :
1318 [ # # ]: 0 : if (!dev) {
1319 : 0 : log_error("Device %s not found (or ignored by filtering).", name);
1320 : 0 : return 0;
1321 : : }
1322 : :
1323 : : /*
1324 : : * This test will fail if the device belongs to an MD array.
1325 : : */
1326 [ # # ]: 0 : if (!dev_test_excl(dev)) {
1327 : : /* FIXME Detect whether device-mapper itself is still using it */
1328 : 0 : log_error("Can't open %s exclusively. Mounted filesystem?",
1329 : : name);
1330 : 0 : return 0;
1331 : : }
1332 : :
1333 : : /* Wipe superblock? */
1334 [ # # ][ # # ]: 0 : if ((wipe_md = dev_is_md(dev, &md_superblock)) == 1 &&
[ # # ]
[ # # # # ]
1335 : 0 : ((!pp->idp && !pp->restorefile) || pp->yes ||
1336 : 0 : (yes_no_prompt("Software RAID md superblock "
1337 : : "detected on %s. Wipe it? [y/n] ", name) == 'y'))) {
1338 : 0 : log_print("Wiping software RAID md superblock on %s", name);
1339 [ # # ]: 0 : if (!dev_set(dev, md_superblock, 4, 0)) {
1340 : 0 : log_error("Failed to wipe RAID md superblock on %s",
1341 : : name);
1342 : 0 : return 0;
1343 : : }
1344 : : }
1345 : :
1346 [ # # ]: 0 : if (wipe_md == -1) {
1347 : 0 : log_error("Fatal error while trying to detect software "
1348 : : "RAID md superblock on %s", name);
1349 : 0 : return 0;
1350 : : }
1351 : :
1352 [ # # ][ # # ]: 0 : if ((wipe_swap = dev_is_swap(dev, &swap_signature)) == 1 &&
[ # # ]
[ # # # # ]
1353 : 0 : ((!pp->idp && !pp->restorefile) || pp->yes ||
1354 : 0 : (yes_no_prompt("Swap signature detected on %s. Wipe it? [y/n] ",
1355 : : name) == 'y'))) {
1356 : 0 : log_print("Wiping swap signature on %s", name);
1357 [ # # ]: 0 : if (!dev_set(dev, swap_signature, 10, 0)) {
1358 : 0 : log_error("Failed to wipe swap signature on %s", name);
1359 : 0 : return 0;
1360 : : }
1361 : : }
1362 : :
1363 [ # # ]: 0 : if (wipe_swap == -1) {
1364 : 0 : log_error("Fatal error while trying to detect swap "
1365 : : "signature on %s", name);
1366 : 0 : return 0;
1367 : : }
1368 : :
1369 [ # # ]: 0 : if (sigint_caught())
1370 : 0 : return 0;
1371 : :
1372 [ # # ][ # # ]: 0 : if (pv && !is_orphan(pv) && pp->force) {
[ # # ]
1373 [ # # ][ # # ]: 0 : log_warn("WARNING: Forcing physical volume creation on "
[ # # ]
1374 : : "%s%s%s%s", name,
1375 : : !is_orphan(pv) ? " of volume group \"" : "",
1376 : : !is_orphan(pv) ? pv_vg_name(pv) : "",
1377 : : !is_orphan(pv) ? "\"" : "");
1378 : : }
1379 : :
1380 : 0 : return 1;
1381 : : }
1382 : :
1383 : 0 : void pvcreate_params_set_defaults(struct pvcreate_params *pp)
1384 : : {
1385 : 0 : memset(pp, 0, sizeof(*pp));
1386 : 0 : pp->zero = 1;
1387 : 0 : pp->size = 0;
1388 : 0 : pp->data_alignment = UINT64_C(0);
1389 : 0 : pp->data_alignment_offset = UINT64_C(0);
1390 : 0 : pp->pvmetadatacopies = DEFAULT_PVMETADATACOPIES;
1391 : 0 : pp->pvmetadatasize = DEFAULT_PVMETADATASIZE;
1392 : 0 : pp->labelsector = DEFAULT_LABELSECTOR;
1393 : 0 : pp->idp = 0;
1394 : 0 : pp->pe_start = 0;
1395 : 0 : pp->extent_count = 0;
1396 : 0 : pp->extent_size = 0;
1397 : 0 : pp->restorefile = 0;
1398 : 0 : pp->force = PROMPT;
1399 : 0 : pp->yes = 0;
1400 : 0 : }
1401 : :
1402 : : /*
1403 : : * pvcreate_single() - initialize a device with PV label and metadata area
1404 : : *
1405 : : * Parameters:
1406 : : * - pv_name: device path to initialize
1407 : : * - pp: parameters to pass to pv_create; if NULL, use default values
1408 : : *
1409 : : * Returns:
1410 : : * NULL: error
1411 : : * struct physical_volume * (non-NULL): handle to physical volume created
1412 : : */
1413 : 0 : struct physical_volume * pvcreate_single(struct cmd_context *cmd,
1414 : : const char *pv_name,
1415 : : struct pvcreate_params *pp)
1416 : : {
1417 : : struct physical_volume *pv;
1418 : : struct device *dev;
1419 : : struct dm_list mdas;
1420 : : struct pvcreate_params default_pp;
1421 : : char buffer[64] __attribute((aligned(8)));
1422 : :
1423 : 0 : pvcreate_params_set_defaults(&default_pp);
1424 [ # # ]: 0 : if (!pp)
1425 : 0 : pp = &default_pp;
1426 : :
1427 [ # # ]: 0 : if (pp->idp) {
1428 [ # # # # ]: 0 : if ((dev = device_from_pvid(cmd, pp->idp, NULL)) &&
1429 : 0 : (dev != dev_cache_get(pv_name, cmd->filter))) {
1430 [ # # ]: 0 : if (!id_write_format((const struct id*)&pp->idp->uuid,
1431 : : buffer, sizeof(buffer)))
1432 : 0 : return_NULL;
1433 : 0 : log_error("uuid %s already in use on \"%s\"", buffer,
1434 : : dev_name(dev));
1435 : 0 : return NULL;
1436 : : }
1437 : : }
1438 : :
1439 [ # # ]: 0 : if (!pvcreate_check(cmd, pv_name, pp))
1440 : 0 : goto error;
1441 : :
1442 [ # # ]: 0 : if (sigint_caught())
1443 : 0 : goto error;
1444 : :
1445 [ # # ]: 0 : if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
1446 : 0 : log_error("%s: Couldn't find device. Check your filters?",
1447 : : pv_name);
1448 : 0 : goto error;
1449 : : }
1450 : :
1451 : 0 : dm_list_init(&mdas);
1452 [ # # ]: 0 : if (!(pv = pv_create(cmd, dev, pp->idp, pp->size,
1453 : 0 : pp->data_alignment, pp->data_alignment_offset,
1454 : : pp->pe_start, pp->extent_count, pp->extent_size,
1455 : : pp->pvmetadatacopies,
1456 : : pp->pvmetadatasize,&mdas))) {
1457 : 0 : log_error("Failed to setup physical volume \"%s\"", pv_name);
1458 : 0 : goto error;
1459 : : }
1460 : :
1461 : 0 : log_verbose("Set up physical volume for \"%s\" with %" PRIu64
1462 : : " available sectors", pv_name, pv_size(pv));
1463 : :
1464 : : /* Wipe existing label first */
1465 [ # # ]: 0 : if (!label_remove(pv_dev(pv))) {
1466 : 0 : log_error("Failed to wipe existing label on %s", pv_name);
1467 : 0 : goto error;
1468 : : }
1469 : :
1470 [ # # ]: 0 : if (pp->zero) {
1471 : 0 : log_verbose("Zeroing start of device %s", pv_name);
1472 [ # # ]: 0 : if (!dev_open_quiet(dev)) {
1473 : 0 : log_error("%s not opened: device not zeroed", pv_name);
1474 : 0 : goto error;
1475 : : }
1476 : :
1477 [ # # ]: 0 : if (!dev_set(dev, UINT64_C(0), (size_t) 2048, 0)) {
1478 : 0 : log_error("%s not wiped: aborting", pv_name);
1479 : 0 : dev_close(dev);
1480 : 0 : goto error;
1481 : : }
1482 : 0 : dev_close(dev);
1483 : : }
1484 : :
1485 : 0 : log_very_verbose("Writing physical volume data to disk \"%s\"",
1486 : : pv_name);
1487 [ # # ]: 0 : if (!(pv_write(cmd, pv, &mdas, pp->labelsector))) {
1488 : 0 : log_error("Failed to write physical volume \"%s\"", pv_name);
1489 : 0 : goto error;
1490 : : }
1491 : :
1492 : 0 : log_print("Physical volume \"%s\" successfully created", pv_name);
1493 : :
1494 : 0 : return pv;
1495 : :
1496 : : error:
1497 : 0 : return NULL;
1498 : : }
1499 : :
1500 : 0 : static void _free_pv(struct dm_pool *mem, struct physical_volume *pv)
1501 : : {
1502 : 0 : dm_pool_free(mem, pv);
1503 : 0 : }
1504 : :
1505 : 0 : static struct physical_volume *_alloc_pv(struct dm_pool *mem, struct device *dev)
1506 : : {
1507 : 0 : struct physical_volume *pv = dm_pool_zalloc(mem, sizeof(*pv));
1508 : :
1509 [ # # ]: 0 : if (!pv)
1510 : 0 : return_NULL;
1511 : :
1512 : 0 : pv->pe_size = 0;
1513 : 0 : pv->pe_start = 0;
1514 : 0 : pv->pe_count = 0;
1515 : 0 : pv->pe_alloc_count = 0;
1516 : 0 : pv->pe_align = 0;
1517 : 0 : pv->pe_align_offset = 0;
1518 : 0 : pv->fmt = NULL;
1519 : 0 : pv->dev = dev;
1520 : :
1521 : 0 : pv->status = ALLOCATABLE_PV;
1522 : :
1523 : 0 : dm_list_init(&pv->tags);
1524 : 0 : dm_list_init(&pv->segments);
1525 : :
1526 : 0 : return pv;
1527 : : }
1528 : :
1529 : : /**
1530 : : * pv_create - initialize a physical volume for use with a volume group
1531 : : *
1532 : : * @fmt: format type
1533 : : * @dev: PV device to initialize
1534 : : * @size: size of the PV in sectors
1535 : : * @data_alignment: requested alignment of data
1536 : : * @data_alignment_offset: requested offset to aligned data
1537 : : * @pe_start: physical extent start
1538 : : * @existing_extent_count
1539 : : * @existing_extent_size
1540 : : * @pvmetadatacopies
1541 : : * @pvmetadatasize
1542 : : * @mdas
1543 : : *
1544 : : * Returns:
1545 : : * PV handle - physical volume initialized successfully
1546 : : * NULL - invalid parameter or problem initializing the physical volume
1547 : : *
1548 : : * Note:
1549 : : * FIXME: shorten argument list and replace with explict 'set' functions
1550 : : */
1551 : 0 : struct physical_volume *pv_create(const struct cmd_context *cmd,
1552 : : struct device *dev,
1553 : : struct id *id, uint64_t size,
1554 : : unsigned long data_alignment,
1555 : : unsigned long data_alignment_offset,
1556 : : uint64_t pe_start,
1557 : : uint32_t existing_extent_count,
1558 : : uint32_t existing_extent_size,
1559 : : int pvmetadatacopies,
1560 : : uint64_t pvmetadatasize, struct dm_list *mdas)
1561 : : {
1562 : 0 : const struct format_type *fmt = cmd->fmt;
1563 : 0 : struct dm_pool *mem = fmt->cmd->mem;
1564 : 0 : struct physical_volume *pv = _alloc_pv(mem, dev);
1565 : :
1566 [ # # ]: 0 : if (!pv)
1567 : 0 : return NULL;
1568 : :
1569 [ # # ]: 0 : if (id)
1570 : 0 : memcpy(&pv->id, id, sizeof(*id));
1571 [ # # ]: 0 : else if (!id_create(&pv->id)) {
1572 : 0 : log_error("Failed to create random uuid for %s.",
1573 : : dev_name(dev));
1574 : 0 : goto bad;
1575 : : }
1576 : :
1577 [ # # ]: 0 : if (!dev_get_size(pv->dev, &pv->size)) {
1578 : 0 : log_error("%s: Couldn't get size.", pv_dev_name(pv));
1579 : 0 : goto bad;
1580 : : }
1581 : :
1582 [ # # ]: 0 : if (size) {
1583 [ # # ]: 0 : if (size > pv->size)
1584 : 0 : log_warn("WARNING: %s: Overriding real size. "
1585 : : "You could lose data.", pv_dev_name(pv));
1586 : 0 : log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
1587 : : pv_dev_name(pv), size);
1588 : 0 : pv->size = size;
1589 : : }
1590 : :
1591 [ # # ]: 0 : if (pv->size < PV_MIN_SIZE) {
1592 : 0 : log_error("%s: Size must exceed minimum of %ld sectors.",
1593 : : pv_dev_name(pv), PV_MIN_SIZE);
1594 : 0 : goto bad;
1595 : : }
1596 : :
1597 [ # # ]: 0 : if (pv->size < data_alignment) {
1598 : 0 : log_error("%s: Data alignment must not exceed device size.",
1599 : : pv_dev_name(pv));
1600 : 0 : goto bad;
1601 : : }
1602 : :
1603 : 0 : pv->fmt = fmt;
1604 : 0 : pv->vg_name = fmt->orphan_vg_name;
1605 : :
1606 [ # # ]: 0 : if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
1607 : : existing_extent_size, data_alignment,
1608 : : data_alignment_offset,
1609 : : pvmetadatacopies, pvmetadatasize, mdas,
1610 : : pv, NULL)) {
1611 : 0 : log_error("%s: Format-specific setup of physical volume "
1612 : : "failed.", pv_dev_name(pv));
1613 : 0 : goto bad;
1614 : : }
1615 : :
1616 : 0 : return pv;
1617 : :
1618 : : bad:
1619 : 0 : _free_pv(mem, pv);
1620 : 0 : return NULL;
1621 : : }
1622 : :
1623 : : /* FIXME: liblvm todo - make into function that returns handle */
1624 : 0 : struct pv_list *find_pv_in_vg(const struct volume_group *vg,
1625 : : const char *pv_name)
1626 : : {
1627 : 0 : return _find_pv_in_vg(vg, pv_name);
1628 : : }
1629 : :
1630 : 0 : static struct pv_list *_find_pv_in_vg(const struct volume_group *vg,
1631 : : const char *pv_name)
1632 : : {
1633 : : struct pv_list *pvl;
1634 : :
1635 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs)
1636 [ # # ]: 0 : if (pvl->pv->dev == dev_cache_get(pv_name, vg->cmd->filter))
1637 : 0 : return pvl;
1638 : :
1639 : 0 : return NULL;
1640 : : }
1641 : :
1642 : 0 : struct pv_list *find_pv_in_pv_list(const struct dm_list *pl,
1643 : : const struct physical_volume *pv)
1644 : : {
1645 : : struct pv_list *pvl;
1646 : :
1647 [ # # ]: 0 : dm_list_iterate_items(pvl, pl)
1648 [ # # ]: 0 : if (pvl->pv == pv)
1649 : 0 : return pvl;
1650 : :
1651 : 0 : return NULL;
1652 : : }
1653 : :
1654 : 0 : int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
1655 : : {
1656 : : struct pv_list *pvl;
1657 : :
1658 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs)
1659 [ # # ]: 0 : if (pv == pvl->pv)
1660 : 0 : return 1;
1661 : :
1662 : 0 : return 0;
1663 : : }
1664 : :
1665 : 0 : static struct pv_list *_find_pv_in_vg_by_uuid(const struct volume_group *vg,
1666 : : const struct id *id)
1667 : : {
1668 : : struct pv_list *pvl;
1669 : :
1670 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs)
1671 [ # # ]: 0 : if (id_equal(&pvl->pv->id, id))
1672 : 0 : return pvl;
1673 : :
1674 : 0 : return NULL;
1675 : : }
1676 : :
1677 : : /**
1678 : : * find_pv_in_vg_by_uuid - Find PV in VG by PV UUID
1679 : : * @vg: volume group to search
1680 : : * @id: UUID of the PV to match
1681 : : *
1682 : : * Returns:
1683 : : * struct pv_list within owning struct volume_group - if UUID of PV found in VG
1684 : : * NULL - invalid parameter or UUID of PV not found in VG
1685 : : *
1686 : : * Note
1687 : : * FIXME - liblvm todo - make into function that takes VG handle
1688 : : */
1689 : 0 : struct pv_list *find_pv_in_vg_by_uuid(const struct volume_group *vg,
1690 : : const struct id *id)
1691 : : {
1692 : 0 : return _find_pv_in_vg_by_uuid(vg, id);
1693 : : }
1694 : :
1695 : 0 : struct lv_list *find_lv_in_vg(const struct volume_group *vg,
1696 : : const char *lv_name)
1697 : : {
1698 : : struct lv_list *lvl;
1699 : : const char *ptr;
1700 : :
1701 : : /* Use last component */
1702 [ # # ]: 0 : if ((ptr = strrchr(lv_name, '/')))
1703 : 0 : ptr++;
1704 : : else
1705 : 0 : ptr = lv_name;
1706 : :
1707 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs)
1708 [ # # ]: 0 : if (!strcmp(lvl->lv->name, ptr))
1709 : 0 : return lvl;
1710 : :
1711 : 0 : return NULL;
1712 : : }
1713 : :
1714 : 0 : struct lv_list *find_lv_in_lv_list(const struct dm_list *ll,
1715 : : const struct logical_volume *lv)
1716 : : {
1717 : : struct lv_list *lvl;
1718 : :
1719 [ # # ]: 0 : dm_list_iterate_items(lvl, ll)
1720 [ # # ]: 0 : if (lvl->lv == lv)
1721 : 0 : return lvl;
1722 : :
1723 : 0 : return NULL;
1724 : : }
1725 : :
1726 : 0 : struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
1727 : : const union lvid *lvid)
1728 : : {
1729 : : struct lv_list *lvl;
1730 : :
1731 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs)
1732 [ # # ]: 0 : if (!strncmp(lvl->lv->lvid.s, lvid->s, sizeof(*lvid)))
1733 : 0 : return lvl;
1734 : :
1735 : 0 : return NULL;
1736 : : }
1737 : :
1738 : 0 : struct logical_volume *find_lv(const struct volume_group *vg,
1739 : : const char *lv_name)
1740 : : {
1741 : 0 : struct lv_list *lvl = find_lv_in_vg(vg, lv_name);
1742 [ # # ]: 0 : return lvl ? lvl->lv : NULL;
1743 : : }
1744 : :
1745 : 0 : struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
1746 : : {
1747 : : struct pv_list *pvl;
1748 : :
1749 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs)
1750 [ # # ]: 0 : if (dev == pvl->pv->dev)
1751 : 0 : return pvl->pv;
1752 : :
1753 : 0 : return NULL;
1754 : : }
1755 : :
1756 : : /* FIXME: liblvm todo - make into function that returns handle */
1757 : 0 : struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
1758 : : const char *pv_name)
1759 : : {
1760 : 0 : return _find_pv_by_name(cmd, pv_name);
1761 : : }
1762 : :
1763 : :
1764 : 0 : static struct physical_volume *_find_pv_by_name(struct cmd_context *cmd,
1765 : : const char *pv_name)
1766 : : {
1767 : : struct dm_list mdas;
1768 : : struct physical_volume *pv;
1769 : :
1770 : 0 : dm_list_init(&mdas);
1771 [ # # ]: 0 : if (!(pv = _pv_read(cmd, cmd->mem, pv_name, &mdas, NULL, 1, 0))) {
1772 : 0 : log_error("Physical volume %s not found", pv_name);
1773 : 0 : return NULL;
1774 : : }
1775 : :
1776 [ # # ][ # # ]: 0 : if (is_orphan_vg(pv->vg_name) && !dm_list_size(&mdas)) {
1777 : : /* If a PV has no MDAs - need to search all VGs for it */
1778 [ # # ]: 0 : if (!scan_vgs_for_pvs(cmd))
1779 : 0 : return_NULL;
1780 [ # # ]: 0 : if (!(pv = _pv_read(cmd, cmd->mem, pv_name, NULL, NULL, 1, 0))) {
1781 : 0 : log_error("Physical volume %s not found", pv_name);
1782 : 0 : return NULL;
1783 : : }
1784 : : }
1785 : :
1786 [ # # ]: 0 : if (is_orphan_vg(pv->vg_name)) {
1787 : 0 : log_error("Physical volume %s not in a volume group", pv_name);
1788 : 0 : return NULL;
1789 : : }
1790 : :
1791 : 0 : return pv;
1792 : : }
1793 : :
1794 : : /* Find segment at a given logical extent in an LV */
1795 : 0 : struct lv_segment *find_seg_by_le(const struct logical_volume *lv, uint32_t le)
1796 : : {
1797 : : struct lv_segment *seg;
1798 : :
1799 [ # # ]: 0 : dm_list_iterate_items(seg, &lv->segments)
1800 [ # # ][ # # ]: 0 : if (le >= seg->le && le < seg->le + seg->len)
1801 : 0 : return seg;
1802 : :
1803 : 0 : return NULL;
1804 : : }
1805 : :
1806 : 0 : struct lv_segment *first_seg(const struct logical_volume *lv)
1807 : : {
1808 : : struct lv_segment *seg;
1809 : :
1810 [ # # ]: 0 : dm_list_iterate_items(seg, &lv->segments)
1811 : 0 : return seg;
1812 : :
1813 : 0 : return NULL;
1814 : : }
1815 : :
1816 : 0 : int vg_remove_mdas(struct volume_group *vg)
1817 : : {
1818 : : struct metadata_area *mda;
1819 : :
1820 : : /* FIXME Improve recovery situation? */
1821 : : /* Remove each copy of the metadata */
1822 [ # # ]: 0 : dm_list_iterate_items(mda, &vg->fid->metadata_areas) {
1823 [ # # # # ]: 0 : if (mda->ops->vg_remove &&
1824 : 0 : !mda->ops->vg_remove(vg->fid, vg, mda))
1825 : 0 : return_0;
1826 : : }
1827 : :
1828 : 0 : return 1;
1829 : : }
1830 : :
1831 : 0 : unsigned snapshot_count(const struct volume_group *vg)
1832 : : {
1833 : : struct lv_list *lvl;
1834 : 0 : unsigned num_snapshots = 0;
1835 : :
1836 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs)
1837 [ # # ]: 0 : if (lv_is_cow(lvl->lv))
1838 : 0 : num_snapshots++;
1839 : :
1840 : 0 : return num_snapshots;
1841 : : }
1842 : :
1843 : 0 : unsigned vg_visible_lvs(const struct volume_group *vg)
1844 : : {
1845 : : struct lv_list *lvl;
1846 : 0 : unsigned lv_count = 0;
1847 : :
1848 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
1849 [ # # ]: 0 : if (lv_is_visible(lvl->lv))
1850 : 0 : lv_count++;
1851 : : }
1852 : :
1853 : 0 : return lv_count;
1854 : : }
1855 : :
1856 : : /*
1857 : : * Determine whether two vgs are compatible for merging.
1858 : : */
1859 : 0 : int vgs_are_compatible(struct cmd_context *cmd __attribute((unused)),
1860 : : struct volume_group *vg_from,
1861 : : struct volume_group *vg_to)
1862 : : {
1863 : : struct lv_list *lvl1, *lvl2;
1864 : : struct pv_list *pvl;
1865 : : char *name1, *name2;
1866 : :
1867 [ # # ]: 0 : if (lvs_in_vg_activated(vg_from)) {
1868 : 0 : log_error("Logical volumes in \"%s\" must be inactive",
1869 : : vg_from->name);
1870 : 0 : return 0;
1871 : : }
1872 : :
1873 : : /* Check compatibility */
1874 [ # # ]: 0 : if (vg_to->extent_size != vg_from->extent_size) {
1875 : 0 : log_error("Extent sizes differ: %d (%s) and %d (%s)",
1876 : : vg_to->extent_size, vg_to->name,
1877 : : vg_from->extent_size, vg_from->name);
1878 : 0 : return 0;
1879 : : }
1880 : :
1881 [ # # ][ # # ]: 0 : if (vg_to->max_pv &&
1882 : 0 : (vg_to->max_pv < vg_to->pv_count + vg_from->pv_count)) {
1883 : 0 : log_error("Maximum number of physical volumes (%d) exceeded "
1884 : : " for \"%s\" and \"%s\"", vg_to->max_pv, vg_to->name,
1885 : : vg_from->name);
1886 : 0 : return 0;
1887 : : }
1888 : :
1889 [ # # # # ]: 0 : if (vg_to->max_lv &&
1890 : 0 : (vg_to->max_lv < vg_visible_lvs(vg_to) + vg_visible_lvs(vg_from))) {
1891 : 0 : log_error("Maximum number of logical volumes (%d) exceeded "
1892 : : " for \"%s\" and \"%s\"", vg_to->max_lv, vg_to->name,
1893 : : vg_from->name);
1894 : 0 : return 0;
1895 : : }
1896 : :
1897 : : /* Metadata types must be the same */
1898 [ # # ]: 0 : if (vg_to->fid->fmt != vg_from->fid->fmt) {
1899 : 0 : log_error("Metadata types differ for \"%s\" and \"%s\"",
1900 : : vg_to->name, vg_from->name);
1901 : 0 : return 0;
1902 : : }
1903 : :
1904 : : /* Clustering attribute must be the same */
1905 [ # # ]: 0 : if (vg_is_clustered(vg_to) != vg_is_clustered(vg_from)) {
1906 : 0 : log_error("Clustered attribute differs for \"%s\" and \"%s\"",
1907 : : vg_to->name, vg_from->name);
1908 : 0 : return 0;
1909 : : }
1910 : :
1911 : : /* Check no conflicts with LV names */
1912 [ # # ]: 0 : dm_list_iterate_items(lvl1, &vg_to->lvs) {
1913 : 0 : name1 = lvl1->lv->name;
1914 : :
1915 [ # # ]: 0 : dm_list_iterate_items(lvl2, &vg_from->lvs) {
1916 : 0 : name2 = lvl2->lv->name;
1917 : :
1918 [ # # ]: 0 : if (!strcmp(name1, name2)) {
1919 : 0 : log_error("Duplicate logical volume "
1920 : : "name \"%s\" "
1921 : : "in \"%s\" and \"%s\"",
1922 : : name1, vg_to->name, vg_from->name);
1923 : 0 : return 0;
1924 : : }
1925 : : }
1926 : : }
1927 : :
1928 : : /* Check no PVs are constructed from either VG */
1929 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg_to->pvs) {
1930 [ # # ]: 0 : if (pv_uses_vg(pvl->pv, vg_from)) {
1931 : 0 : log_error("Physical volume %s might be constructed "
1932 : : "from same volume group %s.",
1933 : : pv_dev_name(pvl->pv), vg_from->name);
1934 : 0 : return 0;
1935 : : }
1936 : : }
1937 : :
1938 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg_from->pvs) {
1939 [ # # ]: 0 : if (pv_uses_vg(pvl->pv, vg_to)) {
1940 : 0 : log_error("Physical volume %s might be constructed "
1941 : : "from same volume group %s.",
1942 : : pv_dev_name(pvl->pv), vg_to->name);
1943 : 0 : return 0;
1944 : : }
1945 : : }
1946 : :
1947 : 0 : return 1;
1948 : : }
1949 : :
1950 : : struct _lv_postorder_baton {
1951 : : int (*fn)(struct logical_volume *lv, void *data);
1952 : : void *data;
1953 : : };
1954 : :
1955 : : static int _lv_postorder_visit(struct logical_volume *,
1956 : : int (*fn)(struct logical_volume *lv, void *data),
1957 : : void *data);
1958 : :
1959 : 0 : static int _lv_postorder_level(struct logical_volume *lv, void *data)
1960 : : {
1961 : 0 : struct _lv_postorder_baton *baton = data;
1962 [ # # ]: 0 : if (lv->status & POSTORDER_OPEN_FLAG)
1963 : 0 : return 1; // a data structure loop has closed...
1964 : 0 : lv->status |= POSTORDER_OPEN_FLAG;
1965 : 0 : int r =_lv_postorder_visit(lv, baton->fn, baton->data);
1966 : 0 : lv->status &= ~POSTORDER_OPEN_FLAG;
1967 : 0 : lv->status |= POSTORDER_FLAG;
1968 : 0 : return r;
1969 : : };
1970 : :
1971 : 0 : static int _lv_each_dependency(struct logical_volume *lv,
1972 : : int (*fn)(struct logical_volume *lv, void *data),
1973 : : void *data)
1974 : : {
1975 : : int i, s;
1976 : : struct lv_segment *lvseg;
1977 : :
1978 : : struct logical_volume *deps[] = {
1979 : 0 : (lv->rdevice && lv != lv->rdevice->lv) ? lv->rdevice->lv : 0,
1980 : 0 : (lv->rdevice && lv != lv->rdevice->slog) ? lv->rdevice->slog : 0,
1981 : 0 : lv->snapshot ? lv->snapshot->origin : 0,
1982 [ # # ][ # # ]: 0 : lv->snapshot ? lv->snapshot->cow : 0 };
[ # # ][ # # ]
[ # # ][ # # ]
1983 [ # # ]: 0 : for (i = 0; i < sizeof(deps) / sizeof(*deps); ++i) {
1984 [ # # ][ # # ]: 0 : if (deps[i] && !fn(deps[i], data))
1985 : 0 : return_0;
1986 : : }
1987 : :
1988 [ # # ]: 0 : dm_list_iterate_items(lvseg, &lv->segments) {
1989 [ # # ][ # # ]: 0 : if (lvseg->log_lv && !fn(lvseg->log_lv, data))
1990 : 0 : return_0;
1991 [ # # ][ # # ]: 0 : if (lvseg->rlog_lv && !fn(lvseg->rlog_lv, data))
1992 : 0 : return_0;
1993 [ # # ]: 0 : for (s = 0; s < lvseg->area_count; ++s) {
1994 [ # # ][ # # ]: 0 : if (seg_type(lvseg, s) == AREA_LV && !fn(seg_lv(lvseg,s), data))
1995 : 0 : return_0;
1996 : : }
1997 : : }
1998 : 0 : return 1;
1999 : : }
2000 : :
2001 : 0 : static int _lv_postorder_cleanup(struct logical_volume *lv, void *data)
2002 : : {
2003 [ # # ]: 0 : if (!(lv->status & POSTORDER_FLAG))
2004 : 0 : return 1;
2005 : 0 : lv->status &= ~POSTORDER_FLAG;
2006 : :
2007 [ # # ]: 0 : if (!_lv_each_dependency(lv, _lv_postorder_cleanup, data))
2008 : 0 : return_0;
2009 : 0 : return 1;
2010 : : }
2011 : :
2012 : 0 : static int _lv_postorder_visit(struct logical_volume *lv,
2013 : : int (*fn)(struct logical_volume *lv, void *data),
2014 : : void *data)
2015 : : {
2016 : : struct _lv_postorder_baton baton;
2017 : : int r;
2018 : :
2019 [ # # ]: 0 : if (lv->status & POSTORDER_FLAG)
2020 : 0 : return 1;
2021 : :
2022 : 0 : baton.fn = fn;
2023 : 0 : baton.data = data;
2024 : 0 : r = _lv_each_dependency(lv, _lv_postorder_level, &baton);
2025 [ # # ]: 0 : if (r)
2026 : 0 : r = fn(lv, data);
2027 : :
2028 : 0 : return r;
2029 : : }
2030 : :
2031 : : /*
2032 : : * This will walk the LV dependency graph in depth-first order and in the
2033 : : * postorder, call a callback function "fn". The void *data is passed along all
2034 : : * the calls. The callback may return zero to indicate an error and terminate
2035 : : * the depth-first walk. The error is propagated to return value of
2036 : : * _lv_postorder.
2037 : : */
2038 : 0 : static int _lv_postorder(struct logical_volume *lv,
2039 : : int (*fn)(struct logical_volume *lv, void *data),
2040 : : void *data)
2041 : : {
2042 : : int r;
2043 : 0 : r = _lv_postorder_visit(lv, fn, data);
2044 : 0 : _lv_postorder_cleanup(lv, 0);
2045 : 0 : return r;
2046 : : }
2047 : :
2048 : : struct _lv_mark_if_partial_baton {
2049 : : int partial;
2050 : : };
2051 : :
2052 : 0 : static int _lv_mark_if_partial_collect(struct logical_volume *lv, void *data)
2053 : : {
2054 : 0 : struct _lv_mark_if_partial_baton *baton = data;
2055 [ # # ]: 0 : if (lv->status & PARTIAL_LV)
2056 : 0 : baton->partial = 1;
2057 : :
2058 : 0 : return 1;
2059 : : }
2060 : :
2061 : 0 : static int _lv_mark_if_partial_single(struct logical_volume *lv, void *data)
2062 : : {
2063 : : int s;
2064 : : struct _lv_mark_if_partial_baton baton;
2065 : : struct lv_segment *lvseg;
2066 : :
2067 [ # # ]: 0 : dm_list_iterate_items(lvseg, &lv->segments) {
2068 [ # # ]: 0 : for (s = 0; s < lvseg->area_count; ++s) {
2069 [ # # ]: 0 : if (seg_type(lvseg, s) == AREA_PV) {
2070 [ # # ]: 0 : if (is_missing_pv(seg_pv(lvseg, s)))
2071 : 0 : lv->status |= PARTIAL_LV;
2072 : : }
2073 : : }
2074 : : }
2075 : :
2076 : 0 : baton.partial = 0;
2077 : 0 : _lv_each_dependency(lv, _lv_mark_if_partial_collect, &baton);
2078 : :
2079 [ # # ]: 0 : if (baton.partial)
2080 : 0 : lv->status |= PARTIAL_LV;
2081 : :
2082 : 0 : return 1;
2083 : : }
2084 : :
2085 : 0 : static int _lv_mark_if_partial(struct logical_volume *lv)
2086 : : {
2087 : 0 : return _lv_postorder(lv, _lv_mark_if_partial_single, NULL);
2088 : : }
2089 : :
2090 : : /*
2091 : : * Mark LVs with missing PVs using PARTIAL_LV status flag. The flag is
2092 : : * propagated transitively, so LVs referencing other LVs are marked
2093 : : * partial as well, if any of their referenced LVs are marked partial.
2094 : : */
2095 : 0 : static int _vg_mark_partial_lvs(struct volume_group *vg)
2096 : : {
2097 : : struct logical_volume *lv;
2098 : : struct lv_list *lvl;
2099 : :
2100 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
2101 : 0 : lv = lvl->lv;
2102 [ # # ]: 0 : if (!_lv_mark_if_partial(lv))
2103 : 0 : return_0;
2104 : : }
2105 : 0 : return 1;
2106 : : }
2107 : :
2108 : : /*
2109 : : * Be sure that all PV devices have cached read ahead in dev-cache
2110 : : * Currently it takes read_ahead from first PV segment only
2111 : : */
2112 : 0 : static int _lv_read_ahead_single(struct logical_volume *lv, void *data)
2113 : : {
2114 : 0 : struct lv_segment *seg = first_seg(lv);
2115 : 0 : uint32_t seg_read_ahead = 0, *read_ahead = data;
2116 : :
2117 [ # # # # ]: 0 : if (seg && seg->area_count && seg_type(seg, 0) == AREA_PV)
[ # # ]
2118 : 0 : dev_get_read_ahead(seg_pv(seg, 0)->dev, &seg_read_ahead);
2119 : :
2120 [ # # ]: 0 : if (seg_read_ahead > *read_ahead)
2121 : 0 : *read_ahead = seg_read_ahead;
2122 : :
2123 : 0 : return 1;
2124 : : }
2125 : :
2126 : : /*
2127 : : * Calculate readahead for logical volume from underlying PV devices.
2128 : : * If read_ahead is NULL, only ensure that readahead of PVs are preloaded
2129 : : * into PV struct device in dev cache.
2130 : : */
2131 : 0 : void lv_calculate_readahead(const struct logical_volume *lv, uint32_t *read_ahead)
2132 : : {
2133 : 0 : uint32_t _read_ahead = 0;
2134 : :
2135 [ # # ]: 0 : if (lv->read_ahead == DM_READ_AHEAD_AUTO)
2136 : 0 : _lv_postorder((struct logical_volume *)lv, _lv_read_ahead_single, &_read_ahead);
2137 : :
2138 [ # # ]: 0 : if (read_ahead) {
2139 : 0 : log_debug("Calculated readahead of LV %s is %u", lv->name, _read_ahead);
2140 : 0 : *read_ahead = _read_ahead;
2141 : : }
2142 : 0 : }
2143 : :
2144 : 0 : int vg_validate(struct volume_group *vg)
2145 : : {
2146 : : struct pv_list *pvl, *pvl2;
2147 : : struct lv_list *lvl, *lvl2;
2148 : : char uuid[64] __attribute((aligned(8)));
2149 : 0 : int r = 1;
2150 : 0 : uint32_t hidden_lv_count = 0, lv_count = 0, lv_visible_count = 0;
2151 : 0 : uint32_t pv_count = 0;
2152 : 0 : uint32_t num_snapshots = 0;
2153 : : uint32_t loop_counter1, loop_counter2;
2154 : :
2155 : : /* FIXME Also check there's no data/metadata overlap */
2156 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
2157 [ # # ]: 0 : if (++pv_count > vg->pv_count) {
2158 : 0 : log_error(INTERNAL_ERROR "PV list corruption detected in VG %s.", vg->name);
2159 : : /* FIXME Dump list structure? */
2160 : 0 : r = 0;
2161 : : }
2162 : : }
2163 : :
2164 : 0 : loop_counter1 = loop_counter2 = 0;
2165 : : /* FIXME Use temp hash table instead? */
2166 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
2167 [ # # ]: 0 : if (++loop_counter1 > pv_count)
2168 : 0 : break;
2169 [ # # ]: 0 : dm_list_iterate_items(pvl2, &vg->pvs) {
2170 [ # # ]: 0 : if (++loop_counter2 > pv_count)
2171 : 0 : break;
2172 [ # # ]: 0 : if (pvl == pvl2)
2173 : 0 : break;
2174 [ # # ]: 0 : if (id_equal(&pvl->pv->id,
2175 : 0 : &pvl2->pv->id)) {
2176 [ # # ]: 0 : if (!id_write_format(&pvl->pv->id, uuid,
2177 : : sizeof(uuid)))
2178 : 0 : stack;
2179 : 0 : log_error(INTERNAL_ERROR "Duplicate PV id "
2180 : : "%s detected for %s in %s.",
2181 : : uuid, pv_dev_name(pvl->pv),
2182 : : vg->name);
2183 : 0 : r = 0;
2184 : : }
2185 : : }
2186 : :
2187 [ # # ]: 0 : if (strcmp(pvl->pv->vg_name, vg->name)) {
2188 : 0 : log_error(INTERNAL_ERROR "VG name for PV %s is corrupted.",
2189 : : pv_dev_name(pvl->pv));
2190 : 0 : r = 0;
2191 : : }
2192 : : }
2193 : :
2194 [ # # ]: 0 : if (!check_pv_segments(vg)) {
2195 : 0 : log_error(INTERNAL_ERROR "PV segments corrupted in %s.",
2196 : : vg->name);
2197 : 0 : r = 0;
2198 : : }
2199 : :
2200 : : /*
2201 : : * Count all non-snapshot invisible LVs
2202 : : */
2203 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
2204 : 0 : lv_count++;
2205 : :
2206 [ # # ]: 0 : if (lv_is_cow(lvl->lv))
2207 : 0 : num_snapshots++;
2208 : :
2209 [ # # ]: 0 : if (lv_is_visible(lvl->lv))
2210 : 0 : lv_visible_count++;
2211 : :
2212 [ # # ]: 0 : if (!check_lv_segments(lvl->lv, 0)) {
2213 : 0 : log_error(INTERNAL_ERROR "LV segments corrupted in %s.",
2214 : : lvl->lv->name);
2215 : 0 : r = 0;
2216 : : }
2217 : :
2218 [ # # ]: 0 : if (lvl->lv->status & VISIBLE_LV)
2219 : 0 : continue;
2220 : :
2221 : : /* snapshots */
2222 [ # # ]: 0 : if (lv_is_cow(lvl->lv))
2223 : 0 : continue;
2224 : :
2225 : : /* virtual origins are always hidden */
2226 [ # # ][ # # ]: 0 : if (lv_is_origin(lvl->lv) && !lv_is_virtual_origin(lvl->lv))
2227 : 0 : continue;
2228 : :
2229 : : /* count other non-snapshot invisible volumes */
2230 : 0 : hidden_lv_count++;
2231 : :
2232 : : /*
2233 : : * FIXME: add check for unreferenced invisible LVs
2234 : : * - snapshot cow & origin
2235 : : * - mirror log & images
2236 : : * - mirror conversion volumes (_mimagetmp*)
2237 : : */
2238 : : }
2239 : :
2240 : : /*
2241 : : * all volumes = visible LVs + snapshot_cows + invisible LVs
2242 : : */
2243 [ # # ]: 0 : if (lv_count != lv_visible_count + num_snapshots + hidden_lv_count) {
2244 : 0 : log_error(INTERNAL_ERROR "#internal LVs (%u) != #LVs (%"
2245 : : PRIu32 ") + #snapshots (%" PRIu32 ") + #internal LVs (%u) in VG %s",
2246 : : lv_count, lv_visible_count,
2247 : : num_snapshots, hidden_lv_count, vg->name);
2248 : 0 : r = 0;
2249 : : }
2250 : :
2251 : : /* Avoid endless loop if lv->segments list is corrupt */
2252 [ # # ]: 0 : if (!r)
2253 : 0 : return r;
2254 : :
2255 : 0 : loop_counter1 = loop_counter2 = 0;
2256 : : /* FIXME Use temp hash table instead? */
2257 [ # # ]: 0 : dm_list_iterate_items(lvl, &vg->lvs) {
2258 [ # # ]: 0 : if (++loop_counter1 > lv_count)
2259 : 0 : break;
2260 [ # # ]: 0 : dm_list_iterate_items(lvl2, &vg->lvs) {
2261 [ # # ]: 0 : if (++loop_counter2 > lv_count)
2262 : 0 : break;
2263 [ # # ]: 0 : if (lvl == lvl2)
2264 : 0 : break;
2265 [ # # ]: 0 : if (!strcmp(lvl->lv->name, lvl2->lv->name)) {
2266 : 0 : log_error(INTERNAL_ERROR "Duplicate LV name "
2267 : : "%s detected in %s.", lvl->lv->name,
2268 : : vg->name);
2269 : 0 : r = 0;
2270 : : }
2271 [ # # ]: 0 : if (id_equal(&lvl->lv->lvid.id[1],
2272 : 0 : &lvl2->lv->lvid.id[1])) {
2273 [ # # ]: 0 : if (!id_write_format(&lvl->lv->lvid.id[1], uuid,
2274 : : sizeof(uuid)))
2275 : 0 : stack;
2276 : 0 : log_error(INTERNAL_ERROR "Duplicate LV id "
2277 : : "%s detected for %s and %s in %s.",
2278 : : uuid, lvl->lv->name, lvl2->lv->name,
2279 : : vg->name);
2280 : 0 : r = 0;
2281 : : }
2282 : : }
2283 : :
2284 [ # # ]: 0 : if (!check_lv_segments(lvl->lv, 1)) {
2285 : 0 : log_error(INTERNAL_ERROR "LV segments corrupted in %s.",
2286 : : lvl->lv->name);
2287 : 0 : r = 0;
2288 : : }
2289 : : }
2290 : :
2291 [ # # ][ # # ]: 0 : if (!(vg->fid->fmt->features & FMT_UNLIMITED_VOLS) &&
[ # # ]
2292 : 0 : (!vg->max_lv || !vg->max_pv)) {
2293 : 0 : log_error(INTERNAL_ERROR "Volume group %s has limited PV/LV count"
2294 : : " but limit is not set.", vg->name);
2295 : 0 : r = 0;
2296 : : }
2297 : :
2298 [ # # ]: 0 : if (vg_max_lv_reached(vg))
2299 : 0 : stack;
2300 : :
2301 : 0 : return r;
2302 : : }
2303 : :
2304 : : /*
2305 : : * After vg_write() returns success,
2306 : : * caller MUST call either vg_commit() or vg_revert()
2307 : : */
2308 : 0 : int vg_write(struct volume_group *vg)
2309 : : {
2310 : : struct dm_list *mdah;
2311 : : struct metadata_area *mda;
2312 : :
2313 [ # # ]: 0 : if (!vg_validate(vg))
2314 : 0 : return_0;
2315 : :
2316 [ # # ]: 0 : if (vg->status & PARTIAL_VG) {
2317 : 0 : log_error("Cannot update partial volume group %s.", vg->name);
2318 : 0 : return 0;
2319 : : }
2320 : :
2321 [ # # ][ # # ]: 0 : if (vg_missing_pv_count(vg) && !vg->cmd->handles_missing_pvs) {
2322 : 0 : log_error("Cannot update volume group %s while physical "
2323 : : "volumes are missing.", vg->name);
2324 : 0 : return 0;
2325 : : }
2326 : :
2327 [ # # ][ # # ]: 0 : if (vg_has_unknown_segments(vg) && !vg->cmd->handles_unknown_segments) {
2328 : 0 : log_error("Cannot update volume group %s with unknown segments in it!",
2329 : : vg->name);
2330 : 0 : return 0;
2331 : : }
2332 : :
2333 : :
2334 [ # # ]: 0 : if (dm_list_empty(&vg->fid->metadata_areas)) {
2335 : 0 : log_error("Aborting vg_write: No metadata areas to write to!");
2336 : 0 : return 0;
2337 : : }
2338 : :
2339 [ # # ]: 0 : if (!drop_cached_metadata(vg)) {
2340 : 0 : log_error("Unable to drop cached metadata for VG %s.", vg->name);
2341 : 0 : return 0;
2342 : : }
2343 : :
2344 : 0 : vg->seqno++;
2345 : :
2346 : : /* Write to each copy of the metadata area */
2347 [ # # ]: 0 : dm_list_iterate_items(mda, &vg->fid->metadata_areas) {
2348 [ # # ]: 0 : if (!mda->ops->vg_write) {
2349 : 0 : log_error("Format does not support writing volume"
2350 : : "group metadata areas");
2351 : : /* Revert */
2352 [ # # ]: 0 : dm_list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) {
2353 : 0 : mda = dm_list_item(mdah, struct metadata_area);
2354 : :
2355 [ # # # # ]: 0 : if (mda->ops->vg_revert &&
2356 : 0 : !mda->ops->vg_revert(vg->fid, vg, mda)) {
2357 : 0 : stack;
2358 : : }
2359 : : }
2360 : 0 : return 0;
2361 : : }
2362 [ # # ]: 0 : if (!mda->ops->vg_write(vg->fid, vg, mda)) {
2363 : 0 : stack;
2364 : : /* Revert */
2365 [ # # ]: 0 : dm_list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) {
2366 : 0 : mda = dm_list_item(mdah, struct metadata_area);
2367 : :
2368 [ # # # # ]: 0 : if (mda->ops->vg_revert &&
2369 : 0 : !mda->ops->vg_revert(vg->fid, vg, mda)) {
2370 : 0 : stack;
2371 : : }
2372 : : }
2373 : 0 : return 0;
2374 : : }
2375 : : }
2376 : :
2377 : : /* Now pre-commit each copy of the new metadata */
2378 [ # # ]: 0 : dm_list_iterate_items(mda, &vg->fid->metadata_areas) {
2379 [ # # # # ]: 0 : if (mda->ops->vg_precommit &&
2380 : 0 : !mda->ops->vg_precommit(vg->fid, vg, mda)) {
2381 : 0 : stack;
2382 : : /* Revert */
2383 [ # # ]: 0 : dm_list_iterate_items(mda, &vg->fid->metadata_areas) {
2384 [ # # # # ]: 0 : if (mda->ops->vg_revert &&
2385 : 0 : !mda->ops->vg_revert(vg->fid, vg, mda)) {
2386 : 0 : stack;
2387 : : }
2388 : : }
2389 : 0 : return 0;
2390 : : }
2391 : : }
2392 : :
2393 : 0 : return 1;
2394 : : }
2395 : :
2396 : : /* Commit pending changes */
2397 : 0 : int vg_commit(struct volume_group *vg)
2398 : : {
2399 : : struct metadata_area *mda;
2400 : 0 : int cache_updated = 0;
2401 : 0 : int failed = 0;
2402 : :
2403 [ # # ]: 0 : if (!vgname_is_locked(vg->name)) {
2404 : 0 : log_error(INTERNAL_ERROR "Attempt to write new VG metadata "
2405 : : "without locking %s", vg->name);
2406 : 0 : return cache_updated;
2407 : : }
2408 : :
2409 : : /* Commit to each copy of the metadata area */
2410 [ # # ]: 0 : dm_list_iterate_items(mda, &vg->fid->metadata_areas) {
2411 : 0 : failed = 0;
2412 [ # # # # ]: 0 : if (mda->ops->vg_commit &&
2413 : 0 : !mda->ops->vg_commit(vg->fid, vg, mda)) {
2414 : 0 : stack;
2415 : 0 : failed = 1;
2416 : : }
2417 : : /* Update cache first time we succeed */
2418 [ # # ][ # # ]: 0 : if (!failed && !cache_updated) {
2419 : 0 : lvmcache_update_vg(vg, 0);
2420 : 0 : cache_updated = 1;
2421 : : }
2422 : : }
2423 : :
2424 : : /*
2425 : : * Instruct remote nodes to upgrade cached metadata.
2426 : : */
2427 [ # # ]: 0 : if (cache_updated)
2428 : 0 : remote_commit_cached_metadata(vg);
2429 : :
2430 : : /* If update failed, remove any cached precommitted metadata. */
2431 [ # # ][ # # ]: 0 : if (!cache_updated && !drop_cached_metadata(vg))
2432 : 0 : log_error("Attempt to drop cached metadata failed "
2433 : : "after commit for VG %s.", vg->name);
2434 : :
2435 : : /* If at least one mda commit succeeded, it was committed */
2436 : 0 : return cache_updated;
2437 : : }
2438 : :
2439 : : /* Don't commit any pending changes */
2440 : 0 : int vg_revert(struct volume_group *vg)
2441 : : {
2442 : : struct metadata_area *mda;
2443 : :
2444 [ # # ]: 0 : dm_list_iterate_items(mda, &vg->fid->metadata_areas) {
2445 [ # # # # ]: 0 : if (mda->ops->vg_revert &&
2446 : 0 : !mda->ops->vg_revert(vg->fid, vg, mda)) {
2447 : 0 : stack;
2448 : : }
2449 : : }
2450 : :
2451 [ # # ]: 0 : if (!drop_cached_metadata(vg))
2452 : 0 : log_error("Attempt to drop cached metadata failed "
2453 : : "after reverted update for VG %s.", vg->name);
2454 : :
2455 : 0 : remote_revert_cached_metadata(vg);
2456 : :
2457 : 0 : return 1;
2458 : : }
2459 : :
2460 : : /* Make orphan PVs look like a VG */
2461 : 3 : static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
2462 : : const char *orphan_vgname)
2463 : : {
2464 : : struct lvmcache_vginfo *vginfo;
2465 : : struct lvmcache_info *info;
2466 : : struct pv_list *pvl;
2467 : : struct volume_group *vg;
2468 : : struct physical_volume *pv;
2469 : : struct dm_pool *mem;
2470 : :
2471 : 3 : lvmcache_label_scan(cmd, 0);
2472 : :
2473 [ - + ]: 3 : if (!(vginfo = vginfo_from_vgname(orphan_vgname, NULL)))
2474 : 0 : return_NULL;
2475 : :
2476 [ - + ]: 3 : if (!(mem = dm_pool_create("vg_read orphan", VG_MEMPOOL_CHUNK)))
2477 : 0 : return_NULL;
2478 : :
2479 [ - + ]: 3 : if (!(vg = dm_pool_zalloc(mem, sizeof(*vg)))) {
2480 : 0 : log_error("vg allocation failed");
2481 : 0 : goto bad;
2482 : : }
2483 : 3 : dm_list_init(&vg->pvs);
2484 : 3 : dm_list_init(&vg->lvs);
2485 : 3 : dm_list_init(&vg->tags);
2486 : 3 : dm_list_init(&vg->removed_pvs);
2487 : 3 : vg->vgmem = mem;
2488 : 3 : vg->cmd = cmd;
2489 [ - + ]: 3 : if (!(vg->name = dm_pool_strdup(mem, orphan_vgname))) {
2490 : 0 : log_error("vg name allocation failed");
2491 : 0 : goto bad;
2492 : : }
2493 : :
2494 : : /* create format instance with appropriate metadata area */
2495 [ - + ]: 3 : if (!(vg->fid = vginfo->fmt->ops->create_instance(vginfo->fmt,
2496 : : orphan_vgname, NULL,
2497 : : NULL))) {
2498 : 0 : log_error("Failed to create format instance");
2499 : 0 : goto bad;
2500 : : }
2501 : :
2502 [ - + ]: 3 : dm_list_iterate_items(info, &vginfo->infos) {
2503 [ # # ]: 0 : if (!(pv = _pv_read(cmd, mem, dev_name(info->dev), NULL, NULL, 1, 0))) {
2504 : 0 : continue;
2505 : : }
2506 [ # # ]: 0 : if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) {
2507 : 0 : log_error("pv_list allocation failed");
2508 : 0 : goto bad;
2509 : : }
2510 : 0 : pvl->pv = pv;
2511 : 0 : dm_list_add(&vg->pvs, &pvl->list);
2512 : 0 : vg->pv_count++;
2513 : : }
2514 : :
2515 : 3 : return vg;
2516 : : bad:
2517 : 0 : dm_pool_destroy(mem);
2518 : 3 : return NULL;
2519 : : }
2520 : :
2521 : 0 : static int _update_pv_list(struct dm_pool *pvmem, struct dm_list *all_pvs, struct volume_group *vg)
2522 : : {
2523 : : struct pv_list *pvl, *pvl2;
2524 : :
2525 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
2526 [ # # ]: 0 : dm_list_iterate_items(pvl2, all_pvs) {
2527 [ # # ]: 0 : if (pvl->pv->dev == pvl2->pv->dev)
2528 : 0 : goto next_pv;
2529 : : }
2530 : :
2531 : : /*
2532 : : * PV is not on list so add it.
2533 : : */
2534 [ # # ]: 0 : if (!(pvl2 = _copy_pvl(pvmem, pvl))) {
2535 : 0 : log_error("pv_list allocation for '%s' failed",
2536 : : pv_dev_name(pvl->pv));
2537 : 0 : return 0;
2538 : : }
2539 : 0 : dm_list_add(all_pvs, &pvl2->list);
2540 : : next_pv:
2541 : : ;
2542 : : }
2543 : :
2544 : 0 : return 1;
2545 : : }
2546 : :
2547 : 0 : int vg_missing_pv_count(const struct volume_group *vg)
2548 : : {
2549 : 0 : int ret = 0;
2550 : : struct pv_list *pvl;
2551 [ # # ]: 0 : dm_list_iterate_items(pvl, &vg->pvs) {
2552 [ # # ]: 0 : if (is_missing_pv(pvl->pv))
2553 : 0 : ++ ret;
2554 : : }
2555 : 0 : return ret;
2556 : : }
2557 : :
2558 : 0 : static void check_reappeared_pv(struct volume_group *correct_vg,
2559 : : struct physical_volume *pv)
2560 : : {
2561 : : struct pv_list *pvl;
2562 : :
2563 [ # # ]: 0 : dm_list_iterate_items(pvl, &correct_vg->pvs)
2564 [ # # ][ # # ]: 0 : if (pv->dev == pvl->pv->dev && is_missing_pv(pvl->pv)) {
2565 : 0 : log_warn("Missing device %s reappeared, updating "
2566 : : "metadata for VG %s to version %u.",
2567 : : pv_dev_name(pvl->pv), pv_vg_name(pvl->pv),
2568 : : correct_vg->seqno);
2569 [ # # ]: 0 : if (pvl->pv->pe_alloc_count == 0) {
2570 : 0 : pv->status &= ~MISSING_PV;
2571 : 0 : pvl->pv->status &= ~MISSING_PV;
2572 : : } else
2573 : 0 : log_warn("Device still marked missing because of alocated data "
2574 : : "on it, remove volumes and consider vgreduce --removemissing.");
2575 : : }
2576 : 0 : }
2577 : : /* Caller sets consistent to 1 if it's safe for vg_read_internal to correct
2578 : : * inconsistent metadata on disk (i.e. the VG write lock is held).
2579 : : * This guarantees only consistent metadata is returned.
2580 : : * If consistent is 0, caller must check whether consistent == 1 on return
2581 : : * and take appropriate action if it isn't (e.g. abort; get write lock
2582 : : * and call vg_read_internal again).
2583 : : *
2584 : : * If precommitted is set, use precommitted metadata if present.
2585 : : *
2586 : : * Either of vgname or vgid may be NULL.
2587 : : */
2588 : 3 : static struct volume_group *_vg_read(struct cmd_context *cmd,
2589 : : const char *vgname,
2590 : : const char *vgid,
2591 : : int *consistent, unsigned precommitted)
2592 : : {
2593 : : struct format_instance *fid;
2594 : : const struct format_type *fmt;
2595 : 3 : struct volume_group *vg, *correct_vg = NULL;
2596 : : struct metadata_area *mda;
2597 : : struct lvmcache_info *info;
2598 : 3 : int inconsistent = 0;
2599 : 3 : int inconsistent_vgid = 0;
2600 : 3 : int inconsistent_pvs = 0;
2601 : 3 : int inconsistent_seqno = 0;
2602 : 3 : unsigned use_precommitted = precommitted;
2603 : 3 : unsigned saved_handles_missing_pvs = cmd->handles_missing_pvs;
2604 : : struct dm_list *pvids;
2605 : : struct pv_list *pvl, *pvl2;
2606 : : struct dm_list all_pvs;
2607 : : char uuid[64] __attribute((aligned(8)));
2608 : :
2609 [ + - ]: 3 : if (is_orphan_vg(vgname)) {
2610 [ - + ]: 3 : if (use_precommitted) {
2611 : 0 : log_error(INTERNAL_ERROR "vg_read_internal requires vgname "
2612 : : "with pre-commit.");
2613 : 0 : return NULL;
2614 : : }
2615 : 3 : *consistent = 1;
2616 : 3 : return _vg_read_orphans(cmd, vgname);
2617 : : }
2618 : :
2619 [ # # ]: 0 : if ((correct_vg = lvmcache_get_vg(vgid, precommitted))) {
2620 [ # # ]: 0 : if (vg_missing_pv_count(correct_vg)) {
2621 : 0 : log_verbose("There are %d physical volumes missing.",
2622 : : vg_missing_pv_count(correct_vg));
2623 : 0 : _vg_mark_partial_lvs(correct_vg);
2624 : : }
2625 : 0 : *consistent = 1;
2626 : 0 : return correct_vg;
2627 : : }
2628 : :
2629 : : /* Find the vgname in the cache */
2630 : : /* If it's not there we must do full scan to be completely sure */
2631 [ # # ]: 0 : if (!(fmt = fmt_from_vgname(vgname, vgid))) {
2632 : 0 : lvmcache_label_scan(cmd, 0);
2633 [ # # ]: 0 : if (!(fmt = fmt_from_vgname(vgname, vgid))) {
2634 [ # # ]: 0 : if (memlock())
2635 : 0 : return_NULL;
2636 : 0 : lvmcache_label_scan(cmd, 2);
2637 [ # # ]: 0 : if (!(fmt = fmt_from_vgname(vgname, vgid)))
2638 : 0 : return_NULL;
2639 : : }
2640 : : }
2641 : :
2642 : : /* Now determine the correct vgname if none was supplied */
2643 [ # # ][ # # ]: 0 : if (!vgname && !(vgname = vgname_from_vgid(cmd->mem, vgid)))
2644 : 0 : return_NULL;
2645 : :
2646 [ # # ][ # # ]: 0 : if (use_precommitted && !(fmt->features & FMT_PRECOMMIT))
2647 : 0 : use_precommitted = 0;
2648 : :
2649 : : /* create format instance with appropriate metadata area */
2650 [ # # ]: 0 : if (!(fid = fmt->ops->create_instance(fmt, vgname, vgid, NULL))) {
2651 : 0 : log_error("Failed to create format instance");
2652 : 0 : return NULL;
2653 : : }
2654 : :
2655 : : /* Store pvids for later so we can check if any are missing */
2656 [ # # ]: 0 : if (!(pvids = lvmcache_get_pvids(cmd, vgname, vgid)))
2657 : 0 : return_NULL;
2658 : :
2659 : : /* Ensure contents of all metadata areas match - else do recovery */
2660 [ # # ]: 0 : dm_list_iterate_items(mda, &fid->metadata_areas) {
2661 [ # # # # ]: 0 : if ((use_precommitted &&
[ # # # # ]
2662 : 0 : !(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) ||
2663 : : (!use_precommitted &&
2664 : 0 : !(vg = mda->ops->vg_read(fid, vgname, mda)))) {
2665 : 0 : inconsistent = 1;
2666 : 0 : vg_release(vg);
2667 : 0 : continue;
2668 : : }
2669 [ # # ]: 0 : if (!correct_vg) {
2670 : 0 : correct_vg = vg;
2671 : 0 : continue;
2672 : : }
2673 : :
2674 : : /* FIXME Also ensure contents same - checksum compare? */
2675 [ # # ]: 0 : if (correct_vg->seqno != vg->seqno) {
2676 : 0 : inconsistent = 1;
2677 : 0 : inconsistent_seqno = 1;
2678 [ # # ]: 0 : if (vg->seqno > correct_vg->seqno) {
2679 : 0 : vg_release(correct_vg);
2680 : 0 : correct_vg = vg;
2681 : : }
2682 : : }
2683 : :
2684 [ # # ]: 0 : if (vg != correct_vg)
2685 : 0 : vg_release(vg);
2686 : : }
2687 : :
2688 : : /* Ensure every PV in the VG was in the cache */
2689 [ # # ]: 0 : if (correct_vg) {
2690 : : /*
2691 : : * If the VG has PVs without mdas, they may still be
2692 : : * orphans in the cache: update the cache state here.
2693 : : */
2694 [ # # # # ]: 0 : if (!inconsistent &&
2695 : 0 : dm_list_size(&correct_vg->pvs) > dm_list_size(pvids)) {
2696 [ # # ]: 0 : dm_list_iterate_items(pvl, &correct_vg->pvs) {
2697 [ # # ]: 0 : if (!pvl->pv->dev) {
2698 : 0 : inconsistent_pvs = 1;
2699 : 0 : break;
2700 : : }
2701 : :
2702 [ # # ]: 0 : if (str_list_match_item(pvids, pvl->pv->dev->pvid))
2703 : 0 : continue;
2704 : :
2705 : : /*
2706 : : * PV not marked as belonging to this VG in cache.
2707 : : * Check it's an orphan without metadata area.
2708 : : */
2709 [ # # ][ # # : 0 : if (!(info = info_from_pvid(pvl->pv->dev->pvid, 1)) ||
# # # # ]
2710 : 0 : !info->vginfo || !is_orphan_vg(info->vginfo->vgname) ||
2711 : 0 : dm_list_size(&info->mdas)) {
2712 : 0 : inconsistent_pvs = 1;
2713 : 0 : break;
2714 : : }
2715 : : }
2716 : :
2717 : : /* If the check passed, let's update VG and recalculate pvids */
2718 [ # # ]: 0 : if (!inconsistent_pvs) {
2719 : 0 : log_debug("Updating cache for PVs without mdas "
2720 : : "in VG %s.", vgname);
2721 : : /*
2722 : : * If there is no precommitted metadata, committed metadata
2723 : : * is read and stored in the cache even if use_precommitted is set
2724 : : */
2725 : 0 : lvmcache_update_vg(correct_vg, correct_vg->status & PRECOMMITTED);
2726 : :
2727 [ # # ]: 0 : if (!(pvids = lvmcache_get_pvids(cmd, vgname, vgid)))
2728 : 0 : return_NULL;
2729 : : }
2730 : : }
2731 : :
2732 [ # # ]: 0 : if (dm_list_size(&correct_vg->pvs) != dm_list_size(pvids)
2733 : 0 : + vg_missing_pv_count(correct_vg)) {
2734 : 0 : log_debug("Cached VG %s had incorrect PV list",
2735 : : vgname);
2736 : :
2737 [ # # ]: 0 : if (memlock())
2738 : 0 : inconsistent = 1;
2739 : : else {
2740 : 0 : vg_release(correct_vg);
2741 : 0 : correct_vg = NULL;
2742 : : }
2743 [ # # ]: 0 : } else dm_list_iterate_items(pvl, &correct_vg->pvs) {
2744 [ # # ]: 0 : if (is_missing_pv(pvl->pv))
2745 : 0 : continue;
2746 [ # # ]: 0 : if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
2747 : 0 : log_debug("Cached VG %s had incorrect PV list",
2748 : : vgname);
2749 : 0 : vg_release(correct_vg);
2750 : 0 : correct_vg = NULL;
2751 : 0 : break;
2752 : : }
2753 : : }
2754 : : }
2755 : :
2756 : 0 : dm_list_init(&all_pvs);
2757 : :
2758 : : /* Failed to find VG where we expected it - full scan and retry */
2759 [ # # ]: 0 : if (!correct_vg) {
2760 : 0 : inconsistent = 0;
2761 : :
2762 [ # # ]: 0 : if (memlock())
2763 : 0 : return_NULL;
2764 : 0 : lvmcache_label_scan(cmd, 2);
2765 [ # # ]: 0 : if (!(fmt = fmt_from_vgname(vgname, vgid)))
2766 : 0 : return_NULL;
2767 : :
2768 [ # # ][ # # ]: 0 : if (precommitted && !(fmt->features & FMT_PRECOMMIT))
2769 : 0 : use_precommitted = 0;
2770 : :
2771 : : /* create format instance with appropriate metadata area */
2772 [ # # ]: 0 : if (!(fid = fmt->ops->create_instance(fmt, vgname, vgid, NULL))) {
2773 : 0 : log_error("Failed to create format instance");
2774 : 0 : return NULL;
2775 : : }
2776 : :
2777 : : /* Ensure contents of all metadata areas match - else recover */
2778 [ # # ]: 0 : dm_list_iterate_items(mda, &fid->metadata_areas) {
2779 [ # # # # ]: 0 : if ((use_precommitted &&
[ # # # # ]
2780 : 0 : !(vg = mda->ops->vg_read_precommit(fid, vgname,
2781 : : mda))) ||
2782 : : (!use_precommitted &&
2783 : 0 : !(vg = mda->ops->vg_read(fid, vgname, mda)))) {
2784 : 0 : inconsistent = 1;
2785 : 0 : continue;
2786 : : }
2787 [ # # ]: 0 : if (!correct_vg) {
2788 : 0 : correct_vg = vg;
2789 [ # # ]: 0 : if (!_update_pv_list(cmd->mem, &all_pvs, correct_vg)) {
2790 : 0 : vg_release(vg);
2791 : 0 : return_NULL;
2792 : : }
2793 : 0 : continue;
2794 : : }
2795 : :
2796 [ # # ]: 0 : if (strncmp((char *)vg->id.uuid,
2797 : : (char *)correct_vg->id.uuid, ID_LEN)) {
2798 : 0 : inconsistent = 1;
2799 : 0 : inconsistent_vgid = 1;
2800 : : }
2801 : :
2802 : : /* FIXME Also ensure contents same - checksums same? */
2803 [ # # ]: 0 : if (correct_vg->seqno != vg->seqno) {
2804 : 0 : inconsistent = 1;
2805 : 0 : inconsistent_seqno = 1;
2806 [ # # ]: 0 : if (!_update_pv_list(cmd->mem, &all_pvs, vg)) {
2807 : 0 : vg_release(vg);
2808 : 0 : vg_release(correct_vg);
2809 : 0 : return_NULL;
2810 : : }
2811 [ # # ]: 0 : if (vg->seqno > correct_vg->seqno) {
2812 : 0 : vg_release(correct_vg);
2813 : 0 : correct_vg = vg;
2814 : : }
2815 : : }
2816 : :
2817 [ # # ]: 0 : if (vg != correct_vg)
2818 : 0 : vg_release(vg);
2819 : : }
2820 : :
2821 : : /* Give up looking */
2822 [ # # ]: 0 : if (!correct_vg)
2823 : 0 : return_NULL;
2824 : : }
2825 : :
2826 : : /*
2827 : : * If there is no precommitted metadata, committed metadata
2828 : : * is read and stored in the cache even if use_precommitted is set
2829 : : */
2830 : 0 : lvmcache_update_vg(correct_vg, correct_vg->status & PRECOMMITTED);
2831 : :
2832 [ # # ]: 0 : if (inconsistent) {
2833 : : /* FIXME Test should be if we're *using* precommitted metadata not if we were searching for it */
2834 [ # # ]: 0 : if (use_precommitted) {
2835 : 0 : log_error("Inconsistent pre-commit metadata copies "
2836 : : "for volume group %s", vgname);
2837 : : /* FIXME: during repair, there is inconsistent flag set because some metadata areas
2838 : : * are missing (on missing PVs). Code should create list of missing PVs, compare it
2839 : : * with PV marked missing in metadata and if equals, use it as consistent vg.
2840 : : * For now, return precommited metadata if remainng seq match here to allow
2841 : : * preloading table in suspend call.
2842 : : */
2843 [ # # ]: 0 : if (!inconsistent_seqno) {
2844 : 0 : *consistent = 0;
2845 : 0 : return correct_vg;
2846 : : }
2847 : 0 : vg_release(correct_vg);
2848 : 0 : return NULL;
2849 : : }
2850 : :
2851 [ # # ]: 0 : if (!*consistent)
2852 : 0 : return correct_vg;
2853 : :
2854 : : /* Don't touch if vgids didn't match */
2855 [ # # ]: 0 : if (inconsistent_vgid) {
2856 : 0 : log_error("Inconsistent metadata UUIDs found for "
2857 : : "volume group %s", vgname);
2858 : 0 : *consistent = 0;
2859 : 0 : return correct_vg;
2860 : : }
2861 : :
2862 : 0 : log_warn("WARNING: Inconsistent metadata found for VG %s - updating "
2863 : : "to use version %u", vgname, correct_vg->seqno);
2864 : :
2865 : : /*
2866 : : * If PV is marked missing but we found it,
2867 : : * update metadata and remove MISSING flag
2868 : : */
2869 [ # # ]: 0 : dm_list_iterate_items(pvl, &all_pvs)
2870 : 0 : check_reappeared_pv(correct_vg, pvl->pv);
2871 : :
2872 : 0 : cmd->handles_missing_pvs = 1;
2873 [ # # ]: 0 : if (!vg_write(correct_vg)) {
2874 : 0 : log_error("Automatic metadata correction failed");
2875 : 0 : vg_release(correct_vg);
2876 : 0 : cmd->handles_missing_pvs = saved_handles_missing_pvs;
2877 : 0 : return NULL;
2878 : : }
2879 : 0 : cmd->handles_missing_pvs = saved_handles_missing_pvs;
2880 : :
2881 [ # # ]: 0 : if (!vg_commit(correct_vg)) {
2882 : 0 : log_error("Automatic metadata correction commit "
2883 : : "failed");
2884 : 0 : vg_release(correct_vg);
2885 : 0 : return NULL;
2886 : : }
2887 : :
2888 [ # # ]: 0 : dm_list_iterate_items(pvl, &all_pvs) {
2889 [ # # ]: 0 : dm_list_iterate_items(pvl2, &correct_vg->pvs) {
2890 [ # # ]: 0 : if (pvl->pv->dev == pvl2->pv->dev)
2891 : 0 : goto next_pv;
2892 : : }
2893 [ # # ]: 0 : if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid))) {
2894 : 0 : vg_release(correct_vg);
2895 : 0 : return_NULL;
2896 : : }
2897 : 0 : log_error("Removing PV %s (%s) that no longer belongs to VG %s",
2898 : : pv_dev_name(pvl->pv), uuid, correct_vg->name);
2899 [ # # ]: 0 : if (!pv_write_orphan(cmd, pvl->pv)) {
2900 : 0 : vg_release(correct_vg);
2901 : 0 : return_NULL;
2902 : : }
2903 : :
2904 : : /* Refresh metadata after orphan write */
2905 : 0 : drop_cached_metadata(correct_vg);
2906 : : next_pv:
2907 : : ;
2908 : : }
2909 : : }
2910 : :
2911 [ # # ]: 0 : if (vg_missing_pv_count(correct_vg)) {
2912 : 0 : log_verbose("There are %d physical volumes missing.",
2913 : : vg_missing_pv_count(correct_vg));
2914 : 0 : _vg_mark_partial_lvs(correct_vg);
2915 : : }
2916 : :
2917 [ # # ][ # # ]: 0 : if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
2918 : 0 : log_error("WARNING: Interrupted pvmove detected in "
2919 : : "volume group %s", correct_vg->name);
2920 : 0 : log_error("Please restore the metadata by running "
2921 : : "vgcfgrestore.");
2922 : 0 : vg_release(correct_vg);
2923 : 0 : return NULL;
2924 : : }
2925 : :
2926 : 0 : *consistent = 1;
2927 : 3 : return correct_vg;
2928 : : }
2929 : :
2930 : 3 : struct volume_group *vg_read_internal(struct cmd_context *cmd, const char *vgname,
2931 : : const char *vgid, int *consistent)
2932 : : {
2933 : : struct volume_group *vg;
2934 : : struct lv_list *lvl;
2935 : :
2936 [ - + ]: 3 : if (!(vg = _vg_read(cmd, vgname, vgid, consistent, 0)))
2937 : 0 : return NULL;
2938 : :
2939 [ - + ]: 3 : if (!check_pv_segments(vg)) {
2940 : 0 : log_error(INTERNAL_ERROR "PV segments corrupted in %s.",
2941 : : vg->name);
2942 : 0 : vg_release(vg);
2943 : 0 : return NULL;
2944 : : }
2945 : :
2946 [ - + ]: 3 : dm_list_iterate_items(lvl, &vg->lvs) {
2947 [ # # ]: 0 : if (!check_lv_segments(lvl->lv, 0)) {
2948 : 0 : log_error(INTERNAL_ERROR "LV segments corrupted in %s.",
2949 : : lvl->lv->name);
2950 : 0 : vg_release(vg);
2951 : 0 : return NULL;
2952 : : }
2953 : : }
2954 : :
2955 [ - + ]: 3 : dm_list_iterate_items(lvl, &vg->lvs) {
2956 : : /*
2957 : : * Checks that cross-reference other LVs.
2958 : : */
2959 [ # # ]: 0 : if (!check_lv_segments(lvl->lv, 1)) {
2960 : 0 : log_error(INTERNAL_ERROR "LV segments corrupted in %s.",
2961 : : lvl->lv->name);
2962 : 0 : vg_release(vg);
2963 : 0 : return NULL;
2964 : : }
2965 : : }
2966 : :
2967 : 3 : return vg;
2968 : : }
2969 : :
2970 : 3 : void vg_release(struct volume_group *vg)
2971 : : {
2972 [ + - ][ - + ]: 3 : if (!vg || !vg->vgmem)
2973 : 0 : return;
2974 : :
2975 [ + - ][ - + ]: 3 : if (vg->cmd && vg->vgmem == vg->cmd->mem)
2976 : 0 : log_error(INTERNAL_ERROR "global memory pool used for VG %s",
2977 : : vg->name);
2978 : :
2979 : 3 : dm_pool_destroy(vg->vgmem);
2980 : : }
2981 : :
2982 : : /* This is only called by lv_from_lvid, which is only called from
2983 : : * activate.c so we know the appropriate VG lock is already held and
2984 : : * the vg_read_internal is therefore safe.
2985 : : */
2986 : 0 : static struct volume_group *_vg_read_by_vgid(struct cmd_context *cmd,
2987 : : const char *vgid,
2988 : : unsigned precommitted)
2989 : : {
2990 : : const char *vgname;
2991 : : struct dm_list *vgnames;
2992 : 0 : struct volume_group *vg = NULL;
2993 : : struct lvmcache_vginfo *vginfo;
2994 : : struct str_list *strl;
2995 : 0 : int consistent = 0;
2996 : :
2997 : : /* Is corresponding vgname already cached? */
2998 [ # # ]: 0 : if ((vginfo = vginfo_from_vgid(vgid)) &&
[ # # # # ]
2999 : 0 : vginfo->vgname && !is_orphan_vg(vginfo->vgname)) {
3000 [ # # ][ # # ]: 0 : if ((vg = _vg_read(cmd, NULL, vgid,
3001 : : &consistent, precommitted)) &&
3002 : 0 : !strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
3003 : :
3004 [ # # ]: 0 : if (!consistent) {
3005 : 0 : log_error("Volume group %s metadata is "
3006 : : "inconsistent", vg->name);
3007 : : }
3008 : 0 : return vg;
3009 : : }
3010 : 0 : vg_release(vg);
3011 : : }
3012 : :
3013 : : /* Mustn't scan if memory locked: ensure cache gets pre-populated! */
3014 [ # # ]: 0 : if (memlock())
3015 : 0 : goto out;
3016 : :
3017 : : /* FIXME Need a genuine read by ID here - don't vg_read_internal by name! */
3018 : : /* FIXME Disabled vgrenames while active for now because we aren't
3019 : : * allowed to do a full scan here any more. */
3020 : :
3021 : : // The slow way - full scan required to cope with vgrename
3022 : 0 : lvmcache_label_scan(cmd, 2);
3023 [ # # ]: 0 : if (!(vgnames = get_vgnames(cmd, 0))) {
3024 : 0 : log_error("vg_read_by_vgid: get_vgnames failed");
3025 : 0 : goto out;
3026 : : }
3027 : :
3028 [ # # ]: 0 : dm_list_iterate_items(strl, vgnames) {
3029 : 0 : vgname = strl->str;
3030 [ # # ]: 0 : if (!vgname)
3031 : 0 : continue; // FIXME Unnecessary?
3032 : 0 : consistent = 0;
3033 [ # # ][ # # ]: 0 : if ((vg = _vg_read(cmd, vgname, vgid, &consistent,
3034 : : precommitted)) &&
3035 : 0 : !strncmp((char *)vg->id.uuid, vgid, ID_LEN)) {
3036 : :
3037 [ # # ]: 0 : if (!consistent) {
3038 : 0 : log_error("Volume group %s metadata is "
3039 : : "inconsistent", vgname);
3040 : 0 : goto out;
3041 : : }
3042 : 0 : return vg;
3043 : : }
3044 : : }
3045 : :
3046 : : out:
3047 : 0 : vg_release(vg);
3048 : 0 : return NULL;
3049 : : }
3050 : :
3051 : : /* Only called by activate.c */
3052 : 0 : struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s,
3053 : : unsigned precommitted)
3054 : : {
3055 : : struct lv_list *lvl;
3056 : : struct volume_group *vg;
3057 : : const union lvid *lvid;
3058 : :
3059 : 0 : lvid = (const union lvid *) lvid_s;
3060 : :
3061 : 0 : log_very_verbose("Finding volume group for uuid %s", lvid_s);
3062 [ # # ]: 0 : if (!(vg = _vg_read_by_vgid(cmd, (char *)lvid->id[0].uuid, precommitted))) {
3063 : 0 : log_error("Volume group for uuid not found: %s", lvid_s);
3064 : 0 : return NULL;
3065 : : }
3066 : :
3067 : 0 : log_verbose("Found volume group \"%s\"", vg->name);
3068 [ # # ]: 0 : if (vg->status & EXPORTED_VG) {
3069 : 0 : log_error("Volume group \"%s\" is exported", vg->name);
3070 : 0 : goto out;
3071 : : }
3072 [ # # ]: 0 : if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
3073 : 0 : log_very_verbose("Can't find logical volume id %s", lvid_s);
3074 : 0 : goto out;
3075 : : }
3076 : :
3077 : 0 : return lvl->lv;
3078 : : out:
3079 : 0 : vg_release(vg);
3080 : 0 : return NULL;
3081 : : }
3082 : :
3083 : : /**
3084 : : * pv_read - read and return a handle to a physical volume
3085 : : * @cmd: LVM command initiating the pv_read
3086 : : * @pv_name: full device name of the PV, including the path
3087 : : * @mdas: list of metadata areas of the PV
3088 : : * @label_sector: sector number where the PV label is stored on @pv_name
3089 : : * @warnings:
3090 : : *
3091 : : * Returns:
3092 : : * PV handle - valid pv_name and successful read of the PV, or
3093 : : * NULL - invalid parameter or error in reading the PV
3094 : : *
3095 : : * Note:
3096 : : * FIXME - liblvm todo - make into function that returns handle
3097 : : */
3098 : 0 : struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
3099 : : struct dm_list *mdas, uint64_t *label_sector,
3100 : : int warnings, int scan_label_only)
3101 : : {
3102 : 0 : return _pv_read(cmd, cmd->mem, pv_name, mdas, label_sector, warnings, scan_label_only);
3103 : : }
3104 : :
3105 : : /* FIXME Use label functions instead of PV functions */
3106 : 0 : static struct physical_volume *_pv_read(struct cmd_context *cmd,
3107 : : struct dm_pool *pvmem,
3108 : : const char *pv_name,
3109 : : struct dm_list *mdas,
3110 : : uint64_t *label_sector,
3111 : : int warnings, int scan_label_only)
3112 : : {
3113 : : struct physical_volume *pv;
3114 : : struct label *label;
3115 : : struct lvmcache_info *info;
3116 : : struct device *dev;
3117 : :
3118 [ # # ]: 0 : if (!(dev = dev_cache_get(pv_name, cmd->filter)))
3119 : 0 : return_NULL;
3120 : :
3121 [ # # ]: 0 : if (!(label_read(dev, &label, UINT64_C(0)))) {
3122 [ # # ]: 0 : if (warnings)
3123 : 0 : log_error("No physical volume label read from %s",
3124 : : pv_name);
3125 : 0 : return NULL;
3126 : : }
3127 : :
3128 : 0 : info = (struct lvmcache_info *) label->info;
3129 [ # # ][ # # ]: 0 : if (label_sector && *label_sector)
3130 : 0 : *label_sector = label->sector;
3131 : :
3132 : 0 : pv = _alloc_pv(pvmem, dev);
3133 [ # # ]: 0 : if (!pv) {
3134 : 0 : log_error("pv allocation for '%s' failed", pv_name);
3135 : 0 : return NULL;
3136 : : }
3137 : :
3138 : : /* FIXME Move more common code up here */
3139 [ # # ]: 0 : if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas,
3140 : : scan_label_only))) {
3141 : 0 : log_error("Failed to read existing physical volume '%s'",
3142 : : pv_name);
3143 : 0 : goto bad;
3144 : : }
3145 : :
3146 [ # # ]: 0 : if (!pv->size)
3147 : 0 : goto bad;
3148 : :
3149 [ # # ]: 0 : if (!alloc_pv_segment_whole_pv(pvmem, pv))
3150 : 0 : goto_bad;
3151 : :
3152 : 0 : return pv;
3153 : : bad:
3154 : 0 : _free_pv(pvmem, pv);
3155 : 0 : return NULL;
3156 : : }
3157 : :
3158 : : /* May return empty list */
3159 : 0 : struct dm_list *get_vgnames(struct cmd_context *cmd, int include_internal)
3160 : : {
3161 : 0 : return lvmcache_get_vgnames(cmd, include_internal);
3162 : : }
3163 : :
3164 : 1 : struct dm_list *get_vgids(struct cmd_context *cmd, int include_internal)
3165 : : {
3166 : 1 : return lvmcache_get_vgids(cmd, include_internal);
3167 : : }
3168 : :
3169 : 1 : static int _get_pvs(struct cmd_context *cmd, struct dm_list **pvslist)
3170 : : {
3171 : : struct str_list *strl;
3172 : 1 : struct dm_list * uninitialized_var(results);
3173 : : const char *vgname, *vgid;
3174 : : struct pv_list *pvl, *pvl_copy;
3175 : : struct dm_list *vgids;
3176 : : struct volume_group *vg;
3177 : 1 : int consistent = 0;
3178 : : int old_pvmove;
3179 : :
3180 : 1 : lvmcache_label_scan(cmd, 0);
3181 : :
3182 [ + - ]: 1 : if (pvslist) {
3183 [ - + ]: 1 : if (!(results = dm_pool_alloc(cmd->mem, sizeof(*results)))) {
3184 : 0 : log_error("PV list allocation failed");
3185 : 0 : return 0;
3186 : : }
3187 : :
3188 : 1 : dm_list_init(results);
3189 : : }
3190 : :
3191 : : /* Get list of VGs */
3192 [ - + ]: 1 : if (!(vgids = get_vgids(cmd, 1))) {
3193 : 0 : log_error("get_pvs: get_vgids failed");
3194 : 0 : return 0;
3195 : : }
3196 : :
3197 : : /* Read every VG to ensure cache consistency */
3198 : : /* Orphan VG is last on list */
3199 : 1 : old_pvmove = pvmove_mode();
3200 : 1 : init_pvmove(1);
3201 [ + + ]: 4 : dm_list_iterate_items(strl, vgids) {
3202 : 3 : vgid = strl->str;
3203 [ - + ]: 3 : if (!vgid)
3204 : 0 : continue; /* FIXME Unnecessary? */
3205 : 3 : consistent = 0;
3206 [ - + ]: 3 : if (!(vgname = vgname_from_vgid(NULL, vgid))) {
3207 : 0 : stack;
3208 : 0 : continue;
3209 : : }
3210 [ - + ]: 3 : if (!(vg = vg_read_internal(cmd, vgname, vgid, &consistent))) {
3211 : 0 : stack;
3212 : 0 : continue;
3213 : : }
3214 [ - + ]: 3 : if (!consistent)
3215 : 0 : log_warn("WARNING: Volume Group %s is not consistent",
3216 : : vgname);
3217 : :
3218 : : /* Move PVs onto results list */
3219 [ + - ]: 3 : if (pvslist)
3220 [ - + ]: 3 : dm_list_iterate_items(pvl, &vg->pvs) {
3221 [ # # ]: 0 : if (!(pvl_copy = _copy_pvl(cmd->mem, pvl))) {
3222 : 0 : log_error("PV list allocation failed");
3223 : 0 : vg_release(vg);
3224 : 0 : return 0;
3225 : : }
3226 : 0 : dm_list_add(results, &pvl_copy->list);
3227 : : }
3228 : 3 : vg_release(vg);
3229 : : }
3230 : 1 : init_pvmove(old_pvmove);
3231 : :
3232 [ + - ]: 1 : if (pvslist)
3233 : 1 : *pvslist = results;
3234 : : else
3235 : 0 : dm_pool_free(cmd->mem, vgids);
3236 : :
3237 : 1 : return 1;
3238 : : }
3239 : :
3240 : 1 : struct dm_list *get_pvs(struct cmd_context *cmd)
3241 : : {
3242 : : struct dm_list *results;
3243 : :
3244 [ - + ]: 1 : if (!_get_pvs(cmd, &results))
3245 : 0 : return NULL;
3246 : :
3247 : 1 : return results;
3248 : : }
3249 : :
3250 : 0 : int scan_vgs_for_pvs(struct cmd_context *cmd)
3251 : : {
3252 : 0 : return _get_pvs(cmd, NULL);
3253 : : }
3254 : :
3255 : 0 : int pv_write(struct cmd_context *cmd __attribute((unused)),
3256 : : struct physical_volume *pv,
3257 : : struct dm_list *mdas, int64_t label_sector)
3258 : : {
3259 [ # # ]: 0 : if (!pv->fmt->ops->pv_write) {
3260 : 0 : log_error("Format does not support writing physical volumes");
3261 : 0 : return 0;
3262 : : }
3263 : :
3264 [ # # ][ # # ]: 0 : if (!is_orphan_vg(pv->vg_name) || pv->pe_alloc_count) {
3265 : 0 : log_error("Assertion failed: can't _pv_write non-orphan PV "
3266 : : "(in VG %s)", pv->vg_name);
3267 : 0 : return 0;
3268 : : }
3269 : :
3270 [ # # ]: 0 : if (!pv->fmt->ops->pv_write(pv->fmt, pv, mdas, label_sector))
3271 : 0 : return_0;
3272 : :
3273 : 0 : return 1;
3274 : : }
3275 : :
3276 : 0 : int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv)
3277 : : {
3278 : 0 : const char *old_vg_name = pv->vg_name;
3279 : :
3280 : 0 : pv->vg_name = cmd->fmt->orphan_vg_name;
3281 : 0 : pv->status = ALLOCATABLE_PV;
3282 : 0 : pv->pe_alloc_count = 0;
3283 : :
3284 [ # # ]: 0 : if (!dev_get_size(pv->dev, &pv->size)) {
3285 : 0 : log_error("%s: Couldn't get size.", pv_dev_name(pv));
3286 : 0 : return 0;
3287 : : }
3288 : :
3289 [ # # ]: 0 : if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
3290 : 0 : log_error("Failed to clear metadata from physical "
3291 : : "volume \"%s\" after removal from \"%s\"",
3292 : : pv_dev_name(pv), old_vg_name);
3293 : 0 : return 0;
3294 : : }
3295 : :
3296 : 0 : return 1;
3297 : : }
3298 : :
3299 : : /**
3300 : : * is_orphan_vg - Determine whether a vg_name is an orphan
3301 : : * @vg_name: pointer to the vg_name
3302 : : */
3303 : 23 : int is_orphan_vg(const char *vg_name)
3304 : : {
3305 [ + - ][ + - ]: 23 : return (vg_name && vg_name[0] == ORPHAN_PREFIX[0]) ? 1 : 0;
3306 : : }
3307 : :
3308 : : /**
3309 : : * is_orphan - Determine whether a pv is an orphan based on its vg_name
3310 : : * @pv: handle to the physical volume
3311 : : */
3312 : 0 : int is_orphan(const struct physical_volume *pv)
3313 : : {
3314 : 0 : return is_orphan_vg(pv_field(pv, vg_name));
3315 : : }
3316 : :
3317 : : /**
3318 : : * is_pv - Determine whether a pv is a real pv or dummy one
3319 : : * @pv: handle to device
3320 : : */
3321 : 0 : int is_pv(struct physical_volume *pv)
3322 : : {
3323 : 0 : return (pv_field(pv, vg_name) ? 1 : 0);
3324 : : }
3325 : :
3326 : 0 : int is_missing_pv(const struct physical_volume *pv)
3327 : : {
3328 : 0 : return pv_field(pv, status) & MISSING_PV ? 1 : 0;
3329 : : }
3330 : :
3331 : : /*
3332 : : * Returns:
3333 : : * 0 - fail
3334 : : * 1 - success
3335 : : */
3336 : 0 : int pv_analyze(struct cmd_context *cmd, const char *pv_name,
3337 : : uint64_t label_sector)
3338 : : {
3339 : : struct label *label;
3340 : : struct device *dev;
3341 : : struct metadata_area *mda;
3342 : : struct lvmcache_info *info;
3343 : :
3344 : 0 : dev = dev_cache_get(pv_name, cmd->filter);
3345 [ # # ]: 0 : if (!dev) {
3346 : 0 : log_error("Device %s not found (or ignored by filtering).",
3347 : : pv_name);
3348 : 0 : return 0;
3349 : : }
3350 : :
3351 : : /*
3352 : : * First, scan for LVM labels.
3353 : : */
3354 [ # # ]: 0 : if (!label_read(dev, &label, label_sector)) {
3355 : 0 : log_error("Could not find LVM label on %s",
3356 : : pv_name);
3357 : 0 : return 0;
3358 : : }
3359 : :
3360 : 0 : log_print("Found label on %s, sector %"PRIu64", type=%s",
3361 : : pv_name, label->sector, label->type);
3362 : :
3363 : : /*
3364 : : * Next, loop through metadata areas
3365 : : */
3366 : 0 : info = label->info;
3367 [ # # ]: 0 : dm_list_iterate_items(mda, &info->mdas)
3368 : 0 : mda->ops->pv_analyze_mda(info->fmt, mda);
3369 : :
3370 : 0 : return 1;
3371 : : }
3372 : :
3373 : : /* FIXME: remove / combine this with locking? */
3374 : 0 : int vg_check_write_mode(struct volume_group *vg)
3375 : : {
3376 [ # # ]: 0 : if (vg->open_mode != 'w') {
3377 : 0 : log_errno(EPERM, "Attempt to modify a read-only VG");
3378 : 0 : return 0;
3379 : : }
3380 : 0 : return 1;
3381 : : }
3382 : :
3383 : : /*
3384 : : * Performs a set of checks against a VG according to bits set in status
3385 : : * and returns FAILED_* bits for those that aren't acceptable.
3386 : : *
3387 : : * FIXME Remove the unnecessary duplicate definitions and return bits directly.
3388 : : */
3389 : 0 : static uint32_t _vg_bad_status_bits(const struct volume_group *vg,
3390 : : uint64_t status)
3391 : : {
3392 : 0 : uint32_t failure = 0;
3393 : :
3394 [ # # # # # : 0 : if ((status & CLUSTERED) &&
# ]
3395 : 0 : (vg_is_clustered(vg)) && !locking_is_clustered()) {
3396 : 0 : log_error("Skipping clustered volume group %s", vg->name);
3397 : : /* Return because other flags are considered undefined. */
3398 : 0 : return FAILED_CLUSTERED;
3399 : : }
3400 : :
3401 [ # # # # ]: 0 : if ((status & EXPORTED_VG) &&
3402 : 0 : vg_is_exported(vg)) {
3403 : 0 : log_error("Volume group %s is exported", vg->name);
3404 : 0 : failure |= FAILED_EXPORTED;
3405 : : }
3406 : :
3407 [ # # ][ # # ]: 0 : if ((status & LVM_WRITE) &&
3408 : 0 : !(vg->status & LVM_WRITE)) {
3409 : 0 : log_error("Volume group %s is read-only", vg->name);
3410 : 0 : failure |= FAILED_READ_ONLY;
3411 : : }
3412 : :
3413 [ # # # # ]: 0 : if ((status & RESIZEABLE_VG) &&
3414 : 0 : !vg_is_resizeable(vg)) {
3415 : 0 : log_error("Volume group %s is not resizeable.", vg->name);
3416 : 0 : failure |= FAILED_RESIZEABLE;
3417 : : }
3418 : :
3419 : 0 : return failure;
3420 : : }
3421 : :
3422 : : /**
3423 : : * vg_check_status - check volume group status flags and log error
3424 : : * @vg - volume group to check status flags
3425 : : * @status - specific status flags to check (e.g. EXPORTED_VG)
3426 : : */
3427 : 0 : int vg_check_status(const struct volume_group *vg, uint64_t status)
3428 : : {
3429 : 0 : return !_vg_bad_status_bits(vg, status);
3430 : : }
3431 : :
3432 : 0 : static struct volume_group *_recover_vg(struct cmd_context *cmd, const char *lock_name,
3433 : : const char *vg_name, const char *vgid,
3434 : : uint32_t lock_flags)
3435 : : {
3436 : 0 : int consistent = 1;
3437 : : struct volume_group *vg;
3438 : :
3439 : 0 : lock_flags &= ~LCK_TYPE_MASK;
3440 : 0 : lock_flags |= LCK_WRITE;
3441 : :
3442 : 0 : unlock_vg(cmd, lock_name);
3443 : :
3444 : 0 : dev_close_all();
3445 : :
3446 [ # # ]: 0 : if (!lock_vol(cmd, lock_name, lock_flags))
3447 : 0 : return_NULL;
3448 : :
3449 [ # # ]: 0 : if (!(vg = vg_read_internal(cmd, vg_name, vgid, &consistent)))
3450 : 0 : return_NULL;
3451 : :
3452 [ # # ]: 0 : if (!consistent) {
3453 : 0 : vg_release(vg);
3454 : 0 : return_NULL;
3455 : : }
3456 : :
3457 : 0 : return (struct volume_group *)vg;
3458 : : }
3459 : :
3460 : : /*
3461 : : * Consolidated locking, reading, and status flag checking.
3462 : : *
3463 : : * If the metadata is inconsistent, setting READ_ALLOW_INCONSISTENT in
3464 : : * misc_flags will return it with FAILED_INCONSISTENT set instead of
3465 : : * giving you nothing.
3466 : : *
3467 : : * Use vg_read_error(vg) to determine the result. Nonzero means there were
3468 : : * problems reading the volume group.
3469 : : * Zero value means that the VG is open and appropriate locks are held.
3470 : : */
3471 : 0 : static struct volume_group *_vg_lock_and_read(struct cmd_context *cmd, const char *vg_name,
3472 : : const char *vgid, uint32_t lock_flags,
3473 : : uint64_t status_flags, uint32_t misc_flags)
3474 : : {
3475 : 0 : struct volume_group *vg = NULL;
3476 : : const char *lock_name;
3477 : 0 : int consistent = 1;
3478 : : int consistent_in;
3479 : 0 : uint32_t failure = 0;
3480 : : int already_locked;
3481 : :
3482 [ # # ][ # # ]: 0 : if (misc_flags & READ_ALLOW_INCONSISTENT || !(lock_flags & LCK_WRITE))
3483 : 0 : consistent = 0;
3484 : :
3485 [ # # ][ # # ]: 0 : if (!validate_name(vg_name) && !is_orphan_vg(vg_name)) {
3486 : 0 : log_error("Volume group name %s has invalid characters",
3487 : : vg_name);
3488 : 0 : return NULL;
3489 : : }
3490 : :
3491 [ # # ]: 0 : lock_name = is_orphan_vg(vg_name) ? VG_ORPHANS : vg_name;
3492 : 0 : already_locked = vgname_is_locked(lock_name);
3493 : :
3494 [ # # # # # : 0 : if (!already_locked && !(misc_flags & READ_WITHOUT_LOCK) &&
# ]
3495 : 0 : !lock_vol(cmd, lock_name, lock_flags)) {
3496 : 0 : log_error("Can't get lock for %s", vg_name);
3497 : 0 : return _vg_make_handle(cmd, vg, FAILED_LOCKING);
3498 : : }
3499 : :
3500 [ # # ]: 0 : if (is_orphan_vg(vg_name))
3501 : 0 : status_flags &= ~LVM_WRITE;
3502 : :
3503 : 0 : consistent_in = consistent;
3504 : :
3505 : : /* If consistent == 1, we get NULL here if correction fails. */
3506 [ # # ]: 0 : if (!(vg = vg_read_internal(cmd, vg_name, vgid, &consistent))) {
3507 [ # # ][ # # ]: 0 : if (consistent_in && !consistent) {
3508 : 0 : log_error("Volume group \"%s\" inconsistent.", vg_name);
3509 : 0 : failure |= FAILED_INCONSISTENT;
3510 : 0 : goto_bad;
3511 : : }
3512 : :
3513 : 0 : log_error("Volume group \"%s\" not found", vg_name);
3514 : :
3515 : 0 : failure |= FAILED_NOTFOUND;
3516 : 0 : goto_bad;
3517 : : }
3518 : :
3519 [ # # ][ # # ]: 0 : if (vg_is_clustered(vg) && !locking_is_clustered()) {
3520 : 0 : log_error("Skipping clustered volume group %s", vg->name);
3521 : 0 : failure |= FAILED_CLUSTERED;
3522 : 0 : goto_bad;
3523 : : }
3524 : :
3525 : : /* consistent == 0 when VG is not found, but failed == FAILED_NOTFOUND */
3526 [ # # ][ # # ]: 0 : if (!consistent && !failure) {
3527 : 0 : vg_release(vg);
3528 [ # # ]: 0 : if (!(vg = _recover_vg(cmd, lock_name, vg_name, vgid, lock_flags))) {
3529 : 0 : log_error("Recovery of volume group \"%s\" failed.",
3530 : : vg_name);
3531 : 0 : failure |= FAILED_INCONSISTENT;
3532 : 0 : goto_bad;
3533 : : }
3534 : : }
3535 : :
3536 : : /*
3537 : : * Check that the tool can handle tricky cases -- missing PVs and
3538 : : * unknown segment types.
3539 : : */
3540 : :
3541 [ # # ][ # # ]: 0 : if (!cmd->handles_missing_pvs && vg_missing_pv_count(vg) &&
[ # # ]
3542 : 0 : (lock_flags & LCK_WRITE)) {
3543 : 0 : log_error("Cannot change VG %s while PVs are missing.", vg->name);
3544 : 0 : log_error("Consider vgreduce --removemissing.");
3545 : 0 : failure |= FAILED_INCONSISTENT; /* FIXME new failure code here? */
3546 : 0 : goto_bad;
3547 : : }
3548 : :
3549 [ # # ][ # # ]: 0 : if (!cmd->handles_unknown_segments && vg_has_unknown_segments(vg) &&
[ # # ]
3550 : 0 : (lock_flags & LCK_WRITE)) {
3551 : 0 : log_error("Cannot change VG %s with unknown segments in it!",
3552 : : vg->name);
3553 : 0 : failure |= FAILED_INCONSISTENT; /* FIXME new failure code here? */
3554 : 0 : goto_bad;
3555 : : }
3556 : :
3557 : 0 : failure |= _vg_bad_status_bits(vg, status_flags);
3558 [ # # ]: 0 : if (failure)
3559 : 0 : goto_bad;
3560 : :
3561 : 0 : return _vg_make_handle(cmd, vg, failure);
3562 : :
3563 : : bad:
3564 [ # # ][ # # ]: 0 : if (!already_locked && !(misc_flags & READ_WITHOUT_LOCK))
3565 : 0 : unlock_vg(cmd, lock_name);
3566 : :
3567 : 0 : return _vg_make_handle(cmd, vg, failure);
3568 : : }
3569 : :
3570 : : /*
3571 : : * vg_read: High-level volume group metadata read function.
3572 : : *
3573 : : * vg_read_error() must be used on any handle returned to check for errors.
3574 : : *
3575 : : * - metadata inconsistent and automatic correction failed: FAILED_INCONSISTENT
3576 : : * - VG is read-only: FAILED_READ_ONLY
3577 : : * - VG is EXPORTED, unless flags has READ_ALLOW_EXPORTED: FAILED_EXPORTED
3578 : : * - VG is not RESIZEABLE: FAILED_RESIZEABLE
3579 : : * - locking failed: FAILED_LOCKING
3580 : : *
3581 : : * On failures, all locks are released, unless one of the following applies:
3582 : : * - vgname_is_locked(lock_name) is true
3583 : : * FIXME: remove the above 2 conditions if possible and make an error always
3584 : : * release the lock.
3585 : : *
3586 : : * Volume groups are opened read-only unless flags contains READ_FOR_UPDATE.
3587 : : *
3588 : : * Checking for VG existence:
3589 : : *
3590 : : * FIXME: We want vg_read to attempt automatic recovery after acquiring a
3591 : : * temporary write lock: if that fails, we bail out as usual, with failed &
3592 : : * FAILED_INCONSISTENT. If it works, we are good to go. Code that's been in
3593 : : * toollib just set lock_flags to LCK_VG_WRITE and called vg_read_internal with
3594 : : * *consistent = 1.
3595 : : */
3596 : 0 : struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
3597 : : const char *vgid, uint32_t flags)
3598 : : {
3599 : 0 : uint64_t status = UINT64_C(0);
3600 : 0 : uint32_t lock_flags = LCK_VG_READ;
3601 : :
3602 [ # # ]: 0 : if (flags & READ_FOR_UPDATE) {
3603 : 0 : status |= EXPORTED_VG | LVM_WRITE;
3604 : 0 : lock_flags = LCK_VG_WRITE;
3605 : : }
3606 : :
3607 [ # # ]: 0 : if (flags & READ_ALLOW_EXPORTED)
3608 : 0 : status &= ~EXPORTED_VG;
3609 : :
3610 : 0 : return _vg_lock_and_read(cmd, vg_name, vgid, lock_flags, status, flags);
3611 : : }
3612 : :
3613 : : /*
3614 : : * A high-level volume group metadata reading function. Open a volume group for
3615 : : * later update (this means the user code can change the metadata and later
3616 : : * request the new metadata to be written and committed).
3617 : : */
3618 : 0 : struct volume_group *vg_read_for_update(struct cmd_context *cmd, const char *vg_name,
3619 : : const char *vgid, uint32_t flags)
3620 : : {
3621 : 0 : return vg_read(cmd, vg_name, vgid, flags | READ_FOR_UPDATE);
3622 : : }
3623 : :
3624 : : /*
3625 : : * Test the validity of a VG handle returned by vg_read() or vg_read_for_update().
3626 : : */
3627 : 0 : uint32_t vg_read_error(struct volume_group *vg_handle)
3628 : : {
3629 [ # # ]: 0 : if (!vg_handle)
3630 : 0 : return FAILED_ALLOCATION;
3631 : :
3632 : 0 : return vg_handle->read_status;
3633 : : }
3634 : :
3635 : : /*
3636 : : * Lock a vgname and/or check for existence.
3637 : : * Takes a WRITE lock on the vgname before scanning.
3638 : : * If scanning fails or vgname found, release the lock.
3639 : : * NOTE: If you find the return codes confusing, you might think of this
3640 : : * function as similar to an open() call with O_CREAT and O_EXCL flags
3641 : : * (open returns fail with -EEXIST if file already exists).
3642 : : *
3643 : : * Returns:
3644 : : * FAILED_LOCKING - Cannot lock name
3645 : : * FAILED_EXIST - VG name already exists - cannot reserve
3646 : : * SUCCESS - VG name does not exist in system and WRITE lock held
3647 : : */
3648 : 0 : uint32_t vg_lock_newname(struct cmd_context *cmd, const char *vgname)
3649 : : {
3650 [ # # ]: 0 : if (!lock_vol(cmd, vgname, LCK_VG_WRITE)) {
3651 : 0 : return FAILED_LOCKING;
3652 : : }
3653 : :
3654 : : /* Find the vgname in the cache */
3655 : : /* If it's not there we must do full scan to be completely sure */
3656 [ # # ]: 0 : if (!fmt_from_vgname(vgname, NULL)) {
3657 : 0 : lvmcache_label_scan(cmd, 0);
3658 [ # # ]: 0 : if (!fmt_from_vgname(vgname, NULL)) {
3659 [ # # ]: 0 : if (memlock()) {
3660 : : /*
3661 : : * FIXME: Disallow calling this function if
3662 : : * memlock() is true.
3663 : : */
3664 : 0 : unlock_vg(cmd, vgname);
3665 : 0 : return FAILED_LOCKING;
3666 : : }
3667 : 0 : lvmcache_label_scan(cmd, 2);
3668 [ # # ]: 0 : if (!fmt_from_vgname(vgname, NULL)) {
3669 : : /* vgname not found after scanning */
3670 : 0 : return SUCCESS;
3671 : : }
3672 : : }
3673 : : }
3674 : :
3675 : : /* Found vgname so cannot reserve. */
3676 : 0 : unlock_vg(cmd, vgname);
3677 : 0 : return FAILED_EXIST;
3678 : : }
3679 : :
3680 : : /*
3681 : : * Gets/Sets for external LVM library
3682 : : */
3683 : 0 : struct id pv_id(const struct physical_volume *pv)
3684 : : {
3685 : 0 : return pv_field(pv, id);
3686 : : }
3687 : :
3688 : 0 : const struct format_type *pv_format_type(const struct physical_volume *pv)
3689 : : {
3690 : 0 : return pv_field(pv, fmt);
3691 : : }
3692 : :
3693 : 0 : struct id pv_vgid(const struct physical_volume *pv)
3694 : : {
3695 : 0 : return pv_field(pv, vgid);
3696 : : }
3697 : :
3698 : 0 : struct device *pv_dev(const struct physical_volume *pv)
3699 : : {
3700 : 0 : return pv_field(pv, dev);
3701 : : }
3702 : :
3703 : 0 : const char *pv_vg_name(const struct physical_volume *pv)
3704 : : {
3705 : 0 : return pv_field(pv, vg_name);
3706 : : }
3707 : :
3708 : 0 : const char *pv_dev_name(const struct physical_volume *pv)
3709 : : {
3710 : 0 : return dev_name(pv_dev(pv));
3711 : : }
3712 : :
3713 : 0 : uint64_t pv_size(const struct physical_volume *pv)
3714 : : {
3715 : 0 : return pv_field(pv, size);
3716 : : }
3717 : :
3718 : 0 : uint64_t pv_dev_size(const struct physical_volume *pv)
3719 : : {
3720 : : uint64_t size;
3721 : :
3722 [ # # ]: 0 : if (!dev_get_size(pv->dev, &size))
3723 : 0 : size = 0;
3724 : 0 : return size;
3725 : : }
3726 : :
3727 : 0 : uint64_t pv_size_field(const struct physical_volume *pv)
3728 : : {
3729 : : uint64_t size;
3730 : :
3731 [ # # ]: 0 : if (!pv->pe_count)
3732 : 0 : size = pv->size;
3733 : : else
3734 : 0 : size = (uint64_t) pv->pe_count * pv->pe_size;
3735 : 0 : return size;
3736 : : }
3737 : :
3738 : 0 : uint64_t pv_free(const struct physical_volume *pv)
3739 : : {
3740 : : uint64_t freespace;
3741 : :
3742 [ # # ]: 0 : if (!pv->pe_count)
3743 : 0 : freespace = pv->size;
3744 : : else
3745 : 0 : freespace = (uint64_t)
3746 : 0 : (pv->pe_count - pv->pe_alloc_count) * pv->pe_size;
3747 : 0 : return freespace;
3748 : : }
3749 : :
3750 : 0 : uint64_t pv_status(const struct physical_volume *pv)
3751 : : {
3752 : 0 : return pv_field(pv, status);
3753 : : }
3754 : :
3755 : 0 : uint32_t pv_pe_size(const struct physical_volume *pv)
3756 : : {
3757 : 0 : return pv_field(pv, pe_size);
3758 : : }
3759 : :
3760 : 0 : uint64_t pv_pe_start(const struct physical_volume *pv)
3761 : : {
3762 : 0 : return pv_field(pv, pe_start);
3763 : : }
3764 : :
3765 : 0 : uint32_t pv_pe_count(const struct physical_volume *pv)
3766 : : {
3767 : 0 : return pv_field(pv, pe_count);
3768 : : }
3769 : :
3770 : 0 : uint32_t pv_pe_alloc_count(const struct physical_volume *pv)
3771 : : {
3772 : 0 : return pv_field(pv, pe_alloc_count);
3773 : : }
3774 : :
3775 : 0 : uint32_t pv_mda_count(const struct physical_volume *pv)
3776 : : {
3777 : : struct lvmcache_info *info;
3778 : :
3779 : 0 : info = info_from_pvid((const char *)&pv->id.uuid, 0);
3780 [ # # ]: 0 : return info ? dm_list_size(&info->mdas) : UINT64_C(0);
3781 : : }
3782 : :
3783 : 0 : uint32_t vg_seqno(const struct volume_group *vg)
3784 : : {
3785 : 0 : return vg->seqno;
3786 : : }
3787 : :
3788 : 0 : uint64_t vg_status(const struct volume_group *vg)
3789 : : {
3790 : 0 : return vg->status;
3791 : : }
3792 : :
3793 : 0 : uint64_t vg_size(const struct volume_group *vg)
3794 : : {
3795 : 0 : return (uint64_t) vg->extent_count * vg->extent_size;
3796 : : }
3797 : :
3798 : 0 : uint64_t vg_free(const struct volume_group *vg)
3799 : : {
3800 : 0 : return (uint64_t) vg->free_count * vg->extent_size;
3801 : : }
3802 : :
3803 : 0 : uint64_t vg_extent_size(const struct volume_group *vg)
3804 : : {
3805 : 0 : return (uint64_t) vg->extent_size;
3806 : : }
3807 : :
3808 : 0 : uint64_t vg_extent_count(const struct volume_group *vg)
3809 : : {
3810 : 0 : return (uint64_t) vg->extent_count;
3811 : : }
3812 : :
3813 : 0 : uint64_t vg_free_count(const struct volume_group *vg)
3814 : : {
3815 : 0 : return (uint64_t) vg->free_count;
3816 : : }
3817 : :
3818 : 0 : uint64_t vg_pv_count(const struct volume_group *vg)
3819 : : {
3820 : 0 : return (uint64_t) vg->pv_count;
3821 : : }
3822 : :
3823 : 0 : uint64_t vg_max_pv(const struct volume_group *vg)
3824 : : {
3825 : 0 : return (uint64_t) vg->max_pv;
3826 : : }
3827 : :
3828 : 0 : uint64_t vg_max_lv(const struct volume_group *vg)
3829 : : {
3830 : 0 : return (uint64_t) vg->max_lv;
3831 : : }
3832 : :
3833 : 0 : uint32_t vg_mda_count(const struct volume_group *vg)
3834 : : {
3835 : 0 : return dm_list_size(&vg->fid->metadata_areas);
3836 : : }
3837 : :
3838 : 0 : uint64_t lv_size(const struct logical_volume *lv)
3839 : : {
3840 : 0 : return lv->size;
3841 : : }
3842 : :
3843 : : /**
3844 : : * pv_by_path - Given a device path return a PV handle if it is a PV
3845 : : * @cmd - handle to the LVM command instance
3846 : : * @pv_name - device path to read for the PV
3847 : : *
3848 : : * Returns:
3849 : : * NULL - device path does not contain a valid PV
3850 : : * non-NULL - PV handle corresponding to device path
3851 : : *
3852 : : * FIXME: merge with find_pv_by_name ?
3853 : : */
3854 : 0 : struct physical_volume *pv_by_path(struct cmd_context *cmd, const char *pv_name)
3855 : : {
3856 : : struct dm_list mdas;
3857 : :
3858 : 0 : dm_list_init(&mdas);
3859 : 0 : return _pv_read(cmd, cmd->mem, pv_name, &mdas, NULL, 1, 0);
3860 : : }
|