/* * Copyright (c) 2018-2021 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include __attribute__((always_inline)) static inline struct sysctl_oid * _skoid_oid_alloc(void) { return sk_alloc_type(struct sysctl_oid, Z_WAITOK | Z_NOFAIL, skmem_tag_oid); } __attribute__((always_inline)) static inline void _skoid_oid_free(struct sysctl_oid *oid) { sk_free_type(struct sysctl_oid, oid); } __attribute__((always_inline)) static inline void _skoid_oid_init(struct skoid *skoid, struct sysctl_oid *oid, struct sysctl_oid_list *parent, int kind, void *arg1, int arg2, const char *name, int (*handler)SYSCTL_HANDLER_ARGS, const char *fmt) { const char *__null_terminated sko_name = NULL; ASSERT(oid != NULL); /* * Note here we use OID2 for current version, which does oid alloc/free * ourselves with mcache */ oid->oid_link.sle_next = NULL; oid->oid_parent = parent; oid->oid_number = OID_AUTO; oid->oid_kind = CTLFLAG_OID2 | kind; oid->oid_arg1 = arg1; oid->oid_arg2 = arg2; if (&skoid->sko_oid == oid) { /* for DNODE, store its name inside skoid */ sko_name = tsnprintf(skoid->sko_name, sizeof(skoid->sko_name), "%s", name); oid->oid_name = sko_name; } else { /* for leaf property, use static name string */ oid->oid_name = name; } oid->oid_handler = handler; oid->oid_fmt = fmt; oid->oid_descr = ""; /* unused for current SYSCTL_OID_VERSION */ oid->oid_version = SYSCTL_OID_VERSION; oid->oid_refcnt = 0; } /* * Create the skoid and register its sysctl_oid. */ void skoid_create(struct skoid *skoid, struct sysctl_oid_list *parent, const char *name, int kind) { struct sysctl_oid *oid = &skoid->sko_oid; _skoid_oid_init(skoid, oid, parent, CTLTYPE_NODE | CTLFLAG_LOCKED | kind, &skoid->sko_oid_list, 0, name, NULL, "N"); sysctl_register_oid(oid); } __attribute__((always_inline)) static inline void _skoid_add_property(struct skoid *skoid, const char *name, int kind, const char *fmt, void *arg1, int arg2, int (*handler)SYSCTL_HANDLER_ARGS) { struct sysctl_oid *oid; oid = _skoid_oid_alloc(); _skoid_oid_init(skoid, oid, &skoid->sko_oid_list, CTLFLAG_LOCKED | kind, arg1, arg2, name, handler, fmt); sysctl_register_oid(oid); } /* * Add int property to skoid. */ void skoid_add_int(struct skoid *skoid, const char *name, int kind, int *int_ptr) { _skoid_add_property(skoid, name, CTLTYPE_INT | kind, "I", int_ptr, 0, sysctl_handle_int); } /* * Add unsigned int property to skoid. */ void skoid_add_uint(struct skoid *skoid, const char *name, int kind, unsigned int *uint_ptr) { _skoid_add_property(skoid, name, CTLTYPE_INT | kind, "IU", uint_ptr, 0, sysctl_handle_int); } /* * Add procedure handler property to skoid. */ void skoid_add_handler(struct skoid *skoid, const char *name, int kind, int (*proc)SYSCTL_HANDLER_ARGS, void *proc_arg1, int proc_arg2) { _skoid_add_property(skoid, name, CTLTYPE_INT | kind, "I", proc_arg1, proc_arg2, proc); } /* * Destroy skoid and its associated properties * * @discussion This functions only handles properties associated with it and * the unregistration of the sysctl_oid. If skoid itself is dynamically * allocated, it's the caller who should release skoid object. */ void skoid_destroy(struct skoid *skoid) { /* * first take down parent sysctl node, which internally deletes it from * sko_oid_list, so we don't free it below */ sysctl_unregister_oid(&skoid->sko_oid); /* then destroy all properties sysctl nodes */ struct sysctl_oid *oid, *oid_tmp; SLIST_FOREACH_SAFE(oid, &skoid->sko_oid_list, oid_link, oid_tmp) { /* sub dynamic node must be destroyed first */ if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) { panic("leaked skoid sub-node detected %p %s", oid, oid->oid_name); __builtin_unreachable(); } sysctl_unregister_oid(oid); ASSERT(oid != &skoid->sko_oid); _skoid_oid_free(oid); } }