1 /*
2 * Copyright (c) 2018-2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <skywalk/os_skywalk_private.h>
29
30 __attribute__((always_inline))
31 static inline struct sysctl_oid *
_skoid_oid_alloc(void)32 _skoid_oid_alloc(void)
33 {
34 return sk_alloc_type(struct sysctl_oid, Z_WAITOK | Z_NOFAIL, skmem_tag_oid);
35 }
36
37 __attribute__((always_inline))
38 static inline void
_skoid_oid_free(struct sysctl_oid * oid)39 _skoid_oid_free(struct sysctl_oid *oid)
40 {
41 sk_free_type(struct sysctl_oid, oid);
42 }
43
44 __attribute__((always_inline))
45 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)46 _skoid_oid_init(struct skoid *skoid, struct sysctl_oid *oid,
47 struct sysctl_oid_list *parent, int kind, void *arg1, int arg2,
48 const char *name, int (*handler)SYSCTL_HANDLER_ARGS, const char *fmt)
49 {
50 const char *__null_terminated sko_name = NULL;
51 ASSERT(oid != NULL);
52 /*
53 * Note here we use OID2 for current version, which does oid alloc/free
54 * ourselves with mcache
55 */
56 oid->oid_link.sle_next = NULL;
57 oid->oid_parent = parent;
58 oid->oid_number = OID_AUTO;
59 oid->oid_kind = CTLFLAG_OID2 | kind;
60 oid->oid_arg1 = arg1;
61 oid->oid_arg2 = arg2;
62 if (&skoid->sko_oid == oid) {
63 /* for DNODE, store its name inside skoid */
64 sko_name = tsnprintf(skoid->sko_name, sizeof(skoid->sko_name),
65 "%s", name);
66 oid->oid_name = sko_name;
67 } else {
68 /* for leaf property, use static name string */
69 oid->oid_name = name;
70 }
71 oid->oid_handler = handler;
72 oid->oid_fmt = fmt;
73 oid->oid_descr = ""; /* unused for current SYSCTL_OID_VERSION */
74 oid->oid_version = SYSCTL_OID_VERSION;
75 oid->oid_refcnt = 0;
76 }
77
78 /*
79 * Create the skoid and register its sysctl_oid.
80 */
81 void
skoid_create(struct skoid * skoid,struct sysctl_oid_list * parent,const char * name,int kind)82 skoid_create(struct skoid *skoid, struct sysctl_oid_list *parent,
83 const char *name, int kind)
84 {
85 struct sysctl_oid *oid = &skoid->sko_oid;
86
87 _skoid_oid_init(skoid, oid, parent,
88 CTLTYPE_NODE | CTLFLAG_LOCKED | kind,
89 &skoid->sko_oid_list, 0, name, NULL, "N");
90 sysctl_register_oid(oid);
91 }
92
93 __attribute__((always_inline))
94 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)95 _skoid_add_property(struct skoid *skoid, const char *name, int kind,
96 const char *fmt, void *arg1, int arg2, int (*handler)SYSCTL_HANDLER_ARGS)
97 {
98 struct sysctl_oid *oid;
99
100 oid = _skoid_oid_alloc();
101 _skoid_oid_init(skoid, oid, &skoid->sko_oid_list, CTLFLAG_LOCKED | kind,
102 arg1, arg2, name, handler, fmt);
103 sysctl_register_oid(oid);
104 }
105
106 /*
107 * Add int property to skoid.
108 */
109 void
skoid_add_int(struct skoid * skoid,const char * name,int kind,int * int_ptr)110 skoid_add_int(struct skoid *skoid, const char *name, int kind,
111 int *int_ptr)
112 {
113 _skoid_add_property(skoid, name, CTLTYPE_INT | kind, "I", int_ptr, 0,
114 sysctl_handle_int);
115 }
116
117 /*
118 * Add unsigned int property to skoid.
119 */
120 void
skoid_add_uint(struct skoid * skoid,const char * name,int kind,unsigned int * uint_ptr)121 skoid_add_uint(struct skoid *skoid, const char *name, int kind,
122 unsigned int *uint_ptr)
123 {
124 _skoid_add_property(skoid, name, CTLTYPE_INT | kind, "IU", uint_ptr, 0,
125 sysctl_handle_int);
126 }
127
128 /*
129 * Add procedure handler property to skoid.
130 */
131 void
skoid_add_handler(struct skoid * skoid,const char * name,int kind,int (* proc)SYSCTL_HANDLER_ARGS,void * proc_arg1,int proc_arg2)132 skoid_add_handler(struct skoid *skoid, const char *name, int kind,
133 int (*proc)SYSCTL_HANDLER_ARGS, void *proc_arg1, int proc_arg2)
134 {
135 _skoid_add_property(skoid, name, CTLTYPE_INT | kind, "I", proc_arg1,
136 proc_arg2, proc);
137 }
138
139 /*
140 * Destroy skoid and its associated properties
141 *
142 * @discussion This functions only handles properties associated with it and
143 * the unregistration of the sysctl_oid. If skoid itself is dynamically
144 * allocated, it's the caller who should release skoid object.
145 */
146 void
skoid_destroy(struct skoid * skoid)147 skoid_destroy(struct skoid *skoid)
148 {
149 /*
150 * first take down parent sysctl node, which internally deletes it from
151 * sko_oid_list, so we don't free it below
152 */
153 sysctl_unregister_oid(&skoid->sko_oid);
154
155 /* then destroy all properties sysctl nodes */
156 struct sysctl_oid *oid, *oid_tmp;
157 SLIST_FOREACH_SAFE(oid, &skoid->sko_oid_list, oid_link, oid_tmp) {
158 /* sub dynamic node must be destroyed first */
159 if ((oid->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
160 panic("leaked skoid sub-node detected %p %s",
161 oid, oid->oid_name);
162 __builtin_unreachable();
163 }
164 sysctl_unregister_oid(oid);
165 ASSERT(oid != &skoid->sko_oid);
166 _skoid_oid_free(oid);
167 }
168 }
169