/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * md_convert.c * * As the size of a metadevice used to be stored in 32 bit signed variables, * there was a limit of 1 TB for the size (2^31 * 512 byte). * In order to be able to create larger metadevices, a 2nd set of structures * with wider variables for the size has been created. * There's one structure being shared by all types (mdc_unit_t) and one * for each type of metadevice (mm_unit_t, ms_unit_t, mr_unit_t, ...). * the wide structures are named like mdc_unit_t, mm_unit_t,.. * The narrow structures are named like mdc_unit32_od_t, mm_unit32_od_t,... * * The wide structures are used for md's >= 1TB, the narrow structures * are used for md's < 1TB. * Once a metadevice grows from < 1TB to >= 1TB the record has to be * converted from a narrow one to a wide one. * * Incore (commands, libs and drivers) we only use the wide structures, * in order to keep it simple. * This means when we snarf a narrow struct, we have to convert it to a * wide incore instance before we can use the md. * * * This file contains conversion routines for the various metadevices. * All the conversion routines take as input two pointers to memory areas * and a direction. The directions specifies which memory area is the * source and which is the destination. */ #include #include #include #include #ifdef _KERNEL #include #else /* !_KERNEL */ #include #endif /* _KERNEL */ #include /* * SVM private devt expansion routine * INPUT: dev a 64 bit container holding either a 32 bit or a 64 bit device * OUTPUT: always an expanded 64 bit device, even if we are running in a * 32 bit Kernel. */ md_dev64_t md_expldev(md_dev64_t dev) { minor_t minor; major_t major = (major_t)(dev >> NBITSMINOR64) & MAXMAJ64; /* Here we were given a 64bit dev, return unchanged */ if (major != (major_t)0) return (dev); /* otherwise we were given a 32 bit dev */ major = (major_t)dev >> NBITSMINOR32 & MAXMAJ32; minor = (minor_t)dev & MAXMIN32; return (((md_dev64_t)major << NBITSMINOR64) | minor); } /* * SVM private devt compact routine * INPUT: dev a 64 bit container holding either a 32 bit or a 64 bit device * OUTPUT: always a compacted 32 bit device, even if we are running in a * 64 bit Kernel. */ dev32_t md_cmpldev(md_dev64_t dev) { minor_t minor; major_t major = (major_t)(dev >> NBITSMINOR64) & MAXMAJ64; /* Here we were given a 32bit dev, return unchanged */ if (major == 0) { return ((dev32_t)dev); } /* otherwise we were given a 64 bit dev */ minor = (minor_t)dev & MAXMIN32; return (((dev32_t)major << NBITSMINOR32) | minor); } /* * given a small stripe unit, compute the size of an appropriate * big stripe unit. * if first_comp_only is set just return the offset of the first component * in the new big unit. * * The function: * usr/src/lib/lvm/libmeta/common/meta_statconcise.c:get_stripe_req_size() * contains code derived from this function and thus if any changes are made to * this function get_stripe_req_size() should be evaluated to determine whether * or not code changes will also be necessary there. * */ size_t get_big_stripe_req_size(ms_unit32_od_t *un, int first_comp_only) { struct ms_row32_od *mdr; uint_t row; uint_t ncomps = 0; size_t mdsize = 0; size_t first_comp = 0; /* Compute the offset of the first component */ first_comp = sizeof (ms_unit_t) + sizeof (struct ms_row) * (un->un_nrows - 1); first_comp = roundup(first_comp, sizeof (long long)); if (first_comp_only == FIRST_COMP_OFFSET) return (first_comp); /* * Requestor wants to have the total size, add the sizes of * all components */ mdr = &un->un_row[0]; for (row = 0; (row < un->un_nrows); row++) ncomps += mdr[row].un_ncomp; mdsize = first_comp + sizeof (ms_comp_t) * ncomps; return (mdsize); } /* * given a big stripe unit, compute the size of an appropriate * small stripe unit. * if first_comp_only is set just return the offset of the first component * in the new small unit. */ size_t get_small_stripe_req_size(ms_unit_t *un, int first_comp_only) { struct ms_row *mdr; uint_t row; uint_t ncomps = 0; size_t mdsize; size_t first_comp; /* Compute the size of the new small ms_unit */ first_comp = sizeof (ms_unit32_od_t) + sizeof (struct ms_row32_od) * (un->un_nrows - 1); first_comp = roundup(first_comp, sizeof (long long)); if (first_comp_only == FIRST_COMP_OFFSET) return (first_comp); /* * Requestor wants to have the total size, add the sizes of * all components */ mdr = &un->un_row[0]; for (row = 0; (row < un->un_nrows); row++) ncomps += mdr[row].un_ncomp; mdsize = first_comp + sizeof (ms_comp32_od_t) * ncomps; return (mdsize); } /* * stripe_convert(small, big, dir) * * Parameters: * small is the address of a ms_unit32_od_t structure * big is the address of a ms_unit_t structure * dir is either BIG2SMALL or SMALL2BIG * Return value is void * * what it does: * if dir is BIG2SMALL, convert from big to small (updating old records) * if dir is SMALL2BIG, convert from small to big (snarfing old records) * * Caveat emptor: big and small must be well allocated memory areas. */ void stripe_convert(caddr_t small, caddr_t big, int direction) { /*LINTED*/ ms_unit32_od_t *small_un = (ms_unit32_od_t *)small; /*LINTED*/ ms_unit_t *big_un = (ms_unit_t *)big; struct ms_row32_od *small_mdr; struct ms_row *big_mdr; uint_t row, comp, ncomps = 0; ms_comp_t *big_mdcomp; ms_comp32_od_t *small_mdcomp; if (direction == BIG_2_SMALL) { MDC_UNIT_BIG2SMALL(big_un, small_un); small_un->un_hsp_id = big_un->un_hsp_id; small_un->un_nrows = big_un->un_nrows; small_un->c.un_size = get_small_stripe_req_size(big_un, COMPLETE_STRUCTURE); small_un->un_ocomp = get_small_stripe_req_size(big_un, FIRST_COMP_OFFSET); /* walk through all rows */ big_mdr = &big_un->un_row[0]; small_mdr = &small_un->un_row[0]; for (row = 0; (row < big_un->un_nrows); row++) { ncomps += big_mdr[row].un_ncomp; MSROW_BIG2SMALL((&(big_mdr[row])), (&(small_mdr[row]))); } /* Now copy the components */ big_mdcomp = (ms_comp_t *)(void *)&((char *)big_un) [big_un->un_ocomp]; small_mdcomp = (ms_comp32_od_t *)(void *)&((char *)small_un) [small_un->un_ocomp]; for (comp = 0; (comp < ncomps); ++comp) { ms_comp_t *big_mdcp = &big_mdcomp[comp]; ms_comp32_od_t *small_mdcp = &small_mdcomp[comp]; MSCOMP_BIG2SMALL(big_mdcp, small_mdcp); } } if (direction == SMALL_2_BIG) { MDC_UNIT_SMALL2BIG(small_un, big_un); big_un->un_hsp_id = small_un->un_hsp_id; big_un->un_nrows = small_un->un_nrows; big_un->c.un_size = get_big_stripe_req_size(small_un, COMPLETE_STRUCTURE); big_un->un_ocomp = get_big_stripe_req_size(small_un, FIRST_COMP_OFFSET); /* walk through all rows */ small_mdr = &small_un->un_row[0]; big_mdr = &big_un->un_row[0]; for (row = 0; (row < small_un->un_nrows); row++) { ncomps += small_mdr[row].un_ncomp; MSROW_SMALL2BIG((&(small_mdr[row])), (&(big_mdr[row]))); } /* Now copy the components */ big_mdcomp = (ms_comp_t *)(void *)&((char *)big_un) [big_un->un_ocomp]; small_mdcomp = (ms_comp32_od_t *)(void *)&((char *)small_un) [small_un->un_ocomp]; for (comp = 0; (comp < ncomps); ++comp) { ms_comp_t *big_mdcp = &big_mdcomp[comp]; ms_comp32_od_t *small_mdcp = &small_mdcomp[comp]; MSCOMP_SMALL2BIG(small_mdcp, big_mdcp); } } } /* * mirror_convert(small, big, dir) * * Parameters: * small is the address of a mm_unit32_od_t structure * big is the address of a mm_unit_t structure * dir is either BIG2SMALL or SMALL2BIG * Return value is void * * what it does: * if dir is BIG2SMALL, convert from big to small (updating old records) * if dir is SMALL2BIG, convert from small to big (snarfing old records) * * Caveat emptor: big and small must be well allocated memory areas. */ void mirror_convert(caddr_t small, caddr_t big, int direction) { /*LINTED*/ mm_unit32_od_t *small_un = (mm_unit32_od_t *)small; /*LINTED*/ mm_unit_t *big_un = (mm_unit_t *)big; int i; if (direction == BIG_2_SMALL) { MDC_UNIT_BIG2SMALL(big_un, small_un); small_un->c.un_size = roundup(sizeof (mm_unit32_od_t), sizeof (long long)); small_un->un_last_read = big_un->un_last_read; small_un->un_changecnt = big_un->un_changecnt; small_un->un_nsm = big_un->un_nsm; for (i = 0; i < NMIRROR; i++) { MMSM_BIG2SMALL((&(big_un->un_sm[i])), (&(small_un->un_sm[i]))); } small_un->un_overlap_tree_flag = big_un->un_overlap_tree_flag; small_un->un_read_option = big_un->un_read_option; small_un->un_write_option = big_un->un_write_option; small_un->un_pass_num = big_un->un_pass_num; small_un->un_rrd_blksize = big_un->un_rrd_blksize; small_un->un_rrd_num = big_un->un_rrd_num; small_un->un_rr_dirty_recid = big_un->un_rr_dirty_recid; small_un->un_rs_copysize = big_un->un_rs_copysize; small_un->un_rs_dests = big_un->un_rs_dests; small_un->un_rs_resync_done = (daddr32_t)big_un->un_rs_resync_done; small_un->un_rs_resync_2_do = (daddr32_t)big_un->un_rs_resync_2_do; small_un->un_rs_dropped_lock = big_un->un_rs_dropped_lock; small_un->un_rs_type = big_un->un_rs_type; } if (direction == SMALL_2_BIG) { MDC_UNIT_SMALL2BIG(small_un, big_un); big_un->c.un_size = roundup(sizeof (mm_unit_t), sizeof (long long)); big_un->un_last_read = small_un->un_last_read; big_un->un_changecnt = small_un->un_changecnt; big_un->un_nsm = small_un->un_nsm; for (i = 0; i < NMIRROR; i++) { MMSM_SMALL2BIG((&(small_un->un_sm[i])), (&(big_un->un_sm[i]))); } /* Now back to the simple things again */ big_un->un_overlap_tree_flag = small_un->un_overlap_tree_flag; big_un->un_read_option = small_un->un_read_option; big_un->un_write_option = small_un->un_write_option; big_un->un_pass_num = small_un->un_pass_num; big_un->un_rrd_blksize = small_un->un_rrd_blksize; big_un->un_rrd_num = small_un->un_rrd_num; big_un->un_rr_dirty_recid = small_un->un_rr_dirty_recid; big_un->un_rs_copysize = small_un->un_rs_copysize; big_un->un_rs_dests = small_un->un_rs_dests; big_un->un_rs_resync_done = (diskaddr_t)small_un->un_rs_resync_done; big_un->un_rs_resync_2_do = (diskaddr_t)small_un->un_rs_resync_2_do; big_un->un_rs_dropped_lock = small_un->un_rs_dropped_lock; big_un->un_rs_type = small_un->un_rs_type; } } /* * raid_convert(small, big, dir) * * Parameters: * small is the address of a mr_unit32_od_t structure * big is the address of a mr_unit_t structure * dir is either BIG2SMALL or SMALL2BIG * Return value is void * * what it does: * if dir is BIG2SMALL, convert from big to small (updating old records) * if dir is SMALL2BIG, convert from small to big (snarfing old records) * * Caveat emptor: big and small must be well allocated memory areas. */ void raid_convert(caddr_t small, caddr_t big, int direction) { /*LINTED*/ mr_unit32_od_t *small_un = (mr_unit32_od_t *)small; /*LINTED*/ mr_unit_t *big_un = (mr_unit_t *)big; int i; uint_t ncol; if (direction == BIG_2_SMALL) { MRUNIT_BIG2SMALL(big_un, small_un); ncol = small_un->un_totalcolumncnt; small_un->c.un_size = sizeof (mr_unit32_od_t); small_un->c.un_size += (ncol - 1) * sizeof (mr_column32_od_t); for (i = 0; i < ncol; i++) { MRCOL_BIG2SMALL((&(big_un->un_column[i])), (&(small_un->un_column[i]))); } } if (direction == SMALL_2_BIG) { MRUNIT_SMALL2BIG(small_un, big_un); ncol = big_un->un_totalcolumncnt; big_un->c.un_size = sizeof (mr_unit_t); big_un->c.un_size += (ncol - 1) * sizeof (mr_column_t); for (i = 0; i < ncol; i++) { MRCOL_SMALL2BIG((&(small_un->un_column[i])), (&(big_un->un_column[i]))); } } } /* * softpart_convert(small, big, dir) * * Parameters: * small is the address of a mp_unit32_od_t structure * big is the address of a mp_unit_t structure * dir is either BIG2SMALL or SMALL2BIG * Return value is void * * what it does: * if dir is BIG2SMALL, convert from big to small (updating old records) * if dir is SMALL2BIG, convert from small to big (snarfing old records) * * Caveat emptor: big and small must be well allocated memory areas. */ void softpart_convert(caddr_t small, caddr_t big, int direction) { /*LINTED*/ mp_unit32_od_t *small_un = (mp_unit32_od_t *)small; /*LINTED*/ mp_unit_t *big_un = (mp_unit_t *)big; if (direction == BIG_2_SMALL) { MPUNIT_BIG2SMALL(big_un, small_un); /* * Note that there isn't a mp_ext32_od_t, it's right to use * mp_ext_t here, too. */ small_un->c.un_size = sizeof (mp_unit32_od_t) + (small_un->un_numexts - 1) * sizeof (mp_ext_t); } if (direction == SMALL_2_BIG) { MPUNIT_SMALL2BIG(small_un, big_un); big_un->c.un_size = sizeof (mp_unit_t) + (big_un->un_numexts - 1) * sizeof (mp_ext_t); } } /* * trans_master_convert(smallp, bigp, dir) * * Parameters: * smallp is the address of a mt_unit32_od_t structure * bigp is the address of a mt_unit_t structure * dir is either BIG2SMALL or SMALL2BIG * Return value is void * * what it does: * if dir is BIG2SMALL, convert from big to small (updating old records) * if dir is SMALL2BIG, convert from small to big (snarfing old records) * * Caveat emptor: bigp and smallp must be well allocated memory areas. */ void trans_master_convert(caddr_t smallp, caddr_t bigp, int direction) { /*LINTED*/ mt_unit32_od_t *small = (mt_unit32_od_t *)smallp; /*LINTED*/ mt_unit_t *big = (mt_unit_t *)bigp; if (direction == SMALL_2_BIG) { MDC_UNIT_SMALL2BIG(small, big); big->c.un_size = roundup(sizeof (mt_unit_t), sizeof (long long)); big->un_flags = small->un_flags; big->un_m_key = small->un_m_key; big->un_m_dev = md_expldev(small->un_m_dev); big->un_l_key = small->un_l_key; big->un_l_dev = md_expldev(small->un_l_dev); big->un_l_sblk = small->un_l_sblk; big->un_l_pwsblk = small->un_l_pwsblk; big->un_l_nblks = small->un_l_nblks; big->un_l_tblks = small->un_l_tblks; big->un_l_head = small->un_l_head; big->un_l_tail = small->un_l_tail; big->un_l_resv = small->un_l_resv; big->un_l_maxresv = small->un_l_maxresv; big->un_l_recid = small->un_l_recid; big->un_l_error = small->un_l_error; big->un_s_dev = md_expldev(small->un_s_dev); big->un_debug = small->un_debug; big->un_dev = md_expldev(small->un_dev); big->un_logreset = small->un_logreset; big->un_l_maxtransfer = small->un_l_maxtransfer; big->un_timestamp.tv_sec = small->un_timestamp.tv_sec; big->un_timestamp.tv_usec = small->un_timestamp.tv_usec; big->un_l_timestamp.tv_sec = small->un_l_timestamp.tv_sec; big->un_l_timestamp.tv_usec = small->un_l_timestamp.tv_usec; } if (direction == BIG_2_SMALL) { MDC_UNIT_BIG2SMALL(big, small); small->c.un_size = roundup(sizeof (mt_unit32_od_t), sizeof (long long)); small->un_flags = big->un_flags; small->un_m_key = big->un_m_key; small->un_m_dev = md_cmpldev(big->un_m_dev); small->un_l_key = big->un_l_key; small->un_l_dev = md_cmpldev(big->un_l_dev); small->un_l_sblk = big->un_l_sblk; small->un_l_pwsblk = big->un_l_pwsblk; small->un_l_nblks = big->un_l_nblks; small->un_l_tblks = big->un_l_tblks; small->un_l_head = big->un_l_head; small->un_l_tail = big->un_l_tail; small->un_l_resv = big->un_l_resv; small->un_l_maxresv = big->un_l_maxresv; small->un_l_maxtransfer = big->un_l_maxtransfer; small->un_l_recid = big->un_l_recid; small->un_l_error = big->un_l_error; small->un_s_dev = md_cmpldev(big->un_s_dev); small->un_debug = big->un_debug; small->un_dev = md_cmpldev(big->un_dev); small->un_logreset = big->un_logreset; small->un_timestamp.tv_sec = big->un_timestamp.tv_sec; small->un_timestamp.tv_usec = big->un_timestamp.tv_usec; small->un_l_timestamp.tv_sec = big->un_l_timestamp.tv_sec; small->un_l_timestamp.tv_usec = big->un_l_timestamp.tv_usec; } } /* * trans_log_convert(smallp, bigp, dir) * * Parameters: * smallp is the address of a ml_unit32_od_t structure * bigp is the address of a ml_unit_t structure * dir is either BIG2SMALL or SMALL2BIG * Return value is void * * what it does: * if dir is BIG2SMALL, convert from big to small (updating old records) * if dir is SMALL2BIG, convert from small to big (snarfing old records) * * Caveat emptor: bigp and smallp must be well allocated memory areas. */ void trans_log_convert(caddr_t smallp, caddr_t bigp, int direction) { /*LINTED*/ ml_unit32_od_t *small = (ml_unit32_od_t *)smallp; /*LINTED*/ ml_unit_t *big = (ml_unit_t *)bigp; if (direction == SMALL_2_BIG) { big->un_revision = small->un_revision; big->un_recid = small->un_recid; big->un_key = small->un_key; big->un_dev = md_expldev(small->un_dev); big->un_opencnt = small->un_opencnt; big->un_transcnt = small->un_transcnt; big->un_head_lof = small->un_head_lof; big->un_head_ident = small->un_head_ident; big->un_tail_lof = small->un_tail_lof; big->un_tail_ident = small->un_tail_ident; big->un_bol_lof = small->un_bol_lof; big->un_eol_lof = small->un_eol_lof; big->un_nblks = small->un_nblks; big->un_tblks = small->un_tblks; big->un_maxtransfer = small->un_maxtransfer; big->un_status = small->un_status; big->un_maxresv = small->un_maxresv; big->un_pwsblk = small->un_pwsblk; big->un_devbsize = small->un_devbsize; big->un_resv = small->un_resv; big->un_resv_wantin = small->un_resv_wantin; big->un_error = small->un_error; big->un_tid = small->un_tid; big->un_head_tid = small->un_head_tid; big->un_timestamp.tv_sec = small->un_timestamp.tv_sec; big->un_timestamp.tv_usec = small->un_timestamp.tv_usec; } if (direction == BIG_2_SMALL) { small->un_revision = big->un_revision; small->un_recid = big->un_recid; small->un_key = big->un_key; small->un_dev = md_cmpldev(big->un_dev); small->un_opencnt = big->un_opencnt; small->un_transcnt = big->un_transcnt; small->un_head_lof = big->un_head_lof; small->un_head_ident = big->un_head_ident; small->un_tail_lof = big->un_tail_lof; small->un_tail_ident = big->un_tail_ident; small->un_bol_lof = big->un_bol_lof; small->un_eol_lof = big->un_eol_lof; small->un_nblks = big->un_nblks; small->un_tblks = big->un_tblks; small->un_maxtransfer = big->un_maxtransfer; small->un_status = big->un_status; small->un_maxresv = big->un_maxresv; small->un_pwsblk = big->un_pwsblk; small->un_devbsize = big->un_devbsize; small->un_resv = big->un_resv; small->un_resv_wantin = big->un_resv_wantin; small->un_error = big->un_error; small->un_tid = big->un_tid; small->un_head_tid = big->un_head_tid; small->un_timestamp.tv_sec = big->un_timestamp.tv_sec; small->un_timestamp.tv_usec = big->un_timestamp.tv_usec; } } /* * hs_convert(small, big, dir) * * Parameters: * small is the address of a hot_spare32_od_t structure * big is the address of a hot_spare_t structure * dir is either BIG2SMALL or SMALL2BIG * Return value is void * * what it does: * if dir is BIG2SMALL, convert from big to small (updating old records) * if dir is SMALL2BIG, convert from small to big (snarfing old records) * * Caveat emptor: big and small must be well allocated memory areas. */ void hs_convert(caddr_t small, caddr_t big, int direction) { /*LINTED*/ hot_spare32_od_t *small_un = (hot_spare32_od_t *)small; /*LINTED*/ hot_spare_t *big_un = (hot_spare_t *)big; if (direction == BIG_2_SMALL) { MHS_BIG2SMALL(big_un, small_un); } if (direction == SMALL_2_BIG) { MHS_SMALL2BIG(small_un, big_un); } }