| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * Copyright (c) 2025, Stefan Metzmacher |
| */ |
| |
| #include "internal.h" |
| #include <linux/module.h> |
| |
| 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"); |