111935SMark.Shellenbaum@Sun.COM /* 211935SMark.Shellenbaum@Sun.COM * CDDL HEADER START 311935SMark.Shellenbaum@Sun.COM * 411935SMark.Shellenbaum@Sun.COM * The contents of this file are subject to the terms of the 511935SMark.Shellenbaum@Sun.COM * Common Development and Distribution License (the "License"). 611935SMark.Shellenbaum@Sun.COM * You may not use this file except in compliance with the License. 711935SMark.Shellenbaum@Sun.COM * 811935SMark.Shellenbaum@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 911935SMark.Shellenbaum@Sun.COM * or http://www.opensolaris.org/os/licensing. 1011935SMark.Shellenbaum@Sun.COM * See the License for the specific language governing permissions 1111935SMark.Shellenbaum@Sun.COM * and limitations under the License. 1211935SMark.Shellenbaum@Sun.COM * 1311935SMark.Shellenbaum@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1411935SMark.Shellenbaum@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1511935SMark.Shellenbaum@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1611935SMark.Shellenbaum@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1711935SMark.Shellenbaum@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1811935SMark.Shellenbaum@Sun.COM * 1911935SMark.Shellenbaum@Sun.COM * CDDL HEADER END 2011935SMark.Shellenbaum@Sun.COM */ 2111935SMark.Shellenbaum@Sun.COM /* 22*12684STom.Erickson@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 2311935SMark.Shellenbaum@Sun.COM */ 2411935SMark.Shellenbaum@Sun.COM 2511935SMark.Shellenbaum@Sun.COM #ifndef _SYS_SA_IMPL_H 2611935SMark.Shellenbaum@Sun.COM #define _SYS_SA_IMPL_H 2711935SMark.Shellenbaum@Sun.COM 2811935SMark.Shellenbaum@Sun.COM #include <sys/dmu.h> 2911935SMark.Shellenbaum@Sun.COM #include <sys/refcount.h> 3011935SMark.Shellenbaum@Sun.COM #include <sys/list.h> 3111935SMark.Shellenbaum@Sun.COM 3211935SMark.Shellenbaum@Sun.COM /* 3311935SMark.Shellenbaum@Sun.COM * Array of known attributes and their 3411935SMark.Shellenbaum@Sun.COM * various characteristics. 3511935SMark.Shellenbaum@Sun.COM */ 3611935SMark.Shellenbaum@Sun.COM typedef struct sa_attr_table { 3711935SMark.Shellenbaum@Sun.COM sa_attr_type_t sa_attr; 3811935SMark.Shellenbaum@Sun.COM uint8_t sa_registered; 3911935SMark.Shellenbaum@Sun.COM uint16_t sa_length; 4011935SMark.Shellenbaum@Sun.COM sa_bswap_type_t sa_byteswap; 4111935SMark.Shellenbaum@Sun.COM char *sa_name; 4211935SMark.Shellenbaum@Sun.COM } sa_attr_table_t; 4311935SMark.Shellenbaum@Sun.COM 4411935SMark.Shellenbaum@Sun.COM /* 4511935SMark.Shellenbaum@Sun.COM * Zap attribute format for attribute registration 4611935SMark.Shellenbaum@Sun.COM * 4711935SMark.Shellenbaum@Sun.COM * 64 56 48 40 32 24 16 8 0 4811935SMark.Shellenbaum@Sun.COM * +-------+-------+-------+-------+-------+-------+-------+-------+ 4911935SMark.Shellenbaum@Sun.COM * | unused | len | bswap | attr num | 5011935SMark.Shellenbaum@Sun.COM * +-------+-------+-------+-------+-------+-------+-------+-------+ 5111935SMark.Shellenbaum@Sun.COM * 5211935SMark.Shellenbaum@Sun.COM * Zap attribute format for layout information. 5311935SMark.Shellenbaum@Sun.COM * 5411935SMark.Shellenbaum@Sun.COM * layout information is stored as an array of attribute numbers 5511935SMark.Shellenbaum@Sun.COM * The name of the attribute is the layout number (0, 1, 2, ...) 5611935SMark.Shellenbaum@Sun.COM * 5711935SMark.Shellenbaum@Sun.COM * 16 0 5811935SMark.Shellenbaum@Sun.COM * +---- ---+ 5911935SMark.Shellenbaum@Sun.COM * | attr # | 6011935SMark.Shellenbaum@Sun.COM * +--------+ 6111935SMark.Shellenbaum@Sun.COM * | attr # | 6211935SMark.Shellenbaum@Sun.COM * +--- ----+ 6311935SMark.Shellenbaum@Sun.COM * ...... 6411935SMark.Shellenbaum@Sun.COM * 6511935SMark.Shellenbaum@Sun.COM */ 6611935SMark.Shellenbaum@Sun.COM 6711935SMark.Shellenbaum@Sun.COM #define ATTR_BSWAP(x) BF32_GET(x, 16, 8) 6811935SMark.Shellenbaum@Sun.COM #define ATTR_LENGTH(x) BF32_GET(x, 24, 16) 6911935SMark.Shellenbaum@Sun.COM #define ATTR_NUM(x) BF32_GET(x, 0, 16) 7011935SMark.Shellenbaum@Sun.COM #define ATTR_ENCODE(x, attr, length, bswap) \ 7111935SMark.Shellenbaum@Sun.COM { \ 7211935SMark.Shellenbaum@Sun.COM BF64_SET(x, 24, 16, length); \ 7311935SMark.Shellenbaum@Sun.COM BF64_SET(x, 16, 8, bswap); \ 7411935SMark.Shellenbaum@Sun.COM BF64_SET(x, 0, 16, attr); \ 7511935SMark.Shellenbaum@Sun.COM } 7611935SMark.Shellenbaum@Sun.COM 7711935SMark.Shellenbaum@Sun.COM #define TOC_OFF(x) BF32_GET(x, 0, 23) 7811935SMark.Shellenbaum@Sun.COM #define TOC_ATTR_PRESENT(x) BF32_GET(x, 31, 1) 7911935SMark.Shellenbaum@Sun.COM #define TOC_LEN_IDX(x) BF32_GET(x, 24, 4) 8011935SMark.Shellenbaum@Sun.COM #define TOC_ATTR_ENCODE(x, len_idx, offset) \ 8111935SMark.Shellenbaum@Sun.COM { \ 8211935SMark.Shellenbaum@Sun.COM BF32_SET(x, 31, 1, 1); \ 8311935SMark.Shellenbaum@Sun.COM BF32_SET(x, 24, 7, len_idx); \ 8411935SMark.Shellenbaum@Sun.COM BF32_SET(x, 0, 24, offset); \ 8511935SMark.Shellenbaum@Sun.COM } 8611935SMark.Shellenbaum@Sun.COM 8711935SMark.Shellenbaum@Sun.COM #define SA_LAYOUTS "LAYOUTS" 8811935SMark.Shellenbaum@Sun.COM #define SA_REGISTRY "REGISTRY" 8911935SMark.Shellenbaum@Sun.COM 9011935SMark.Shellenbaum@Sun.COM /* 9111935SMark.Shellenbaum@Sun.COM * Each unique layout will have their own table 9211935SMark.Shellenbaum@Sun.COM * sa_lot (layout_table) 9311935SMark.Shellenbaum@Sun.COM */ 9411935SMark.Shellenbaum@Sun.COM typedef struct sa_lot { 9511935SMark.Shellenbaum@Sun.COM avl_node_t lot_num_node; 9611935SMark.Shellenbaum@Sun.COM avl_node_t lot_hash_node; 9711935SMark.Shellenbaum@Sun.COM uint64_t lot_num; 9811935SMark.Shellenbaum@Sun.COM uint64_t lot_hash; 9911935SMark.Shellenbaum@Sun.COM sa_attr_type_t *lot_attrs; /* array of attr #'s */ 10011935SMark.Shellenbaum@Sun.COM uint32_t lot_var_sizes; /* how many aren't fixed size */ 10111935SMark.Shellenbaum@Sun.COM uint32_t lot_attr_count; /* total attr count */ 10211935SMark.Shellenbaum@Sun.COM list_t lot_idx_tab; /* should be only a couple of entries */ 10311935SMark.Shellenbaum@Sun.COM int lot_instance; /* used with lot_hash to identify entry */ 10411935SMark.Shellenbaum@Sun.COM } sa_lot_t; 10511935SMark.Shellenbaum@Sun.COM 10611935SMark.Shellenbaum@Sun.COM /* index table of offsets */ 10711935SMark.Shellenbaum@Sun.COM typedef struct sa_idx_tab { 10811935SMark.Shellenbaum@Sun.COM list_node_t sa_next; 10911935SMark.Shellenbaum@Sun.COM sa_lot_t *sa_layout; 11011935SMark.Shellenbaum@Sun.COM uint16_t *sa_variable_lengths; 11111935SMark.Shellenbaum@Sun.COM refcount_t sa_refcount; 11211935SMark.Shellenbaum@Sun.COM uint32_t *sa_idx_tab; /* array of offsets */ 11311935SMark.Shellenbaum@Sun.COM } sa_idx_tab_t; 11411935SMark.Shellenbaum@Sun.COM 11511935SMark.Shellenbaum@Sun.COM /* 11611935SMark.Shellenbaum@Sun.COM * Since the offset/index information into the actual data 11711935SMark.Shellenbaum@Sun.COM * will usually be identical we can share that information with 11811935SMark.Shellenbaum@Sun.COM * all handles that have the exact same offsets. 11911935SMark.Shellenbaum@Sun.COM * 12011935SMark.Shellenbaum@Sun.COM * You would typically only have a large number of different table of 12111935SMark.Shellenbaum@Sun.COM * contents if you had a several variable sized attributes. 12211935SMark.Shellenbaum@Sun.COM * 12311935SMark.Shellenbaum@Sun.COM * Two AVL trees are used to track the attribute layout numbers. 12411935SMark.Shellenbaum@Sun.COM * one is keyed by number and will be consulted when a DMU_OT_SA 12511935SMark.Shellenbaum@Sun.COM * object is first read. The second tree is keyed by the hash signature 12611935SMark.Shellenbaum@Sun.COM * of the attributes and will be consulted when an attribute is added 12711935SMark.Shellenbaum@Sun.COM * to determine if we already have an instance of that layout. Both 12811935SMark.Shellenbaum@Sun.COM * of these tree's are interconnected. The only difference is that 12911935SMark.Shellenbaum@Sun.COM * when an entry is found in the "hash" tree the list of attributes will 13011935SMark.Shellenbaum@Sun.COM * need to be compared against the list of attributes you have in hand. 13111935SMark.Shellenbaum@Sun.COM * The assumption is that typically attributes will just be updated and 13211935SMark.Shellenbaum@Sun.COM * adding a completely new attribute is a very rare operation. 13311935SMark.Shellenbaum@Sun.COM */ 13411935SMark.Shellenbaum@Sun.COM struct sa_os { 13511935SMark.Shellenbaum@Sun.COM kmutex_t sa_lock; 13611935SMark.Shellenbaum@Sun.COM boolean_t sa_need_attr_registration; 13711935SMark.Shellenbaum@Sun.COM boolean_t sa_force_spill; 13811935SMark.Shellenbaum@Sun.COM uint64_t sa_master_obj; 13911935SMark.Shellenbaum@Sun.COM uint64_t sa_reg_attr_obj; 14011935SMark.Shellenbaum@Sun.COM uint64_t sa_layout_attr_obj; 14111935SMark.Shellenbaum@Sun.COM int sa_num_attrs; 14211935SMark.Shellenbaum@Sun.COM sa_attr_table_t *sa_attr_table; /* private attr table */ 14311935SMark.Shellenbaum@Sun.COM sa_update_cb_t *sa_update_cb; 14411935SMark.Shellenbaum@Sun.COM avl_tree_t sa_layout_num_tree; /* keyed by layout number */ 14511935SMark.Shellenbaum@Sun.COM avl_tree_t sa_layout_hash_tree; /* keyed by layout hash value */ 14611935SMark.Shellenbaum@Sun.COM int sa_user_table_sz; 14711935SMark.Shellenbaum@Sun.COM sa_attr_type_t *sa_user_table; /* user name->attr mapping table */ 14811935SMark.Shellenbaum@Sun.COM }; 14911935SMark.Shellenbaum@Sun.COM 15011935SMark.Shellenbaum@Sun.COM /* 15111935SMark.Shellenbaum@Sun.COM * header for all bonus and spill buffers. 15211935SMark.Shellenbaum@Sun.COM * The header has a fixed portion with a variable number 15311935SMark.Shellenbaum@Sun.COM * of "lengths" depending on the number of variable sized 15411935SMark.Shellenbaum@Sun.COM * attribues which are determined by the "layout number" 15511935SMark.Shellenbaum@Sun.COM */ 15611935SMark.Shellenbaum@Sun.COM 15711935SMark.Shellenbaum@Sun.COM #define SA_MAGIC 0x2F505A /* ZFS SA */ 15811935SMark.Shellenbaum@Sun.COM typedef struct sa_hdr_phys { 15911935SMark.Shellenbaum@Sun.COM uint32_t sa_magic; 16011935SMark.Shellenbaum@Sun.COM uint16_t sa_layout_info; /* Encoded with hdrsize and layout number */ 16111935SMark.Shellenbaum@Sun.COM uint16_t sa_lengths[1]; /* optional sizes for variable length attrs */ 16211935SMark.Shellenbaum@Sun.COM /* ... Data follows the lengths. */ 16311935SMark.Shellenbaum@Sun.COM } sa_hdr_phys_t; 16411935SMark.Shellenbaum@Sun.COM 16511935SMark.Shellenbaum@Sun.COM /* 16611935SMark.Shellenbaum@Sun.COM * sa_hdr_phys -> sa_layout_info 16711935SMark.Shellenbaum@Sun.COM * 16811935SMark.Shellenbaum@Sun.COM * 16 10 0 16911935SMark.Shellenbaum@Sun.COM * +--------+-------+ 17011935SMark.Shellenbaum@Sun.COM * | hdrsz |layout | 17111935SMark.Shellenbaum@Sun.COM * +--------+-------+ 17211935SMark.Shellenbaum@Sun.COM * 17311935SMark.Shellenbaum@Sun.COM * Bits 0-10 are the layout number 17411935SMark.Shellenbaum@Sun.COM * Bits 11-16 are the size of the header. 17511935SMark.Shellenbaum@Sun.COM * The hdrsize is the number * 8 17611935SMark.Shellenbaum@Sun.COM * 17711935SMark.Shellenbaum@Sun.COM * For example. 17811935SMark.Shellenbaum@Sun.COM * hdrsz of 1 ==> 8 byte header 17911935SMark.Shellenbaum@Sun.COM * 2 ==> 16 byte header 18011935SMark.Shellenbaum@Sun.COM * 18111935SMark.Shellenbaum@Sun.COM */ 18211935SMark.Shellenbaum@Sun.COM 18311935SMark.Shellenbaum@Sun.COM #define SA_HDR_LAYOUT_NUM(hdr) BF32_GET(hdr->sa_layout_info, 0, 10) 18411935SMark.Shellenbaum@Sun.COM #define SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 16, 3, 0) 18511935SMark.Shellenbaum@Sun.COM #define SA_HDR_LAYOUT_INFO_ENCODE(x, num, size) \ 18611935SMark.Shellenbaum@Sun.COM { \ 18711935SMark.Shellenbaum@Sun.COM BF32_SET_SB(x, 10, 6, 3, 0, size); \ 18811935SMark.Shellenbaum@Sun.COM BF32_SET(x, 0, 10, num); \ 18911935SMark.Shellenbaum@Sun.COM } 19011935SMark.Shellenbaum@Sun.COM 19111935SMark.Shellenbaum@Sun.COM typedef enum sa_buf_type { 19211935SMark.Shellenbaum@Sun.COM SA_BONUS = 1, 19311935SMark.Shellenbaum@Sun.COM SA_SPILL = 2 19411935SMark.Shellenbaum@Sun.COM } sa_buf_type_t; 19511935SMark.Shellenbaum@Sun.COM 19611935SMark.Shellenbaum@Sun.COM typedef enum sa_data_op { 19711935SMark.Shellenbaum@Sun.COM SA_LOOKUP, 19811935SMark.Shellenbaum@Sun.COM SA_UPDATE, 19911935SMark.Shellenbaum@Sun.COM SA_ADD, 20011935SMark.Shellenbaum@Sun.COM SA_REPLACE, 20111935SMark.Shellenbaum@Sun.COM SA_REMOVE 20211935SMark.Shellenbaum@Sun.COM } sa_data_op_t; 20311935SMark.Shellenbaum@Sun.COM 20411935SMark.Shellenbaum@Sun.COM /* 20511935SMark.Shellenbaum@Sun.COM * Opaque handle used for most sa functions 20611935SMark.Shellenbaum@Sun.COM * 20711935SMark.Shellenbaum@Sun.COM * This needs to be kept as small as possible. 20811935SMark.Shellenbaum@Sun.COM */ 20911935SMark.Shellenbaum@Sun.COM 21011935SMark.Shellenbaum@Sun.COM struct sa_handle { 21111935SMark.Shellenbaum@Sun.COM kmutex_t sa_lock; 21211935SMark.Shellenbaum@Sun.COM dmu_buf_t *sa_bonus; 21311935SMark.Shellenbaum@Sun.COM dmu_buf_t *sa_spill; 21411935SMark.Shellenbaum@Sun.COM objset_t *sa_os; 21511935SMark.Shellenbaum@Sun.COM void *sa_userp; 21611935SMark.Shellenbaum@Sun.COM sa_idx_tab_t *sa_bonus_tab; /* idx of bonus */ 21711935SMark.Shellenbaum@Sun.COM sa_idx_tab_t *sa_spill_tab; /* only present if spill activated */ 21811935SMark.Shellenbaum@Sun.COM }; 21911935SMark.Shellenbaum@Sun.COM 22011935SMark.Shellenbaum@Sun.COM #define SA_GET_DB(hdl, type) \ 22111935SMark.Shellenbaum@Sun.COM (dmu_buf_impl_t *)((type == SA_BONUS) ? hdl->sa_bonus : hdl->sa_spill) 22211935SMark.Shellenbaum@Sun.COM 22311935SMark.Shellenbaum@Sun.COM #define SA_GET_HDR(hdl, type) \ 22411935SMark.Shellenbaum@Sun.COM ((sa_hdr_phys_t *)((dmu_buf_impl_t *)(SA_GET_DB(hdl, \ 22511935SMark.Shellenbaum@Sun.COM type))->db.db_data)) 22611935SMark.Shellenbaum@Sun.COM 22711935SMark.Shellenbaum@Sun.COM #define SA_IDX_TAB_GET(hdl, type) \ 22811935SMark.Shellenbaum@Sun.COM (type == SA_BONUS ? hdl->sa_bonus_tab : hdl->sa_spill_tab) 22911935SMark.Shellenbaum@Sun.COM 23011935SMark.Shellenbaum@Sun.COM #define IS_SA_BONUSTYPE(a) \ 23111935SMark.Shellenbaum@Sun.COM ((a == DMU_OT_SA) ? B_TRUE : B_FALSE) 23211935SMark.Shellenbaum@Sun.COM 23311935SMark.Shellenbaum@Sun.COM #define SA_BONUSTYPE_FROM_DB(db) \ 234*12684STom.Erickson@Sun.COM (dmu_get_bonustype((dmu_buf_t *)db)) 23511935SMark.Shellenbaum@Sun.COM 23611935SMark.Shellenbaum@Sun.COM #define SA_BLKPTR_SPACE (DN_MAX_BONUSLEN - sizeof (blkptr_t)) 23711935SMark.Shellenbaum@Sun.COM 23811935SMark.Shellenbaum@Sun.COM #define SA_LAYOUT_NUM(x, type) \ 23911935SMark.Shellenbaum@Sun.COM ((!IS_SA_BONUSTYPE(type) ? 0 : (((IS_SA_BONUSTYPE(type)) && \ 24011935SMark.Shellenbaum@Sun.COM ((SA_HDR_LAYOUT_NUM(x)) == 0)) ? 1 : SA_HDR_LAYOUT_NUM(x)))) 24111935SMark.Shellenbaum@Sun.COM 24211935SMark.Shellenbaum@Sun.COM 24311935SMark.Shellenbaum@Sun.COM #define SA_REGISTERED_LEN(sa, attr) sa->sa_attr_table[attr].sa_length 24411935SMark.Shellenbaum@Sun.COM 24511935SMark.Shellenbaum@Sun.COM #define SA_ATTR_LEN(sa, idx, attr, hdr) ((SA_REGISTERED_LEN(sa, attr) == 0) ?\ 24611935SMark.Shellenbaum@Sun.COM hdr->sa_lengths[TOC_LEN_IDX(idx->sa_idx_tab[attr])] : \ 24711935SMark.Shellenbaum@Sun.COM SA_REGISTERED_LEN(sa, attr)) 24811935SMark.Shellenbaum@Sun.COM 24911935SMark.Shellenbaum@Sun.COM #define SA_SET_HDR(hdr, num, size) \ 25011935SMark.Shellenbaum@Sun.COM { \ 25111935SMark.Shellenbaum@Sun.COM hdr->sa_magic = SA_MAGIC; \ 25211935SMark.Shellenbaum@Sun.COM SA_HDR_LAYOUT_INFO_ENCODE(hdr->sa_layout_info, num, size); \ 25311935SMark.Shellenbaum@Sun.COM } 25411935SMark.Shellenbaum@Sun.COM 25511935SMark.Shellenbaum@Sun.COM #define SA_ATTR_INFO(sa, idx, hdr, attr, bulk, type, hdl) \ 25611935SMark.Shellenbaum@Sun.COM { \ 25711935SMark.Shellenbaum@Sun.COM bulk.sa_size = SA_ATTR_LEN(sa, idx, attr, hdr); \ 25811935SMark.Shellenbaum@Sun.COM bulk.sa_buftype = type; \ 25911935SMark.Shellenbaum@Sun.COM bulk.sa_addr = \ 26011935SMark.Shellenbaum@Sun.COM (void *)((uintptr_t)TOC_OFF(idx->sa_idx_tab[attr]) + \ 26111935SMark.Shellenbaum@Sun.COM (uintptr_t)hdr); \ 26211935SMark.Shellenbaum@Sun.COM } 26311935SMark.Shellenbaum@Sun.COM 26411935SMark.Shellenbaum@Sun.COM #define SA_HDR_SIZE_MATCH_LAYOUT(hdr, tb) \ 26511935SMark.Shellenbaum@Sun.COM (SA_HDR_SIZE(hdr) == (sizeof (sa_hdr_phys_t) + \ 26611935SMark.Shellenbaum@Sun.COM (tb->lot_var_sizes > 1 ? P2ROUNDUP((tb->lot_var_sizes - 1) * \ 26711935SMark.Shellenbaum@Sun.COM sizeof (uint16_t), 8) : 0))) 26811935SMark.Shellenbaum@Sun.COM 26911935SMark.Shellenbaum@Sun.COM int sa_add_impl(sa_handle_t *, sa_attr_type_t, 27011935SMark.Shellenbaum@Sun.COM uint32_t, sa_data_locator_t, void *, dmu_tx_t *); 27111935SMark.Shellenbaum@Sun.COM 27211935SMark.Shellenbaum@Sun.COM void sa_register_update_callback_locked(objset_t *, sa_update_cb_t *); 27311935SMark.Shellenbaum@Sun.COM int sa_size_locked(sa_handle_t *, sa_attr_type_t, int *); 27411935SMark.Shellenbaum@Sun.COM 27511935SMark.Shellenbaum@Sun.COM void sa_default_locator(void **, uint32_t *, uint32_t, boolean_t, void *); 27611935SMark.Shellenbaum@Sun.COM int sa_attr_size(sa_os_t *, sa_idx_tab_t *, sa_attr_type_t, 27711935SMark.Shellenbaum@Sun.COM uint16_t *, sa_hdr_phys_t *); 27811935SMark.Shellenbaum@Sun.COM 27911935SMark.Shellenbaum@Sun.COM #ifdef __cplusplus 28011935SMark.Shellenbaum@Sun.COM extern "C" { 28111935SMark.Shellenbaum@Sun.COM #endif 28211935SMark.Shellenbaum@Sun.COM 28311935SMark.Shellenbaum@Sun.COM #ifdef __cplusplus 28411935SMark.Shellenbaum@Sun.COM } 28511935SMark.Shellenbaum@Sun.COM #endif 28611935SMark.Shellenbaum@Sun.COM 28711935SMark.Shellenbaum@Sun.COM #endif /* _SYS_SA_IMPL_H */ 288