// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2025, Stefan Metzmacher */ #include "internal.h" #include struct smbdirect_module_state smbdirect_globals = { .mutex = __MUTEX_INITIALIZER(smbdirect_globals.mutex), }; static __init int smbdirect_module_init(void) { int ret = -ENOMEM; pr_notice("subsystem loading...\n"); mutex_lock(&smbdirect_globals.mutex); smbdirect_globals.workqueues.accept = alloc_workqueue("smbdirect-accept", WQ_SYSFS | WQ_PERCPU | WQ_POWER_EFFICIENT, 0); if (smbdirect_globals.workqueues.accept == NULL) goto alloc_accept_wq_failed; smbdirect_globals.workqueues.connect = alloc_workqueue("smbdirect-connect", WQ_SYSFS | WQ_PERCPU | WQ_POWER_EFFICIENT, 0); if (smbdirect_globals.workqueues.connect == NULL) goto alloc_connect_wq_failed; smbdirect_globals.workqueues.idle = alloc_workqueue("smbdirect-idle", WQ_SYSFS | WQ_PERCPU | WQ_POWER_EFFICIENT, 0); if (smbdirect_globals.workqueues.idle == NULL) goto alloc_idle_wq_failed; smbdirect_globals.workqueues.refill = alloc_workqueue("smbdirect-refill", WQ_HIGHPRI | WQ_SYSFS | WQ_PERCPU | WQ_POWER_EFFICIENT, 0); if (smbdirect_globals.workqueues.refill == NULL) goto alloc_refill_wq_failed; smbdirect_globals.workqueues.immediate = alloc_workqueue("smbdirect-immediate", WQ_HIGHPRI | WQ_SYSFS | WQ_PERCPU | WQ_POWER_EFFICIENT, 0); if (smbdirect_globals.workqueues.immediate == NULL) goto alloc_immediate_wq_failed; smbdirect_globals.workqueues.cleanup = alloc_workqueue("smbdirect-cleanup", WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_SYSFS | WQ_PERCPU | WQ_POWER_EFFICIENT, 0); if (smbdirect_globals.workqueues.cleanup == NULL) goto alloc_cleanup_wq_failed; ret = smbdirect_devices_init(); if (ret) goto devices_init_failed; mutex_unlock(&smbdirect_globals.mutex); pr_notice("subsystem loaded\n"); return 0; devices_init_failed: destroy_workqueue(smbdirect_globals.workqueues.cleanup); alloc_cleanup_wq_failed: destroy_workqueue(smbdirect_globals.workqueues.immediate); alloc_immediate_wq_failed: destroy_workqueue(smbdirect_globals.workqueues.refill); alloc_refill_wq_failed: destroy_workqueue(smbdirect_globals.workqueues.idle); alloc_idle_wq_failed: destroy_workqueue(smbdirect_globals.workqueues.connect); alloc_connect_wq_failed: destroy_workqueue(smbdirect_globals.workqueues.accept); alloc_accept_wq_failed: mutex_unlock(&smbdirect_globals.mutex); pr_crit("failed to loaded: %d (%1pe)\n", ret, SMBDIRECT_DEBUG_ERR_PTR(ret)); return ret; } static __exit void smbdirect_module_exit(void) { pr_notice("subsystem unloading...\n"); mutex_lock(&smbdirect_globals.mutex); smbdirect_devices_exit(); destroy_workqueue(smbdirect_globals.workqueues.accept); destroy_workqueue(smbdirect_globals.workqueues.connect); destroy_workqueue(smbdirect_globals.workqueues.idle); destroy_workqueue(smbdirect_globals.workqueues.refill); destroy_workqueue(smbdirect_globals.workqueues.immediate); destroy_workqueue(smbdirect_globals.workqueues.cleanup); mutex_unlock(&smbdirect_globals.mutex); pr_notice("subsystem unloaded\n"); } module_init(smbdirect_module_init); module_exit(smbdirect_module_exit); MODULE_DESCRIPTION("smbdirect subsystem"); MODULE_LICENSE("GPL");