4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 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
22 #include "toolcontext.h"
23 #include "lvm1-label.h"
27 /* VG consistency checks */
28 static int _check_vgs(struct dm_list
*pvs
)
30 struct dm_list
*pvh
, *t
;
31 struct disk_list
*dl
= NULL
;
32 struct disk_list
*first
= NULL
;
34 uint32_t pv_count
= 0;
35 uint32_t exported
= 0;
39 * If there are exported and unexported PVs, ignore exported ones.
40 * This means an active VG won't be affected if disks are inserted
41 * bearing an exported VG with the same name.
43 dm_list_iterate_items(dl
, pvs
) {
45 exported
= dl
->pvd
.pv_status
& VG_EXPORTED
;
50 if (exported
!= (dl
->pvd
.pv_status
& VG_EXPORTED
)) {
51 /* Remove exported PVs */
52 dm_list_iterate_safe(pvh
, t
, pvs
) {
53 dl
= dm_list_item(pvh
, struct disk_list
);
54 if (dl
->pvd
.pv_status
& VG_EXPORTED
)
61 /* Remove any PVs with VG structs that differ from the first */
62 dm_list_iterate_safe(pvh
, t
, pvs
) {
63 dl
= dm_list_item(pvh
, struct disk_list
);
68 else if (memcmp(&first
->vgd
, &dl
->vgd
, sizeof(first
->vgd
))) {
69 log_error("VG data differs between PVs %s and %s",
70 dev_name(first
->dev
), dev_name(dl
->dev
));
71 log_debug("VG data on %s: %s %s %" PRIu32
" %" PRIu32
72 " %" PRIu32
" %" PRIu32
" %" PRIu32
" %"
73 PRIu32
" %" PRIu32
" %" PRIu32
" %" PRIu32
74 " %" PRIu32
" %" PRIu32
" %" PRIu32
" %"
75 PRIu32
" %" PRIu32
" %" PRIu32
,
76 dev_name(first
->dev
), first
->vgd
.vg_uuid
,
77 first
->vgd
.vg_name_dummy
,
78 first
->vgd
.vg_number
, first
->vgd
.vg_access
,
79 first
->vgd
.vg_status
, first
->vgd
.lv_max
,
80 first
->vgd
.lv_cur
, first
->vgd
.lv_open
,
81 first
->vgd
.pv_max
, first
->vgd
.pv_cur
,
82 first
->vgd
.pv_act
, first
->vgd
.dummy
,
83 first
->vgd
.vgda
, first
->vgd
.pe_size
,
84 first
->vgd
.pe_total
, first
->vgd
.pe_allocated
,
85 first
->vgd
.pvg_total
);
86 log_debug("VG data on %s: %s %s %" PRIu32
" %" PRIu32
87 " %" PRIu32
" %" PRIu32
" %" PRIu32
" %"
88 PRIu32
" %" PRIu32
" %" PRIu32
" %" PRIu32
89 " %" PRIu32
" %" PRIu32
" %" PRIu32
" %"
90 PRIu32
" %" PRIu32
" %" PRIu32
,
91 dev_name(dl
->dev
), dl
->vgd
.vg_uuid
,
92 dl
->vgd
.vg_name_dummy
, dl
->vgd
.vg_number
,
93 dl
->vgd
.vg_access
, dl
->vgd
.vg_status
,
94 dl
->vgd
.lv_max
, dl
->vgd
.lv_cur
,
95 dl
->vgd
.lv_open
, dl
->vgd
.pv_max
,
96 dl
->vgd
.pv_cur
, dl
->vgd
.pv_act
, dl
->vgd
.dummy
,
97 dl
->vgd
.vgda
, dl
->vgd
.pe_size
,
98 dl
->vgd
.pe_total
, dl
->vgd
.pe_allocated
,
106 /* On entry to fn, list known to be non-empty */
107 if (pv_count
!= first
->vgd
.pv_cur
) {
108 log_error("%d PV(s) found for VG %s: expected %d",
109 pv_count
, first
->pvd
.vg_name
, first
->vgd
.pv_cur
);
115 static struct volume_group
*_build_vg(struct format_instance
*fid
,
119 struct volume_group
*vg
= dm_pool_alloc(mem
, sizeof(*vg
));
120 struct disk_list
*dl
;
125 if (dm_list_empty(pvs
))
128 memset(vg
, 0, sizeof(*vg
));
130 vg
->cmd
= fid
->fmt
->cmd
;
134 dm_list_init(&vg
->pvs
);
135 dm_list_init(&vg
->lvs
);
136 dm_list_init(&vg
->tags
);
137 dm_list_init(&vg
->removed_pvs
);
139 if (!_check_vgs(pvs
))
142 dl
= dm_list_item(pvs
->n
, struct disk_list
);
144 if (!import_vg(mem
, vg
, dl
))
147 if (!import_pvs(fid
->fmt
, mem
, vg
, pvs
, &vg
->pvs
, &vg
->pv_count
))
150 if (!import_lvs(mem
, vg
, pvs
))
153 if (!import_extents(fid
->fmt
->cmd
, vg
, pvs
))
156 if (!import_snapshots(mem
, vg
, pvs
))
162 dm_pool_free(mem
, vg
);
166 static struct volume_group
*_format1_vg_read(struct format_instance
*fid
,
168 struct metadata_area
*mda
__attribute((unused
)))
170 struct dm_pool
*mem
= dm_pool_create("lvm1 vg_read", VG_MEMPOOL_CHUNK
);
172 struct volume_group
*vg
= NULL
;
178 /* Strip dev_dir if present */
179 vg_name
= strip_dir(vg_name
, fid
->fmt
->cmd
->dev_dir
);
182 (fid
->fmt
, vg_name
, fid
->fmt
->cmd
->filter
, mem
, &pvs
))
185 if (!(vg
= _build_vg(fid
, &pvs
, mem
)))
190 dm_pool_destroy(mem
);
194 static struct disk_list
*_flatten_pv(struct format_instance
*fid
,
195 struct dm_pool
*mem
, struct volume_group
*vg
,
196 struct physical_volume
*pv
,
199 struct disk_list
*dl
= dm_pool_alloc(mem
, sizeof(*dl
));
207 dm_list_init(&dl
->uuids
);
208 dm_list_init(&dl
->lvds
);
210 if (!export_pv(fid
->fmt
->cmd
, mem
, vg
, &dl
->pvd
, pv
) ||
211 !export_vg(&dl
->vgd
, vg
) ||
212 !export_uuids(dl
, vg
) ||
213 !export_lvs(dl
, vg
, pv
, dev_dir
) || !calculate_layout(dl
)) {
214 dm_pool_free(mem
, dl
);
221 static int _flatten_vg(struct format_instance
*fid
, struct dm_pool
*mem
,
222 struct volume_group
*vg
,
223 struct dm_list
*pvds
, const char *dev_dir
,
224 struct dev_filter
*filter
)
227 struct disk_list
*data
;
229 dm_list_iterate_items(pvl
, &vg
->pvs
) {
230 if (!(data
= _flatten_pv(fid
, mem
, vg
, pvl
->pv
, dev_dir
)))
233 dm_list_add(pvds
, &data
->list
);
236 export_numbers(pvds
, vg
);
239 if (!export_vg_number(fid
, pvds
, vg
->name
, filter
))
245 static int _format1_vg_write(struct format_instance
*fid
, struct volume_group
*vg
,
246 struct metadata_area
*mda
__attribute((unused
)))
248 struct dm_pool
*mem
= dm_pool_create("lvm1 vg_write", VG_MEMPOOL_CHUNK
);
257 r
= (_flatten_vg(fid
, mem
, vg
, &pvds
, fid
->fmt
->cmd
->dev_dir
,
258 fid
->fmt
->cmd
->filter
) &&
259 write_disks(fid
->fmt
, &pvds
));
261 lvmcache_update_vg(vg
, 0);
262 dm_pool_destroy(mem
);
266 static int _format1_pv_read(const struct format_type
*fmt
, const char *pv_name
,
267 struct physical_volume
*pv
, struct dm_list
*mdas
__attribute((unused
)),
268 int scan_label_only
__attribute((unused
)))
270 struct dm_pool
*mem
= dm_pool_create("lvm1 pv_read", 1024);
271 struct disk_list
*dl
;
275 log_very_verbose("Reading physical volume data %s from disk", pv_name
);
280 if (!(dev
= dev_cache_get(pv_name
, fmt
->cmd
->filter
)))
283 if (!(dl
= read_disk(fmt
, dev
, mem
, NULL
)))
286 if (!import_pv(fmt
, fmt
->cmd
->mem
, dl
->dev
, NULL
, pv
, &dl
->pvd
, &dl
->vgd
))
294 dm_pool_destroy(mem
);
298 static int _format1_pv_setup(const struct format_type
*fmt
,
299 uint64_t pe_start
, uint32_t extent_count
,
300 uint32_t extent_size
,
301 unsigned long data_alignment
__attribute((unused
)),
302 unsigned long data_alignment_offset
__attribute((unused
)),
303 int pvmetadatacopies
__attribute((unused
)),
304 uint64_t pvmetadatasize
__attribute((unused
)), struct dm_list
*mdas
__attribute((unused
)),
305 struct physical_volume
*pv
, struct volume_group
*vg
__attribute((unused
)))
307 if (pv
->size
> MAX_PV_SIZE
)
309 if (pv
->size
> MAX_PV_SIZE
) {
310 log_error("Physical volumes cannot be bigger than %s",
311 display_size(fmt
->cmd
, (uint64_t) MAX_PV_SIZE
));
315 /* Nothing more to do if extent size isn't provided */
320 * This works out pe_start and pe_count.
322 if (!calculate_extent_count(pv
, extent_size
, extent_count
, pe_start
))
325 /* Retain existing extent locations exactly */
326 if (((pe_start
|| extent_count
) && (pe_start
!= pv
->pe_start
)) ||
327 (extent_count
&& (extent_count
!= pv
->pe_count
))) {
328 log_error("Metadata would overwrite physical extents");
335 static int _format1_lv_setup(struct format_instance
*fid
, struct logical_volume
*lv
)
337 uint64_t max_size
= UINT_MAX
;
340 lvid_from_lvnum(&lv
->lvid
, &lv
->vg
->id
, find_free_lvnum(lv
));
342 if (lv
->le_count
> MAX_LE_TOTAL
) {
343 log_error("logical volumes cannot contain more than "
344 "%d extents.", MAX_LE_TOTAL
);
347 if (lv
->size
> max_size
) {
348 log_error("logical volumes cannot be larger than %s",
349 display_size(fid
->fmt
->cmd
, max_size
));
356 static int _format1_pv_write(const struct format_type
*fmt
, struct physical_volume
*pv
,
357 struct dm_list
*mdas
__attribute((unused
)), int64_t sector
__attribute((unused
)))
360 struct disk_list
*dl
;
363 struct lvmcache_info
*info
;
365 if (!(info
= lvmcache_add(fmt
->labeller
, (char *) &pv
->id
, pv
->dev
,
366 pv
->vg_name
, NULL
, 0)))
369 info
->device_size
= pv
->size
<< SECTOR_SHIFT
;
372 dm_list_init(&info
->mdas
);
376 /* Ensure any residual PE structure is gone */
377 pv
->pe_size
= pv
->pe_count
= 0;
378 pv
->pe_start
= LVM1_PE_ALIGN
;
380 if (!(mem
= dm_pool_create("lvm1 pv_write", 1024)))
383 if (!(dl
= dm_pool_alloc(mem
, sizeof(*dl
))))
389 if (!export_pv(fmt
->cmd
, mem
, NULL
, &dl
->pvd
, pv
))
392 /* must be set to be able to zero gap after PV structure in
393 dev_write in order to make other disk tools happy */
394 dl
->pvd
.pv_on_disk
.base
= METADATA_BASE
;
395 dl
->pvd
.pv_on_disk
.size
= PV_SIZE
;
396 dl
->pvd
.pe_on_disk
.base
= LVM1_PE_ALIGN
<< SECTOR_SHIFT
;
398 dm_list_add(&pvs
, &dl
->list
);
399 if (!write_disks(fmt
, &pvs
))
402 dm_pool_destroy(mem
);
406 dm_pool_destroy(mem
);
410 static int _format1_vg_setup(struct format_instance
*fid
, struct volume_group
*vg
)
412 /* just check max_pv and max_lv */
413 if (!vg
->max_lv
|| vg
->max_lv
>= MAX_LV
)
414 vg
->max_lv
= MAX_LV
- 1;
416 if (!vg
->max_pv
|| vg
->max_pv
>= MAX_PV
)
417 vg
->max_pv
= MAX_PV
- 1;
419 if (vg
->extent_size
> MAX_PE_SIZE
|| vg
->extent_size
< MIN_PE_SIZE
) {
420 log_error("Extent size must be between %s and %s",
421 display_size(fid
->fmt
->cmd
, (uint64_t) MIN_PE_SIZE
),
422 display_size(fid
->fmt
->cmd
, (uint64_t) MAX_PE_SIZE
));
427 if (vg
->extent_size
% MIN_PE_SIZE
) {
428 log_error("Extent size must be multiple of %s",
429 display_size(fid
->fmt
->cmd
, (uint64_t) MIN_PE_SIZE
));
434 if (vg
->extent_size
& (vg
->extent_size
- 1)) {
435 log_error("Extent size must be power of 2");
442 static int _format1_segtype_supported(struct format_instance
*fid
__attribute((unused
)),
443 const struct segment_type
*segtype
)
445 if (!(segtype
->flags
& SEG_FORMAT1_SUPPORT
))
451 static struct metadata_area_ops _metadata_format1_ops
= {
452 .vg_read
= _format1_vg_read
,
453 .vg_write
= _format1_vg_write
,
456 static struct format_instance
*_format1_create_instance(const struct format_type
*fmt
,
457 const char *vgname
__attribute((unused
)),
458 const char *vgid
__attribute((unused
)),
459 void *private __attribute((unused
)))
461 struct format_instance
*fid
;
462 struct metadata_area
*mda
;
464 if (!(fid
= dm_pool_alloc(fmt
->cmd
->mem
, sizeof(*fid
))))
468 dm_list_init(&fid
->metadata_areas
);
470 /* Define a NULL metadata area */
471 if (!(mda
= dm_pool_alloc(fmt
->cmd
->mem
, sizeof(*mda
)))) {
472 dm_pool_free(fmt
->cmd
->mem
, fid
);
476 mda
->ops
= &_metadata_format1_ops
;
477 mda
->metadata_locn
= NULL
;
478 dm_list_add(&fid
->metadata_areas
, &mda
->list
);
483 static void _format1_destroy_instance(struct format_instance
*fid
__attribute((unused
)))
488 static void _format1_destroy(const struct format_type
*fmt
)
490 dm_free((void *) fmt
);
493 static struct format_handler _format1_ops
= {
494 .pv_read
= _format1_pv_read
,
495 .pv_setup
= _format1_pv_setup
,
496 .pv_write
= _format1_pv_write
,
497 .lv_setup
= _format1_lv_setup
,
498 .vg_setup
= _format1_vg_setup
,
499 .segtype_supported
= _format1_segtype_supported
,
500 .create_instance
= _format1_create_instance
,
501 .destroy_instance
= _format1_destroy_instance
,
502 .destroy
= _format1_destroy
,
506 struct format_type
*init_lvm1_format(struct cmd_context
*cmd
)
508 struct format_type
*init_format(struct cmd_context
*cmd
);
509 struct format_type
*init_format(struct cmd_context
*cmd
)
512 struct format_type
*fmt
= dm_malloc(sizeof(*fmt
));
518 fmt
->ops
= &_format1_ops
;
519 fmt
->name
= FMT_LVM1_NAME
;
521 fmt
->orphan_vg_name
= FMT_LVM1_ORPHAN_VG_NAME
;
522 fmt
->features
= FMT_RESTRICTED_LVIDS
| FMT_ORPHAN_ALLOCATABLE
|
523 FMT_RESTRICTED_READAHEAD
;
526 if (!(fmt
->labeller
= lvm1_labeller_create(fmt
))) {
527 log_error("Couldn't create lvm1 label handler.");
531 if (!(label_register_handler(FMT_LVM1_NAME
, fmt
->labeller
))) {
532 log_error("Couldn't register lvm1 label handler.");
536 log_very_verbose("Initialised format: %s", fmt
->name
);