]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * CDDL HEADER START | |
3 | * | |
4 | * The contents of this file are subject to the terms of the | |
5 | * Common Development and Distribution License (the "License"). | |
6 | * You may not use this file except in compliance with the License. | |
7 | * | |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 | * or http://www.opensolaris.org/os/licensing. | |
10 | * See the License for the specific language governing permissions | |
11 | * and limitations under the License. | |
12 | * | |
13 | * When distributing Covered Code, include this CDDL HEADER in each | |
14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 | * If applicable, add the following below this CDDL HEADER, with the | |
16 | * fields enclosed by brackets "[]" replaced with your own identifying | |
17 | * information: Portions Copyright [yyyy] [name of copyright owner] | |
18 | * | |
19 | * CDDL HEADER END | |
20 | */ | |
21 | /* | |
22 | * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. | |
23 | * Copyright (c) 2013 by Delphix. All rights reserved. | |
24 | * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. | |
25 | */ | |
26 | ||
27 | #ifndef _SYS_SA_IMPL_H | |
28 | #define _SYS_SA_IMPL_H | |
29 | ||
30 | #include <sys/dmu.h> | |
31 | #include <sys/refcount.h> | |
32 | #include <sys/list.h> | |
33 | ||
34 | /* | |
35 | * Array of known attributes and their | |
36 | * various characteristics. | |
37 | */ | |
38 | typedef struct sa_attr_table { | |
39 | sa_attr_type_t sa_attr; | |
40 | uint8_t sa_registered; | |
41 | uint16_t sa_length; | |
42 | sa_bswap_type_t sa_byteswap; | |
43 | char *sa_name; | |
44 | } sa_attr_table_t; | |
45 | ||
46 | /* | |
47 | * Zap attribute format for attribute registration | |
48 | * | |
49 | * 64 56 48 40 32 24 16 8 0 | |
50 | * +-------+-------+-------+-------+-------+-------+-------+-------+ | |
51 | * | unused | len | bswap | attr num | | |
52 | * +-------+-------+-------+-------+-------+-------+-------+-------+ | |
53 | * | |
54 | * Zap attribute format for layout information. | |
55 | * | |
56 | * layout information is stored as an array of attribute numbers | |
57 | * The name of the attribute is the layout number (0, 1, 2, ...) | |
58 | * | |
59 | * 16 0 | |
60 | * +---- ---+ | |
61 | * | attr # | | |
62 | * +--------+ | |
63 | * | attr # | | |
64 | * +--- ----+ | |
65 | * ...... | |
66 | * | |
67 | */ | |
68 | ||
69 | #define ATTR_BSWAP(x) BF32_GET(x, 16, 8) | |
70 | #define ATTR_LENGTH(x) BF32_GET(x, 24, 16) | |
71 | #define ATTR_NUM(x) BF32_GET(x, 0, 16) | |
72 | #define ATTR_ENCODE(x, attr, length, bswap) \ | |
73 | { \ | |
74 | BF64_SET(x, 24, 16, length); \ | |
75 | BF64_SET(x, 16, 8, bswap); \ | |
76 | BF64_SET(x, 0, 16, attr); \ | |
77 | } | |
78 | ||
79 | #define TOC_OFF(x) BF32_GET(x, 0, 23) | |
80 | #define TOC_ATTR_PRESENT(x) BF32_GET(x, 31, 1) | |
81 | #define TOC_LEN_IDX(x) BF32_GET(x, 24, 4) | |
82 | #define TOC_ATTR_ENCODE(x, len_idx, offset) \ | |
83 | { \ | |
84 | BF32_SET(x, 31, 1, 1); \ | |
85 | BF32_SET(x, 24, 7, len_idx); \ | |
86 | BF32_SET(x, 0, 24, offset); \ | |
87 | } | |
88 | ||
89 | #define SA_LAYOUTS "LAYOUTS" | |
90 | #define SA_REGISTRY "REGISTRY" | |
91 | ||
92 | /* | |
93 | * Each unique layout will have their own table | |
94 | * sa_lot (layout_table) | |
95 | */ | |
96 | typedef struct sa_lot { | |
97 | avl_node_t lot_num_node; | |
98 | avl_node_t lot_hash_node; | |
99 | uint64_t lot_num; | |
100 | uint64_t lot_hash; | |
101 | sa_attr_type_t *lot_attrs; /* array of attr #'s */ | |
102 | uint32_t lot_var_sizes; /* how many aren't fixed size */ | |
103 | uint32_t lot_attr_count; /* total attr count */ | |
104 | list_t lot_idx_tab; /* should be only a couple of entries */ | |
105 | int lot_instance; /* used with lot_hash to identify entry */ | |
106 | } sa_lot_t; | |
107 | ||
108 | /* index table of offsets */ | |
109 | typedef struct sa_idx_tab { | |
110 | list_node_t sa_next; | |
111 | sa_lot_t *sa_layout; | |
112 | uint16_t *sa_variable_lengths; | |
113 | zfs_refcount_t sa_refcount; | |
114 | uint32_t *sa_idx_tab; /* array of offsets */ | |
115 | } sa_idx_tab_t; | |
116 | ||
117 | /* | |
118 | * Since the offset/index information into the actual data | |
119 | * will usually be identical we can share that information with | |
120 | * all handles that have the exact same offsets. | |
121 | * | |
122 | * You would typically only have a large number of different table of | |
123 | * contents if you had a several variable sized attributes. | |
124 | * | |
125 | * Two AVL trees are used to track the attribute layout numbers. | |
126 | * one is keyed by number and will be consulted when a DMU_OT_SA | |
127 | * object is first read. The second tree is keyed by the hash signature | |
128 | * of the attributes and will be consulted when an attribute is added | |
129 | * to determine if we already have an instance of that layout. Both | |
130 | * of these tree's are interconnected. The only difference is that | |
131 | * when an entry is found in the "hash" tree the list of attributes will | |
132 | * need to be compared against the list of attributes you have in hand. | |
133 | * The assumption is that typically attributes will just be updated and | |
134 | * adding a completely new attribute is a very rare operation. | |
135 | */ | |
136 | struct sa_os { | |
137 | kmutex_t sa_lock; | |
138 | boolean_t sa_need_attr_registration; | |
139 | boolean_t sa_force_spill; | |
140 | uint64_t sa_master_obj; | |
141 | uint64_t sa_reg_attr_obj; | |
142 | uint64_t sa_layout_attr_obj; | |
143 | int sa_num_attrs; | |
144 | sa_attr_table_t *sa_attr_table; /* private attr table */ | |
145 | sa_update_cb_t *sa_update_cb; | |
146 | avl_tree_t sa_layout_num_tree; /* keyed by layout number */ | |
147 | avl_tree_t sa_layout_hash_tree; /* keyed by layout hash value */ | |
148 | int sa_user_table_sz; | |
149 | sa_attr_type_t *sa_user_table; /* user name->attr mapping table */ | |
150 | }; | |
151 | ||
152 | /* | |
153 | * header for all bonus and spill buffers. | |
154 | * | |
155 | * The header has a fixed portion with a variable number | |
156 | * of "lengths" depending on the number of variable sized | |
157 | * attributes which are determined by the "layout number" | |
158 | */ | |
159 | ||
160 | #define SA_MAGIC 0x2F505A /* ZFS SA */ | |
161 | typedef struct sa_hdr_phys { | |
162 | uint32_t sa_magic; | |
163 | /* | |
164 | * Encoded with hdrsize and layout number as follows: | |
165 | * 16 10 0 | |
166 | * +--------+-------+ | |
167 | * | hdrsz |layout | | |
168 | * +--------+-------+ | |
169 | * | |
170 | * Bits 0-10 are the layout number | |
171 | * Bits 11-16 are the size of the header. | |
172 | * The hdrsize is the number * 8 | |
173 | * | |
174 | * For example. | |
175 | * hdrsz of 1 ==> 8 byte header | |
176 | * 2 ==> 16 byte header | |
177 | * | |
178 | */ | |
179 | uint16_t sa_layout_info; | |
180 | uint16_t sa_lengths[1]; /* optional sizes for variable length attrs */ | |
181 | /* ... Data follows the lengths. */ | |
182 | } sa_hdr_phys_t; | |
183 | ||
184 | #define SA_HDR_LAYOUT_NUM(hdr) BF32_GET(hdr->sa_layout_info, 0, 10) | |
185 | #define SA_HDR_SIZE(hdr) BF32_GET_SB(hdr->sa_layout_info, 10, 6, 3, 0) | |
186 | #define SA_HDR_LAYOUT_INFO_ENCODE(x, num, size) \ | |
187 | { \ | |
188 | BF32_SET_SB(x, 10, 6, 3, 0, size); \ | |
189 | BF32_SET(x, 0, 10, num); \ | |
190 | } | |
191 | ||
192 | typedef enum sa_buf_type { | |
193 | SA_BONUS = 1, | |
194 | SA_SPILL = 2 | |
195 | } sa_buf_type_t; | |
196 | ||
197 | typedef enum sa_data_op { | |
198 | SA_LOOKUP, | |
199 | SA_UPDATE, | |
200 | SA_ADD, | |
201 | SA_REPLACE, | |
202 | SA_REMOVE | |
203 | } sa_data_op_t; | |
204 | ||
205 | /* | |
206 | * Opaque handle used for most sa functions | |
207 | * | |
208 | * This needs to be kept as small as possible. | |
209 | */ | |
210 | ||
211 | struct sa_handle { | |
212 | dmu_buf_user_t sa_dbu; | |
213 | kmutex_t sa_lock; | |
214 | dmu_buf_t *sa_bonus; | |
215 | dmu_buf_t *sa_spill; | |
216 | objset_t *sa_os; | |
217 | void *sa_userp; | |
218 | sa_idx_tab_t *sa_bonus_tab; /* idx of bonus */ | |
219 | sa_idx_tab_t *sa_spill_tab; /* only present if spill activated */ | |
220 | }; | |
221 | ||
222 | #define SA_GET_DB(hdl, type) \ | |
223 | (dmu_buf_impl_t *)((type == SA_BONUS) ? hdl->sa_bonus : hdl->sa_spill) | |
224 | ||
225 | #define SA_GET_HDR(hdl, type) \ | |
226 | ((sa_hdr_phys_t *)((dmu_buf_impl_t *)(SA_GET_DB(hdl, \ | |
227 | type))->db.db_data)) | |
228 | ||
229 | #define SA_IDX_TAB_GET(hdl, type) \ | |
230 | (type == SA_BONUS ? hdl->sa_bonus_tab : hdl->sa_spill_tab) | |
231 | ||
232 | #define IS_SA_BONUSTYPE(a) \ | |
233 | ((a == DMU_OT_SA) ? B_TRUE : B_FALSE) | |
234 | ||
235 | #define SA_BONUSTYPE_FROM_DB(db) \ | |
236 | (dmu_get_bonustype((dmu_buf_t *)db)) | |
237 | ||
238 | #define SA_BLKPTR_SPACE (DN_OLD_MAX_BONUSLEN - sizeof (blkptr_t)) | |
239 | ||
240 | #define SA_LAYOUT_NUM(x, type) \ | |
241 | ((!IS_SA_BONUSTYPE(type) ? 0 : (((IS_SA_BONUSTYPE(type)) && \ | |
242 | ((SA_HDR_LAYOUT_NUM(x)) == 0)) ? 1 : SA_HDR_LAYOUT_NUM(x)))) | |
243 | ||
244 | ||
245 | #define SA_REGISTERED_LEN(sa, attr) sa->sa_attr_table[attr].sa_length | |
246 | ||
247 | #define SA_ATTR_LEN(sa, idx, attr, hdr) ((SA_REGISTERED_LEN(sa, attr) == 0) ?\ | |
248 | hdr->sa_lengths[TOC_LEN_IDX(idx->sa_idx_tab[attr])] : \ | |
249 | SA_REGISTERED_LEN(sa, attr)) | |
250 | ||
251 | #define SA_SET_HDR(hdr, num, size) \ | |
252 | { \ | |
253 | hdr->sa_magic = SA_MAGIC; \ | |
254 | SA_HDR_LAYOUT_INFO_ENCODE(hdr->sa_layout_info, num, size); \ | |
255 | } | |
256 | ||
257 | #define SA_ATTR_INFO(sa, idx, hdr, attr, bulk, type, hdl) \ | |
258 | { \ | |
259 | bulk.sa_size = SA_ATTR_LEN(sa, idx, attr, hdr); \ | |
260 | bulk.sa_buftype = type; \ | |
261 | bulk.sa_addr = \ | |
262 | (void *)((uintptr_t)TOC_OFF(idx->sa_idx_tab[attr]) + \ | |
263 | (uintptr_t)hdr); \ | |
264 | } | |
265 | ||
266 | #define SA_HDR_SIZE_MATCH_LAYOUT(hdr, tb) \ | |
267 | (SA_HDR_SIZE(hdr) == (sizeof (sa_hdr_phys_t) + \ | |
268 | (tb->lot_var_sizes > 1 ? P2ROUNDUP((tb->lot_var_sizes - 1) * \ | |
269 | sizeof (uint16_t), 8) : 0))) | |
270 | ||
271 | int sa_add_impl(sa_handle_t *, sa_attr_type_t, | |
272 | uint32_t, sa_data_locator_t, void *, dmu_tx_t *); | |
273 | ||
274 | void sa_register_update_callback_locked(objset_t *, sa_update_cb_t *); | |
275 | int sa_size_locked(sa_handle_t *, sa_attr_type_t, int *); | |
276 | ||
277 | void sa_default_locator(void **, uint32_t *, uint32_t, boolean_t, void *); | |
278 | int sa_attr_size(sa_os_t *, sa_idx_tab_t *, sa_attr_type_t, | |
279 | uint16_t *, sa_hdr_phys_t *); | |
280 | ||
281 | #ifdef __cplusplus | |
282 | extern "C" { | |
283 | #endif | |
284 | ||
285 | #ifdef __cplusplus | |
286 | } | |
287 | #endif | |
288 | ||
289 | #endif /* _SYS_SA_IMPL_H */ |