| /* |
| * Copyright (C) 1997-2004 Sistina Software, Inc. All rights reserved. |
| * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
| * |
| * This file is part of LVM2. |
| * |
| * This copyrighted material is made available to anyone wishing to use, |
| * modify, copy, or redistribute it subject to the terms and conditions |
| * of the GNU Lesser General Public License v.2.1. |
| * |
| * You should have received a copy of the GNU Lesser General Public License |
| * along with this program; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include "lib.h" |
| #include "label.h" |
| #include "metadata.h" |
| #include "disk_rep.h" |
| #include "sptype_names.h" |
| #include "lv_alloc.h" |
| #include "pv_alloc.h" |
| #include "str_list.h" |
| #include "display.h" |
| #include "segtype.h" |
| #include "toolcontext.h" |
| |
| /* This file contains only imports at the moment... */ |
| |
| int import_pool_vg(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls) |
| { |
| struct pool_list *pl; |
| |
| dm_list_iterate_items(pl, pls) { |
| vg->extent_count += |
| ((pl->pd.pl_blocks) / POOL_PE_SIZE); |
| |
| vg->free_count = vg->extent_count; |
| |
| if (vg->name) |
| continue; |
| |
| vg->name = dm_pool_strdup(mem, pl->pd.pl_pool_name); |
| get_pool_vg_uuid(&vg->id, &pl->pd); |
| vg->extent_size = POOL_PE_SIZE; |
| vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED; |
| vg->max_lv = 1; |
| vg->max_pv = POOL_MAX_DEVICES; |
| vg->alloc = ALLOC_NORMAL; |
| } |
| |
| return 1; |
| } |
| |
| int import_pool_lvs(struct volume_group *vg, struct dm_pool *mem, struct dm_list *pls) |
| { |
| struct pool_list *pl; |
| struct logical_volume *lv; |
| |
| if (!(lv = alloc_lv(mem))) |
| return_0; |
| |
| lv->status = 0; |
| lv->alloc = ALLOC_NORMAL; |
| lv->size = 0; |
| lv->name = NULL; |
| lv->le_count = 0; |
| lv->read_ahead = vg->cmd->default_settings.read_ahead; |
| |
| dm_list_iterate_items(pl, pls) { |
| lv->size += pl->pd.pl_blocks; |
| |
| if (lv->name) |
| continue; |
| |
| if (!(lv->name = dm_pool_strdup(mem, pl->pd.pl_pool_name))) |
| return_0; |
| |
| get_pool_lv_uuid(lv->lvid.id, &pl->pd); |
| log_debug_metadata("Calculated lv uuid for lv %s: %s", lv->name, |
| lv->lvid.s); |
| |
| lv->status |= VISIBLE_LV | LVM_READ | LVM_WRITE; |
| lv->major = POOL_MAJOR; |
| |
| /* for pool a minor of 0 is dynamic */ |
| if (pl->pd.pl_minor) { |
| lv->status |= FIXED_MINOR; |
| lv->minor = pl->pd.pl_minor + MINOR_OFFSET; |
| } else { |
| lv->minor = -1; |
| } |
| } |
| |
| lv->le_count = lv->size / POOL_PE_SIZE; |
| |
| return link_lv_to_vg(vg, lv); |
| } |
| |
| int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg, |
| struct dm_pool *mem, struct dm_list *pls) |
| { |
| struct pv_list *pvl; |
| struct pool_list *pl; |
| |
| dm_list_iterate_items(pl, pls) { |
| if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl)))) { |
| log_error("Unable to allocate pv list structure"); |
| return 0; |
| } |
| if (!(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) { |
| log_error("Unable to allocate pv structure"); |
| return 0; |
| } |
| if (!import_pool_pv(fmt, mem, vg, pvl->pv, pl)) { |
| return 0; |
| } |
| pl->pv = pvl->pv; |
| pvl->mdas = NULL; |
| pvl->pe_ranges = NULL; |
| add_pvl_to_vgs(vg, pvl); |
| } |
| |
| return 1; |
| } |
| |
| int import_pool_pv(const struct format_type *fmt, struct dm_pool *mem, |
| struct volume_group *vg, struct physical_volume *pv, |
| struct pool_list *pl) |
| { |
| struct pool_disk *pd = &pl->pd; |
| |
| memset(pv, 0, sizeof(*pv)); |
| |
| get_pool_pv_uuid(&pv->id, pd); |
| pv->fmt = fmt; |
| |
| pv->dev = pl->dev; |
| if (!(pv->vg_name = dm_pool_strdup(mem, pd->pl_pool_name))) { |
| log_error("Unable to duplicate vg_name string"); |
| return 0; |
| } |
| if (vg != NULL) |
| memcpy(&pv->vgid, &vg->id, sizeof(vg->id)); |
| pv->status = 0; |
| pv->size = pd->pl_blocks; |
| pv->pe_size = POOL_PE_SIZE; |
| pv->pe_start = POOL_PE_START; |
| pv->pe_count = pv->size / POOL_PE_SIZE; |
| pv->pe_alloc_count = 0; |
| pv->pe_align = 0; |
| |
| dm_list_init(&pv->tags); |
| dm_list_init(&pv->segments); |
| |
| if (!alloc_pv_segment_whole_pv(mem, pv)) |
| return_0; |
| |
| return 1; |
| } |
| |
| static const char *_cvt_sptype(uint32_t sptype) |
| { |
| int i; |
| for (i = 0; sptype_names[i].name[0]; i++) { |
| if (sptype == sptype_names[i].label) { |
| break; |
| } |
| } |
| log_debug_metadata("Found sptype %X and converted it to %s", |
| sptype, sptype_names[i].name); |
| return sptype_names[i].name; |
| } |
| |
| static int _add_stripe_seg(struct dm_pool *mem, |
| struct user_subpool *usp, struct logical_volume *lv, |
| uint32_t *le_cur) |
| { |
| struct lv_segment *seg; |
| struct segment_type *segtype; |
| unsigned j; |
| uint32_t area_len; |
| |
| if (!is_power_of_2(usp->striping)) { |
| log_error("Stripe size must be a power of 2"); |
| return 0; |
| } |
| |
| area_len = (usp->devs[0].blocks) / POOL_PE_SIZE; |
| |
| if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED))) |
| return_0; |
| |
| if (!(seg = alloc_lv_segment(segtype, lv, *le_cur, |
| area_len * usp->num_devs, 0, |
| usp->striping, NULL, usp->num_devs, |
| area_len, 0, 0, 0, NULL))) { |
| log_error("Unable to allocate striped lv_segment structure"); |
| return 0; |
| } |
| |
| for (j = 0; j < usp->num_devs; j++) |
| if (!set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0)) |
| return_0; |
| |
| /* add the subpool type to the segment tag list */ |
| if (!str_list_add(mem, &seg->tags, _cvt_sptype(usp->type))) { |
| log_error("Allocation failed for str_list."); |
| return 0; |
| } |
| |
| dm_list_add(&lv->segments, &seg->list); |
| |
| *le_cur += seg->len; |
| |
| return 1; |
| } |
| |
| static int _add_linear_seg(struct dm_pool *mem, |
| struct user_subpool *usp, struct logical_volume *lv, |
| uint32_t *le_cur) |
| { |
| struct lv_segment *seg; |
| struct segment_type *segtype; |
| unsigned j; |
| uint32_t area_len; |
| |
| if (!(segtype = get_segtype_from_string(lv->vg->cmd, SEG_TYPE_NAME_STRIPED))) |
| return_0; |
| |
| for (j = 0; j < usp->num_devs; j++) { |
| area_len = (usp->devs[j].blocks) / POOL_PE_SIZE; |
| |
| if (!(seg = alloc_lv_segment(segtype, lv, *le_cur, |
| area_len, 0, usp->striping, |
| NULL, 1, area_len, |
| POOL_PE_SIZE, 0, 0, NULL))) { |
| log_error("Unable to allocate linear lv_segment " |
| "structure"); |
| return 0; |
| } |
| |
| /* add the subpool type to the segment tag list */ |
| if (!str_list_add(mem, &seg->tags, _cvt_sptype(usp->type))) { |
| log_error("Allocation failed for str_list."); |
| return 0; |
| } |
| |
| if (!set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0)) |
| return_0; |
| dm_list_add(&lv->segments, &seg->list); |
| |
| *le_cur += seg->len; |
| } |
| |
| return 1; |
| } |
| |
| int import_pool_segments(struct dm_list *lvs, struct dm_pool *mem, |
| struct user_subpool *usp, int subpools) |
| { |
| struct lv_list *lvl; |
| struct logical_volume *lv; |
| uint32_t le_cur = 0; |
| int i; |
| |
| dm_list_iterate_items(lvl, lvs) { |
| lv = lvl->lv; |
| |
| if (lv->status & SNAPSHOT) |
| continue; |
| |
| for (i = 0; i < subpools; i++) { |
| if (usp[i].striping) { |
| if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) |
| return_0; |
| } else { |
| if (!_add_linear_seg(mem, &usp[i], lv, &le_cur)) |
| return_0; |
| } |
| } |
| } |
| |
| return 1; |
| } |