4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * Translates between disk and in-core formats.
24 #include "lvm-string.h"
26 #include "toolcontext.h"
35 static int _check_vg_name(const char *name
)
37 return strlen(name
) < NAME_LEN
;
41 * Extracts the last part of a path.
43 static char *_create_lv_name(struct dm_pool
*mem
, const char *full_name
)
45 const char *ptr
= strrchr(full_name
, '/');
52 return dm_pool_strdup(mem
, ptr
);
55 int import_pv(const struct format_type
*fmt
, struct dm_pool
*mem
,
56 struct device
*dev
, struct volume_group
*vg
,
57 struct physical_volume
*pv
, struct pv_disk
*pvd
,
62 memset(pv
, 0, sizeof(*pv
));
63 memcpy(&pv
->id
, pvd
->pv_uuid
, ID_LEN
);
67 pv
->vg_name
= fmt
->orphan_vg_name
;
68 else if (!(pv
->vg_name
= dm_pool_strdup(mem
, (char *)pvd
->vg_name
))) {
69 log_error("Volume Group name allocation failed.");
73 memcpy(&pv
->vgid
, vgd
->vg_uuid
, sizeof(vg
->id
));
75 /* Store system_id from first PV if PV belongs to a VG */
76 if (vg
&& !*vg
->system_id
)
77 strncpy(vg
->system_id
, (char *)pvd
->system_id
, NAME_LEN
);
80 strncmp(vg
->system_id
, (char *)pvd
->system_id
, sizeof(pvd
->system_id
)))
81 log_very_verbose("System ID %s on %s differs from %s for "
82 "volume group", pvd
->system_id
,
83 pv_dev_name(pv
), vg
->system_id
);
86 * If exported, we still need to flag in pv->status too because
87 * we don't always have a struct volume_group when we need this.
89 if (pvd
->pv_status
& VG_EXPORTED
)
90 pv
->status
|= EXPORTED_VG
;
92 if (pvd
->pv_allocatable
)
93 pv
->status
|= ALLOCATABLE_PV
;
95 pv
->size
= pvd
->pv_size
;
96 pv
->pe_size
= pvd
->pe_size
;
97 pv
->pe_start
= pvd
->pe_start
;
98 pv
->pe_count
= pvd
->pe_total
;
99 pv
->pe_alloc_count
= 0;
102 /* Fix up pv size if missing or impossibly large */
103 if (!pv
->size
|| pv
->size
> (1ULL << 62)) {
104 if (!dev_get_size(dev
, &pv
->size
)) {
105 log_error("%s: Couldn't get size.", pv_dev_name(pv
));
108 log_verbose("Fixing up missing format1 size (%s) "
109 "for PV %s", display_size(fmt
->cmd
, pv
->size
),
112 size
= pv
->pe_count
* (uint64_t) vg
->extent_size
+
115 log_error("WARNING: Physical Volume %s is too "
116 "large for underlying device",
121 dm_list_init(&pv
->tags
);
122 dm_list_init(&pv
->segments
);
124 if (!alloc_pv_segment_whole_pv(mem
, pv
))
130 static int _system_id(struct cmd_context
*cmd
, char *s
, const char *prefix
)
133 if (dm_snprintf(s
, NAME_LEN
, "%s%s%lu",
134 prefix
, cmd
->hostname
, time(NULL
)) < 0) {
135 log_error("Generated system_id too long");
142 int export_pv(struct cmd_context
*cmd
, struct dm_pool
*mem
__attribute((unused
)),
143 struct volume_group
*vg
,
144 struct pv_disk
*pvd
, struct physical_volume
*pv
)
146 memset(pvd
, 0, sizeof(*pvd
));
152 memcpy(pvd
->pv_uuid
, pv
->id
.uuid
, ID_LEN
);
154 if (pv
->vg_name
&& !is_orphan(pv
)) {
155 if (!_check_vg_name(pv
->vg_name
))
157 strncpy((char *)pvd
->vg_name
, pv
->vg_name
, sizeof(pvd
->vg_name
));
160 /* Preserve existing system_id if it exists */
161 if (vg
&& *vg
->system_id
)
162 strncpy((char *)pvd
->system_id
, vg
->system_id
, sizeof(pvd
->system_id
));
164 /* Is VG already exported or being exported? */
165 if (vg
&& vg_is_exported(vg
)) {
166 /* Does system_id need setting? */
167 if (!*vg
->system_id
||
168 strncmp(vg
->system_id
, EXPORTED_TAG
,
169 sizeof(EXPORTED_TAG
) - 1)) {
170 if (!_system_id(cmd
, (char *)pvd
->system_id
, EXPORTED_TAG
))
173 if (strlen((char *)pvd
->vg_name
) + sizeof(EXPORTED_TAG
) >
174 sizeof(pvd
->vg_name
)) {
175 log_error("Volume group name %s too long to export",
179 strcat((char *)pvd
->vg_name
, EXPORTED_TAG
);
182 /* Is VG being imported? */
183 if (vg
&& !vg_is_exported(vg
) && *vg
->system_id
&&
184 !strncmp(vg
->system_id
, EXPORTED_TAG
, sizeof(EXPORTED_TAG
) - 1)) {
185 if (!_system_id(cmd
, (char *)pvd
->system_id
, IMPORTED_TAG
))
189 /* Generate system_id if PV is in VG */
190 if (!pvd
->system_id
|| !*pvd
->system_id
)
191 if (!_system_id(cmd
, (char *)pvd
->system_id
, ""))
194 /* Update internal system_id if we changed it */
197 strncmp(vg
->system_id
, (char *)pvd
->system_id
, sizeof(pvd
->system_id
))))
198 strncpy(vg
->system_id
, (char *)pvd
->system_id
, NAME_LEN
);
200 //pvd->pv_major = MAJOR(pv->dev);
202 if (pv
->status
& ALLOCATABLE_PV
)
203 pvd
->pv_allocatable
= PV_ALLOCATABLE
;
205 pvd
->pv_size
= pv
->size
;
206 pvd
->lv_cur
= 0; /* this is set when exporting the lv list */
208 pvd
->pe_size
= vg
->extent_size
;
210 pvd
->pe_size
= pv
->pe_size
;
211 pvd
->pe_total
= pv
->pe_count
;
212 pvd
->pe_allocated
= pv
->pe_alloc_count
;
213 pvd
->pe_start
= pv
->pe_start
;
218 int import_vg(struct dm_pool
*mem
,
219 struct volume_group
*vg
, struct disk_list
*dl
)
221 struct vg_disk
*vgd
= &dl
->vgd
;
222 memcpy(vg
->id
.uuid
, vgd
->vg_uuid
, ID_LEN
);
224 if (!_check_vg_name((char *)dl
->pvd
.vg_name
))
227 if (!(vg
->name
= dm_pool_strdup(mem
, (char *)dl
->pvd
.vg_name
)))
230 if (!(vg
->system_id
= dm_pool_alloc(mem
, NAME_LEN
)))
233 *vg
->system_id
= '\0';
235 if (vgd
->vg_status
& VG_EXPORTED
)
236 vg
->status
|= EXPORTED_VG
;
238 if (vgd
->vg_status
& VG_EXTENDABLE
)
239 vg
->status
|= RESIZEABLE_VG
;
241 if (vgd
->vg_access
& VG_READ
)
242 vg
->status
|= LVM_READ
;
244 if (vgd
->vg_access
& VG_WRITE
)
245 vg
->status
|= LVM_WRITE
;
247 if (vgd
->vg_access
& VG_CLUSTERED
)
248 vg
->status
|= CLUSTERED
;
250 if (vgd
->vg_access
& VG_SHARED
)
251 vg
->status
|= SHARED
;
253 vg
->extent_size
= vgd
->pe_size
;
254 vg
->extent_count
= vgd
->pe_total
;
255 vg
->free_count
= vgd
->pe_total
;
256 vg
->max_lv
= vgd
->lv_max
;
257 vg
->max_pv
= vgd
->pv_max
;
258 vg
->alloc
= ALLOC_NORMAL
;
263 int export_vg(struct vg_disk
*vgd
, struct volume_group
*vg
)
265 memset(vgd
, 0, sizeof(*vgd
));
266 memcpy(vgd
->vg_uuid
, vg
->id
.uuid
, ID_LEN
);
268 if (vg
->status
& LVM_READ
)
269 vgd
->vg_access
|= VG_READ
;
271 if (vg
->status
& LVM_WRITE
)
272 vgd
->vg_access
|= VG_WRITE
;
274 if (vg_is_clustered(vg
))
275 vgd
->vg_access
|= VG_CLUSTERED
;
277 if (vg
->status
& SHARED
)
278 vgd
->vg_access
|= VG_SHARED
;
280 if (vg_is_exported(vg
))
281 vgd
->vg_status
|= VG_EXPORTED
;
283 if (vg_is_resizeable(vg
))
284 vgd
->vg_status
|= VG_EXTENDABLE
;
286 vgd
->lv_max
= vg
->max_lv
;
287 vgd
->lv_cur
= vg_visible_lvs(vg
) + snapshot_count(vg
);
289 vgd
->pv_max
= vg
->max_pv
;
290 vgd
->pv_cur
= vg
->pv_count
;
292 vgd
->pe_size
= vg
->extent_size
;
293 vgd
->pe_total
= vg
->extent_count
;
294 vgd
->pe_allocated
= vg
->extent_count
- vg
->free_count
;
299 int import_lv(struct cmd_context
*cmd
, struct dm_pool
*mem
,
300 struct logical_volume
*lv
, struct lv_disk
*lvd
)
302 if (!(lv
->name
= _create_lv_name(mem
, (char *)lvd
->lv_name
)))
305 lv
->status
|= VISIBLE_LV
;
307 if (lvd
->lv_status
& LV_SPINDOWN
)
308 lv
->status
|= SPINDOWN_LV
;
310 if (lvd
->lv_status
& LV_PERSISTENT_MINOR
) {
311 lv
->status
|= FIXED_MINOR
;
312 lv
->minor
= MINOR(lvd
->lv_dev
);
313 lv
->major
= MAJOR(lvd
->lv_dev
);
319 if (lvd
->lv_access
& LV_READ
)
320 lv
->status
|= LVM_READ
;
322 if (lvd
->lv_access
& LV_WRITE
)
323 lv
->status
|= LVM_WRITE
;
325 if (lvd
->lv_badblock
)
326 lv
->status
|= BADBLOCK_ON
;
328 /* Drop the unused LV_STRICT here */
329 if (lvd
->lv_allocation
& LV_CONTIGUOUS
)
330 lv
->alloc
= ALLOC_CONTIGUOUS
;
332 lv
->alloc
= ALLOC_NORMAL
;
334 if (!lvd
->lv_read_ahead
)
335 lv
->read_ahead
= cmd
->default_settings
.read_ahead
;
337 lv
->read_ahead
= lvd
->lv_read_ahead
;
339 lv
->size
= lvd
->lv_size
;
340 lv
->le_count
= lvd
->lv_allocated_le
;
345 static void _export_lv(struct lv_disk
*lvd
, struct volume_group
*vg
,
346 struct logical_volume
*lv
, const char *dev_dir
)
348 memset(lvd
, 0, sizeof(*lvd
));
349 snprintf((char *)lvd
->lv_name
, sizeof(lvd
->lv_name
), "%s%s/%s",
350 dev_dir
, vg
->name
, lv
->name
);
352 strcpy((char *)lvd
->vg_name
, vg
->name
);
354 if (lv
->status
& LVM_READ
)
355 lvd
->lv_access
|= LV_READ
;
357 if (lv
->status
& LVM_WRITE
)
358 lvd
->lv_access
|= LV_WRITE
;
360 if (lv
->status
& SPINDOWN_LV
)
361 lvd
->lv_status
|= LV_SPINDOWN
;
363 if (lv
->status
& FIXED_MINOR
) {
364 lvd
->lv_status
|= LV_PERSISTENT_MINOR
;
365 lvd
->lv_dev
= MKDEV(lv
->major
, lv
->minor
);
367 lvd
->lv_dev
= MKDEV(LVM_BLK_MAJOR
, lvnum_from_lvid(&lv
->lvid
));
370 if (lv
->read_ahead
== DM_READ_AHEAD_AUTO
||
371 lv
->read_ahead
== DM_READ_AHEAD_NONE
)
372 lvd
->lv_read_ahead
= 0;
374 lvd
->lv_read_ahead
= lv
->read_ahead
;
377 dm_list_item(lv
->segments
.n
, struct lv_segment
)->area_count
;
379 dm_list_item(lv
->segments
.n
, struct lv_segment
)->stripe_size
;
381 lvd
->lv_size
= lv
->size
;
382 lvd
->lv_allocated_le
= lv
->le_count
;
384 if (lv
->status
& BADBLOCK_ON
)
385 lvd
->lv_badblock
= LV_BADBLOCK_ON
;
387 if (lv
->alloc
== ALLOC_CONTIGUOUS
)
388 lvd
->lv_allocation
|= LV_CONTIGUOUS
;
391 int export_extents(struct disk_list
*dl
, uint32_t lv_num
,
392 struct logical_volume
*lv
, struct physical_volume
*pv
)
395 struct lv_segment
*seg
;
398 dm_list_iterate_items(seg
, &lv
->segments
) {
399 for (s
= 0; s
< seg
->area_count
; s
++) {
400 if (!(seg
->segtype
->flags
& SEG_FORMAT1_SUPPORT
)) {
401 log_error("Segment type %s in LV %s: "
402 "unsupported by format1",
403 seg
->segtype
->name
, lv
->name
);
406 if (seg_type(seg
, s
) != AREA_PV
) {
407 log_error("Non-PV stripe found in LV %s: "
408 "unsupported by format1", lv
->name
);
411 if (seg_pv(seg
, s
) != pv
)
412 continue; /* not our pv */
414 for (pe
= 0; pe
< (seg
->len
/ seg
->area_count
); pe
++) {
415 ped
= &dl
->extents
[pe
+ seg_pe(seg
, s
)];
416 ped
->lv_num
= lv_num
;
417 ped
->le_num
= (seg
->le
/ seg
->area_count
) + pe
+
418 s
* (lv
->le_count
/ seg
->area_count
);
426 int import_pvs(const struct format_type
*fmt
, struct dm_pool
*mem
,
427 struct volume_group
*vg
,
428 struct dm_list
*pvds
, struct dm_list
*results
, uint32_t *count
)
430 struct disk_list
*dl
;
434 dm_list_iterate_items(dl
, pvds
) {
435 if (!(pvl
= dm_pool_zalloc(mem
, sizeof(*pvl
))) ||
436 !(pvl
->pv
= dm_pool_alloc(mem
, sizeof(*pvl
->pv
))))
439 if (!import_pv(fmt
, mem
, dl
->dev
, vg
, pvl
->pv
, &dl
->pvd
, &dl
->vgd
))
443 dm_list_add(results
, &pvl
->list
);
450 static struct logical_volume
*_add_lv(struct dm_pool
*mem
,
451 struct volume_group
*vg
,
454 struct logical_volume
*lv
;
456 if (!(lv
= alloc_lv(mem
)))
459 lvid_from_lvnum(&lv
->lvid
, &vg
->id
, lvd
->lv_number
);
461 if (!import_lv(vg
->cmd
, mem
, lv
, lvd
))
464 if (!link_lv_to_vg(vg
, lv
))
469 dm_pool_free(mem
, lv
);
473 int import_lvs(struct dm_pool
*mem
, struct volume_group
*vg
, struct dm_list
*pvds
)
475 struct disk_list
*dl
;
479 dm_list_iterate_items(dl
, pvds
) {
480 dm_list_iterate_items(ll
, &dl
->lvds
) {
483 if (!find_lv(vg
, (char *)lvd
->lv_name
) &&
484 !_add_lv(mem
, vg
, lvd
))
493 int export_lvs(struct disk_list
*dl
, struct volume_group
*vg
,
494 struct physical_volume
*pv
, const char *dev_dir
)
498 struct lvd_list
*lvdl
;
501 struct dm_hash_table
*lvd_hash
;
503 if (!_check_vg_name(vg
->name
))
506 if (!(lvd_hash
= dm_hash_create(32)))
510 * setup the pv's extents array
512 len
= sizeof(struct pe_disk
) * dl
->pvd
.pe_total
;
513 if (!(dl
->extents
= dm_pool_alloc(dl
->mem
, len
)))
515 memset(dl
->extents
, 0, len
);
517 dm_list_iterate_items(ll
, &vg
->lvs
) {
518 if (ll
->lv
->status
& SNAPSHOT
)
521 if (!(lvdl
= dm_pool_alloc(dl
->mem
, sizeof(*lvdl
))))
524 _export_lv(&lvdl
->lvd
, vg
, ll
->lv
, dev_dir
);
526 lv_num
= lvnum_from_lvid(&ll
->lv
->lvid
);
527 lvdl
->lvd
.lv_number
= lv_num
;
529 if (!dm_hash_insert(lvd_hash
, ll
->lv
->name
, &lvdl
->lvd
))
532 if (!export_extents(dl
, lv_num
+ 1, ll
->lv
, pv
))
535 if (lv_is_origin(ll
->lv
))
536 lvdl
->lvd
.lv_access
|= LV_SNAPSHOT_ORG
;
538 if (lv_is_cow(ll
->lv
)) {
539 lvdl
->lvd
.lv_access
|= LV_SNAPSHOT
;
540 lvdl
->lvd
.lv_chunk_size
= ll
->lv
->snapshot
->chunk_size
;
541 lvdl
->lvd
.lv_snapshot_minor
=
542 lvnum_from_lvid(&ll
->lv
->snapshot
->origin
->lvid
);
545 dm_list_add(&dl
->lvds
, &lvdl
->list
);
552 dm_hash_destroy(lvd_hash
);
557 * FIXME: More inefficient code.
559 int import_snapshots(struct dm_pool
*mem
__attribute((unused
)), struct volume_group
*vg
,
560 struct dm_list
*pvds
)
562 struct logical_volume
*lvs
[MAX_LV
];
563 struct disk_list
*dl
;
567 struct logical_volume
*org
, *cow
;
569 /* build an index of lv numbers */
570 memset(lvs
, 0, sizeof(lvs
));
571 dm_list_iterate_items(dl
, pvds
) {
572 dm_list_iterate_items(ll
, &dl
->lvds
) {
575 lvnum
= lvd
->lv_number
;
577 if (lvnum
>= MAX_LV
) {
578 log_error("Logical volume number "
584 !(lvs
[lvnum
] = find_lv(vg
, (char *)lvd
->lv_name
))) {
585 log_error("Couldn't find logical volume '%s'.",
593 * Now iterate through yet again adding the snapshots.
595 dm_list_iterate_items(dl
, pvds
) {
596 dm_list_iterate_items(ll
, &dl
->lvds
) {
599 if (!(lvd
->lv_access
& LV_SNAPSHOT
))
602 lvnum
= lvd
->lv_number
;
604 if (!(org
= lvs
[lvd
->lv_snapshot_minor
])) {
605 log_error("Couldn't find origin logical volume "
606 "for snapshot '%s'.", lvd
->lv_name
);
610 /* we may have already added this snapshot */
614 /* insert the snapshot */
615 if (!vg_add_snapshot(org
, cow
, NULL
,
617 lvd
->lv_chunk_size
)) {
618 log_error("Couldn't add snapshot.");
627 int export_uuids(struct disk_list
*dl
, struct volume_group
*vg
)
629 struct uuid_list
*ul
;
632 dm_list_iterate_items(pvl
, &vg
->pvs
) {
633 if (!(ul
= dm_pool_alloc(dl
->mem
, sizeof(*ul
))))
636 memset(ul
->uuid
, 0, sizeof(ul
->uuid
));
637 memcpy(ul
->uuid
, pvl
->pv
->id
.uuid
, ID_LEN
);
639 dm_list_add(&dl
->uuids
, &ul
->list
);
645 * This calculates the nasty pv_number field
648 void export_numbers(struct dm_list
*pvds
, struct volume_group
*vg
__attribute((unused
)))
650 struct disk_list
*dl
;
653 dm_list_iterate_items(dl
, pvds
)
654 dl
->pvd
.pv_number
= pv_num
++;
658 * Calculate vg_disk->pv_act.
660 void export_pv_act(struct dm_list
*pvds
)
662 struct disk_list
*dl
;
665 dm_list_iterate_items(dl
, pvds
)
666 if (dl
->pvd
.pv_status
& PV_ACTIVE
)
669 dm_list_iterate_items(dl
, pvds
)
670 dl
->vgd
.pv_act
= act
;
673 int export_vg_number(struct format_instance
*fid
, struct dm_list
*pvds
,
674 const char *vg_name
, struct dev_filter
*filter
)
676 struct disk_list
*dl
;
679 if (!get_free_vg_number(fid
, filter
, vg_name
, &vg_num
))
682 dm_list_iterate_items(dl
, pvds
)
683 dl
->vgd
.vg_number
= vg_num
;