diff options
Diffstat (limited to 'usr/src/common/lvm/md_convert.c')
-rw-r--r-- | usr/src/common/lvm/md_convert.c | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/usr/src/common/lvm/md_convert.c b/usr/src/common/lvm/md_convert.c new file mode 100644 index 0000000000..bb8912b3b9 --- /dev/null +++ b/usr/src/common/lvm/md_convert.c @@ -0,0 +1,669 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (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 2005 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 <sys/sysmacros.h> +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/lvm/mdvar.h> +#ifdef _KERNEL +#include <sys/lvm/md_basic.h> +#else /* !_KERNEL */ +#include <meta_basic.h> +#endif /* _KERNEL */ +#include <sys/lvm/md_convert.h> + + +/* + * 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_ovrlap_chn_flg = big_un->un_ovrlap_chn_flg; + 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_ovrlap_chn_flg = small_un->un_ovrlap_chn_flg; + 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); + } +} |