DF-2986 / cv2986.c
/* DF-2986: cv_destroy performs no waiters validation - destroying a cv * with a live waiter (cv_waiters==1) is completely undiagnosed. */ #include <sys/param.h> #include <sys/module.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/condvar.h> #include <sys/kthread.h> #include <sys/lock.h> static struct cv probe_cv; static int waiter_done; static void cv2986_thread(void *arg) { cv_wait(&probe_cv, NULL); /* blocks forever until signalled */ waiter_done = 1; lwkt_exit(); } static int cv2986_modevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: cv_init(&probe_cv, "df2986"); kthread_create(cv2986_thread, NULL, NULL, "df2986w"); kprintf("DF2986: waiter thread parked in cv_wait\n"); tsleep(&probe_cv, 0, "df2986a", hz); /* let it block */ kprintf("DF2986: cv_waiters=%u (thread is blocked on cv)\n", probe_cv.cv_waiters); cv_destroy(&probe_cv); /* <-- destroy with live waiter */ kprintf("DF2986: cv_destroy returned with NO diagnostic " "(spin_uninit is a no-op) - bug reproduced\n"); /* Wake the waiter through the destroyed cv to release it cleanly */ cv_signal(&probe_cv); tsleep(&probe_cv, 0, "df2986b", 2*hz); kprintf("DF2986: waiter_done=%d (stale cv identity still wakes it)\n", waiter_done); break; case MOD_UNLOAD: break; default: return EOPNOTSUPP; } return 0; } static moduledata_t cv2986_mod = { "cv2986", cv2986_modevent, NULL }; DECLARE_MODULE(cv2986, cv2986_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); |