1 1.2 andvar /* $NetBSD: simplehook_tester.c,v 1.2 2022/04/10 09:50:46 andvar Exp $ */ 2 1.1 yamaguch /* 3 1.1 yamaguch * Copyright (c) 2021 Internet Initiative Japan Inc. 4 1.1 yamaguch * All rights reserved. 5 1.1 yamaguch * 6 1.1 yamaguch * Redistribution and use in source and binary forms, with or without 7 1.1 yamaguch * modification, are permitted provided that the following conditions 8 1.1 yamaguch * are met: 9 1.1 yamaguch * 1. Redistributions of source code must retain the above copyright 10 1.1 yamaguch * notice, this list of conditions and the following disclaimer. 11 1.1 yamaguch * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 yamaguch * notice, this list of conditions and the following disclaimer in the 13 1.1 yamaguch * documentation and/or other materials provided with the distribution. 14 1.1 yamaguch * 15 1.1 yamaguch * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 1.1 yamaguch * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 1.1 yamaguch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 1.1 yamaguch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 1.1 yamaguch * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 1.1 yamaguch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 1.1 yamaguch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 1.1 yamaguch * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 1.1 yamaguch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 1.1 yamaguch * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 1.1 yamaguch * POSSIBILITY OF SUCH DAMAGE. 26 1.1 yamaguch */ 27 1.1 yamaguch 28 1.1 yamaguch #include <sys/cdefs.h> 29 1.2 andvar __KERNEL_RCSID(0, "$NetBSD: simplehook_tester.c,v 1.2 2022/04/10 09:50:46 andvar Exp $"); 30 1.1 yamaguch 31 1.1 yamaguch #include <sys/param.h> 32 1.1 yamaguch 33 1.1 yamaguch #include <sys/condvar.h> 34 1.1 yamaguch #include <sys/hook.h> 35 1.1 yamaguch #include <sys/module.h> 36 1.1 yamaguch #include <sys/mutex.h> 37 1.1 yamaguch #include <sys/sysctl.h> 38 1.1 yamaguch #include <sys/workqueue.h> 39 1.1 yamaguch 40 1.1 yamaguch #ifdef SIMPLEHOOK_TESTER_DEBUG 41 1.1 yamaguch #define HK_DPRINTF(a) printf a 42 1.1 yamaguch #else 43 1.1 yamaguch #define HK_DPRINTF(a) __nothing 44 1.1 yamaguch #endif 45 1.1 yamaguch 46 1.1 yamaguch MODULE(MODULE_CLASS_MISC, simplehook_tester, NULL); 47 1.1 yamaguch extern int simplehook_tester_init(void); 48 1.1 yamaguch struct tester_context; 49 1.1 yamaguch 50 1.1 yamaguch struct tester_hook { 51 1.1 yamaguch struct tester_context *th_ctx; 52 1.1 yamaguch khook_t *th_hook; 53 1.1 yamaguch size_t th_idx; 54 1.1 yamaguch int th_count; 55 1.1 yamaguch bool th_stopping; 56 1.1 yamaguch bool th_stopped; 57 1.1 yamaguch bool th_disestablish; 58 1.1 yamaguch }; 59 1.1 yamaguch 60 1.1 yamaguch static struct tester_context { 61 1.1 yamaguch kmutex_t ctx_mutex; 62 1.1 yamaguch kcondvar_t ctx_cv; 63 1.1 yamaguch struct sysctllog *ctx_sysctllog; 64 1.1 yamaguch struct workqueue *ctx_wq; 65 1.1 yamaguch struct work ctx_wk; 66 1.1 yamaguch bool ctx_wk_enqueued; 67 1.1 yamaguch bool ctx_wk_waiting; 68 1.1 yamaguch 69 1.1 yamaguch khook_list_t *ctx_hooks; 70 1.1 yamaguch struct tester_hook ctx_hook[2]; 71 1.1 yamaguch 72 1.1 yamaguch khook_t *ctx_nbhook; 73 1.1 yamaguch } tester_ctx; 74 1.1 yamaguch 75 1.1 yamaguch static int 76 1.1 yamaguch simplehook_tester_created(SYSCTLFN_ARGS) 77 1.1 yamaguch { 78 1.1 yamaguch struct sysctlnode node; 79 1.1 yamaguch struct tester_context *ctx; 80 1.1 yamaguch int error, val; 81 1.1 yamaguch size_t i; 82 1.1 yamaguch 83 1.1 yamaguch node = *rnode; 84 1.1 yamaguch ctx = node.sysctl_data; 85 1.1 yamaguch 86 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 87 1.1 yamaguch val = ctx->ctx_hooks != NULL ? 1 : 0; 88 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 89 1.1 yamaguch 90 1.1 yamaguch node.sysctl_data = &val; 91 1.1 yamaguch node.sysctl_size = sizeof(val); 92 1.1 yamaguch 93 1.1 yamaguch error = sysctl_lookup(SYSCTLFN_CALL(&node)); 94 1.1 yamaguch if (error || newp == NULL) 95 1.1 yamaguch return error; 96 1.1 yamaguch 97 1.1 yamaguch if (val != 0 && val != 1) 98 1.1 yamaguch return EINVAL; 99 1.1 yamaguch 100 1.1 yamaguch error = 0; 101 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 102 1.1 yamaguch if (val == 1) { 103 1.1 yamaguch if (ctx->ctx_hooks != NULL) { 104 1.1 yamaguch error = EEXIST; 105 1.1 yamaguch } else { 106 1.1 yamaguch HK_DPRINTF(("[%s, %d]: create hook list\n", 107 1.1 yamaguch __func__, __LINE__)); 108 1.1 yamaguch ctx->ctx_hooks = simplehook_create(IPL_NONE, 109 1.1 yamaguch "tester hooks"); 110 1.1 yamaguch KASSERT(ctx->ctx_hooks != NULL); 111 1.1 yamaguch } 112 1.1 yamaguch } else { 113 1.1 yamaguch if (ctx->ctx_hooks == NULL) { 114 1.1 yamaguch error = ENXIO; 115 1.1 yamaguch } else if (ctx->ctx_wk_waiting) { 116 1.1 yamaguch error = EBUSY; 117 1.1 yamaguch } else { 118 1.1 yamaguch ctx->ctx_wk_waiting = true; 119 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 120 1.1 yamaguch 121 1.1 yamaguch workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk); 122 1.1 yamaguch 123 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 124 1.1 yamaguch ctx->ctx_wk_waiting = false; 125 1.1 yamaguch 126 1.1 yamaguch HK_DPRINTF(("[%s, %d]: destroy hook list\n", 127 1.1 yamaguch __func__, __LINE__)); 128 1.1 yamaguch simplehook_destroy(ctx->ctx_hooks); 129 1.1 yamaguch ctx->ctx_hooks = NULL; 130 1.1 yamaguch ctx->ctx_nbhook = NULL; 131 1.1 yamaguch for (i = 0; i < __arraycount(ctx->ctx_hook); i++) { 132 1.1 yamaguch ctx->ctx_hook[i].th_hook = NULL; 133 1.1 yamaguch } 134 1.1 yamaguch } 135 1.1 yamaguch } 136 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 137 1.1 yamaguch 138 1.1 yamaguch return error; 139 1.1 yamaguch } 140 1.1 yamaguch 141 1.1 yamaguch static void 142 1.1 yamaguch simplehook_tester_work(struct work *wk, void *xctx) 143 1.1 yamaguch { 144 1.1 yamaguch struct tester_context *ctx; 145 1.1 yamaguch 146 1.1 yamaguch ctx = xctx; 147 1.1 yamaguch 148 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 149 1.1 yamaguch ctx->ctx_wk_enqueued = false; 150 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 151 1.1 yamaguch 152 1.1 yamaguch simplehook_dohooks(ctx->ctx_hooks); 153 1.1 yamaguch } 154 1.1 yamaguch 155 1.1 yamaguch static int 156 1.1 yamaguch simplehook_tester_dohooks(SYSCTLFN_ARGS) 157 1.1 yamaguch { 158 1.1 yamaguch struct sysctlnode node; 159 1.1 yamaguch struct tester_context *ctx; 160 1.1 yamaguch int error, val; 161 1.1 yamaguch 162 1.1 yamaguch node = *rnode; 163 1.1 yamaguch ctx = node.sysctl_data; 164 1.1 yamaguch 165 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 166 1.1 yamaguch val = ctx->ctx_wk_enqueued ? 1 : 0; 167 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 168 1.1 yamaguch 169 1.1 yamaguch node.sysctl_data = &val; 170 1.1 yamaguch node.sysctl_size = sizeof(val); 171 1.1 yamaguch 172 1.1 yamaguch error = sysctl_lookup(SYSCTLFN_CALL(&node)); 173 1.1 yamaguch if (error || newp == NULL) 174 1.1 yamaguch return error; 175 1.1 yamaguch 176 1.1 yamaguch if (val != 0 && val != 1) 177 1.1 yamaguch return EINVAL; 178 1.1 yamaguch 179 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 180 1.1 yamaguch if (val == 1) { 181 1.1 yamaguch if (ctx->ctx_wk_enqueued) { 182 1.1 yamaguch error = EEXIST; 183 1.1 yamaguch } else if (ctx->ctx_wk_waiting) { 184 1.1 yamaguch error = EBUSY; 185 1.1 yamaguch } else if (ctx->ctx_hooks == NULL) { 186 1.1 yamaguch error = ENXIO; 187 1.1 yamaguch } else { 188 1.1 yamaguch HK_DPRINTF(("[%s, %d]: dohook\n", __func__, __LINE__)); 189 1.1 yamaguch ctx->ctx_wk_enqueued = true; 190 1.1 yamaguch workqueue_enqueue(ctx->ctx_wq, 191 1.1 yamaguch &ctx->ctx_wk, NULL); 192 1.1 yamaguch } 193 1.1 yamaguch } else { 194 1.1 yamaguch if (ctx->ctx_wk_waiting) { 195 1.1 yamaguch error = EBUSY; 196 1.1 yamaguch } else { 197 1.1 yamaguch ctx->ctx_wk_waiting = true; 198 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 199 1.1 yamaguch 200 1.1 yamaguch workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk); 201 1.1 yamaguch 202 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 203 1.1 yamaguch ctx->ctx_wk_waiting = false; 204 1.1 yamaguch } 205 1.1 yamaguch } 206 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 207 1.1 yamaguch 208 1.1 yamaguch return error; 209 1.1 yamaguch } 210 1.1 yamaguch 211 1.1 yamaguch static void 212 1.1 yamaguch simplehook_tester_hook(void *xth) 213 1.1 yamaguch { 214 1.1 yamaguch struct tester_context *ctx; 215 1.1 yamaguch struct tester_hook *th; 216 1.1 yamaguch 217 1.1 yamaguch th = xth; 218 1.1 yamaguch ctx = th->th_ctx; 219 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 220 1.1 yamaguch 221 1.1 yamaguch HK_DPRINTF(("[%s, %d]: hook%zu called\n", 222 1.1 yamaguch __func__, __LINE__, th->th_idx)); 223 1.1 yamaguch 224 1.1 yamaguch th->th_stopped = false; 225 1.1 yamaguch 226 1.1 yamaguch while (th->th_stopping) { 227 1.1 yamaguch HK_DPRINTF(("[%s, %d]: hook%zu stopping\n", 228 1.1 yamaguch __func__, __LINE__, th->th_idx)); 229 1.1 yamaguch th->th_stopped = true; 230 1.1 yamaguch cv_wait(&ctx->ctx_cv, &ctx->ctx_mutex); 231 1.1 yamaguch } 232 1.1 yamaguch 233 1.1 yamaguch if (th->th_stopped) { 234 1.1 yamaguch HK_DPRINTF(("[%s, %d]: hook%zu restart\n", 235 1.1 yamaguch __func__, __LINE__, th->th_idx)); 236 1.1 yamaguch th->th_stopped = false; 237 1.1 yamaguch } 238 1.1 yamaguch 239 1.1 yamaguch th->th_count++; 240 1.1 yamaguch 241 1.1 yamaguch if (th->th_disestablish && th->th_hook != NULL) { 242 1.2 andvar HK_DPRINTF(("[%s, %d]: disestablish running hook%zu\n", 243 1.1 yamaguch __func__, __LINE__, th->th_idx)); 244 1.1 yamaguch simplehook_disestablish(ctx->ctx_hooks, 245 1.1 yamaguch th->th_hook, &ctx->ctx_mutex); 246 1.1 yamaguch th->th_hook = NULL; 247 1.1 yamaguch } 248 1.1 yamaguch 249 1.1 yamaguch HK_DPRINTF(("[%s, %d]: hook%zu exit\n", 250 1.1 yamaguch __func__, __LINE__, th->th_idx)); 251 1.1 yamaguch 252 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 253 1.1 yamaguch } 254 1.1 yamaguch 255 1.1 yamaguch static void 256 1.1 yamaguch simplehook_tester_hook_nb(void *xctx) 257 1.1 yamaguch { 258 1.1 yamaguch 259 1.1 yamaguch HK_DPRINTF(("[%s, %d]: non-block hook called\n", 260 1.1 yamaguch __func__, __LINE__)); 261 1.1 yamaguch 262 1.1 yamaguch HK_DPRINTF(("[%s, %d]: sleep 1 sec\n", 263 1.1 yamaguch __func__, __LINE__)); 264 1.1 yamaguch kpause("smplhk_nb", true, 1 * hz, NULL); 265 1.1 yamaguch 266 1.1 yamaguch HK_DPRINTF(("[%s, %d]: non-block hook exit\n", 267 1.1 yamaguch __func__, __LINE__)); 268 1.1 yamaguch } 269 1.1 yamaguch 270 1.1 yamaguch static int 271 1.1 yamaguch simplehook_tester_established(SYSCTLFN_ARGS) 272 1.1 yamaguch { 273 1.1 yamaguch struct sysctlnode node; 274 1.1 yamaguch struct tester_context *ctx; 275 1.1 yamaguch struct tester_hook *th; 276 1.1 yamaguch int val, error; 277 1.1 yamaguch 278 1.1 yamaguch node = *rnode; 279 1.1 yamaguch th = node.sysctl_data; 280 1.1 yamaguch ctx = th->th_ctx; 281 1.1 yamaguch 282 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 283 1.1 yamaguch val = th->th_hook == NULL ? 0 : 1; 284 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 285 1.1 yamaguch 286 1.1 yamaguch node.sysctl_data = &val; 287 1.1 yamaguch node.sysctl_size = sizeof(val); 288 1.1 yamaguch 289 1.1 yamaguch error = sysctl_lookup(SYSCTLFN_CALL(&node)); 290 1.1 yamaguch if (error || newp == NULL) 291 1.1 yamaguch return error; 292 1.1 yamaguch 293 1.1 yamaguch error = 0; 294 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 295 1.1 yamaguch 296 1.1 yamaguch if (val == 1) { 297 1.1 yamaguch if (th->th_hook != NULL) { 298 1.1 yamaguch error = EEXIST; 299 1.1 yamaguch } else { 300 1.1 yamaguch th->th_hook = simplehook_establish(ctx->ctx_hooks, 301 1.1 yamaguch simplehook_tester_hook, th); 302 1.1 yamaguch KASSERT(th->th_hook != NULL); 303 1.1 yamaguch HK_DPRINTF(("[%s, %d]: established hook%zu (%p)\n", 304 1.1 yamaguch __func__, __LINE__, th->th_idx, th->th_hook)); 305 1.1 yamaguch } 306 1.1 yamaguch } else { 307 1.1 yamaguch if (th->th_hook == NULL) { 308 1.1 yamaguch error = ENXIO; 309 1.1 yamaguch } else { 310 1.1 yamaguch bool stopped = false; 311 1.1 yamaguch if (th->th_stopping) { 312 1.1 yamaguch HK_DPRINTF(("[%s, %d]: stopping = false\n", 313 1.1 yamaguch __func__, __LINE__)); 314 1.1 yamaguch th->th_stopping = false; 315 1.1 yamaguch cv_broadcast(&ctx->ctx_cv); 316 1.1 yamaguch stopped = true; 317 1.1 yamaguch } 318 1.1 yamaguch HK_DPRINTF(("[%s, %d]: disestablish hook%zu (%p)\n", 319 1.1 yamaguch __func__, __LINE__, th->th_idx, th->th_hook)); 320 1.1 yamaguch simplehook_disestablish(ctx->ctx_hooks, 321 1.1 yamaguch th->th_hook, &ctx->ctx_mutex); 322 1.1 yamaguch th->th_hook = NULL; 323 1.1 yamaguch if (stopped) { 324 1.1 yamaguch HK_DPRINTF(("[%s, %d]: disestablished hook%zu\n", 325 1.1 yamaguch __func__, __LINE__, th->th_idx)); 326 1.1 yamaguch } 327 1.1 yamaguch } 328 1.1 yamaguch } 329 1.1 yamaguch 330 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 331 1.1 yamaguch 332 1.1 yamaguch return error; 333 1.1 yamaguch } 334 1.1 yamaguch 335 1.1 yamaguch static int 336 1.1 yamaguch simplehook_tester_established_nb(SYSCTLFN_ARGS) 337 1.1 yamaguch { 338 1.1 yamaguch struct sysctlnode node; 339 1.1 yamaguch struct tester_context *ctx; 340 1.1 yamaguch int val, error; 341 1.1 yamaguch 342 1.1 yamaguch node = *rnode; 343 1.1 yamaguch ctx = node.sysctl_data; 344 1.1 yamaguch 345 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 346 1.1 yamaguch val = ctx->ctx_nbhook == NULL ? 0 : 1; 347 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 348 1.1 yamaguch 349 1.1 yamaguch node.sysctl_data = &val; 350 1.1 yamaguch node.sysctl_size = sizeof(val); 351 1.1 yamaguch 352 1.1 yamaguch error = sysctl_lookup(SYSCTLFN_CALL(&node)); 353 1.1 yamaguch if (error || newp == NULL) 354 1.1 yamaguch return error; 355 1.1 yamaguch 356 1.1 yamaguch error = 0; 357 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 358 1.1 yamaguch 359 1.1 yamaguch if (val == 1) { 360 1.1 yamaguch if (ctx->ctx_nbhook != NULL) { 361 1.1 yamaguch error = EEXIST; 362 1.1 yamaguch } else { 363 1.1 yamaguch ctx->ctx_nbhook = simplehook_establish(ctx->ctx_hooks, 364 1.1 yamaguch simplehook_tester_hook_nb, ctx); 365 1.1 yamaguch KASSERT(ctx->ctx_nbhook != NULL); 366 1.1 yamaguch HK_DPRINTF(("[%s, %d]: established nbhook (%p)\n", 367 1.1 yamaguch __func__, __LINE__, ctx->ctx_nbhook)); 368 1.1 yamaguch } 369 1.1 yamaguch } else { 370 1.1 yamaguch if (ctx->ctx_nbhook == NULL) { 371 1.1 yamaguch error = ENXIO; 372 1.1 yamaguch } else { 373 1.1 yamaguch HK_DPRINTF(("[%s, %d]: disestablish nbhook (%p)\n", 374 1.1 yamaguch __func__, __LINE__, ctx->ctx_nbhook)); 375 1.1 yamaguch simplehook_disestablish(ctx->ctx_hooks, 376 1.1 yamaguch ctx->ctx_nbhook, NULL); 377 1.1 yamaguch ctx->ctx_nbhook = NULL; 378 1.1 yamaguch HK_DPRINTF(("[%s, %d]: disestablished\n", 379 1.1 yamaguch __func__, __LINE__)); 380 1.1 yamaguch } 381 1.1 yamaguch } 382 1.1 yamaguch 383 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 384 1.1 yamaguch 385 1.1 yamaguch return error; 386 1.1 yamaguch } 387 1.1 yamaguch 388 1.1 yamaguch static int 389 1.1 yamaguch simplehook_tester_stopping(SYSCTLFN_ARGS) 390 1.1 yamaguch { 391 1.1 yamaguch struct sysctlnode node; 392 1.1 yamaguch struct tester_context *ctx; 393 1.1 yamaguch struct tester_hook *th; 394 1.1 yamaguch int error; 395 1.1 yamaguch bool val; 396 1.1 yamaguch 397 1.1 yamaguch node = *rnode; 398 1.1 yamaguch th = node.sysctl_data; 399 1.1 yamaguch ctx = th->th_ctx; 400 1.1 yamaguch 401 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 402 1.1 yamaguch val = th->th_stopping; 403 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 404 1.1 yamaguch 405 1.1 yamaguch node.sysctl_data = &val; 406 1.1 yamaguch node.sysctl_size = sizeof(val); 407 1.1 yamaguch 408 1.1 yamaguch error = sysctl_lookup(SYSCTLFN_CALL(&node)); 409 1.1 yamaguch if (error || newp == NULL) 410 1.1 yamaguch return error; 411 1.1 yamaguch 412 1.1 yamaguch error = 0; 413 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 414 1.1 yamaguch if (val == true && !th->th_stopping) { 415 1.1 yamaguch th->th_stopping = true; 416 1.1 yamaguch } else if (val == false && th->th_stopping) { 417 1.1 yamaguch th->th_stopping = false; 418 1.1 yamaguch cv_broadcast(&ctx->ctx_cv); 419 1.1 yamaguch } 420 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 421 1.1 yamaguch 422 1.1 yamaguch return error; 423 1.1 yamaguch } 424 1.1 yamaguch 425 1.1 yamaguch static int 426 1.1 yamaguch simplehook_tester_stopped(SYSCTLFN_ARGS) 427 1.1 yamaguch { 428 1.1 yamaguch struct sysctlnode node; 429 1.1 yamaguch struct tester_context *ctx; 430 1.1 yamaguch struct tester_hook *th; 431 1.1 yamaguch bool val; 432 1.1 yamaguch 433 1.1 yamaguch node = *rnode; 434 1.1 yamaguch th = node.sysctl_data; 435 1.1 yamaguch ctx = th->th_ctx; 436 1.1 yamaguch 437 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 438 1.1 yamaguch val = th->th_stopped; 439 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 440 1.1 yamaguch 441 1.1 yamaguch node.sysctl_data = &val; 442 1.1 yamaguch node.sysctl_size = sizeof(val); 443 1.1 yamaguch 444 1.1 yamaguch return sysctl_lookup(SYSCTLFN_CALL(&node)); 445 1.1 yamaguch } 446 1.1 yamaguch 447 1.1 yamaguch static int 448 1.1 yamaguch simplehook_tester_disestablish(SYSCTLFN_ARGS) 449 1.1 yamaguch { 450 1.1 yamaguch struct sysctlnode node; 451 1.1 yamaguch struct tester_context *ctx; 452 1.1 yamaguch struct tester_hook *th; 453 1.1 yamaguch int error; 454 1.1 yamaguch bool val; 455 1.1 yamaguch 456 1.1 yamaguch node = *rnode; 457 1.1 yamaguch th = node.sysctl_data; 458 1.1 yamaguch ctx = th->th_ctx; 459 1.1 yamaguch 460 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 461 1.1 yamaguch val = th->th_disestablish; 462 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 463 1.1 yamaguch 464 1.1 yamaguch node.sysctl_data = &val; 465 1.1 yamaguch node.sysctl_size = sizeof(val); 466 1.1 yamaguch 467 1.1 yamaguch error = sysctl_lookup(SYSCTLFN_CALL(&node)); 468 1.1 yamaguch if (error || newp == NULL) 469 1.1 yamaguch return error; 470 1.1 yamaguch 471 1.1 yamaguch if (val != 0 && val != 1) 472 1.1 yamaguch return EINVAL; 473 1.1 yamaguch 474 1.1 yamaguch error = 0; 475 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 476 1.1 yamaguch if (val == true && !th->th_disestablish) { 477 1.1 yamaguch th->th_disestablish = true; 478 1.1 yamaguch } else if (val == false && th->th_disestablish) { 479 1.1 yamaguch th->th_disestablish = false; 480 1.1 yamaguch } 481 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 482 1.1 yamaguch 483 1.1 yamaguch return 0; 484 1.1 yamaguch } 485 1.1 yamaguch 486 1.1 yamaguch static int 487 1.1 yamaguch simplehook_tester_count(SYSCTLFN_ARGS) 488 1.1 yamaguch { 489 1.1 yamaguch struct sysctlnode node; 490 1.1 yamaguch struct tester_context *ctx; 491 1.1 yamaguch struct tester_hook *th; 492 1.1 yamaguch int error, val; 493 1.1 yamaguch 494 1.1 yamaguch node = *rnode; 495 1.1 yamaguch th = node.sysctl_data; 496 1.1 yamaguch ctx = th->th_ctx; 497 1.1 yamaguch 498 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 499 1.1 yamaguch val = th->th_count; 500 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 501 1.1 yamaguch 502 1.1 yamaguch node.sysctl_data = &val; 503 1.1 yamaguch node.sysctl_size = sizeof(val); 504 1.1 yamaguch 505 1.1 yamaguch error = sysctl_lookup(SYSCTLFN_CALL(&node)); 506 1.1 yamaguch if (error || newp == NULL) 507 1.1 yamaguch return error; 508 1.1 yamaguch 509 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 510 1.1 yamaguch th->th_count = val; 511 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 512 1.1 yamaguch 513 1.1 yamaguch return 0; 514 1.1 yamaguch } 515 1.1 yamaguch 516 1.1 yamaguch static int 517 1.1 yamaguch simplehook_tester_create_sysctl(struct tester_context *ctx) 518 1.1 yamaguch { 519 1.1 yamaguch struct sysctllog **log; 520 1.1 yamaguch const struct sysctlnode *rnode, *cnode; 521 1.1 yamaguch void *ptr; 522 1.1 yamaguch char buf[32]; 523 1.1 yamaguch int error; 524 1.1 yamaguch size_t i; 525 1.1 yamaguch 526 1.1 yamaguch log = &ctx->ctx_sysctllog; 527 1.1 yamaguch ptr = (void *)ctx; 528 1.1 yamaguch 529 1.1 yamaguch error = sysctl_createv(log, 0, NULL, &rnode, CTLFLAG_PERMANENT, 530 1.1 yamaguch CTLTYPE_NODE, "simplehook_tester", 531 1.1 yamaguch SYSCTL_DESCR("simplehook testing interface"), 532 1.1 yamaguch NULL, 0, NULL, 0, CTL_KERN, CTL_CREATE, CTL_EOL); 533 1.1 yamaguch if (error != 0) 534 1.1 yamaguch goto bad; 535 1.1 yamaguch 536 1.1 yamaguch error = sysctl_createv(log, 0, &rnode, &cnode, 537 1.1 yamaguch CTLFLAG_PERMANENT, CTLTYPE_NODE, "hook_list", 538 1.1 yamaguch SYSCTL_DESCR("hook list"), NULL, 0, NULL, 0, 539 1.1 yamaguch CTL_CREATE, CTL_EOL); 540 1.1 yamaguch 541 1.1 yamaguch error = sysctl_createv(log, 0, &cnode, NULL, 542 1.1 yamaguch CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 543 1.1 yamaguch "created", SYSCTL_DESCR("create and destroy hook list"), 544 1.1 yamaguch simplehook_tester_created, 0, ptr, 0, 545 1.1 yamaguch CTL_CREATE, CTL_EOL); 546 1.1 yamaguch if (error != 0) 547 1.1 yamaguch goto bad; 548 1.1 yamaguch 549 1.1 yamaguch error = sysctl_createv(log, 0, &cnode, NULL, 550 1.1 yamaguch CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 551 1.1 yamaguch "dohooks", SYSCTL_DESCR("do hooks"), 552 1.1 yamaguch simplehook_tester_dohooks, 0, ptr, 0, 553 1.1 yamaguch CTL_CREATE, CTL_EOL); 554 1.1 yamaguch if (error != 0) 555 1.1 yamaguch goto bad; 556 1.1 yamaguch 557 1.1 yamaguch error = sysctl_createv(log, 0, &rnode, &cnode, 558 1.1 yamaguch CTLFLAG_PERMANENT, CTLTYPE_NODE, "nbhook", 559 1.1 yamaguch SYSCTL_DESCR("non-blocking hook"), NULL, 0, NULL, 0, 560 1.1 yamaguch CTL_CREATE, CTL_EOL); 561 1.1 yamaguch if (error != 0) 562 1.1 yamaguch goto bad; 563 1.1 yamaguch 564 1.1 yamaguch error = sysctl_createv(log, 0, &cnode, NULL, 565 1.1 yamaguch CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 566 1.1 yamaguch CTLTYPE_INT, "established", 567 1.1 yamaguch SYSCTL_DESCR("establish and disestablish hook"), 568 1.1 yamaguch simplehook_tester_established_nb, 569 1.1 yamaguch 0, ptr, 0, CTL_CREATE, CTL_EOL); 570 1.1 yamaguch if (error != 0) 571 1.1 yamaguch goto bad; 572 1.1 yamaguch 573 1.1 yamaguch for (i = 0; i < __arraycount(ctx->ctx_hook); i++) { 574 1.1 yamaguch snprintf(buf, sizeof(buf), "hook%zu", i); 575 1.1 yamaguch ptr = (void *)&ctx->ctx_hook[i]; 576 1.1 yamaguch 577 1.1 yamaguch error = sysctl_createv(log, 0, &rnode, &cnode, 578 1.1 yamaguch CTLFLAG_PERMANENT, CTLTYPE_NODE, buf, 579 1.1 yamaguch SYSCTL_DESCR("hook information"), NULL, 0, NULL, 0, 580 1.1 yamaguch CTL_CREATE, CTL_EOL); 581 1.1 yamaguch if (error != 0) 582 1.1 yamaguch goto bad; 583 1.1 yamaguch 584 1.1 yamaguch error = sysctl_createv(log, 0, &cnode, NULL, 585 1.1 yamaguch CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 586 1.1 yamaguch CTLTYPE_INT, "established", 587 1.1 yamaguch SYSCTL_DESCR("establish and disestablish hook"), 588 1.1 yamaguch simplehook_tester_established, 589 1.1 yamaguch 0, ptr, 0, CTL_CREATE, CTL_EOL); 590 1.1 yamaguch if (error != 0) 591 1.1 yamaguch goto bad; 592 1.1 yamaguch 593 1.1 yamaguch error = sysctl_createv(log, 0, &cnode, NULL, 594 1.1 yamaguch CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 595 1.1 yamaguch CTLTYPE_BOOL, "stopping", 596 1.1 yamaguch SYSCTL_DESCR("stopping at beginning of the hook"), 597 1.1 yamaguch simplehook_tester_stopping, 0, ptr, 0, 598 1.1 yamaguch CTL_CREATE, CTL_EOL); 599 1.1 yamaguch if (error != 0) 600 1.1 yamaguch goto bad; 601 1.1 yamaguch 602 1.1 yamaguch error = sysctl_createv(log, 0, &cnode, NULL, 603 1.1 yamaguch CTLFLAG_PERMANENT|CTLFLAG_READONLY, 604 1.1 yamaguch CTLTYPE_BOOL, "stopped", 605 1.1 yamaguch SYSCTL_DESCR("the hook is stopped"), 606 1.1 yamaguch simplehook_tester_stopped, 0, ptr, 0, 607 1.1 yamaguch CTL_CREATE, CTL_EOL); 608 1.1 yamaguch if (error != 0) 609 1.1 yamaguch goto bad; 610 1.1 yamaguch 611 1.1 yamaguch error = sysctl_createv(log, 0, &cnode, NULL, 612 1.1 yamaguch CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_BOOL, 613 1.1 yamaguch "disestablish_in_hook", 614 1.1 yamaguch SYSCTL_DESCR("disestablish this hook in it"), 615 1.1 yamaguch simplehook_tester_disestablish, 0, ptr, 0, 616 1.1 yamaguch CTL_CREATE, CTL_EOL); 617 1.1 yamaguch if (error != 0) 618 1.1 yamaguch goto bad; 619 1.1 yamaguch 620 1.1 yamaguch error = sysctl_createv(log, 0, &cnode, NULL, 621 1.1 yamaguch CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 622 1.1 yamaguch CTLTYPE_INT, "count", 623 1.1 yamaguch SYSCTL_DESCR("the number of calls of the hook"), 624 1.1 yamaguch simplehook_tester_count, 0, ptr, 0, 625 1.1 yamaguch CTL_CREATE, CTL_EOL); 626 1.1 yamaguch if (error != 0) 627 1.1 yamaguch goto bad; 628 1.1 yamaguch } 629 1.1 yamaguch 630 1.1 yamaguch HK_DPRINTF(("[%s, %d]: created sysctls\n", __func__, __LINE__)); 631 1.1 yamaguch return 0; 632 1.1 yamaguch 633 1.1 yamaguch bad: 634 1.1 yamaguch sysctl_teardown(log); 635 1.1 yamaguch return error; 636 1.1 yamaguch } 637 1.1 yamaguch 638 1.1 yamaguch static void 639 1.1 yamaguch simplehook_tester_init_ctx(struct tester_context *ctx) 640 1.1 yamaguch { 641 1.1 yamaguch size_t i; 642 1.1 yamaguch 643 1.1 yamaguch memset(ctx, 0, sizeof(*ctx)); 644 1.1 yamaguch mutex_init(&ctx->ctx_mutex, MUTEX_DEFAULT, IPL_NONE); 645 1.1 yamaguch workqueue_create(&ctx->ctx_wq, "shook_tester_wq", 646 1.1 yamaguch simplehook_tester_work, ctx, PRI_NONE, IPL_NONE, WQ_MPSAFE); 647 1.1 yamaguch cv_init(&ctx->ctx_cv, "simplehook_tester_cv"); 648 1.1 yamaguch 649 1.1 yamaguch for (i = 0; i < __arraycount(ctx->ctx_hook); i++) { 650 1.1 yamaguch ctx->ctx_hook[i].th_ctx = ctx; 651 1.1 yamaguch ctx->ctx_hook[i].th_idx = i; 652 1.1 yamaguch } 653 1.1 yamaguch } 654 1.1 yamaguch 655 1.1 yamaguch 656 1.1 yamaguch int 657 1.1 yamaguch simplehook_tester_init(void) 658 1.1 yamaguch { 659 1.1 yamaguch int error; 660 1.1 yamaguch 661 1.1 yamaguch simplehook_tester_init_ctx(&tester_ctx); 662 1.1 yamaguch error = simplehook_tester_create_sysctl(&tester_ctx); 663 1.1 yamaguch 664 1.1 yamaguch return error; 665 1.1 yamaguch } 666 1.1 yamaguch 667 1.1 yamaguch static int 668 1.1 yamaguch simplehook_tester_fini(void) 669 1.1 yamaguch { 670 1.1 yamaguch struct tester_context *ctx; 671 1.1 yamaguch struct tester_hook *th; 672 1.1 yamaguch khook_list_t *hooks; 673 1.1 yamaguch size_t i; 674 1.1 yamaguch 675 1.1 yamaguch ctx = &tester_ctx; 676 1.1 yamaguch 677 1.1 yamaguch sysctl_teardown(&ctx->ctx_sysctllog); 678 1.1 yamaguch 679 1.1 yamaguch mutex_enter(&ctx->ctx_mutex); 680 1.1 yamaguch 681 1.1 yamaguch hooks = ctx->ctx_hooks; 682 1.1 yamaguch ctx->ctx_hooks = NULL; 683 1.1 yamaguch ctx->ctx_wk_waiting = true; 684 1.1 yamaguch 685 1.1 yamaguch for (i = 0; i < __arraycount(ctx->ctx_hook); i++) { 686 1.1 yamaguch th = &ctx->ctx_hook[i]; 687 1.1 yamaguch th->th_stopping = false; 688 1.1 yamaguch } 689 1.1 yamaguch cv_broadcast(&ctx->ctx_cv); 690 1.1 yamaguch 691 1.1 yamaguch mutex_exit(&ctx->ctx_mutex); 692 1.1 yamaguch 693 1.1 yamaguch workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk); 694 1.1 yamaguch 695 1.1 yamaguch workqueue_destroy(ctx->ctx_wq); 696 1.1 yamaguch if (hooks != NULL) 697 1.1 yamaguch simplehook_destroy(hooks); 698 1.1 yamaguch cv_destroy(&ctx->ctx_cv); 699 1.1 yamaguch mutex_destroy(&ctx->ctx_mutex); 700 1.1 yamaguch 701 1.1 yamaguch return 0; 702 1.1 yamaguch } 703 1.1 yamaguch 704 1.1 yamaguch static int 705 1.1 yamaguch simplehook_tester_modcmd(modcmd_t cmd, void *arg __unused) 706 1.1 yamaguch { 707 1.1 yamaguch int error; 708 1.1 yamaguch 709 1.1 yamaguch switch (cmd) { 710 1.1 yamaguch case MODULE_CMD_INIT: 711 1.1 yamaguch error = simplehook_tester_init(); 712 1.1 yamaguch break; 713 1.1 yamaguch 714 1.1 yamaguch case MODULE_CMD_FINI: 715 1.1 yamaguch error = simplehook_tester_fini(); 716 1.1 yamaguch break; 717 1.1 yamaguch 718 1.1 yamaguch case MODULE_CMD_STAT: 719 1.1 yamaguch default: 720 1.1 yamaguch error = ENOTTY; 721 1.1 yamaguch } 722 1.1 yamaguch 723 1.1 yamaguch return error; 724 1.1 yamaguch } 725