
Prevent loading the kernel module if the kernel can be involuntarily preempted CAS will work if the kernel has been compiled with either CONFIG_PREEMPT_NONE, CONFIG_PREEMPT_VOLUNTARY, or CONFIG_PREEMPT_DYNAMIC. If the dynamic configuration is enabled, the kernel must be booted with preempt=none or preempt=voluntary. Signed-off-by: Michal Mielewczyk <michal.mielewczyk@huawei.com>
172 lines
4.5 KiB
C
172 lines
4.5 KiB
C
/*
|
|
* Copyright(c) 2012-2022 Intel Corporation
|
|
* Copyright(c) 2025 Huawei Technologies
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "cas_cache.h"
|
|
|
|
/* Layer information. */
|
|
MODULE_AUTHOR("Intel(R) Corporation");
|
|
MODULE_LICENSE("Dual BSD/GPL");
|
|
MODULE_VERSION(CAS_VERSION);
|
|
|
|
u32 max_writeback_queue_size = 65536;
|
|
module_param(max_writeback_queue_size, uint, (S_IRUSR | S_IRGRP));
|
|
MODULE_PARM_DESC(max_writeback_queue_size,
|
|
"Max cache writeback queue size (65536)");
|
|
|
|
u32 writeback_queue_unblock_size = 60000;
|
|
module_param(writeback_queue_unblock_size, uint, (S_IRUSR | S_IRGRP));
|
|
MODULE_PARM_DESC(writeback_queue_unblock_size,
|
|
"Cache writeback queue size (60000) at which queue "
|
|
"is unblocked when blocked");
|
|
|
|
u32 use_io_scheduler = 1;
|
|
module_param(use_io_scheduler, uint, (S_IRUSR | S_IRGRP));
|
|
MODULE_PARM_DESC(use_io_scheduler,
|
|
"Configure how IO shall be handled. "
|
|
"0 - in make request function, 1 - in request function");
|
|
|
|
u32 unaligned_io = 1;
|
|
module_param(unaligned_io, uint, (S_IRUSR | S_IRGRP));
|
|
MODULE_PARM_DESC(unaligned_io,
|
|
"Define how to handle I/O requests unaligned to 4 kiB, "
|
|
"0 - apply PT, 1 - handle by cache");
|
|
|
|
u32 seq_cut_off_mb = 1;
|
|
module_param(seq_cut_off_mb, uint, (S_IRUSR | S_IRGRP));
|
|
MODULE_PARM_DESC(seq_cut_off_mb,
|
|
"Sequential cut off threshold in MiB. 0 - disable");
|
|
|
|
/* globals */
|
|
ocf_ctx_t cas_ctx;
|
|
struct cas_module cas_module;
|
|
|
|
static inline uint32_t involuntary_preemption_enabled(void)
|
|
{
|
|
bool config_dynamic = IS_ENABLED(CONFIG_PREEMPT_DYNAMIC);
|
|
bool config_rt = IS_ENABLED(CONFIG_PREEMPT_RT);
|
|
bool config_preempt = IS_ENABLED(CONFIG_PREEMPT);
|
|
bool config_lazy = IS_ENABLED(CONFIG_PREEMPT_LAZY);
|
|
bool config_none = IS_ENABLED(CONFIG_PREEMPT_NONE);
|
|
|
|
if (!config_dynamic && !config_rt && !config_preempt && !config_lazy)
|
|
return false;
|
|
|
|
if (config_none)
|
|
return false;
|
|
|
|
if (config_rt || config_preempt || config_lazy) {
|
|
printk(KERN_ERR OCF_PREFIX_SHORT
|
|
"The kernel has been built with involuntary preemption "
|
|
"enabled.\nFailed to load Open CAS kernel module.\n");
|
|
return true;
|
|
}
|
|
|
|
#ifdef CONFIG_PREEMPT_DYNAMIC
|
|
/* preempt_model_none() or preempt_model_voluntary() are not defined if
|
|
* the kernel has been compiled without PREEMPT_DYNAMIC
|
|
*/
|
|
printk(KERN_WARNING OCF_PREFIX_SHORT
|
|
"The kernel has been compiled with preemption configurable\n"
|
|
"at boot time (PREEMPT_DYNAMIC=y). Open CAS doesn't support\n"
|
|
"kernels with involuntary preemption so make sure to set\n"
|
|
"\"preempt=\" to \"none\" or \"voluntary\" in the kernel"
|
|
" command line\n");
|
|
|
|
if (!preempt_model_none() && !preempt_model_voluntary()) {
|
|
printk(KERN_ERR OCF_PREFIX_SHORT
|
|
"The kernel has been booted with involuntary "
|
|
"preemption enabled.\nFailed to load Open CAS kernel "
|
|
"module.\n");
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
static int __init cas_init_module(void)
|
|
{
|
|
int result = 0;
|
|
|
|
if (involuntary_preemption_enabled())
|
|
return -ENOTSUP;
|
|
|
|
if (!writeback_queue_unblock_size || !max_writeback_queue_size) {
|
|
printk(KERN_ERR OCF_PREFIX_SHORT
|
|
"Invalid module parameter.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (writeback_queue_unblock_size >= max_writeback_queue_size) {
|
|
printk(KERN_ERR OCF_PREFIX_SHORT
|
|
"parameter writeback_queue_unblock_size"
|
|
" must be less than max_writeback_queue_size\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (unaligned_io != 0 && unaligned_io != 1) {
|
|
printk(KERN_ERR OCF_PREFIX_SHORT
|
|
"Invalid value for unaligned_io parameter\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (use_io_scheduler != 0 && use_io_scheduler != 1) {
|
|
printk(KERN_ERR OCF_PREFIX_SHORT
|
|
"Invalid value for use_io_scheduler parameter\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
result = cas_init_exp_objs();
|
|
if (result)
|
|
return result;
|
|
|
|
result = cas_init_disks();
|
|
if (result)
|
|
goto error_init_disks;
|
|
|
|
result = cas_initialize_context();
|
|
if (result) {
|
|
printk(KERN_ERR OCF_PREFIX_SHORT
|
|
"Cannot initialize cache library\n");
|
|
goto error_init_context;
|
|
}
|
|
|
|
result = cas_ctrl_device_init();
|
|
if (result) {
|
|
printk(KERN_ERR OCF_PREFIX_SHORT
|
|
"Cannot initialize control device\n");
|
|
goto error_init_device;
|
|
}
|
|
|
|
printk(KERN_INFO "%s Version %s (%s)::Module loaded successfully\n",
|
|
OCF_PREFIX_LONG, CAS_VERSION, CAS_KERNEL);
|
|
|
|
return 0;
|
|
|
|
error_init_device:
|
|
cas_cleanup_context();
|
|
error_init_context:
|
|
cas_deinit_disks();
|
|
error_init_disks:
|
|
cas_deinit_exp_objs();
|
|
|
|
return result;
|
|
}
|
|
|
|
module_init(cas_init_module);
|
|
|
|
static void __exit cas_exit_module(void)
|
|
{
|
|
cas_ctrl_device_deinit();
|
|
cas_cleanup_context();
|
|
cas_deinit_disks();
|
|
cas_deinit_exp_objs();
|
|
}
|
|
|
|
module_exit(cas_exit_module);
|