Viewing: ofd_oss.c
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
* Copyright (c) 2011, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
*
* Author: Peter J. Braam <braam@clusterfs.com>
* Author: Phil Schwan <phil@clusterfs.com>
*/
#define DEBUG_SUBSYSTEM S_OST
#include <linux/module.h>
#include <lustre_dlm.h>
#include <lprocfs_status.h>
#include <lustre_nodemap.h>
#include <obd_class.h>
#include "ofd_internal.h"
#define OSS_SERVICE_WATCHDOG_FACTOR 2
static int oss_max_threads = 512;
module_param(oss_max_threads, int, 0444);
MODULE_PARM_DESC(oss_max_threads, "maximum number of OSS service threads");
static int oss_num_threads;
module_param(oss_num_threads, int, 0444);
MODULE_PARM_DESC(oss_num_threads, "number of OSS service threads to start");
static unsigned int oss_cpu_bind = 1;
module_param(oss_cpu_bind, uint, 0444);
MODULE_PARM_DESC(oss_cpu_bind,
"bind OSS service threads to particular CPU partitions");
static int oss_num_create_threads;
module_param(oss_num_create_threads, int, 0444);
MODULE_PARM_DESC(oss_num_create_threads,
"number of OSS create threads to start");
static unsigned int oss_create_cpu_bind = 1;
module_param(oss_create_cpu_bind, uint, 0444);
MODULE_PARM_DESC(oss_create_cpu_bind,
"bind OSS create threads to particular CPU partitions");
static char *oss_cpts;
module_param(oss_cpts, charp, 0444);
MODULE_PARM_DESC(oss_cpts, "CPU partitions OSS threads should run on");
static char *oss_io_cpts;
module_param(oss_io_cpts, charp, 0444);
MODULE_PARM_DESC(oss_io_cpts, "CPU partitions OSS IO threads should run on");
static struct cfs_cpt_table *ost_io_cptable;
/* Sigh - really, this is an OSS, the _server_, not the _target_ */
static int oss_device_init(const struct lu_env *env, struct lu_device *lu,
const char *name, struct lu_device *next)
{
static struct ptlrpc_service_conf svc_conf;
struct obd_device *obd = lu->ld_obd;
struct ost_obd *ost = obd2ost(obd);
nodemask_t *mask;
int rc;
ENTRY;
rc = lprocfs_obd_setup(obd, true);
if (rc)
return rc;
mutex_init(&ost->ost_health_mutex);
svc_conf = (typeof(svc_conf)) {
.psc_name = LUSTRE_OSS_NAME,
.psc_watchdog_factor = OSS_SERVICE_WATCHDOG_FACTOR,
.psc_buf = {
.bc_nbufs = OST_NBUFS,
.bc_buf_size = OST_BUFSIZE,
.bc_req_max_size = OST_MAXREQSIZE,
.bc_rep_max_size = OST_MAXREPSIZE,
.bc_req_portal = OST_REQUEST_PORTAL,
.bc_rep_portal = OSC_REPLY_PORTAL,
},
.psc_thr = {
.tc_thr_name = "ll_ost",
.tc_thr_factor = OSS_THR_FACTOR,
.tc_nthrs_init = OSS_NTHRS_INIT,
.tc_nthrs_base = OSS_NTHRS_BASE,
.tc_nthrs_max = oss_max_threads,
.tc_nthrs_user = oss_num_threads,
.tc_cpu_bind = oss_cpu_bind,
.tc_ctx_tags = LCT_DT_THREAD,
},
.psc_cpt = {
.cc_pattern = oss_cpts,
.cc_affinity = true,
},
.psc_ops = {
.so_req_handler = tgt_request_handle,
.so_req_printer = target_print_req,
.so_hpreq_handler = ptlrpc_hpreq_handler,
},
};
ost->ost_service = ptlrpc_register_service(&svc_conf,
&obd->obd_kset,
obd->obd_debugfs_entry);
if (IS_ERR(ost->ost_service)) {
rc = PTR_ERR(ost->ost_service);
CERROR("oss: failed to start service: %d\n", rc);
GOTO(out_lprocfs, rc);
}
memset(&svc_conf, 0, sizeof(svc_conf));
svc_conf = (typeof(svc_conf)) {
.psc_name = "ost_create",
.psc_watchdog_factor = OSS_SERVICE_WATCHDOG_FACTOR,
.psc_buf = {
.bc_nbufs = OST_NBUFS,
.bc_buf_size = OST_BUFSIZE,
.bc_req_max_size = OST_MAXREQSIZE,
.bc_rep_max_size = OST_MAXREPSIZE,
.bc_req_portal = OST_CREATE_PORTAL,
.bc_rep_portal = OSC_REPLY_PORTAL,
},
.psc_thr = {
.tc_thr_name = "ll_ost_create",
.tc_thr_factor = OSS_CR_THR_FACTOR,
.tc_nthrs_init = OSS_CR_NTHRS_INIT,
.tc_nthrs_base = OSS_CR_NTHRS_BASE,
.tc_nthrs_max = OSS_CR_NTHRS_MAX,
.tc_nthrs_user = oss_num_create_threads,
.tc_cpu_bind = oss_create_cpu_bind,
.tc_ctx_tags = LCT_DT_THREAD,
},
.psc_cpt = {
.cc_pattern = oss_cpts,
.cc_affinity = true,
},
.psc_ops = {
.so_req_handler = tgt_request_handle,
.so_req_printer = target_print_req,
},
};
ost->ost_create_service = ptlrpc_register_service(&svc_conf,
&obd->obd_kset,
obd->obd_debugfs_entry
);
if (IS_ERR(ost->ost_create_service)) {
rc = PTR_ERR(ost->ost_create_service);
CERROR("oss: failed to start OST create service: %d\n", rc);
GOTO(out_service, rc);
}
mask = cfs_cpt_nodemask(cfs_cpt_tab, CFS_CPT_ANY);
/* event CPT feature is disabled in libcfs level by set partition
* number to 1, we still want to set node affinity for io service
*/
if (cfs_cpt_number(cfs_cpt_tab) == 1 && nodes_weight(*mask) > 1) {
int cpt = 0;
int i;
ost_io_cptable = cfs_cpt_table_alloc(nodes_weight(*mask));
for_each_node_mask(i, *mask) {
if (!ost_io_cptable) {
CWARN("oss: failed to create CPT table\n");
break;
}
rc = cfs_cpt_set_node(ost_io_cptable, cpt++, i);
if (!rc) {
CWARN("oss: Failed to set node %d for IO CPT table\n",
i);
cfs_cpt_table_free(ost_io_cptable);
ost_io_cptable = NULL;
break;
}
}
rc = 0;
}
memset(&svc_conf, 0, sizeof(svc_conf));
svc_conf = (typeof(svc_conf)) {
.psc_name = "ost_io",
.psc_watchdog_factor = OSS_SERVICE_WATCHDOG_FACTOR,
.psc_buf = {
.bc_nbufs = OST_NBUFS,
.bc_buf_size = OST_IO_BUFSIZE,
.bc_req_max_size = OST_IO_MAXREQSIZE,
.bc_rep_max_size = OST_IO_MAXREPSIZE,
.bc_req_portal = OST_IO_PORTAL,
.bc_rep_portal = OSC_REPLY_PORTAL,
},
.psc_thr = {
.tc_thr_name = "ll_ost_io",
.tc_thr_factor = OSS_THR_FACTOR,
.tc_nthrs_init = OSS_NTHRS_INIT,
.tc_nthrs_base = OSS_NTHRS_BASE,
.tc_nthrs_max = oss_max_threads,
.tc_nthrs_user = oss_num_threads,
.tc_cpu_bind = oss_cpu_bind,
.tc_ctx_tags = LCT_DT_THREAD,
},
.psc_cpt = {
.cc_cptable = ost_io_cptable,
.cc_pattern = ost_io_cptable == NULL ?
oss_io_cpts : NULL,
.cc_affinity = true,
},
.psc_ops = {
.so_thr_init = tgt_io_thread_init,
.so_thr_done = tgt_io_thread_done,
.so_req_handler = tgt_request_handle,
.so_hpreq_handler = tgt_hpreq_handler,
.so_req_printer = target_print_req,
},
};
ost->ost_io_service = ptlrpc_register_service(&svc_conf,
&obd->obd_kset,
obd->obd_debugfs_entry);
if (IS_ERR(ost->ost_io_service)) {
rc = PTR_ERR(ost->ost_io_service);
CERROR("oss: failed to start OST I/O service: rc = %d\n", rc);
ost->ost_io_service = NULL;
GOTO(out_create, rc);
}
memset(&svc_conf, 0, sizeof(svc_conf));
svc_conf = (typeof(svc_conf)) {
.psc_name = "ost_seq",
.psc_watchdog_factor = OSS_SERVICE_WATCHDOG_FACTOR,
.psc_buf = {
.bc_nbufs = OST_NBUFS,
.bc_buf_size = OST_BUFSIZE,
.bc_req_max_size = OST_MAXREQSIZE,
.bc_rep_max_size = OST_MAXREPSIZE,
.bc_req_portal = SEQ_DATA_PORTAL,
.bc_rep_portal = OSC_REPLY_PORTAL,
},
.psc_thr = {
.tc_thr_name = "ll_ost_seq",
.tc_thr_factor = OSS_CR_THR_FACTOR,
.tc_nthrs_init = OSS_CR_NTHRS_INIT,
.tc_nthrs_base = OSS_CR_NTHRS_BASE,
.tc_nthrs_max = OSS_CR_NTHRS_MAX,
.tc_nthrs_user = oss_num_create_threads,
.tc_cpu_bind = oss_create_cpu_bind,
.tc_ctx_tags = LCT_DT_THREAD,
},
.psc_cpt = {
.cc_pattern = oss_cpts,
.cc_affinity = true,
},
.psc_ops = {
.so_req_handler = tgt_request_handle,
.so_req_printer = target_print_req,
.so_hpreq_handler = NULL,
},
};
ost->ost_seq_service = ptlrpc_register_service(&svc_conf,
&obd->obd_kset,
obd->obd_debugfs_entry);
if (IS_ERR(ost->ost_seq_service)) {
rc = PTR_ERR(ost->ost_seq_service);
CERROR("oss: failed to start OST seq service: %d\n", rc);
ost->ost_seq_service = NULL;
GOTO(out_io, rc);
}
/* Object update service */
memset(&svc_conf, 0, sizeof(svc_conf));
svc_conf = (typeof(svc_conf)) {
.psc_name = "ost_out",
.psc_watchdog_factor = OSS_SERVICE_WATCHDOG_FACTOR,
.psc_buf = {
.bc_nbufs = OST_NBUFS,
.bc_buf_size = OUT_BUFSIZE,
.bc_req_max_size = OUT_MAXREQSIZE,
.bc_rep_max_size = OUT_MAXREPSIZE,
.bc_req_portal = OUT_PORTAL,
.bc_rep_portal = OSC_REPLY_PORTAL,
},
/*
* We'd like to have a mechanism to set this on a per-device
* basis, but alas...
*/
.psc_thr = {
.tc_thr_name = "ll_ost_out",
.tc_thr_factor = OSS_CR_THR_FACTOR,
.tc_nthrs_init = OSS_CR_NTHRS_INIT,
.tc_nthrs_base = OSS_CR_NTHRS_BASE,
.tc_nthrs_max = OSS_CR_NTHRS_MAX,
.tc_nthrs_user = oss_num_create_threads,
.tc_cpu_bind = oss_create_cpu_bind,
.tc_ctx_tags = LCT_MD_THREAD |
LCT_DT_THREAD,
},
.psc_cpt = {
.cc_pattern = oss_cpts,
.cc_affinity = true,
},
.psc_ops = {
.so_req_handler = tgt_request_handle,
.so_req_printer = target_print_req,
.so_hpreq_handler = NULL,
},
};
ost->ost_out_service = ptlrpc_register_service(&svc_conf,
&obd->obd_kset,
obd->obd_debugfs_entry);
if (IS_ERR(ost->ost_out_service)) {
rc = PTR_ERR(ost->ost_out_service);
CERROR("oss: failed to start out service: %d\n", rc);
ost->ost_out_service = NULL;
GOTO(out_seq, rc);
}
ping_evictor_start();
RETURN(0);
out_seq:
ptlrpc_unregister_service(ost->ost_seq_service);
ost->ost_seq_service = NULL;
out_io:
ptlrpc_unregister_service(ost->ost_io_service);
ost->ost_io_service = NULL;
out_create:
ptlrpc_unregister_service(ost->ost_create_service);
ost->ost_create_service = NULL;
out_service:
ptlrpc_unregister_service(ost->ost_service);
ost->ost_service = NULL;
out_lprocfs:
lprocfs_obd_cleanup(obd);
RETURN(rc);
}
static struct lu_device *oss_device_free(const struct lu_env *env,
struct lu_device *lu)
{
struct obd_device *obd = lu->ld_obd;
struct ost_obd *ost = obd2ost(obd);
ENTRY;
ping_evictor_stop();
/* there is no recovery for OST OBD, all recovery is controlled by
* obdfilter OBD
*/
LASSERT(!test_bit(OBDF_RECOVERING, obd->obd_flags));
mutex_lock(&ost->ost_health_mutex);
ptlrpc_unregister_service(ost->ost_service);
ptlrpc_unregister_service(ost->ost_create_service);
ptlrpc_unregister_service(ost->ost_io_service);
ptlrpc_unregister_service(ost->ost_seq_service);
ptlrpc_unregister_service(ost->ost_out_service);
ost->ost_service = NULL;
ost->ost_create_service = NULL;
ost->ost_io_service = NULL;
ost->ost_seq_service = NULL;
ost->ost_out_service = NULL;
mutex_unlock(&ost->ost_health_mutex);
lprocfs_obd_cleanup(obd);
if (ost_io_cptable) {
cfs_cpt_table_free(ost_io_cptable);
ost_io_cptable = NULL;
}
OBD_FREE_PTR(lu);
RETURN(NULL);
}
static int oss_health_check(const struct lu_env *env, struct obd_device *obd)
{
struct ost_obd *ost = obd2ost(obd);
int rc = 0;
mutex_lock(&ost->ost_health_mutex);
rc |= ptlrpc_service_health_check(ost->ost_service);
rc |= ptlrpc_service_health_check(ost->ost_create_service);
rc |= ptlrpc_service_health_check(ost->ost_io_service);
rc |= ptlrpc_service_health_check(ost->ost_seq_service);
mutex_unlock(&ost->ost_health_mutex);
return rc != 0 ? 1 : 0;
}
/* ioctls on obd dev */
static int oss_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
void *karg, void __user *uarg)
{
struct obd_device *obd = exp->exp_obd;
struct obd_ioctl_data *data;
bool dynamic = true;
int rc = 0;
ENTRY;
CDEBUG(D_IOCTL, "%s: cmd=%x len=%u karg=%pK uarg=%pK\n",
obd->obd_name, cmd, len, karg, uarg);
data = karg;
/* we only support nodemap ioctls, for now */
if (cmd != OBD_IOC_NODEMAP)
GOTO(out, rc = -EINVAL);
rc = server_iocontrol_nodemap(obd, data, &dynamic, NULL, NULL);
if (rc)
GOTO(out, rc);
out:
RETURN(rc);
}
static const struct lu_device_type_operations oss_type_ops = {
.ldto_device_free = oss_device_free,
.ldto_device_init = oss_device_init,
};
static struct lu_device_type oss_device_type = {
.ldt_tags = LU_DEVICE_MISC,
.ldt_name = LUSTRE_OSS_NAME,
.ldt_ops = &oss_type_ops,
.ldt_ctx_tags = LCT_LOCAL
};
/* use obd ops to offer management infrastructure */
static const struct obd_ops oss_obd_ops = {
.o_owner = THIS_MODULE,
.o_health_check = oss_health_check,
.o_iocontrol = oss_iocontrol,
};
int oss_mod_init(void)
{
int rc;
ENTRY;
rc = libcfs_setup();
if (rc)
RETURN(rc);
rc = class_register_type(&oss_obd_ops, NULL, false,
LUSTRE_OSS_NAME,
&oss_device_type);
RETURN(rc);
}
void oss_mod_exit(void)
{
class_unregister_type(LUSTRE_OSS_NAME);
}