1/*-
2 * Copyright (c) 2014-2018 Netflix, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * A kernel and user space statistics gathering API + infrastructure.
29 *
30 * Author: Lawrence Stewart <lstewart@netflix.com>
31 *
32 * Things to ponder:
33 *   - Register callbacks for events e.g. counter stat passing a threshold
34 *
35 *   - How could this become SIFTRv2? Perhaps publishing records to a ring
36 *     mapped between userspace and kernel?
37 *
38 *   - Potential stat types:
39 *       RATE: events per unit time
40 *       TIMESERIES: timestamped records. Stored in voistate?
41 *       EWMA: Exponential weighted moving average.
42 *
43 *   - How should second order stats work e.g. stat "A" depends on "B"
44 *
45 *   - How do variable time windows work e.g. give me per-RTT stats
46 *
47 *   - Should the API always require the caller to manage locking? Or should the
48 *     API provide optional functionality to lock a blob during operations.
49 *
50 *   - Should we continue to store unpacked naturally aligned structs in the
51 *     blob or move to packed structs? Relates to inter-host
52 *     serialisation/endian issues.
53 */
54
55#ifndef _SYS_STATS_H_
56#define _SYS_STATS_H_
57
58#include <sys/limits.h>
59#ifdef DIAGNOSTIC
60#include <sys/tree.h>
61#endif
62
63#ifndef _KERNEL
64/*
65 * XXXLAS: Hacks to enable sharing template creation code between kernel and
66 * userland e.g. tcp_stats.c
67 */
68#define	VNET(n) n
69#define	VNET_DEFINE(t, n) static t n __unused
70#endif /* ! _KERNEL */
71
72#define	TPL_MAX_NAME_LEN 64
73
74/*
75 * The longest template string spec format i.e. the normative spec format, is:
76 *
77 *     "<tplname>":<tplhash>
78 *
79 * Therefore, the max string length of a template string spec is:
80 *
81 * - TPL_MAX_NAME_LEN
82 * - 2 chars for ""
83 * - 1 char for : separating name and hash
84 * - 10 chars for 32bit hash
85 */
86#define	STATS_TPL_MAX_STR_SPEC_LEN (TPL_MAX_NAME_LEN + 13)
87
88struct sbuf;
89struct sysctl_oid;
90struct sysctl_req;
91
92enum sb_str_fmt {
93	SB_STRFMT_FREEFORM = 0,
94	SB_STRFMT_JSON,
95	SB_STRFMT_NUM_FMTS	/* +1 to highest numbered format type. */
96};
97
98/* VOI stat types. */
99enum voi_stype {
100	VS_STYPE_VOISTATE = 0,	/* Reserved for internal API use. */
101	VS_STYPE_SUM,
102	VS_STYPE_MAX,
103	VS_STYPE_MIN,
104	VS_STYPE_HIST,
105	VS_STYPE_TDGST,
106	VS_NUM_STYPES		/* +1 to highest numbered stat type. */
107};
108
109/*
110 * VOI stat data types used as storage for certain stat types and to marshall
111 * data through various API calls.
112 */
113enum vsd_dtype {
114	VSD_DTYPE_VOISTATE = 0,	/* Reserved for internal API use. */
115	VSD_DTYPE_INT_S32,	/* int32_t */
116	VSD_DTYPE_INT_U32,	/* uint32_t */
117	VSD_DTYPE_INT_S64,	/* int64_t */
118	VSD_DTYPE_INT_U64,	/* uint64_t */
119	VSD_DTYPE_INT_SLONG,	/* long */
120	VSD_DTYPE_INT_ULONG,	/* unsigned long */
121	VSD_DTYPE_Q_S32,	/* s32q_t */
122	VSD_DTYPE_Q_U32,	/* u32q_t */
123	VSD_DTYPE_Q_S64,	/* s64q_t */
124	VSD_DTYPE_Q_U64,	/* u64q_t */
125	VSD_DTYPE_CRHIST32,	/* continuous range histogram, 32bit buckets */
126	VSD_DTYPE_DRHIST32,	/* discrete range histogram, 32bit buckets */
127	VSD_DTYPE_DVHIST32,	/* discrete value histogram, 32bit buckets */
128	VSD_DTYPE_CRHIST64,	/* continuous range histogram, 64bit buckets */
129	VSD_DTYPE_DRHIST64,	/* discrete range histogram, 64bit buckets */
130	VSD_DTYPE_DVHIST64,	/* discrete value histogram, 64bit buckets */
131	VSD_DTYPE_TDGSTCLUST32,	/* clustering variant t-digest, 32bit buckets */
132	VSD_DTYPE_TDGSTCLUST64,	/* clustering variant t-digest, 64bit buckets */
133	VSD_NUM_DTYPES		/* +1 to highest numbered data type. */
134};
135
136struct voistatdata_int32 {
137	union {
138		int32_t		s32;
139		uint32_t	u32;
140	};
141};
142
143struct voistatdata_int64 {
144	union {
145		int64_t		s64;
146		uint64_t	u64;
147		//counter_u64_t	u64pcpu;
148	};
149};
150
151struct voistatdata_intlong {
152	union {
153		long		slong;
154		unsigned long	ulong;
155	};
156};
157
158struct voistatdata_q32 {
159	union {
160		s32q_t		sq32;
161		u32q_t		uq32;
162	};
163};
164
165struct voistatdata_q64 {
166	union {
167		s64q_t		sq64;
168		u64q_t		uq64;
169	};
170};
171
172struct voistatdata_numeric {
173	union {
174		struct {
175#if BYTE_ORDER == BIG_ENDIAN
176			uint32_t		pad;
177#endif
178			union {
179				int32_t		s32;
180				uint32_t	u32;
181			};
182#if BYTE_ORDER == LITTLE_ENDIAN
183			uint32_t		pad;
184#endif
185		} int32;
186
187		struct {
188#if BYTE_ORDER == BIG_ENDIAN
189			uint32_t		pad;
190#endif
191			union {
192				s32q_t		sq32;
193				u32q_t		uq32;
194			};
195#if BYTE_ORDER == LITTLE_ENDIAN
196			uint32_t		pad;
197#endif
198		} q32;
199
200		struct {
201#if BYTE_ORDER == BIG_ENDIAN && LONG_BIT == 32
202			uint32_t		pad;
203#endif
204			union {
205				long		slong;
206				unsigned long	ulong;
207			};
208#if BYTE_ORDER == LITTLE_ENDIAN && LONG_BIT == 32
209			uint32_t		pad;
210#endif
211		} intlong;
212
213		struct voistatdata_int64	int64;
214		struct voistatdata_q64		q64;
215	};
216};
217
218/* Continuous range histogram with 32bit buckets. */
219struct voistatdata_crhist32 {
220	uint32_t	oob;
221	struct {
222		struct voistatdata_numeric lb;
223		uint32_t cnt;
224	} bkts[];
225};
226
227/* Continuous range histogram with 64bit buckets. */
228struct voistatdata_crhist64 {
229	uint64_t	oob;
230	struct {
231		struct voistatdata_numeric lb;
232		uint64_t cnt;
233	} bkts[];
234};
235
236/* Discrete range histogram with 32bit buckets. */
237struct voistatdata_drhist32 {
238	uint32_t	oob;
239	struct {
240		struct voistatdata_numeric lb, ub;
241		uint32_t cnt;
242	} bkts[];
243};
244
245/* Discrete range histogram with 64bit buckets. */
246struct voistatdata_drhist64 {
247	uint64_t	oob;
248	struct {
249		struct voistatdata_numeric lb, ub;
250		uint64_t cnt;
251	} bkts[];
252};
253
254/* Discrete value histogram with 32bit buckets. */
255struct voistatdata_dvhist32 {
256	uint32_t	oob;
257	struct {
258		struct voistatdata_numeric val;
259		uint32_t cnt;
260	} bkts[];
261};
262
263/* Discrete value histogram with 64bit buckets. */
264struct voistatdata_dvhist64 {
265	uint64_t	oob;
266	struct {
267		struct voistatdata_numeric val;
268		uint64_t cnt;
269	} bkts[];
270};
271
272struct voistatdata_hist {
273	union {
274		struct voistatdata_crhist32	crhist32;
275		struct voistatdata_crhist64	crhist64;
276		struct voistatdata_dvhist32	dvhist32;
277		struct voistatdata_dvhist64	dvhist64;
278		struct voistatdata_drhist32	drhist32;
279		struct voistatdata_drhist64	drhist64;
280	};
281};
282
283struct voistatdata_tdgstctd32 {
284	ARB16_ENTRY()	ctdlnk;
285#ifdef DIAGNOSTIC
286	RB_ENTRY(voistatdata_tdgstctd32) rblnk;
287#endif
288	s32q_t		mu;
289	int32_t		cnt;
290};
291
292struct voistatdata_tdgstctd64 {
293	ARB16_ENTRY()	ctdlnk;
294#ifdef DIAGNOSTIC
295	RB_ENTRY(voistatdata_tdgstctd64) rblnk;
296#endif
297	s64q_t		mu;
298	int64_t		cnt;
299};
300
301struct voistatdata_tdgstctd {
302	union {
303		struct voistatdata_tdgstctd32	tdgstctd32;
304		struct voistatdata_tdgstctd64	tdgstctd64;
305	};
306};
307
308/* Clustering variant, fixed-point t-digest with 32bit mu/counts. */
309struct voistatdata_tdgstclust32 {
310	uint32_t	smplcnt;	/* Count of samples. */
311	uint32_t	compcnt;	/* Count of digest compressions. */
312#ifdef DIAGNOSTIC
313	RB_HEAD(rbctdth32, voistatdata_tdgstctd32) rbctdtree;
314#endif
315	/* Array-based red-black tree of centroids. */
316	ARB16_HEAD(ctdth32, voistatdata_tdgstctd32) ctdtree;
317};
318
319/* Clustering variant, fixed-point t-digest with 64bit mu/counts. */
320struct voistatdata_tdgstclust64 {
321	uint64_t	smplcnt;	/* Count of samples. */
322	uint32_t	compcnt;	/* Count of digest compressions. */
323#ifdef DIAGNOSTIC
324	RB_HEAD(rbctdth64, voistatdata_tdgstctd64) rbctdtree;
325#endif
326	/* Array-based red-black tree of centroids. */
327	ARB16_HEAD(ctdth64, voistatdata_tdgstctd64) ctdtree;
328};
329
330struct voistatdata_tdgst {
331	union {
332		struct voistatdata_tdgstclust32	tdgstclust32;
333		struct voistatdata_tdgstclust64	tdgstclust64;
334	};
335};
336
337struct voistatdata {
338	union {
339		struct voistatdata_int32	int32;
340		struct voistatdata_int64	int64;
341		struct voistatdata_intlong	intlong;
342		struct voistatdata_q32		q32;
343		struct voistatdata_q64		q64;
344		struct voistatdata_crhist32	crhist32;
345		struct voistatdata_crhist64	crhist64;
346		struct voistatdata_dvhist32	dvhist32;
347		struct voistatdata_dvhist64	dvhist64;
348		struct voistatdata_drhist32	drhist32;
349		struct voistatdata_drhist64	drhist64;
350		struct voistatdata_tdgstclust32	tdgstclust32;
351		struct voistatdata_tdgstclust64	tdgstclust64;
352	};
353};
354
355#define	VSD_HIST_LBOUND_INF 0x01
356#define	VSD_HIST_UBOUND_INF 0x02
357struct vss_hist_hlpr_info {
358	enum hist_bkt_alloc {
359		BKT_LIN,	/* Linear steps. */
360		BKT_EXP,	/* Exponential steps. */
361		BKT_LINEXP,	/* Exponential steps, linear sub-steps. */
362		BKT_USR		/* User specified buckets. */
363	}				scheme;
364	enum vsd_dtype			voi_dtype;
365	enum vsd_dtype			hist_dtype;
366	uint32_t			flags;
367	struct voistatdata_numeric	lb;
368	struct voistatdata_numeric	ub;
369	union {
370		struct {
371			const uint64_t	stepinc;
372		} lin;
373		struct {
374			const uint64_t	stepbase;
375			const uint64_t	stepexp;
376		} exp;
377		struct {
378			const uint64_t	stepbase;
379			const uint64_t	linstepdiv;
380		} linexp;
381		struct {
382			const uint16_t nbkts;
383			const struct {
384				struct voistatdata_numeric lb, ub;
385			} *bkts;
386		} usr;
387	};
388};
389
390struct vss_tdgst_hlpr_info {
391	enum vsd_dtype		voi_dtype;
392	enum vsd_dtype		tdgst_dtype;
393	uint32_t		nctds;
394	uint32_t		prec;
395} __aligned(sizeof(void *));
396
397struct vss_numeric_hlpr_info {
398	uint32_t		prec;
399};
400
401struct vss_hlpr_info {
402	union {
403		struct vss_tdgst_hlpr_info	tdgst;
404		struct vss_hist_hlpr_info	hist;
405		struct vss_numeric_hlpr_info	numeric;
406	};
407};
408
409struct voistatspec;
410typedef int (*vss_hlpr_fn)(enum vsd_dtype, struct voistatspec *,
411    struct vss_hlpr_info *);
412
413struct voistatspec {
414	vss_hlpr_fn		hlpr;		/* iv helper function. */
415	struct vss_hlpr_info	*hlprinfo;	/* Helper function context. */
416	struct voistatdata	*iv;		/* Initialisation value. */
417	size_t			vsdsz;		/* Size of iv. */
418	uint32_t		flags;		/* Stat flags. */
419	enum vsd_dtype		vs_dtype : 8;	/* Stat's dtype. */
420	enum voi_stype		stype : 8;	/* Stat type. */
421};
422
423extern const char *vs_stype2name[VS_NUM_STYPES];
424extern const char *vs_stype2desc[VS_NUM_STYPES];
425extern const char *vsd_dtype2name[VSD_NUM_DTYPES];
426extern const size_t vsd_dtype2size[VSD_NUM_DTYPES];
427#define	LIM_MIN 0
428#define	LIM_MAX 1
429extern const struct voistatdata_numeric numeric_limits[2][VSD_DTYPE_Q_U64 + 1];
430
431#define	TYPEOF_MEMBER(type, member) __typeof(((type *)0)->member)
432#define	TYPEOF_MEMBER_PTR(type, member) __typeof(*(((type *)0)->member))
433#define	SIZEOF_MEMBER(type, member) sizeof(TYPEOF_MEMBER(type, member))
434
435/* Cast a pointer to a voistatdata struct of requested type. */
436#define	_VSD(cnst, type, ptr) ((cnst struct voistatdata_##type *)(ptr))
437#define	VSD(type, ptr) _VSD(, type, ptr)
438#define	CONSTVSD(type, ptr) _VSD(const, type, ptr)
439
440#define	NVSS(vss_slots) (sizeof((vss_slots)) / sizeof(struct voistatspec))
441#define	STATS_VSS(st, vsf, dt, hlp, hlpi) \
442((struct voistatspec){ \
443	.stype = (st), \
444	.flags = (vsf), \
445	.vs_dtype = (dt), \
446	.hlpr = (hlp), \
447	.hlprinfo = (hlpi), \
448})
449
450#define	STATS_VSS_SUM() STATS_VSS(VS_STYPE_SUM, 0, 0, \
451    (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL)
452
453#define	STATS_VSS_MAX() STATS_VSS(VS_STYPE_MAX, 0, 0, \
454    (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL)
455
456#define	STATS_VSS_MIN() STATS_VSS(VS_STYPE_MIN, 0, 0, \
457    (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL)
458
459#define	STATS_VSS_HIST(htype, hist_hlpr_info) STATS_VSS(VS_STYPE_HIST, 0, \
460    htype, (vss_hlpr_fn)&stats_vss_hist_hlpr, \
461    (struct vss_hlpr_info *)(hist_hlpr_info))
462
463#define	STATS_VSS_TDIGEST(tdtype, tdgst_hlpr_info) STATS_VSS(VS_STYPE_TDGST, \
464    0, tdtype, (vss_hlpr_fn)&stats_vss_tdgst_hlpr, \
465    (struct vss_hlpr_info *)(tdgst_hlpr_info))
466
467#define	TDGST_NCTRS2VSDSZ(tdtype, nctds) (sizeof(struct voistatdata_##tdtype) + \
468    ((nctds) * sizeof(TYPEOF_MEMBER_PTR(struct voistatdata_##tdtype, \
469    ctdtree.arb_nodes))))
470
471#define	TDGST_HLPR_INFO(dt, nc, nf) \
472(&(struct vss_tdgst_hlpr_info){ \
473    .tdgst_dtype = (dt), \
474    .nctds = (nc), \
475    .prec = (nf) \
476})
477
478#define	STATS_VSS_TDGSTCLUST32(nctds, prec) \
479    STATS_VSS_TDIGEST(VSD_DTYPE_TDGSTCLUST32, \
480    TDGST_HLPR_INFO(VSD_DTYPE_TDGSTCLUST32, nctds, prec))
481
482#define	STATS_VSS_TDGSTCLUST64(nctds, prec) \
483    STATS_VSS_TDIGEST(VSD_DTYPE_TDGSTCLUST64, \
484    TDGST_HLPR_INFO(VSD_DTYPE_TDGSTCLUST64, nctds, prec))
485
486#define	HIST_VSDSZ2NBKTS(htype, dsz) \
487    ((dsz - sizeof(struct voistatdata_##htype)) / \
488    sizeof(TYPEOF_MEMBER(struct voistatdata_##htype, bkts[0])))
489
490#define	HIST_NBKTS2VSDSZ(htype, nbkts) (sizeof(struct voistatdata_##htype) + \
491    ((nbkts) * sizeof(TYPEOF_MEMBER_PTR(struct voistatdata_##htype, bkts))))
492
493#define	HIST_HLPR_INFO_LIN_FIELDS(si) .lin.stepinc = (si)
494
495#define	HIST_HLPR_INFO_EXP_FIELDS(sb, se) \
496    .exp.stepbase = (sb), .exp.stepexp = (se)
497
498#define	HIST_HLPR_INFO_LINEXP_FIELDS(nss, sb) \
499    .linexp.linstepdiv = (nss), .linexp.stepbase = (sb)
500
501#define	HIST_HLPR_INFO_USR_FIELDS(bbs) \
502    .usr.bkts = (TYPEOF_MEMBER(struct vss_hist_hlpr_info, usr.bkts))(bbs), \
503    .usr.nbkts = (sizeof(bbs) / sizeof(struct voistatdata_numeric[2]))
504
505#define	HIST_HLPR_INFO(dt, sch, f, lbd, ubd, bkthlpr_fields) \
506(&(struct vss_hist_hlpr_info){ \
507    .scheme = (sch), \
508    .hist_dtype = (dt), \
509    .flags = (f), \
510    .lb = stats_ctor_vsd_numeric(lbd), \
511    .ub = stats_ctor_vsd_numeric(ubd), \
512    bkthlpr_fields \
513})
514
515#define	STATS_VSS_CRHIST32_LIN(lb, ub, stepinc, vsdflags) \
516    STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
517    BKT_LIN, vsdflags, lb, ub, HIST_HLPR_INFO_LIN_FIELDS(stepinc)))
518#define	STATS_VSS_CRHIST64_LIN(lb, ub, stepinc, vsdflags) \
519    STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
520    BKT_LIN, vsdflags, lb, ub, HIST_HLPR_INFO_LIN_FIELDS(stepinc)))
521
522#define	STATS_VSS_CRHIST32_EXP(lb, ub, stepbase, stepexp, vsdflags) \
523    STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
524    BKT_EXP, vsdflags, lb, ub, HIST_HLPR_INFO_EXP_FIELDS(stepbase, stepexp)))
525#define	STATS_VSS_CRHIST64_EXP(lb, ub, stepbase, stepexp, vsdflags) \
526    STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
527    BKT_EXP, vsdflags, lb, ub, HIST_HLPR_INFO_EXP_FIELDS(stepbase, stepexp)))
528
529#define	STATS_VSS_CRHIST32_LINEXP(lb, ub, nlinsteps, stepbase, vsdflags) \
530    STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
531    BKT_LINEXP, vsdflags, lb, ub, HIST_HLPR_INFO_LINEXP_FIELDS(nlinsteps, \
532    stepbase)))
533#define	STATS_VSS_CRHIST64_LINEXP(lb, ub, nlinsteps, stepbase, vsdflags) \
534    STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
535    BKT_LINEXP, vsdflags, lb, ub, HIST_HLPR_INFO_LINEXP_FIELDS(nlinsteps, \
536    stepbase)))
537
538#define	STATS_VSS_CRHIST32_USR(bkts, vsdflags) \
539    STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
540    BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
541#define	STATS_VSS_CRHIST64_USR(bkts, vsdflags) \
542    STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
543    BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
544
545#define	STATS_VSS_DRHIST32_USR(bkts, vsdflags) \
546    STATS_VSS_HIST(VSD_DTYPE_DRHIST32, HIST_HLPR_INFO(VSD_DTYPE_DRHIST32, \
547    BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
548#define	STATS_VSS_DRHIST64_USR(bkts, vsdflags) \
549    STATS_VSS_HIST(VSD_DTYPE_DRHIST64, HIST_HLPR_INFO(VSD_DTYPE_DRHIST64, \
550    BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
551
552#define	STATS_VSS_DVHIST32_USR(vals, vsdflags) \
553    STATS_VSS_HIST(VSD_DTYPE_DVHIST32, HIST_HLPR_INFO(VSD_DTYPE_DVHIST32, \
554    BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(vals)))
555#define	STATS_VSS_DVHIST64_USR(vals, vsdflags) \
556    STATS_VSS_HIST(VSD_DTYPE_DVHIST64, HIST_HLPR_INFO(VSD_DTYPE_DVHIST64, \
557    BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(vals)))
558#define	DRBKT(lb, ub) { stats_ctor_vsd_numeric(lb), stats_ctor_vsd_numeric(ub) }
559#define	DVBKT(val) DRBKT(val, val)
560#define	CRBKT(lb) DRBKT(lb, lb)
561#define	HBKTS(...) ((struct voistatdata_numeric [][2]){__VA_ARGS__})
562
563#define	VSD_HIST_FIELD(hist, cnst, hist_dtype, op, field) \
564    (VSD_DTYPE_CRHIST32 == (hist_dtype) ? \
565    op(_VSD(cnst, crhist32, hist)->field) : \
566    (VSD_DTYPE_DRHIST32 == (hist_dtype) ? \
567    op(_VSD(cnst, drhist32, hist)->field) : \
568    (VSD_DTYPE_DVHIST32 == (hist_dtype) ? \
569    op(_VSD(cnst, dvhist32, hist)->field) : \
570    (VSD_DTYPE_CRHIST64 == (hist_dtype) ? \
571    op(_VSD(cnst, crhist64, hist)->field) : \
572    (VSD_DTYPE_DRHIST64 == (hist_dtype) ? \
573    op(_VSD(cnst, drhist64, hist)->field) : \
574    (op(_VSD(cnst, dvhist64, hist)->field)))))))
575#define	VSD_HIST_FIELDVAL(hist, hist_dtype, field) \
576    VSD_HIST_FIELD(hist, , hist_dtype, ,field)
577#define	VSD_CONSTHIST_FIELDVAL(hist, hist_dtype, field) \
578    VSD_HIST_FIELD(hist, const, hist_dtype, ,field)
579#define	VSD_HIST_FIELDPTR(hist, hist_dtype, field) \
580    VSD_HIST_FIELD(hist, , hist_dtype, (void *)&,field)
581#define	VSD_CONSTHIST_FIELDPTR(hist, hist_dtype, field) \
582    VSD_HIST_FIELD(hist, const, hist_dtype, (void *)&,field)
583
584#define	VSD_CRHIST_FIELD(hist, cnst, hist_dtype, op, field) \
585    (VSD_DTYPE_CRHIST32 == (hist_dtype) ? \
586    op(_VSD(cnst, crhist32, hist)->field) : \
587    op(_VSD(cnst, crhist64, hist)->field))
588#define	VSD_CRHIST_FIELDVAL(hist, hist_dtype, field) \
589    VSD_CRHIST_FIELD(hist, , hist_dtype, , field)
590#define	VSD_CONSTCRHIST_FIELDVAL(hist, hist_dtype, field) \
591    VSD_CRHIST_FIELD(hist, const, hist_dtype, , field)
592#define	VSD_CRHIST_FIELDPTR(hist, hist_dtype, field) \
593    VSD_CRHIST_FIELD(hist, , hist_dtype, &, field)
594#define	VSD_CONSTCRHIST_FIELDPTR(hist, hist_dtype, field) \
595    VSD_CRHIST_FIELD(hist, const, hist_dtype, &, field)
596
597#define	VSD_DRHIST_FIELD(hist, cnst, hist_dtype, op, field) \
598    (VSD_DTYPE_DRHIST32 == (hist_dtype) ? \
599    op(_VSD(cnst, drhist32, hist)->field) : \
600    op(_VSD(cnst, drhist64, hist)->field))
601#define	VSD_DRHIST_FIELDVAL(hist, hist_dtype, field) \
602    VSD_DRHIST_FIELD(hist, , hist_dtype, , field)
603#define	VSD_CONSTDRHIST_FIELDVAL(hist, hist_dtype, field) \
604    VSD_DRHIST_FIELD(hist, const, hist_dtype, , field)
605#define	VSD_DRHIST_FIELDPTR(hist, hist_dtype, field) \
606    VSD_DRHIST_FIELD(hist, , hist_dtype, &, field)
607#define	VSD_CONSTDRHIST_FIELDPTR(hist, hist_dtype, field) \
608    VSD_DRHIST_FIELD(hist, const, hist_dtype, &, field)
609
610#define	VSD_DVHIST_FIELD(hist, cnst, hist_dtype, op, field) \
611    (VSD_DTYPE_DVHIST32 == (hist_dtype) ? \
612    op(_VSD(cnst, dvhist32, hist)->field) : \
613    op(_VSD(cnst, dvhist64, hist)->field))
614#define	VSD_DVHIST_FIELDVAL(hist, hist_dtype, field) \
615    VSD_DVHIST_FIELD(hist, , hist_dtype, , field)
616#define	VSD_CONSTDVHIST_FIELDVAL(hist, hist_dtype, field) \
617    VSD_DVHIST_FIELD(hist, const, hist_dtype, , field)
618#define	VSD_DVHIST_FIELDPTR(hist, hist_dtype, field) \
619    VSD_DVHIST_FIELD(hist, , hist_dtype, &, field)
620#define	VSD_CONSTDVHIST_FIELDPTR(hist, hist_dtype, field) \
621    VSD_DVHIST_FIELD(hist, const, hist_dtype, &, field)
622
623#define	STATS_ABI_V1	1
624struct statsblobv1;
625
626enum sb_endianness {
627	SB_UE = 0,	/* Unknown endian. */
628	SB_LE,		/* Little endian. */
629	SB_BE		/* Big endian. */
630};
631
632struct statsblob {
633	uint8_t		abi;
634	uint8_t		endian;
635	uint16_t	flags;
636	uint16_t	maxsz;
637	uint16_t	cursz;
638	uint8_t		opaque[];
639} __aligned(sizeof(void *));
640
641struct metablob {
642	char		*tplname;
643	uint32_t	tplhash;
644	struct voi_meta {
645		char *name;
646		char *desc;
647	}		*voi_meta;
648};
649
650struct statsblob_tpl {
651	struct metablob		*mb;	/* Template metadata */
652	struct statsblob	*sb;	/* Template schema */
653};
654
655struct stats_tpl_sample_rate {
656	/* XXXLAS: Storing slot_id assumes templates are never removed. */
657	int32_t		tpl_slot_id;
658	uint32_t	tpl_sample_pct;
659};
660
661/* Template sample rates list management callback actions. */
662enum stats_tpl_sr_cb_action {
663	TPL_SR_UNLOCKED_GET,
664	TPL_SR_RLOCKED_GET,
665	TPL_SR_RUNLOCK,
666	TPL_SR_PUT
667};
668
669/*
670 * Callback function pointer passed as arg1 to stats_tpl_sample_rates(). ctx is
671 * a heap-allocated, zero-initialised blob of contextual memory valid during a
672 * single stats_tpl_sample_rates() call and sized per the value passed as arg2.
673 * Returns 0 on success, an errno on error.
674 * - When called with "action == TPL_SR_*_GET", return the subsystem's rates
675 *   list ptr and count, locked or unlocked as requested.
676 * - When called with "action == TPL_SR_RUNLOCK", unlock the subsystem's rates
677 *   list ptr and count. Pair with a prior "action == TPL_SR_RLOCKED_GET" call.
678 * - When called with "action == TPL_SR_PUT, update the subsystem's rates list
679 *   ptr and count to the sysctl processed values and return the inactive list
680 *   details in rates/nrates for garbage collection by stats_tpl_sample_rates().
681 */
682typedef int (*stats_tpl_sr_cb_t)(enum stats_tpl_sr_cb_action action,
683    struct stats_tpl_sample_rate **rates, int *nrates, void *ctx);
684
685/* Flags related to iterating over a stats blob. */
686#define	SB_IT_FIRST_CB		0x0001
687#define	SB_IT_LAST_CB		0x0002
688#define	SB_IT_FIRST_VOI		0x0004
689#define	SB_IT_LAST_VOI		0x0008
690#define	SB_IT_FIRST_VOISTAT	0x0010
691#define	SB_IT_LAST_VOISTAT	0x0020
692#define	SB_IT_NULLVOI		0x0040
693#define	SB_IT_NULLVOISTAT	0x0080
694
695struct sb_visit {
696	struct voistatdata	*vs_data;
697	uint32_t		tplhash;
698	uint32_t		flags;
699	int16_t			voi_id;
700	int16_t			vs_dsz;
701	uint16_t		vs_errs;
702	enum vsd_dtype		voi_dtype : 8;
703	enum vsd_dtype		vs_dtype : 8;
704	int8_t			vs_stype;
705};
706
707/* Stats blob iterator callback called for each struct voi. */
708typedef int (*stats_blob_visitcb_t)(struct sb_visit *sbv, void *usrctx);
709
710/* ABI specific functions. */
711int stats_v1_tpl_alloc(const char *name, uint32_t flags);
712int stats_v1_tpl_add_voistats(uint32_t tpl_id, int32_t voi_id,
713    const char *voi_name, enum vsd_dtype voi_dtype, uint32_t nvss,
714    struct voistatspec *vss, uint32_t flags);
715int stats_v1_blob_init(struct statsblobv1 *sb, uint32_t tpl_id, uint32_t flags);
716struct statsblobv1 * stats_v1_blob_alloc(uint32_t tpl_id, uint32_t flags);
717int stats_v1_blob_clone(struct statsblobv1 **dst, size_t dstmaxsz,
718    struct statsblobv1 *src, uint32_t flags);
719void stats_v1_blob_destroy(struct statsblobv1 *sb);
720#define	SB_CLONE_RSTSRC		0x0001 /* Reset src blob if clone successful. */
721#define	SB_CLONE_ALLOCDST	0x0002 /* Allocate src->cursz memory for dst. */
722#define	SB_CLONE_USRDSTNOFAULT	0x0004 /* Clone to wired userspace dst. */
723#define	SB_CLONE_USRDST		0x0008 /* Clone to unwired userspace dst. */
724int stats_v1_blob_snapshot(struct statsblobv1 **dst, size_t dstmaxsz,
725    struct statsblobv1 *src, uint32_t flags);
726#define	SB_TOSTR_OBJDUMP	0x00000001
727#define	SB_TOSTR_META		0x00000002 /* Lookup metablob and render metadata */
728int stats_v1_blob_tostr(struct statsblobv1 *sb, struct sbuf *buf,
729    enum sb_str_fmt fmt, uint32_t flags);
730int stats_v1_blob_visit(struct statsblobv1 *sb, stats_blob_visitcb_t func,
731    void *usrctx);
732/* VOI related function flags. */
733#define	SB_VOI_RELUPDATE	0x00000001 /* voival is relative to previous value. */
734int stats_v1_voi_update(struct statsblobv1 *sb, int32_t voi_id,
735    enum vsd_dtype voi_dtype, struct voistatdata *voival, uint32_t flags);
736int stats_v1_voistat_fetch_dptr(struct statsblobv1 *sb, int32_t voi_id,
737    enum voi_stype stype, enum vsd_dtype *retdtype, struct voistatdata **retvsd,
738    size_t *retvsdsz);
739
740/* End ABI specific functions. */
741
742/* ABI agnostic functions. */
743int stats_vss_hlpr_init(enum vsd_dtype voi_dtype, uint32_t nvss,
744    struct voistatspec *vss);
745void stats_vss_hlpr_cleanup(uint32_t nvss, struct voistatspec *vss);
746int stats_vss_hist_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss,
747    struct vss_hist_hlpr_info *info);
748int stats_vss_numeric_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss,
749    struct vss_numeric_hlpr_info *info);
750int stats_vss_tdgst_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss,
751    struct vss_tdgst_hlpr_info *info);
752int stats_tpl_fetch(int tpl_id, struct statsblob_tpl **tpl);
753int stats_tpl_fetch_allocid(const char *name, uint32_t hash);
754int stats_tpl_id2name(uint32_t tpl_id, char *buf, size_t len);
755int stats_tpl_sample_rates(struct sysctl_oid *oidp, void *arg1, intmax_t arg2,
756    struct sysctl_req *req);
757int stats_tpl_sample_rollthedice(struct stats_tpl_sample_rate *rates,
758    int nrates, void *seed_bytes, size_t seed_len);
759int stats_voistatdata_tostr(const struct voistatdata *vsd,
760    enum vsd_dtype voi_dtype, enum vsd_dtype vsd_dtype, size_t vsd_sz,
761    enum sb_str_fmt fmt, struct sbuf *buf, int objdump);
762
763static inline struct voistatdata_numeric
764stats_ctor_vsd_numeric(uint64_t val)
765{
766	struct voistatdata_numeric tmp;
767
768	tmp.int64.u64 = val;
769
770	return (tmp);
771}
772
773static inline int
774stats_tpl_alloc(const char *name, uint32_t flags)
775{
776
777	return (stats_v1_tpl_alloc(name, flags));
778}
779
780static inline int
781stats_tpl_add_voistats(uint32_t tpl_id, int32_t voi_id, const char *voi_name,
782    enum vsd_dtype voi_dtype, uint32_t nvss, struct voistatspec *vss,
783    uint32_t flags)
784{
785	int ret;
786
787	if ((ret = stats_vss_hlpr_init(voi_dtype, nvss, vss)) == 0) {
788		ret = stats_v1_tpl_add_voistats(tpl_id, voi_id, voi_name,
789		    voi_dtype, nvss, vss, flags);
790	}
791	stats_vss_hlpr_cleanup(nvss, vss);
792
793	return (ret);
794}
795
796static inline int
797stats_blob_init(struct statsblob *sb, uint32_t tpl_id, uint32_t flags)
798{
799
800	return (stats_v1_blob_init((struct statsblobv1 *)sb, tpl_id, flags));
801}
802
803static inline struct statsblob *
804stats_blob_alloc(uint32_t tpl_id, uint32_t flags)
805{
806
807	return ((struct statsblob *)stats_v1_blob_alloc(tpl_id, flags));
808}
809
810static inline int
811stats_blob_clone(struct statsblob **dst, size_t dstmaxsz, struct statsblob *src,
812    uint32_t flags)
813{
814
815	return (stats_v1_blob_clone((struct statsblobv1 **)dst, dstmaxsz,
816	    (struct statsblobv1 *)src, flags));
817}
818
819static inline void
820stats_blob_destroy(struct statsblob *sb)
821{
822
823	stats_v1_blob_destroy((struct statsblobv1 *)sb);
824}
825
826static inline int
827stats_blob_visit(struct statsblob *sb, stats_blob_visitcb_t func, void *usrctx)
828{
829
830	return (stats_v1_blob_visit((struct statsblobv1 *)sb, func, usrctx));
831}
832
833static inline int
834stats_blob_tostr(struct statsblob *sb, struct sbuf *buf,
835    enum sb_str_fmt fmt, uint32_t flags)
836{
837
838	return (stats_v1_blob_tostr((struct statsblobv1 *)sb, buf, fmt, flags));
839}
840
841static inline int
842stats_voistat_fetch_dptr(struct statsblob *sb, int32_t voi_id,
843    enum voi_stype stype, enum vsd_dtype *retdtype, struct voistatdata **retvsd,
844    size_t *retvsdsz)
845{
846
847	return (stats_v1_voistat_fetch_dptr((struct statsblobv1 *)sb,
848	    voi_id, stype, retdtype, retvsd, retvsdsz));
849}
850
851static inline int
852stats_voistat_fetch_s64(struct statsblob *sb, int32_t voi_id,
853    enum voi_stype stype, int64_t *ret)
854{
855	struct voistatdata *vsd;
856	enum vsd_dtype vs_dtype;
857	int error;
858
859	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
860	    NULL)))
861		return (error);
862	else if (VSD_DTYPE_INT_S64 != vs_dtype)
863		return (EFTYPE);
864
865	*ret = vsd->int64.s64;
866	return (0);
867}
868
869static inline int
870stats_voistat_fetch_u64(struct statsblob *sb, int32_t voi_id,
871    enum voi_stype stype, uint64_t *ret)
872{
873	struct voistatdata *vsd;
874	enum vsd_dtype vs_dtype;
875	int error;
876
877	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
878	    NULL)))
879		return (error);
880	else if (VSD_DTYPE_INT_U64 != vs_dtype)
881		return (EFTYPE);
882
883	*ret = vsd->int64.u64;
884	return (0);
885}
886
887static inline int
888stats_voistat_fetch_s32(struct statsblob *sb, int32_t voi_id,
889    enum voi_stype stype, int32_t *ret)
890{
891	struct voistatdata *vsd;
892	enum vsd_dtype vs_dtype;
893	int error;
894
895	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
896	    NULL)))
897		return (error);
898	else if (VSD_DTYPE_INT_S32 != vs_dtype)
899		return (EFTYPE);
900
901	*ret = vsd->int32.s32;
902	return (0);
903}
904
905static inline int
906stats_voistat_fetch_u32(struct statsblob *sb, int32_t voi_id,
907    enum voi_stype stype, uint32_t *ret)
908{
909	struct voistatdata *vsd;
910	enum vsd_dtype vs_dtype;
911	int error;
912
913	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
914	    NULL)))
915		return (error);
916	else if (VSD_DTYPE_INT_U32 != vs_dtype)
917		return (EFTYPE);
918
919	*ret = vsd->int32.u32;
920	return (0);
921}
922
923static inline int
924stats_voistat_fetch_slong(struct statsblob *sb, int32_t voi_id,
925    enum voi_stype stype, long *ret)
926{
927	struct voistatdata *vsd;
928	enum vsd_dtype vs_dtype;
929	int error;
930
931	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
932	    NULL)))
933		return (error);
934	else if (VSD_DTYPE_INT_SLONG != vs_dtype)
935		return (EFTYPE);
936
937	*ret = vsd->intlong.slong;
938	return (0);
939}
940
941static inline int
942stats_voistat_fetch_ulong(struct statsblob *sb, int32_t voi_id,
943    enum voi_stype stype, unsigned long *ret)
944{
945	struct voistatdata *vsd;
946	enum vsd_dtype vs_dtype;
947	int error;
948
949	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
950	    NULL)))
951		return (error);
952	else if (VSD_DTYPE_INT_ULONG != vs_dtype)
953		return (EFTYPE);
954
955	*ret = vsd->intlong.ulong;
956	return (0);
957}
958
959static inline int
960stats_blob_snapshot(struct statsblob **dst, size_t dstmaxsz,
961    struct statsblob *src, uint32_t flags)
962{
963
964	return (stats_v1_blob_snapshot((struct statsblobv1 **)dst, dstmaxsz,
965	    (struct statsblobv1 *)src, flags));
966}
967
968static inline int
969stats_voi_update_abs_s32(struct statsblob *sb, int32_t voi_id, int32_t voival)
970{
971
972	if (sb == NULL)
973		return (0);
974
975	struct voistatdata tmp;
976	tmp.int32.s32 = voival;
977
978	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
979	    VSD_DTYPE_INT_S32, &tmp, 0));
980}
981
982static inline int
983stats_voi_update_rel_s32(struct statsblob *sb, int32_t voi_id, int32_t voival)
984{
985
986	if (sb == NULL)
987		return (0);
988
989	struct voistatdata tmp;
990	tmp.int32.s32 = voival;
991
992	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
993	    VSD_DTYPE_INT_S32, &tmp, SB_VOI_RELUPDATE));
994}
995
996static inline int
997stats_voi_update_abs_u32(struct statsblob *sb, int32_t voi_id, uint32_t voival)
998{
999
1000	if (sb == NULL)
1001		return (0);
1002
1003	struct voistatdata tmp;
1004	tmp.int32.u32 = voival;
1005
1006	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1007	    VSD_DTYPE_INT_U32, &tmp, 0));
1008}
1009
1010static inline int
1011stats_voi_update_rel_u32(struct statsblob *sb, int32_t voi_id, uint32_t voival)
1012{
1013
1014	if (sb == NULL)
1015		return (0);
1016
1017	struct voistatdata tmp;
1018	tmp.int32.u32 = voival;
1019
1020	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1021	    VSD_DTYPE_INT_U32, &tmp, SB_VOI_RELUPDATE));
1022}
1023
1024static inline int
1025stats_voi_update_abs_s64(struct statsblob *sb, int32_t voi_id, int64_t voival)
1026{
1027
1028	if (sb == NULL)
1029		return (0);
1030
1031	struct voistatdata tmp;
1032	tmp.int64.s64 = voival;
1033
1034	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1035	    VSD_DTYPE_INT_S64, &tmp, 0));
1036}
1037
1038static inline int
1039stats_voi_update_rel_s64(struct statsblob *sb, int32_t voi_id, int64_t voival)
1040{
1041
1042	if (sb == NULL)
1043		return (0);
1044
1045	struct voistatdata tmp;
1046	tmp.int64.s64 = voival;
1047
1048	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1049	    VSD_DTYPE_INT_S64, &tmp, SB_VOI_RELUPDATE));
1050}
1051
1052static inline int
1053stats_voi_update_abs_u64(struct statsblob *sb, int32_t voi_id, uint64_t voival)
1054{
1055
1056	if (sb == NULL)
1057		return (0);
1058
1059	struct voistatdata tmp;
1060	tmp.int64.u64 = voival;
1061
1062	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1063	    VSD_DTYPE_INT_U64, &tmp, 0));
1064}
1065
1066static inline int
1067stats_voi_update_rel_u64(struct statsblob *sb, int32_t voi_id, uint64_t voival)
1068{
1069
1070	if (sb == NULL)
1071		return (0);
1072
1073	struct voistatdata tmp;
1074	tmp.int64.u64 = voival;
1075
1076	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1077	    VSD_DTYPE_INT_U64, &tmp, SB_VOI_RELUPDATE));
1078}
1079
1080static inline int
1081stats_voi_update_abs_slong(struct statsblob *sb, int32_t voi_id, long voival)
1082{
1083
1084	if (sb == NULL)
1085		return (0);
1086
1087	struct voistatdata tmp;
1088	tmp.intlong.slong = voival;
1089
1090	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1091	    VSD_DTYPE_INT_SLONG, &tmp, 0));
1092}
1093
1094static inline int
1095stats_voi_update_rel_slong(struct statsblob *sb, int32_t voi_id, long voival)
1096{
1097
1098	if (sb == NULL)
1099		return (0);
1100
1101	struct voistatdata tmp;
1102	tmp.intlong.slong = voival;
1103
1104	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1105	    VSD_DTYPE_INT_SLONG, &tmp, SB_VOI_RELUPDATE));
1106}
1107
1108static inline int
1109stats_voi_update_abs_ulong(struct statsblob *sb, int32_t voi_id,
1110    unsigned long voival)
1111{
1112
1113	if (sb == NULL)
1114		return (0);
1115
1116	struct voistatdata tmp;
1117	tmp.intlong.ulong = voival;
1118
1119	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1120	    VSD_DTYPE_INT_ULONG, &tmp, 0));
1121}
1122
1123static inline int
1124stats_voi_update_rel_ulong(struct statsblob *sb, int32_t voi_id,
1125    unsigned long voival)
1126{
1127
1128	if (sb == NULL)
1129		return (0);
1130
1131	struct voistatdata tmp;
1132	tmp.intlong.ulong = voival;
1133
1134	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1135	    VSD_DTYPE_INT_ULONG, &tmp, SB_VOI_RELUPDATE));
1136}
1137
1138static inline int
1139stats_voi_update_abs_sq32(struct statsblob *sb, int32_t voi_id, s32q_t voival)
1140{
1141
1142	if (sb == NULL)
1143		return (0);
1144
1145	struct voistatdata tmp;
1146	tmp.q32.sq32 = voival;
1147
1148	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1149	    VSD_DTYPE_Q_S32, &tmp, 0));
1150}
1151
1152static inline int
1153stats_voi_update_rel_sq32(struct statsblob *sb, int32_t voi_id, s32q_t voival)
1154{
1155
1156	if (sb == NULL)
1157		return (0);
1158
1159	struct voistatdata tmp;
1160	tmp.q32.sq32 = voival;
1161
1162	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1163	    VSD_DTYPE_Q_S32, &tmp, SB_VOI_RELUPDATE));
1164}
1165
1166static inline int
1167stats_voi_update_abs_uq32(struct statsblob *sb, int32_t voi_id, u32q_t voival)
1168{
1169
1170	if (sb == NULL)
1171		return (0);
1172
1173	struct voistatdata tmp;
1174	tmp.q32.uq32 = voival;
1175
1176	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1177	    VSD_DTYPE_Q_U32, &tmp, 0));
1178}
1179
1180static inline int
1181stats_voi_update_rel_uq32(struct statsblob *sb, int32_t voi_id, u32q_t voival)
1182{
1183
1184	if (sb == NULL)
1185		return (0);
1186
1187	struct voistatdata tmp;
1188	tmp.q32.uq32 = voival;
1189
1190	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1191	    VSD_DTYPE_Q_U32, &tmp, SB_VOI_RELUPDATE));
1192}
1193
1194static inline int
1195stats_voi_update_abs_sq64(struct statsblob *sb, int32_t voi_id, s64q_t voival)
1196{
1197
1198	if (sb == NULL)
1199		return (0);
1200
1201	struct voistatdata tmp;
1202	tmp.q64.sq64 = voival;
1203
1204	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1205	    VSD_DTYPE_Q_S64, &tmp, 0));
1206}
1207
1208static inline int
1209stats_voi_update_rel_sq64(struct statsblob *sb, int32_t voi_id, s64q_t voival)
1210{
1211
1212	if (sb == NULL)
1213		return (0);
1214
1215	struct voistatdata tmp;
1216	tmp.q64.sq64 = voival;
1217
1218	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1219	    VSD_DTYPE_Q_S64, &tmp, SB_VOI_RELUPDATE));
1220}
1221
1222static inline int
1223stats_voi_update_abs_uq64(struct statsblob *sb, int32_t voi_id, u64q_t voival)
1224{
1225
1226	if (sb == NULL)
1227		return (0);
1228
1229	struct voistatdata tmp;
1230	tmp.q64.uq64 = voival;
1231
1232	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1233	    VSD_DTYPE_Q_U64, &tmp, 0));
1234}
1235
1236static inline int
1237stats_voi_update_rel_uq64(struct statsblob *sb, int32_t voi_id, u64q_t voival)
1238{
1239
1240	if (sb == NULL)
1241		return (0);
1242
1243	struct voistatdata tmp;
1244	tmp.q64.uq64 = voival;
1245
1246	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1247	    VSD_DTYPE_Q_U64, &tmp, SB_VOI_RELUPDATE));
1248}
1249
1250/* End ABI agnostic functions. */
1251
1252#endif /* _SYS_STATS_H_ */
1253