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_ */