1*75d2abaeSandvar /* $NetBSD: simplehook_tester.c,v 1.2 2022/04/10 09:50:46 andvar Exp $ */
25256dbbcSyamaguchi /*
35256dbbcSyamaguchi * Copyright (c) 2021 Internet Initiative Japan Inc.
45256dbbcSyamaguchi * All rights reserved.
55256dbbcSyamaguchi *
65256dbbcSyamaguchi * Redistribution and use in source and binary forms, with or without
75256dbbcSyamaguchi * modification, are permitted provided that the following conditions
85256dbbcSyamaguchi * are met:
95256dbbcSyamaguchi * 1. Redistributions of source code must retain the above copyright
105256dbbcSyamaguchi * notice, this list of conditions and the following disclaimer.
115256dbbcSyamaguchi * 2. Redistributions in binary form must reproduce the above copyright
125256dbbcSyamaguchi * notice, this list of conditions and the following disclaimer in the
135256dbbcSyamaguchi * documentation and/or other materials provided with the distribution.
145256dbbcSyamaguchi *
155256dbbcSyamaguchi * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
165256dbbcSyamaguchi * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
175256dbbcSyamaguchi * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
185256dbbcSyamaguchi * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
195256dbbcSyamaguchi * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
205256dbbcSyamaguchi * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
215256dbbcSyamaguchi * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
225256dbbcSyamaguchi * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
235256dbbcSyamaguchi * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
245256dbbcSyamaguchi * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
255256dbbcSyamaguchi * POSSIBILITY OF SUCH DAMAGE.
265256dbbcSyamaguchi */
275256dbbcSyamaguchi
285256dbbcSyamaguchi #include <sys/cdefs.h>
29*75d2abaeSandvar __KERNEL_RCSID(0, "$NetBSD: simplehook_tester.c,v 1.2 2022/04/10 09:50:46 andvar Exp $");
305256dbbcSyamaguchi
315256dbbcSyamaguchi #include <sys/param.h>
325256dbbcSyamaguchi
335256dbbcSyamaguchi #include <sys/condvar.h>
345256dbbcSyamaguchi #include <sys/hook.h>
355256dbbcSyamaguchi #include <sys/module.h>
365256dbbcSyamaguchi #include <sys/mutex.h>
375256dbbcSyamaguchi #include <sys/sysctl.h>
385256dbbcSyamaguchi #include <sys/workqueue.h>
395256dbbcSyamaguchi
405256dbbcSyamaguchi #ifdef SIMPLEHOOK_TESTER_DEBUG
415256dbbcSyamaguchi #define HK_DPRINTF(a) printf a
425256dbbcSyamaguchi #else
435256dbbcSyamaguchi #define HK_DPRINTF(a) __nothing
445256dbbcSyamaguchi #endif
455256dbbcSyamaguchi
465256dbbcSyamaguchi MODULE(MODULE_CLASS_MISC, simplehook_tester, NULL);
475256dbbcSyamaguchi extern int simplehook_tester_init(void);
485256dbbcSyamaguchi struct tester_context;
495256dbbcSyamaguchi
505256dbbcSyamaguchi struct tester_hook {
515256dbbcSyamaguchi struct tester_context *th_ctx;
525256dbbcSyamaguchi khook_t *th_hook;
535256dbbcSyamaguchi size_t th_idx;
545256dbbcSyamaguchi int th_count;
555256dbbcSyamaguchi bool th_stopping;
565256dbbcSyamaguchi bool th_stopped;
575256dbbcSyamaguchi bool th_disestablish;
585256dbbcSyamaguchi };
595256dbbcSyamaguchi
605256dbbcSyamaguchi static struct tester_context {
615256dbbcSyamaguchi kmutex_t ctx_mutex;
625256dbbcSyamaguchi kcondvar_t ctx_cv;
635256dbbcSyamaguchi struct sysctllog *ctx_sysctllog;
645256dbbcSyamaguchi struct workqueue *ctx_wq;
655256dbbcSyamaguchi struct work ctx_wk;
665256dbbcSyamaguchi bool ctx_wk_enqueued;
675256dbbcSyamaguchi bool ctx_wk_waiting;
685256dbbcSyamaguchi
695256dbbcSyamaguchi khook_list_t *ctx_hooks;
705256dbbcSyamaguchi struct tester_hook ctx_hook[2];
715256dbbcSyamaguchi
725256dbbcSyamaguchi khook_t *ctx_nbhook;
735256dbbcSyamaguchi } tester_ctx;
745256dbbcSyamaguchi
755256dbbcSyamaguchi static int
simplehook_tester_created(SYSCTLFN_ARGS)765256dbbcSyamaguchi simplehook_tester_created(SYSCTLFN_ARGS)
775256dbbcSyamaguchi {
785256dbbcSyamaguchi struct sysctlnode node;
795256dbbcSyamaguchi struct tester_context *ctx;
805256dbbcSyamaguchi int error, val;
815256dbbcSyamaguchi size_t i;
825256dbbcSyamaguchi
835256dbbcSyamaguchi node = *rnode;
845256dbbcSyamaguchi ctx = node.sysctl_data;
855256dbbcSyamaguchi
865256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
875256dbbcSyamaguchi val = ctx->ctx_hooks != NULL ? 1 : 0;
885256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
895256dbbcSyamaguchi
905256dbbcSyamaguchi node.sysctl_data = &val;
915256dbbcSyamaguchi node.sysctl_size = sizeof(val);
925256dbbcSyamaguchi
935256dbbcSyamaguchi error = sysctl_lookup(SYSCTLFN_CALL(&node));
945256dbbcSyamaguchi if (error || newp == NULL)
955256dbbcSyamaguchi return error;
965256dbbcSyamaguchi
975256dbbcSyamaguchi if (val != 0 && val != 1)
985256dbbcSyamaguchi return EINVAL;
995256dbbcSyamaguchi
1005256dbbcSyamaguchi error = 0;
1015256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
1025256dbbcSyamaguchi if (val == 1) {
1035256dbbcSyamaguchi if (ctx->ctx_hooks != NULL) {
1045256dbbcSyamaguchi error = EEXIST;
1055256dbbcSyamaguchi } else {
1065256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: create hook list\n",
1075256dbbcSyamaguchi __func__, __LINE__));
1085256dbbcSyamaguchi ctx->ctx_hooks = simplehook_create(IPL_NONE,
1095256dbbcSyamaguchi "tester hooks");
1105256dbbcSyamaguchi KASSERT(ctx->ctx_hooks != NULL);
1115256dbbcSyamaguchi }
1125256dbbcSyamaguchi } else {
1135256dbbcSyamaguchi if (ctx->ctx_hooks == NULL) {
1145256dbbcSyamaguchi error = ENXIO;
1155256dbbcSyamaguchi } else if (ctx->ctx_wk_waiting) {
1165256dbbcSyamaguchi error = EBUSY;
1175256dbbcSyamaguchi } else {
1185256dbbcSyamaguchi ctx->ctx_wk_waiting = true;
1195256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
1205256dbbcSyamaguchi
1215256dbbcSyamaguchi workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk);
1225256dbbcSyamaguchi
1235256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
1245256dbbcSyamaguchi ctx->ctx_wk_waiting = false;
1255256dbbcSyamaguchi
1265256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: destroy hook list\n",
1275256dbbcSyamaguchi __func__, __LINE__));
1285256dbbcSyamaguchi simplehook_destroy(ctx->ctx_hooks);
1295256dbbcSyamaguchi ctx->ctx_hooks = NULL;
1305256dbbcSyamaguchi ctx->ctx_nbhook = NULL;
1315256dbbcSyamaguchi for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
1325256dbbcSyamaguchi ctx->ctx_hook[i].th_hook = NULL;
1335256dbbcSyamaguchi }
1345256dbbcSyamaguchi }
1355256dbbcSyamaguchi }
1365256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
1375256dbbcSyamaguchi
1385256dbbcSyamaguchi return error;
1395256dbbcSyamaguchi }
1405256dbbcSyamaguchi
1415256dbbcSyamaguchi static void
simplehook_tester_work(struct work * wk,void * xctx)1425256dbbcSyamaguchi simplehook_tester_work(struct work *wk, void *xctx)
1435256dbbcSyamaguchi {
1445256dbbcSyamaguchi struct tester_context *ctx;
1455256dbbcSyamaguchi
1465256dbbcSyamaguchi ctx = xctx;
1475256dbbcSyamaguchi
1485256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
1495256dbbcSyamaguchi ctx->ctx_wk_enqueued = false;
1505256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
1515256dbbcSyamaguchi
1525256dbbcSyamaguchi simplehook_dohooks(ctx->ctx_hooks);
1535256dbbcSyamaguchi }
1545256dbbcSyamaguchi
1555256dbbcSyamaguchi static int
simplehook_tester_dohooks(SYSCTLFN_ARGS)1565256dbbcSyamaguchi simplehook_tester_dohooks(SYSCTLFN_ARGS)
1575256dbbcSyamaguchi {
1585256dbbcSyamaguchi struct sysctlnode node;
1595256dbbcSyamaguchi struct tester_context *ctx;
1605256dbbcSyamaguchi int error, val;
1615256dbbcSyamaguchi
1625256dbbcSyamaguchi node = *rnode;
1635256dbbcSyamaguchi ctx = node.sysctl_data;
1645256dbbcSyamaguchi
1655256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
1665256dbbcSyamaguchi val = ctx->ctx_wk_enqueued ? 1 : 0;
1675256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
1685256dbbcSyamaguchi
1695256dbbcSyamaguchi node.sysctl_data = &val;
1705256dbbcSyamaguchi node.sysctl_size = sizeof(val);
1715256dbbcSyamaguchi
1725256dbbcSyamaguchi error = sysctl_lookup(SYSCTLFN_CALL(&node));
1735256dbbcSyamaguchi if (error || newp == NULL)
1745256dbbcSyamaguchi return error;
1755256dbbcSyamaguchi
1765256dbbcSyamaguchi if (val != 0 && val != 1)
1775256dbbcSyamaguchi return EINVAL;
1785256dbbcSyamaguchi
1795256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
1805256dbbcSyamaguchi if (val == 1) {
1815256dbbcSyamaguchi if (ctx->ctx_wk_enqueued) {
1825256dbbcSyamaguchi error = EEXIST;
1835256dbbcSyamaguchi } else if (ctx->ctx_wk_waiting) {
1845256dbbcSyamaguchi error = EBUSY;
1855256dbbcSyamaguchi } else if (ctx->ctx_hooks == NULL) {
1865256dbbcSyamaguchi error = ENXIO;
1875256dbbcSyamaguchi } else {
1885256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: dohook\n", __func__, __LINE__));
1895256dbbcSyamaguchi ctx->ctx_wk_enqueued = true;
1905256dbbcSyamaguchi workqueue_enqueue(ctx->ctx_wq,
1915256dbbcSyamaguchi &ctx->ctx_wk, NULL);
1925256dbbcSyamaguchi }
1935256dbbcSyamaguchi } else {
1945256dbbcSyamaguchi if (ctx->ctx_wk_waiting) {
1955256dbbcSyamaguchi error = EBUSY;
1965256dbbcSyamaguchi } else {
1975256dbbcSyamaguchi ctx->ctx_wk_waiting = true;
1985256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
1995256dbbcSyamaguchi
2005256dbbcSyamaguchi workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk);
2015256dbbcSyamaguchi
2025256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
2035256dbbcSyamaguchi ctx->ctx_wk_waiting = false;
2045256dbbcSyamaguchi }
2055256dbbcSyamaguchi }
2065256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
2075256dbbcSyamaguchi
2085256dbbcSyamaguchi return error;
2095256dbbcSyamaguchi }
2105256dbbcSyamaguchi
2115256dbbcSyamaguchi static void
simplehook_tester_hook(void * xth)2125256dbbcSyamaguchi simplehook_tester_hook(void *xth)
2135256dbbcSyamaguchi {
2145256dbbcSyamaguchi struct tester_context *ctx;
2155256dbbcSyamaguchi struct tester_hook *th;
2165256dbbcSyamaguchi
2175256dbbcSyamaguchi th = xth;
2185256dbbcSyamaguchi ctx = th->th_ctx;
2195256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
2205256dbbcSyamaguchi
2215256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: hook%zu called\n",
2225256dbbcSyamaguchi __func__, __LINE__, th->th_idx));
2235256dbbcSyamaguchi
2245256dbbcSyamaguchi th->th_stopped = false;
2255256dbbcSyamaguchi
2265256dbbcSyamaguchi while (th->th_stopping) {
2275256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: hook%zu stopping\n",
2285256dbbcSyamaguchi __func__, __LINE__, th->th_idx));
2295256dbbcSyamaguchi th->th_stopped = true;
2305256dbbcSyamaguchi cv_wait(&ctx->ctx_cv, &ctx->ctx_mutex);
2315256dbbcSyamaguchi }
2325256dbbcSyamaguchi
2335256dbbcSyamaguchi if (th->th_stopped) {
2345256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: hook%zu restart\n",
2355256dbbcSyamaguchi __func__, __LINE__, th->th_idx));
2365256dbbcSyamaguchi th->th_stopped = false;
2375256dbbcSyamaguchi }
2385256dbbcSyamaguchi
2395256dbbcSyamaguchi th->th_count++;
2405256dbbcSyamaguchi
2415256dbbcSyamaguchi if (th->th_disestablish && th->th_hook != NULL) {
242*75d2abaeSandvar HK_DPRINTF(("[%s, %d]: disestablish running hook%zu\n",
2435256dbbcSyamaguchi __func__, __LINE__, th->th_idx));
2445256dbbcSyamaguchi simplehook_disestablish(ctx->ctx_hooks,
2455256dbbcSyamaguchi th->th_hook, &ctx->ctx_mutex);
2465256dbbcSyamaguchi th->th_hook = NULL;
2475256dbbcSyamaguchi }
2485256dbbcSyamaguchi
2495256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: hook%zu exit\n",
2505256dbbcSyamaguchi __func__, __LINE__, th->th_idx));
2515256dbbcSyamaguchi
2525256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
2535256dbbcSyamaguchi }
2545256dbbcSyamaguchi
2555256dbbcSyamaguchi static void
simplehook_tester_hook_nb(void * xctx)2565256dbbcSyamaguchi simplehook_tester_hook_nb(void *xctx)
2575256dbbcSyamaguchi {
2585256dbbcSyamaguchi
2595256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: non-block hook called\n",
2605256dbbcSyamaguchi __func__, __LINE__));
2615256dbbcSyamaguchi
2625256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: sleep 1 sec\n",
2635256dbbcSyamaguchi __func__, __LINE__));
2645256dbbcSyamaguchi kpause("smplhk_nb", true, 1 * hz, NULL);
2655256dbbcSyamaguchi
2665256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: non-block hook exit\n",
2675256dbbcSyamaguchi __func__, __LINE__));
2685256dbbcSyamaguchi }
2695256dbbcSyamaguchi
2705256dbbcSyamaguchi static int
simplehook_tester_established(SYSCTLFN_ARGS)2715256dbbcSyamaguchi simplehook_tester_established(SYSCTLFN_ARGS)
2725256dbbcSyamaguchi {
2735256dbbcSyamaguchi struct sysctlnode node;
2745256dbbcSyamaguchi struct tester_context *ctx;
2755256dbbcSyamaguchi struct tester_hook *th;
2765256dbbcSyamaguchi int val, error;
2775256dbbcSyamaguchi
2785256dbbcSyamaguchi node = *rnode;
2795256dbbcSyamaguchi th = node.sysctl_data;
2805256dbbcSyamaguchi ctx = th->th_ctx;
2815256dbbcSyamaguchi
2825256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
2835256dbbcSyamaguchi val = th->th_hook == NULL ? 0 : 1;
2845256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
2855256dbbcSyamaguchi
2865256dbbcSyamaguchi node.sysctl_data = &val;
2875256dbbcSyamaguchi node.sysctl_size = sizeof(val);
2885256dbbcSyamaguchi
2895256dbbcSyamaguchi error = sysctl_lookup(SYSCTLFN_CALL(&node));
2905256dbbcSyamaguchi if (error || newp == NULL)
2915256dbbcSyamaguchi return error;
2925256dbbcSyamaguchi
2935256dbbcSyamaguchi error = 0;
2945256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
2955256dbbcSyamaguchi
2965256dbbcSyamaguchi if (val == 1) {
2975256dbbcSyamaguchi if (th->th_hook != NULL) {
2985256dbbcSyamaguchi error = EEXIST;
2995256dbbcSyamaguchi } else {
3005256dbbcSyamaguchi th->th_hook = simplehook_establish(ctx->ctx_hooks,
3015256dbbcSyamaguchi simplehook_tester_hook, th);
3025256dbbcSyamaguchi KASSERT(th->th_hook != NULL);
3035256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: established hook%zu (%p)\n",
3045256dbbcSyamaguchi __func__, __LINE__, th->th_idx, th->th_hook));
3055256dbbcSyamaguchi }
3065256dbbcSyamaguchi } else {
3075256dbbcSyamaguchi if (th->th_hook == NULL) {
3085256dbbcSyamaguchi error = ENXIO;
3095256dbbcSyamaguchi } else {
3105256dbbcSyamaguchi bool stopped = false;
3115256dbbcSyamaguchi if (th->th_stopping) {
3125256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: stopping = false\n",
3135256dbbcSyamaguchi __func__, __LINE__));
3145256dbbcSyamaguchi th->th_stopping = false;
3155256dbbcSyamaguchi cv_broadcast(&ctx->ctx_cv);
3165256dbbcSyamaguchi stopped = true;
3175256dbbcSyamaguchi }
3185256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: disestablish hook%zu (%p)\n",
3195256dbbcSyamaguchi __func__, __LINE__, th->th_idx, th->th_hook));
3205256dbbcSyamaguchi simplehook_disestablish(ctx->ctx_hooks,
3215256dbbcSyamaguchi th->th_hook, &ctx->ctx_mutex);
3225256dbbcSyamaguchi th->th_hook = NULL;
3235256dbbcSyamaguchi if (stopped) {
3245256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: disestablished hook%zu\n",
3255256dbbcSyamaguchi __func__, __LINE__, th->th_idx));
3265256dbbcSyamaguchi }
3275256dbbcSyamaguchi }
3285256dbbcSyamaguchi }
3295256dbbcSyamaguchi
3305256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
3315256dbbcSyamaguchi
3325256dbbcSyamaguchi return error;
3335256dbbcSyamaguchi }
3345256dbbcSyamaguchi
3355256dbbcSyamaguchi static int
simplehook_tester_established_nb(SYSCTLFN_ARGS)3365256dbbcSyamaguchi simplehook_tester_established_nb(SYSCTLFN_ARGS)
3375256dbbcSyamaguchi {
3385256dbbcSyamaguchi struct sysctlnode node;
3395256dbbcSyamaguchi struct tester_context *ctx;
3405256dbbcSyamaguchi int val, error;
3415256dbbcSyamaguchi
3425256dbbcSyamaguchi node = *rnode;
3435256dbbcSyamaguchi ctx = node.sysctl_data;
3445256dbbcSyamaguchi
3455256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
3465256dbbcSyamaguchi val = ctx->ctx_nbhook == NULL ? 0 : 1;
3475256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
3485256dbbcSyamaguchi
3495256dbbcSyamaguchi node.sysctl_data = &val;
3505256dbbcSyamaguchi node.sysctl_size = sizeof(val);
3515256dbbcSyamaguchi
3525256dbbcSyamaguchi error = sysctl_lookup(SYSCTLFN_CALL(&node));
3535256dbbcSyamaguchi if (error || newp == NULL)
3545256dbbcSyamaguchi return error;
3555256dbbcSyamaguchi
3565256dbbcSyamaguchi error = 0;
3575256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
3585256dbbcSyamaguchi
3595256dbbcSyamaguchi if (val == 1) {
3605256dbbcSyamaguchi if (ctx->ctx_nbhook != NULL) {
3615256dbbcSyamaguchi error = EEXIST;
3625256dbbcSyamaguchi } else {
3635256dbbcSyamaguchi ctx->ctx_nbhook = simplehook_establish(ctx->ctx_hooks,
3645256dbbcSyamaguchi simplehook_tester_hook_nb, ctx);
3655256dbbcSyamaguchi KASSERT(ctx->ctx_nbhook != NULL);
3665256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: established nbhook (%p)\n",
3675256dbbcSyamaguchi __func__, __LINE__, ctx->ctx_nbhook));
3685256dbbcSyamaguchi }
3695256dbbcSyamaguchi } else {
3705256dbbcSyamaguchi if (ctx->ctx_nbhook == NULL) {
3715256dbbcSyamaguchi error = ENXIO;
3725256dbbcSyamaguchi } else {
3735256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: disestablish nbhook (%p)\n",
3745256dbbcSyamaguchi __func__, __LINE__, ctx->ctx_nbhook));
3755256dbbcSyamaguchi simplehook_disestablish(ctx->ctx_hooks,
3765256dbbcSyamaguchi ctx->ctx_nbhook, NULL);
3775256dbbcSyamaguchi ctx->ctx_nbhook = NULL;
3785256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: disestablished\n",
3795256dbbcSyamaguchi __func__, __LINE__));
3805256dbbcSyamaguchi }
3815256dbbcSyamaguchi }
3825256dbbcSyamaguchi
3835256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
3845256dbbcSyamaguchi
3855256dbbcSyamaguchi return error;
3865256dbbcSyamaguchi }
3875256dbbcSyamaguchi
3885256dbbcSyamaguchi static int
simplehook_tester_stopping(SYSCTLFN_ARGS)3895256dbbcSyamaguchi simplehook_tester_stopping(SYSCTLFN_ARGS)
3905256dbbcSyamaguchi {
3915256dbbcSyamaguchi struct sysctlnode node;
3925256dbbcSyamaguchi struct tester_context *ctx;
3935256dbbcSyamaguchi struct tester_hook *th;
3945256dbbcSyamaguchi int error;
3955256dbbcSyamaguchi bool val;
3965256dbbcSyamaguchi
3975256dbbcSyamaguchi node = *rnode;
3985256dbbcSyamaguchi th = node.sysctl_data;
3995256dbbcSyamaguchi ctx = th->th_ctx;
4005256dbbcSyamaguchi
4015256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
4025256dbbcSyamaguchi val = th->th_stopping;
4035256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
4045256dbbcSyamaguchi
4055256dbbcSyamaguchi node.sysctl_data = &val;
4065256dbbcSyamaguchi node.sysctl_size = sizeof(val);
4075256dbbcSyamaguchi
4085256dbbcSyamaguchi error = sysctl_lookup(SYSCTLFN_CALL(&node));
4095256dbbcSyamaguchi if (error || newp == NULL)
4105256dbbcSyamaguchi return error;
4115256dbbcSyamaguchi
4125256dbbcSyamaguchi error = 0;
4135256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
4145256dbbcSyamaguchi if (val == true && !th->th_stopping) {
4155256dbbcSyamaguchi th->th_stopping = true;
4165256dbbcSyamaguchi } else if (val == false && th->th_stopping) {
4175256dbbcSyamaguchi th->th_stopping = false;
4185256dbbcSyamaguchi cv_broadcast(&ctx->ctx_cv);
4195256dbbcSyamaguchi }
4205256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
4215256dbbcSyamaguchi
4225256dbbcSyamaguchi return error;
4235256dbbcSyamaguchi }
4245256dbbcSyamaguchi
4255256dbbcSyamaguchi static int
simplehook_tester_stopped(SYSCTLFN_ARGS)4265256dbbcSyamaguchi simplehook_tester_stopped(SYSCTLFN_ARGS)
4275256dbbcSyamaguchi {
4285256dbbcSyamaguchi struct sysctlnode node;
4295256dbbcSyamaguchi struct tester_context *ctx;
4305256dbbcSyamaguchi struct tester_hook *th;
4315256dbbcSyamaguchi bool val;
4325256dbbcSyamaguchi
4335256dbbcSyamaguchi node = *rnode;
4345256dbbcSyamaguchi th = node.sysctl_data;
4355256dbbcSyamaguchi ctx = th->th_ctx;
4365256dbbcSyamaguchi
4375256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
4385256dbbcSyamaguchi val = th->th_stopped;
4395256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
4405256dbbcSyamaguchi
4415256dbbcSyamaguchi node.sysctl_data = &val;
4425256dbbcSyamaguchi node.sysctl_size = sizeof(val);
4435256dbbcSyamaguchi
4445256dbbcSyamaguchi return sysctl_lookup(SYSCTLFN_CALL(&node));
4455256dbbcSyamaguchi }
4465256dbbcSyamaguchi
4475256dbbcSyamaguchi static int
simplehook_tester_disestablish(SYSCTLFN_ARGS)4485256dbbcSyamaguchi simplehook_tester_disestablish(SYSCTLFN_ARGS)
4495256dbbcSyamaguchi {
4505256dbbcSyamaguchi struct sysctlnode node;
4515256dbbcSyamaguchi struct tester_context *ctx;
4525256dbbcSyamaguchi struct tester_hook *th;
4535256dbbcSyamaguchi int error;
4545256dbbcSyamaguchi bool val;
4555256dbbcSyamaguchi
4565256dbbcSyamaguchi node = *rnode;
4575256dbbcSyamaguchi th = node.sysctl_data;
4585256dbbcSyamaguchi ctx = th->th_ctx;
4595256dbbcSyamaguchi
4605256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
4615256dbbcSyamaguchi val = th->th_disestablish;
4625256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
4635256dbbcSyamaguchi
4645256dbbcSyamaguchi node.sysctl_data = &val;
4655256dbbcSyamaguchi node.sysctl_size = sizeof(val);
4665256dbbcSyamaguchi
4675256dbbcSyamaguchi error = sysctl_lookup(SYSCTLFN_CALL(&node));
4685256dbbcSyamaguchi if (error || newp == NULL)
4695256dbbcSyamaguchi return error;
4705256dbbcSyamaguchi
4715256dbbcSyamaguchi if (val != 0 && val != 1)
4725256dbbcSyamaguchi return EINVAL;
4735256dbbcSyamaguchi
4745256dbbcSyamaguchi error = 0;
4755256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
4765256dbbcSyamaguchi if (val == true && !th->th_disestablish) {
4775256dbbcSyamaguchi th->th_disestablish = true;
4785256dbbcSyamaguchi } else if (val == false && th->th_disestablish) {
4795256dbbcSyamaguchi th->th_disestablish = false;
4805256dbbcSyamaguchi }
4815256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
4825256dbbcSyamaguchi
4835256dbbcSyamaguchi return 0;
4845256dbbcSyamaguchi }
4855256dbbcSyamaguchi
4865256dbbcSyamaguchi static int
simplehook_tester_count(SYSCTLFN_ARGS)4875256dbbcSyamaguchi simplehook_tester_count(SYSCTLFN_ARGS)
4885256dbbcSyamaguchi {
4895256dbbcSyamaguchi struct sysctlnode node;
4905256dbbcSyamaguchi struct tester_context *ctx;
4915256dbbcSyamaguchi struct tester_hook *th;
4925256dbbcSyamaguchi int error, val;
4935256dbbcSyamaguchi
4945256dbbcSyamaguchi node = *rnode;
4955256dbbcSyamaguchi th = node.sysctl_data;
4965256dbbcSyamaguchi ctx = th->th_ctx;
4975256dbbcSyamaguchi
4985256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
4995256dbbcSyamaguchi val = th->th_count;
5005256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
5015256dbbcSyamaguchi
5025256dbbcSyamaguchi node.sysctl_data = &val;
5035256dbbcSyamaguchi node.sysctl_size = sizeof(val);
5045256dbbcSyamaguchi
5055256dbbcSyamaguchi error = sysctl_lookup(SYSCTLFN_CALL(&node));
5065256dbbcSyamaguchi if (error || newp == NULL)
5075256dbbcSyamaguchi return error;
5085256dbbcSyamaguchi
5095256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
5105256dbbcSyamaguchi th->th_count = val;
5115256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
5125256dbbcSyamaguchi
5135256dbbcSyamaguchi return 0;
5145256dbbcSyamaguchi }
5155256dbbcSyamaguchi
5165256dbbcSyamaguchi static int
simplehook_tester_create_sysctl(struct tester_context * ctx)5175256dbbcSyamaguchi simplehook_tester_create_sysctl(struct tester_context *ctx)
5185256dbbcSyamaguchi {
5195256dbbcSyamaguchi struct sysctllog **log;
5205256dbbcSyamaguchi const struct sysctlnode *rnode, *cnode;
5215256dbbcSyamaguchi void *ptr;
5225256dbbcSyamaguchi char buf[32];
5235256dbbcSyamaguchi int error;
5245256dbbcSyamaguchi size_t i;
5255256dbbcSyamaguchi
5265256dbbcSyamaguchi log = &ctx->ctx_sysctllog;
5275256dbbcSyamaguchi ptr = (void *)ctx;
5285256dbbcSyamaguchi
5295256dbbcSyamaguchi error = sysctl_createv(log, 0, NULL, &rnode, CTLFLAG_PERMANENT,
5305256dbbcSyamaguchi CTLTYPE_NODE, "simplehook_tester",
5315256dbbcSyamaguchi SYSCTL_DESCR("simplehook testing interface"),
5325256dbbcSyamaguchi NULL, 0, NULL, 0, CTL_KERN, CTL_CREATE, CTL_EOL);
5335256dbbcSyamaguchi if (error != 0)
5345256dbbcSyamaguchi goto bad;
5355256dbbcSyamaguchi
5365256dbbcSyamaguchi error = sysctl_createv(log, 0, &rnode, &cnode,
5375256dbbcSyamaguchi CTLFLAG_PERMANENT, CTLTYPE_NODE, "hook_list",
5385256dbbcSyamaguchi SYSCTL_DESCR("hook list"), NULL, 0, NULL, 0,
5395256dbbcSyamaguchi CTL_CREATE, CTL_EOL);
5405256dbbcSyamaguchi
5415256dbbcSyamaguchi error = sysctl_createv(log, 0, &cnode, NULL,
5425256dbbcSyamaguchi CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
5435256dbbcSyamaguchi "created", SYSCTL_DESCR("create and destroy hook list"),
5445256dbbcSyamaguchi simplehook_tester_created, 0, ptr, 0,
5455256dbbcSyamaguchi CTL_CREATE, CTL_EOL);
5465256dbbcSyamaguchi if (error != 0)
5475256dbbcSyamaguchi goto bad;
5485256dbbcSyamaguchi
5495256dbbcSyamaguchi error = sysctl_createv(log, 0, &cnode, NULL,
5505256dbbcSyamaguchi CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
5515256dbbcSyamaguchi "dohooks", SYSCTL_DESCR("do hooks"),
5525256dbbcSyamaguchi simplehook_tester_dohooks, 0, ptr, 0,
5535256dbbcSyamaguchi CTL_CREATE, CTL_EOL);
5545256dbbcSyamaguchi if (error != 0)
5555256dbbcSyamaguchi goto bad;
5565256dbbcSyamaguchi
5575256dbbcSyamaguchi error = sysctl_createv(log, 0, &rnode, &cnode,
5585256dbbcSyamaguchi CTLFLAG_PERMANENT, CTLTYPE_NODE, "nbhook",
5595256dbbcSyamaguchi SYSCTL_DESCR("non-blocking hook"), NULL, 0, NULL, 0,
5605256dbbcSyamaguchi CTL_CREATE, CTL_EOL);
5615256dbbcSyamaguchi if (error != 0)
5625256dbbcSyamaguchi goto bad;
5635256dbbcSyamaguchi
5645256dbbcSyamaguchi error = sysctl_createv(log, 0, &cnode, NULL,
5655256dbbcSyamaguchi CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
5665256dbbcSyamaguchi CTLTYPE_INT, "established",
5675256dbbcSyamaguchi SYSCTL_DESCR("establish and disestablish hook"),
5685256dbbcSyamaguchi simplehook_tester_established_nb,
5695256dbbcSyamaguchi 0, ptr, 0, CTL_CREATE, CTL_EOL);
5705256dbbcSyamaguchi if (error != 0)
5715256dbbcSyamaguchi goto bad;
5725256dbbcSyamaguchi
5735256dbbcSyamaguchi for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
5745256dbbcSyamaguchi snprintf(buf, sizeof(buf), "hook%zu", i);
5755256dbbcSyamaguchi ptr = (void *)&ctx->ctx_hook[i];
5765256dbbcSyamaguchi
5775256dbbcSyamaguchi error = sysctl_createv(log, 0, &rnode, &cnode,
5785256dbbcSyamaguchi CTLFLAG_PERMANENT, CTLTYPE_NODE, buf,
5795256dbbcSyamaguchi SYSCTL_DESCR("hook information"), NULL, 0, NULL, 0,
5805256dbbcSyamaguchi CTL_CREATE, CTL_EOL);
5815256dbbcSyamaguchi if (error != 0)
5825256dbbcSyamaguchi goto bad;
5835256dbbcSyamaguchi
5845256dbbcSyamaguchi error = sysctl_createv(log, 0, &cnode, NULL,
5855256dbbcSyamaguchi CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
5865256dbbcSyamaguchi CTLTYPE_INT, "established",
5875256dbbcSyamaguchi SYSCTL_DESCR("establish and disestablish hook"),
5885256dbbcSyamaguchi simplehook_tester_established,
5895256dbbcSyamaguchi 0, ptr, 0, CTL_CREATE, CTL_EOL);
5905256dbbcSyamaguchi if (error != 0)
5915256dbbcSyamaguchi goto bad;
5925256dbbcSyamaguchi
5935256dbbcSyamaguchi error = sysctl_createv(log, 0, &cnode, NULL,
5945256dbbcSyamaguchi CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
5955256dbbcSyamaguchi CTLTYPE_BOOL, "stopping",
5965256dbbcSyamaguchi SYSCTL_DESCR("stopping at beginning of the hook"),
5975256dbbcSyamaguchi simplehook_tester_stopping, 0, ptr, 0,
5985256dbbcSyamaguchi CTL_CREATE, CTL_EOL);
5995256dbbcSyamaguchi if (error != 0)
6005256dbbcSyamaguchi goto bad;
6015256dbbcSyamaguchi
6025256dbbcSyamaguchi error = sysctl_createv(log, 0, &cnode, NULL,
6035256dbbcSyamaguchi CTLFLAG_PERMANENT|CTLFLAG_READONLY,
6045256dbbcSyamaguchi CTLTYPE_BOOL, "stopped",
6055256dbbcSyamaguchi SYSCTL_DESCR("the hook is stopped"),
6065256dbbcSyamaguchi simplehook_tester_stopped, 0, ptr, 0,
6075256dbbcSyamaguchi CTL_CREATE, CTL_EOL);
6085256dbbcSyamaguchi if (error != 0)
6095256dbbcSyamaguchi goto bad;
6105256dbbcSyamaguchi
6115256dbbcSyamaguchi error = sysctl_createv(log, 0, &cnode, NULL,
6125256dbbcSyamaguchi CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_BOOL,
6135256dbbcSyamaguchi "disestablish_in_hook",
6145256dbbcSyamaguchi SYSCTL_DESCR("disestablish this hook in it"),
6155256dbbcSyamaguchi simplehook_tester_disestablish, 0, ptr, 0,
6165256dbbcSyamaguchi CTL_CREATE, CTL_EOL);
6175256dbbcSyamaguchi if (error != 0)
6185256dbbcSyamaguchi goto bad;
6195256dbbcSyamaguchi
6205256dbbcSyamaguchi error = sysctl_createv(log, 0, &cnode, NULL,
6215256dbbcSyamaguchi CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
6225256dbbcSyamaguchi CTLTYPE_INT, "count",
6235256dbbcSyamaguchi SYSCTL_DESCR("the number of calls of the hook"),
6245256dbbcSyamaguchi simplehook_tester_count, 0, ptr, 0,
6255256dbbcSyamaguchi CTL_CREATE, CTL_EOL);
6265256dbbcSyamaguchi if (error != 0)
6275256dbbcSyamaguchi goto bad;
6285256dbbcSyamaguchi }
6295256dbbcSyamaguchi
6305256dbbcSyamaguchi HK_DPRINTF(("[%s, %d]: created sysctls\n", __func__, __LINE__));
6315256dbbcSyamaguchi return 0;
6325256dbbcSyamaguchi
6335256dbbcSyamaguchi bad:
6345256dbbcSyamaguchi sysctl_teardown(log);
6355256dbbcSyamaguchi return error;
6365256dbbcSyamaguchi }
6375256dbbcSyamaguchi
6385256dbbcSyamaguchi static void
simplehook_tester_init_ctx(struct tester_context * ctx)6395256dbbcSyamaguchi simplehook_tester_init_ctx(struct tester_context *ctx)
6405256dbbcSyamaguchi {
6415256dbbcSyamaguchi size_t i;
6425256dbbcSyamaguchi
6435256dbbcSyamaguchi memset(ctx, 0, sizeof(*ctx));
6445256dbbcSyamaguchi mutex_init(&ctx->ctx_mutex, MUTEX_DEFAULT, IPL_NONE);
6455256dbbcSyamaguchi workqueue_create(&ctx->ctx_wq, "shook_tester_wq",
6465256dbbcSyamaguchi simplehook_tester_work, ctx, PRI_NONE, IPL_NONE, WQ_MPSAFE);
6475256dbbcSyamaguchi cv_init(&ctx->ctx_cv, "simplehook_tester_cv");
6485256dbbcSyamaguchi
6495256dbbcSyamaguchi for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
6505256dbbcSyamaguchi ctx->ctx_hook[i].th_ctx = ctx;
6515256dbbcSyamaguchi ctx->ctx_hook[i].th_idx = i;
6525256dbbcSyamaguchi }
6535256dbbcSyamaguchi }
6545256dbbcSyamaguchi
6555256dbbcSyamaguchi
6565256dbbcSyamaguchi int
simplehook_tester_init(void)6575256dbbcSyamaguchi simplehook_tester_init(void)
6585256dbbcSyamaguchi {
6595256dbbcSyamaguchi int error;
6605256dbbcSyamaguchi
6615256dbbcSyamaguchi simplehook_tester_init_ctx(&tester_ctx);
6625256dbbcSyamaguchi error = simplehook_tester_create_sysctl(&tester_ctx);
6635256dbbcSyamaguchi
6645256dbbcSyamaguchi return error;
6655256dbbcSyamaguchi }
6665256dbbcSyamaguchi
6675256dbbcSyamaguchi static int
simplehook_tester_fini(void)6685256dbbcSyamaguchi simplehook_tester_fini(void)
6695256dbbcSyamaguchi {
6705256dbbcSyamaguchi struct tester_context *ctx;
6715256dbbcSyamaguchi struct tester_hook *th;
6725256dbbcSyamaguchi khook_list_t *hooks;
6735256dbbcSyamaguchi size_t i;
6745256dbbcSyamaguchi
6755256dbbcSyamaguchi ctx = &tester_ctx;
6765256dbbcSyamaguchi
6775256dbbcSyamaguchi sysctl_teardown(&ctx->ctx_sysctllog);
6785256dbbcSyamaguchi
6795256dbbcSyamaguchi mutex_enter(&ctx->ctx_mutex);
6805256dbbcSyamaguchi
6815256dbbcSyamaguchi hooks = ctx->ctx_hooks;
6825256dbbcSyamaguchi ctx->ctx_hooks = NULL;
6835256dbbcSyamaguchi ctx->ctx_wk_waiting = true;
6845256dbbcSyamaguchi
6855256dbbcSyamaguchi for (i = 0; i < __arraycount(ctx->ctx_hook); i++) {
6865256dbbcSyamaguchi th = &ctx->ctx_hook[i];
6875256dbbcSyamaguchi th->th_stopping = false;
6885256dbbcSyamaguchi }
6895256dbbcSyamaguchi cv_broadcast(&ctx->ctx_cv);
6905256dbbcSyamaguchi
6915256dbbcSyamaguchi mutex_exit(&ctx->ctx_mutex);
6925256dbbcSyamaguchi
6935256dbbcSyamaguchi workqueue_wait(ctx->ctx_wq, &ctx->ctx_wk);
6945256dbbcSyamaguchi
6955256dbbcSyamaguchi workqueue_destroy(ctx->ctx_wq);
6965256dbbcSyamaguchi if (hooks != NULL)
6975256dbbcSyamaguchi simplehook_destroy(hooks);
6985256dbbcSyamaguchi cv_destroy(&ctx->ctx_cv);
6995256dbbcSyamaguchi mutex_destroy(&ctx->ctx_mutex);
7005256dbbcSyamaguchi
7015256dbbcSyamaguchi return 0;
7025256dbbcSyamaguchi }
7035256dbbcSyamaguchi
7045256dbbcSyamaguchi static int
simplehook_tester_modcmd(modcmd_t cmd,void * arg __unused)7055256dbbcSyamaguchi simplehook_tester_modcmd(modcmd_t cmd, void *arg __unused)
7065256dbbcSyamaguchi {
7075256dbbcSyamaguchi int error;
7085256dbbcSyamaguchi
7095256dbbcSyamaguchi switch (cmd) {
7105256dbbcSyamaguchi case MODULE_CMD_INIT:
7115256dbbcSyamaguchi error = simplehook_tester_init();
7125256dbbcSyamaguchi break;
7135256dbbcSyamaguchi
7145256dbbcSyamaguchi case MODULE_CMD_FINI:
7155256dbbcSyamaguchi error = simplehook_tester_fini();
7165256dbbcSyamaguchi break;
7175256dbbcSyamaguchi
7185256dbbcSyamaguchi case MODULE_CMD_STAT:
7195256dbbcSyamaguchi default:
7205256dbbcSyamaguchi error = ENOTTY;
7215256dbbcSyamaguchi }
7225256dbbcSyamaguchi
7235256dbbcSyamaguchi return error;
7245256dbbcSyamaguchi }
725