xref: /illumos-gate/usr/src/uts/common/fs/zfs/sys/sa_impl.h (revision 54811da5ac6b517992fdc173df5d605e4e61fdc0)
10a586ceaSMark Shellenbaum /*
20a586ceaSMark Shellenbaum  * CDDL HEADER START
30a586ceaSMark Shellenbaum  *
40a586ceaSMark Shellenbaum  * The contents of this file are subject to the terms of the
50a586ceaSMark Shellenbaum  * Common Development and Distribution License (the "License").
60a586ceaSMark Shellenbaum  * You may not use this file except in compliance with the License.
70a586ceaSMark Shellenbaum  *
80a586ceaSMark Shellenbaum  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90a586ceaSMark Shellenbaum  * or http://www.opensolaris.org/os/licensing.
100a586ceaSMark Shellenbaum  * See the License for the specific language governing permissions
110a586ceaSMark Shellenbaum  * and limitations under the License.
120a586ceaSMark Shellenbaum  *
130a586ceaSMark Shellenbaum  * When distributing Covered Code, include this CDDL HEADER in each
140a586ceaSMark Shellenbaum  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150a586ceaSMark Shellenbaum  * If applicable, add the following below this CDDL HEADER, with the
160a586ceaSMark Shellenbaum  * fields enclosed by brackets "[]" replaced with your own identifying
170a586ceaSMark Shellenbaum  * information: Portions Copyright [yyyy] [name of copyright owner]
180a586ceaSMark Shellenbaum  *
190a586ceaSMark Shellenbaum  * CDDL HEADER END
200a586ceaSMark Shellenbaum  */
210a586ceaSMark Shellenbaum /*
22744947dcSTom Erickson  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2369962b56SMatthew Ahrens  * Copyright (c) 2013 by Delphix. All rights reserved.
24bc9014e6SJustin Gibbs  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
250a586ceaSMark Shellenbaum  */
260a586ceaSMark Shellenbaum 
270a586ceaSMark Shellenbaum #ifndef	_SYS_SA_IMPL_H
280a586ceaSMark Shellenbaum #define	_SYS_SA_IMPL_H
290a586ceaSMark Shellenbaum 
300a586ceaSMark Shellenbaum #include <sys/dmu.h>
310a586ceaSMark Shellenbaum #include <sys/refcount.h>
320a586ceaSMark Shellenbaum #include <sys/list.h>
330a586ceaSMark Shellenbaum 
340a586ceaSMark Shellenbaum /*
350a586ceaSMark Shellenbaum  * Array of known attributes and their
360a586ceaSMark Shellenbaum  * various characteristics.
370a586ceaSMark Shellenbaum  */
380a586ceaSMark Shellenbaum typedef struct sa_attr_table {
390a586ceaSMark Shellenbaum 	sa_attr_type_t	sa_attr;
400a586ceaSMark Shellenbaum 	uint8_t sa_registered;
410a586ceaSMark Shellenbaum 	uint16_t sa_length;
420a586ceaSMark Shellenbaum 	sa_bswap_type_t sa_byteswap;
430a586ceaSMark Shellenbaum 	char *sa_name;
440a586ceaSMark Shellenbaum } sa_attr_table_t;
450a586ceaSMark Shellenbaum 
460a586ceaSMark Shellenbaum /*
470a586ceaSMark Shellenbaum  * Zap attribute format for attribute registration
480a586ceaSMark Shellenbaum  *
490a586ceaSMark Shellenbaum  * 64      56      48      40      32      24      16      8       0
500a586ceaSMark Shellenbaum  * +-------+-------+-------+-------+-------+-------+-------+-------+
510a586ceaSMark Shellenbaum  * |        unused         |      len      | bswap |   attr num    |
520a586ceaSMark Shellenbaum  * +-------+-------+-------+-------+-------+-------+-------+-------+
530a586ceaSMark Shellenbaum  *
540a586ceaSMark Shellenbaum  * Zap attribute format for layout information.
550a586ceaSMark Shellenbaum  *
560a586ceaSMark Shellenbaum  * layout information is stored as an array of attribute numbers
570a586ceaSMark Shellenbaum  * The name of the attribute is the layout number (0, 1, 2, ...)
580a586ceaSMark Shellenbaum  *
590a586ceaSMark Shellenbaum  * 16       0
600a586ceaSMark Shellenbaum  * +---- ---+
610a586ceaSMark Shellenbaum  * | attr # |
620a586ceaSMark Shellenbaum  * +--------+
630a586ceaSMark Shellenbaum  * | attr # |
640a586ceaSMark Shellenbaum  * +--- ----+
650a586ceaSMark Shellenbaum  *  ......
660a586ceaSMark Shellenbaum  *
670a586ceaSMark Shellenbaum  */
680a586ceaSMark Shellenbaum 
690a586ceaSMark Shellenbaum #define	ATTR_BSWAP(x)	BF32_GET(x, 16, 8)
700a586ceaSMark Shellenbaum #define	ATTR_LENGTH(x)	BF32_GET(x, 24, 16)
710a586ceaSMark Shellenbaum #define	ATTR_NUM(x)	BF32_GET(x, 0, 16)
720a586ceaSMark Shellenbaum #define	ATTR_ENCODE(x, attr, length, bswap) \
730a586ceaSMark Shellenbaum { \
740a586ceaSMark Shellenbaum 	BF64_SET(x, 24, 16, length); \
750a586ceaSMark Shellenbaum 	BF64_SET(x, 16, 8, bswap); \
760a586ceaSMark Shellenbaum 	BF64_SET(x, 0, 16, attr); \
770a586ceaSMark Shellenbaum }
780a586ceaSMark Shellenbaum 
790a586ceaSMark Shellenbaum #define	TOC_OFF(x)		BF32_GET(x, 0, 23)
800a586ceaSMark Shellenbaum #define	TOC_ATTR_PRESENT(x)	BF32_GET(x, 31, 1)
810a586ceaSMark Shellenbaum #define	TOC_LEN_IDX(x)		BF32_GET(x, 24, 4)
820a586ceaSMark Shellenbaum #define	TOC_ATTR_ENCODE(x, len_idx, offset) \
830a586ceaSMark Shellenbaum { \
840a586ceaSMark Shellenbaum 	BF32_SET(x, 31, 1, 1); \
850a586ceaSMark Shellenbaum 	BF32_SET(x, 24, 7, len_idx); \
860a586ceaSMark Shellenbaum 	BF32_SET(x, 0, 24, offset); \
870a586ceaSMark Shellenbaum }
880a586ceaSMark Shellenbaum 
890a586ceaSMark Shellenbaum #define	SA_LAYOUTS	"LAYOUTS"
900a586ceaSMark Shellenbaum #define	SA_REGISTRY	"REGISTRY"
910a586ceaSMark Shellenbaum 
920a586ceaSMark Shellenbaum /*
930a586ceaSMark Shellenbaum  * Each unique layout will have their own table
940a586ceaSMark Shellenbaum  * sa_lot (layout_table)
950a586ceaSMark Shellenbaum  */
960a586ceaSMark Shellenbaum typedef struct sa_lot {
970a586ceaSMark Shellenbaum 	avl_node_t lot_num_node;
980a586ceaSMark Shellenbaum 	avl_node_t lot_hash_node;
990a586ceaSMark Shellenbaum 	uint64_t lot_num;
1000a586ceaSMark Shellenbaum 	uint64_t lot_hash;
1010a586ceaSMark Shellenbaum 	sa_attr_type_t *lot_attrs;	/* array of attr #'s */
1020a586ceaSMark Shellenbaum 	uint32_t lot_var_sizes;	/* how many aren't fixed size */
1030a586ceaSMark Shellenbaum 	uint32_t lot_attr_count;	/* total attr count */
104*54811da5SToomas Soome 	list_t	lot_idx_tab;	/* should be only a couple of entries */
1050a586ceaSMark Shellenbaum 	int	lot_instance;	/* used with lot_hash to identify entry */
1060a586ceaSMark Shellenbaum } sa_lot_t;
1070a586ceaSMark Shellenbaum 
1080a586ceaSMark Shellenbaum /* index table of offsets */
1090a586ceaSMark Shellenbaum typedef struct sa_idx_tab {
1100a586ceaSMark Shellenbaum 	list_node_t	sa_next;
1110a586ceaSMark Shellenbaum 	sa_lot_t	*sa_layout;
1120a586ceaSMark Shellenbaum 	uint16_t	*sa_variable_lengths;
1130a586ceaSMark Shellenbaum 	refcount_t	sa_refcount;
1140a586ceaSMark Shellenbaum 	uint32_t	*sa_idx_tab;	/* array of offsets */
1150a586ceaSMark Shellenbaum } sa_idx_tab_t;
1160a586ceaSMark Shellenbaum 
1170a586ceaSMark Shellenbaum /*
1180a586ceaSMark Shellenbaum  * Since the offset/index information into the actual data
1190a586ceaSMark Shellenbaum  * will usually be identical we can share that information with
1200a586ceaSMark Shellenbaum  * all handles that have the exact same offsets.
1210a586ceaSMark Shellenbaum  *
1220a586ceaSMark Shellenbaum  * You would typically only have a large number of different table of
1230a586ceaSMark Shellenbaum  * contents if you had a several variable sized attributes.
1240a586ceaSMark Shellenbaum  *
1250a586ceaSMark Shellenbaum  * Two AVL trees are used to track the attribute layout numbers.
1260a586ceaSMark Shellenbaum  * one is keyed by number and will be consulted when a DMU_OT_SA
1270a586ceaSMark Shellenbaum  * object is first read.  The second tree is keyed by the hash signature
1280a586ceaSMark Shellenbaum  * of the attributes and will be consulted when an attribute is added
1290a586ceaSMark Shellenbaum  * to determine if we already have an instance of that layout.  Both
1300a586ceaSMark Shellenbaum  * of these tree's are interconnected.  The only difference is that
1310a586ceaSMark Shellenbaum  * when an entry is found in the "hash" tree the list of attributes will
1320a586ceaSMark Shellenbaum  * need to be compared against the list of attributes you have in hand.
1330a586ceaSMark Shellenbaum  * The assumption is that typically attributes will just be updated and
1340a586ceaSMark Shellenbaum  * adding a completely new attribute is a very rare operation.
1350a586ceaSMark Shellenbaum  */
1360a586ceaSMark Shellenbaum struct sa_os {
137*54811da5SToomas Soome 	kmutex_t	sa_lock;
1380a586ceaSMark Shellenbaum 	boolean_t	sa_need_attr_registration;
1390a586ceaSMark Shellenbaum 	boolean_t	sa_force_spill;
1400a586ceaSMark Shellenbaum 	uint64_t	sa_master_obj;
1410a586ceaSMark Shellenbaum 	uint64_t	sa_reg_attr_obj;
1420a586ceaSMark Shellenbaum 	uint64_t	sa_layout_attr_obj;
1430a586ceaSMark Shellenbaum 	int		sa_num_attrs;
1440a586ceaSMark Shellenbaum 	sa_attr_table_t *sa_attr_table;	 /* private attr table */
1450a586ceaSMark Shellenbaum 	sa_update_cb_t	*sa_update_cb;
1460a586ceaSMark Shellenbaum 	avl_tree_t	sa_layout_num_tree;  /* keyed by layout number */
1470a586ceaSMark Shellenbaum 	avl_tree_t	sa_layout_hash_tree; /* keyed by layout hash value */
1480a586ceaSMark Shellenbaum 	int		sa_user_table_sz;
1490a586ceaSMark Shellenbaum 	sa_attr_type_t	*sa_user_table; /* user name->attr mapping table */
1500a586ceaSMark Shellenbaum };
1510a586ceaSMark Shellenbaum 
1520a586ceaSMark Shellenbaum /*
1530a586ceaSMark Shellenbaum  * header for all bonus and spill buffers.
154f7170741SWill Andrews  *
1550a586ceaSMark Shellenbaum  * The header has a fixed portion with a variable number
1560a586ceaSMark Shellenbaum  * of "lengths" depending on the number of variable sized
15769962b56SMatthew Ahrens  * attributes which are determined by the "layout number"
1580a586ceaSMark Shellenbaum  */
1590a586ceaSMark Shellenbaum 
1600a586ceaSMark Shellenbaum #define	SA_MAGIC	0x2F505A  /* ZFS SA */
1610a586ceaSMark Shellenbaum typedef struct sa_hdr_phys {
1620a586ceaSMark Shellenbaum 	uint32_t sa_magic;
16369962b56SMatthew Ahrens 	/* BEGIN CSTYLED */
164f7170741SWill Andrews 	/*
165f7170741SWill Andrews 	 * Encoded with hdrsize and layout number as follows:
166f7170741SWill Andrews 	 * 16      10       0
167f7170741SWill Andrews 	 * +--------+-------+
168f7170741SWill Andrews 	 * | hdrsz  |layout |
169f7170741SWill Andrews 	 * +--------+-------+
170f7170741SWill Andrews 	 *
171f7170741SWill Andrews 	 * Bits 0-10 are the layout number
172f7170741SWill Andrews 	 * Bits 11-16 are the size of the header.
173f7170741SWill Andrews 	 * The hdrsize is the number * 8
174f7170741SWill Andrews 	 *
175f7170741SWill Andrews 	 * For example.
176f7170741SWill Andrews 	 * hdrsz of 1 ==> 8 byte header
177f7170741SWill Andrews 	 *          2 ==> 16 byte header
178f7170741SWill Andrews 	 *
179f7170741SWill Andrews 	 */
18069962b56SMatthew Ahrens 	/* END CSTYLED */
181f7170741SWill Andrews 	uint16_t sa_layout_info;
1820a586ceaSMark Shellenbaum 	uint16_t sa_lengths[1];	/* optional sizes for variable length attrs */
1830a586ceaSMark Shellenbaum 	/* ... Data follows the lengths.  */
1840a586ceaSMark Shellenbaum } sa_hdr_phys_t;
1850a586ceaSMark Shellenbaum 
1860a586ceaSMark Shellenbaum #define	SA_HDR_LAYOUT_NUM(hdr) BF32_GET(hdr->sa_layout_info, 0, 10)
187e828a46dSMatthew Ahrens #define	SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 6, 3, 0)
1880a586ceaSMark Shellenbaum #define	SA_HDR_LAYOUT_INFO_ENCODE(x, num, size) \
1890a586ceaSMark Shellenbaum { \
1900a586ceaSMark Shellenbaum 	BF32_SET_SB(x, 10, 6, 3, 0, size); \
1910a586ceaSMark Shellenbaum 	BF32_SET(x, 0, 10, num); \
1920a586ceaSMark Shellenbaum }
1930a586ceaSMark Shellenbaum 
1940a586ceaSMark Shellenbaum typedef enum sa_buf_type {
1950a586ceaSMark Shellenbaum 	SA_BONUS = 1,
1960a586ceaSMark Shellenbaum 	SA_SPILL = 2
1970a586ceaSMark Shellenbaum } sa_buf_type_t;
1980a586ceaSMark Shellenbaum 
1990a586ceaSMark Shellenbaum typedef enum sa_data_op {
2000a586ceaSMark Shellenbaum 	SA_LOOKUP,
2010a586ceaSMark Shellenbaum 	SA_UPDATE,
2020a586ceaSMark Shellenbaum 	SA_ADD,
2030a586ceaSMark Shellenbaum 	SA_REPLACE,
2040a586ceaSMark Shellenbaum 	SA_REMOVE
2050a586ceaSMark Shellenbaum } sa_data_op_t;
2060a586ceaSMark Shellenbaum 
2070a586ceaSMark Shellenbaum /*
2080a586ceaSMark Shellenbaum  * Opaque handle used for most sa functions
2090a586ceaSMark Shellenbaum  *
2100a586ceaSMark Shellenbaum  * This needs to be kept as small as possible.
2110a586ceaSMark Shellenbaum  */
2120a586ceaSMark Shellenbaum 
2130a586ceaSMark Shellenbaum struct sa_handle {
214bc9014e6SJustin Gibbs 	dmu_buf_user_t	sa_dbu;
2150a586ceaSMark Shellenbaum 	kmutex_t	sa_lock;
2160a586ceaSMark Shellenbaum 	dmu_buf_t	*sa_bonus;
2170a586ceaSMark Shellenbaum 	dmu_buf_t	*sa_spill;
2180a586ceaSMark Shellenbaum 	objset_t	*sa_os;
219bc9014e6SJustin Gibbs 	void		*sa_userp;
2200a586ceaSMark Shellenbaum 	sa_idx_tab_t	*sa_bonus_tab;	 /* idx of bonus */
2210a586ceaSMark Shellenbaum 	sa_idx_tab_t	*sa_spill_tab; /* only present if spill activated */
2220a586ceaSMark Shellenbaum };
2230a586ceaSMark Shellenbaum 
2240a586ceaSMark Shellenbaum #define	SA_GET_DB(hdl, type)	\
2250a586ceaSMark Shellenbaum 	(dmu_buf_impl_t *)((type == SA_BONUS) ? hdl->sa_bonus : hdl->sa_spill)
2260a586ceaSMark Shellenbaum 
2270a586ceaSMark Shellenbaum #define	SA_GET_HDR(hdl, type) \
2280a586ceaSMark Shellenbaum 	((sa_hdr_phys_t *)((dmu_buf_impl_t *)(SA_GET_DB(hdl, \
2290a586ceaSMark Shellenbaum 	type))->db.db_data))
2300a586ceaSMark Shellenbaum 
2310a586ceaSMark Shellenbaum #define	SA_IDX_TAB_GET(hdl, type) \
2320a586ceaSMark Shellenbaum 	(type == SA_BONUS ? hdl->sa_bonus_tab : hdl->sa_spill_tab)
2330a586ceaSMark Shellenbaum 
2340a586ceaSMark Shellenbaum #define	IS_SA_BONUSTYPE(a)	\
2350a586ceaSMark Shellenbaum 	((a == DMU_OT_SA) ? B_TRUE : B_FALSE)
2360a586ceaSMark Shellenbaum 
2370a586ceaSMark Shellenbaum #define	SA_BONUSTYPE_FROM_DB(db) \
238744947dcSTom Erickson 	(dmu_get_bonustype((dmu_buf_t *)db))
2390a586ceaSMark Shellenbaum 
240*54811da5SToomas Soome #define	SA_BLKPTR_SPACE	(DN_OLD_MAX_BONUSLEN - sizeof (blkptr_t))
2410a586ceaSMark Shellenbaum 
2420a586ceaSMark Shellenbaum #define	SA_LAYOUT_NUM(x, type) \
2430a586ceaSMark Shellenbaum 	((!IS_SA_BONUSTYPE(type) ? 0 : (((IS_SA_BONUSTYPE(type)) && \
2440a586ceaSMark Shellenbaum 	((SA_HDR_LAYOUT_NUM(x)) == 0)) ? 1 : SA_HDR_LAYOUT_NUM(x))))
2450a586ceaSMark Shellenbaum 
2460a586ceaSMark Shellenbaum 
2470a586ceaSMark Shellenbaum #define	SA_REGISTERED_LEN(sa, attr) sa->sa_attr_table[attr].sa_length
2480a586ceaSMark Shellenbaum 
2490a586ceaSMark Shellenbaum #define	SA_ATTR_LEN(sa, idx, attr, hdr) ((SA_REGISTERED_LEN(sa, attr) == 0) ?\
2500a586ceaSMark Shellenbaum 	hdr->sa_lengths[TOC_LEN_IDX(idx->sa_idx_tab[attr])] : \
2510a586ceaSMark Shellenbaum 	SA_REGISTERED_LEN(sa, attr))
2520a586ceaSMark Shellenbaum 
2530a586ceaSMark Shellenbaum #define	SA_SET_HDR(hdr, num, size) \
2540a586ceaSMark Shellenbaum 	{ \
2550a586ceaSMark Shellenbaum 		hdr->sa_magic = SA_MAGIC; \
2560a586ceaSMark Shellenbaum 		SA_HDR_LAYOUT_INFO_ENCODE(hdr->sa_layout_info, num, size); \
2570a586ceaSMark Shellenbaum 	}
2580a586ceaSMark Shellenbaum 
2590a586ceaSMark Shellenbaum #define	SA_ATTR_INFO(sa, idx, hdr, attr, bulk, type, hdl) \
2600a586ceaSMark Shellenbaum 	{ \
2610a586ceaSMark Shellenbaum 		bulk.sa_size = SA_ATTR_LEN(sa, idx, attr, hdr); \
2620a586ceaSMark Shellenbaum 		bulk.sa_buftype = type; \
2630a586ceaSMark Shellenbaum 		bulk.sa_addr = \
2640a586ceaSMark Shellenbaum 		    (void *)((uintptr_t)TOC_OFF(idx->sa_idx_tab[attr]) + \
2650a586ceaSMark Shellenbaum 		    (uintptr_t)hdr); \
2660a586ceaSMark Shellenbaum }
2670a586ceaSMark Shellenbaum 
2680a586ceaSMark Shellenbaum #define	SA_HDR_SIZE_MATCH_LAYOUT(hdr, tb) \
2690a586ceaSMark Shellenbaum 	(SA_HDR_SIZE(hdr) == (sizeof (sa_hdr_phys_t) + \
2700a586ceaSMark Shellenbaum 	(tb->lot_var_sizes > 1 ? P2ROUNDUP((tb->lot_var_sizes - 1) * \
2710a586ceaSMark Shellenbaum 	sizeof (uint16_t), 8) : 0)))
2720a586ceaSMark Shellenbaum 
2730a586ceaSMark Shellenbaum int sa_add_impl(sa_handle_t *, sa_attr_type_t,
2740a586ceaSMark Shellenbaum     uint32_t, sa_data_locator_t, void *, dmu_tx_t *);
2750a586ceaSMark Shellenbaum 
2760a586ceaSMark Shellenbaum void sa_register_update_callback_locked(objset_t *, sa_update_cb_t *);
2770a586ceaSMark Shellenbaum int sa_size_locked(sa_handle_t *, sa_attr_type_t, int *);
2780a586ceaSMark Shellenbaum 
2790a586ceaSMark Shellenbaum void sa_default_locator(void **, uint32_t *, uint32_t, boolean_t, void *);
2800a586ceaSMark Shellenbaum int sa_attr_size(sa_os_t *, sa_idx_tab_t *, sa_attr_type_t,
2810a586ceaSMark Shellenbaum     uint16_t *, sa_hdr_phys_t *);
2820a586ceaSMark Shellenbaum 
2830a586ceaSMark Shellenbaum #ifdef	__cplusplus
2840a586ceaSMark Shellenbaum extern "C" {
2850a586ceaSMark Shellenbaum #endif
2860a586ceaSMark Shellenbaum 
2870a586ceaSMark Shellenbaum #ifdef	__cplusplus
2880a586ceaSMark Shellenbaum }
2890a586ceaSMark Shellenbaum #endif
2900a586ceaSMark Shellenbaum 
2910a586ceaSMark Shellenbaum #endif	/* _SYS_SA_IMPL_H */
292