xref: /xnu-12377.41.6/bsd/skywalk/core/skywalk_sysctl.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
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