diff --git a/include/os/windows/spl/sys/kmem.h b/include/os/windows/spl/sys/kmem.h index 4efcc9af24e5..f457df156439 100644 --- a/include/os/windows/spl/sys/kmem.h +++ b/include/os/windows/spl/sys/kmem.h @@ -78,6 +78,7 @@ void spl_kmem_init(uint64_t); void spl_kmem_thread_init(); void spl_kmem_mp_init(); void spl_kmem_thread_fini(); +void spl_kmem_timer_fini(); void spl_kmem_fini(); uint64_t kmem_size(void); diff --git a/include/os/windows/spl/sys/systm.h b/include/os/windows/spl/sys/systm.h index 3ac5da75b0c2..495660807f83 100644 --- a/include/os/windows/spl/sys/systm.h +++ b/include/os/windows/spl/sys/systm.h @@ -52,7 +52,7 @@ static inline void bsd_timeout_handler(void *arg) static inline void bsd_untimeout(void(*func)(void *), void *ID) { /* - * Unfortunately, calling KeSetTimer() does not Signal (or abort) any thread + * Unfortunately, calling KeCancelTimer() does not Signal (or abort) any thread * sitting in KeWaitForSingleObject() so they would wait forever. Instead we * change the timeout to be now, so that the threads can exit. */ @@ -93,4 +93,29 @@ static inline void bsd_timeout(void *FUNC, void *ID, struct timespec *TIM) } } +/* + * Unfortunately, calling KeCancelTimer() does not Signal (or abort) any thread + * sitting in KeWaitForSingleObject() so they would wait forever. Call this + * function only when there are no threads waiting in bsd_timeout_handler(). + * Unloading the driver with loaded timer object can cause bugcheck when the + * timer fires. + */ +static inline void bsd_timeout_cancel(void *ID) +{ + struct bsd_timeout_wrapper *btw = (struct bsd_timeout_wrapper *)ID; + + if (btw == NULL) { + dprintf("%s NULL ID is not implemented\n", __func__); + return; + } + + if (btw->func != NULL) { + if (KeCancelTimer(&btw->timer)) { + dprintf("timer object was loaded.Cancelled it.\n"); + } else { + dprintf("timer object is not loaded.\n"); + } + } +} + #endif /* SPL_SYSTM_H */ diff --git a/include/os/windows/spl/sys/vmem.h b/include/os/windows/spl/sys/vmem.h index f1014ac80cbc..035beeb53cac 100644 --- a/include/os/windows/spl/sys/vmem.h +++ b/include/os/windows/spl/sys/vmem.h @@ -137,6 +137,7 @@ typedef void *(vmem_ximport_t)(vmem_t *, size_t *, size_t, int); extern vmem_t *vmem_init(const char *, void *, size_t, size_t, vmem_alloc_t *, vmem_free_t *); extern void vmem_fini(vmem_t *); +extern void vmem_timer_fini(); extern void vmem_update(void *); extern int vmem_is_populator(); extern size_t vmem_seg_size; diff --git a/module/os/windows/spl/spl-kmem.c b/module/os/windows/spl/spl-kmem.c index d8bec5880db7..6d7c4ac81fbe 100644 --- a/module/os/windows/spl/spl-kmem.c +++ b/module/os/windows/spl/spl-kmem.c @@ -5381,6 +5381,14 @@ spl_kmem_thread_fini(void) } +void +spl_kmem_timer_fini(void) +{ + bsd_timeout_cancel(&kmem_update_timer); + bsd_timeout_cancel(&kmem_reaping); + bsd_timeout_cancel(&kmem_reaping_idspace); +} + void spl_kmem_mp_init(void) { diff --git a/module/os/windows/spl/spl-lookasidelist.c b/module/os/windows/spl/spl-lookasidelist.c index 926f07f9ef19..afb0f1506a65 100644 --- a/module/os/windows/spl/spl-lookasidelist.c +++ b/module/os/windows/spl/spl-lookasidelist.c @@ -135,13 +135,14 @@ lookasidelist_cache_destroy(lookasidelist_cache_t *pLookasidelist_cache) if (pLookasidelist_cache != NULL) { ExFlushLookasideListEx(&pLookasidelist_cache->lookasideField); ExDeleteLookasideListEx(&pLookasidelist_cache->lookasideField); - ExFreePoolWithTag(pLookasidelist_cache, - ZFS_LookAsideList_DRV_TAG); if (pLookasidelist_cache->cache_kstat != NULL) { kstat_delete(pLookasidelist_cache->cache_kstat); pLookasidelist_cache->cache_kstat = NULL; } + + ExFreePoolWithTag(pLookasidelist_cache, + ZFS_LookAsideList_DRV_TAG); } } diff --git a/module/os/windows/spl/spl-vmem.c b/module/os/windows/spl/spl-vmem.c index c8b253a10f90..c84abb73a64d 100644 --- a/module/os/windows/spl/spl-vmem.c +++ b/module/os/windows/spl/spl-vmem.c @@ -3563,6 +3563,12 @@ vmem_fini_void(void *vmp, void *start, size_t size) { } +void +vmem_timer_fini() +{ + bsd_timeout_cancel(&vmem_update_timer); +} + void vmem_fini(vmem_t *heap) { diff --git a/module/os/windows/spl/spl-windows.c b/module/os/windows/spl/spl-windows.c index 9a35484524cc..a58fdcc88198 100644 --- a/module/os/windows/spl/spl-windows.c +++ b/module/os/windows/spl/spl-windows.c @@ -554,6 +554,15 @@ spl_stop(void) IOLog("SPL: active threads %d\n", zfs_threads); delay(hz << 2); } + + /* + * At this point, all threads waiting on bsd_timers in + * bsd_timeout_handler() are exited and timer can be cancelled. If the + * timer is still loaded,it could fire after driver unload and bugcheck + */ + spl_kmem_timer_fini(); + vmem_timer_fini(); + return (STATUS_SUCCESS); }