162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2015-2018 Oracle. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2005-2006 Network Appliance, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the BSD-type 1062306a36Sopenharmony_ci * license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1362306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 1462306a36Sopenharmony_ci * are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Redistributions of source code must retain the above copyright 1762306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Redistributions in binary form must reproduce the above 2062306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2162306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials provided 2262306a36Sopenharmony_ci * with the distribution. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Neither the name of the Network Appliance, Inc. nor the names of 2562306a36Sopenharmony_ci * its contributors may be used to endorse or promote products 2662306a36Sopenharmony_ci * derived from this software without specific prior written 2762306a36Sopenharmony_ci * permission. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3062306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3162306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3262306a36Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3362306a36Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3462306a36Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3562306a36Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3662306a36Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3762306a36Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3862306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3962306a36Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * Author: Tom Tucker <tom@opengridcomputing.com> 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include <linux/slab.h> 4562306a36Sopenharmony_ci#include <linux/fs.h> 4662306a36Sopenharmony_ci#include <linux/sysctl.h> 4762306a36Sopenharmony_ci#include <linux/workqueue.h> 4862306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h> 4962306a36Sopenharmony_ci#include <linux/sunrpc/sched.h> 5062306a36Sopenharmony_ci#include <linux/sunrpc/svc_rdma.h> 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define RPCDBG_FACILITY RPCDBG_SVCXPRT 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* RPC/RDMA parameters */ 5562306a36Sopenharmony_ciunsigned int svcrdma_ord = 16; /* historical default */ 5662306a36Sopenharmony_cistatic unsigned int min_ord = 1; 5762306a36Sopenharmony_cistatic unsigned int max_ord = 255; 5862306a36Sopenharmony_ciunsigned int svcrdma_max_requests = RPCRDMA_MAX_REQUESTS; 5962306a36Sopenharmony_ciunsigned int svcrdma_max_bc_requests = RPCRDMA_MAX_BC_REQUESTS; 6062306a36Sopenharmony_cistatic unsigned int min_max_requests = 4; 6162306a36Sopenharmony_cistatic unsigned int max_max_requests = 16384; 6262306a36Sopenharmony_ciunsigned int svcrdma_max_req_size = RPCRDMA_DEF_INLINE_THRESH; 6362306a36Sopenharmony_cistatic unsigned int min_max_inline = RPCRDMA_DEF_INLINE_THRESH; 6462306a36Sopenharmony_cistatic unsigned int max_max_inline = RPCRDMA_MAX_INLINE_THRESH; 6562306a36Sopenharmony_cistatic unsigned int svcrdma_stat_unused; 6662306a36Sopenharmony_cistatic unsigned int zero; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistruct percpu_counter svcrdma_stat_read; 6962306a36Sopenharmony_cistruct percpu_counter svcrdma_stat_recv; 7062306a36Sopenharmony_cistruct percpu_counter svcrdma_stat_sq_starve; 7162306a36Sopenharmony_cistruct percpu_counter svcrdma_stat_write; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cienum { 7462306a36Sopenharmony_ci SVCRDMA_COUNTER_BUFSIZ = sizeof(unsigned long long), 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int svcrdma_counter_handler(struct ctl_table *table, int write, 7862306a36Sopenharmony_ci void *buffer, size_t *lenp, loff_t *ppos) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct percpu_counter *stat = (struct percpu_counter *)table->data; 8162306a36Sopenharmony_ci char tmp[SVCRDMA_COUNTER_BUFSIZ + 1]; 8262306a36Sopenharmony_ci int len; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (write) { 8562306a36Sopenharmony_ci percpu_counter_set(stat, 0); 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci len = snprintf(tmp, SVCRDMA_COUNTER_BUFSIZ, "%lld\n", 9062306a36Sopenharmony_ci percpu_counter_sum_positive(stat)); 9162306a36Sopenharmony_ci if (len >= SVCRDMA_COUNTER_BUFSIZ) 9262306a36Sopenharmony_ci return -EFAULT; 9362306a36Sopenharmony_ci len = strlen(tmp); 9462306a36Sopenharmony_ci if (*ppos > len) { 9562306a36Sopenharmony_ci *lenp = 0; 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci len -= *ppos; 9962306a36Sopenharmony_ci if (len > *lenp) 10062306a36Sopenharmony_ci len = *lenp; 10162306a36Sopenharmony_ci if (len) 10262306a36Sopenharmony_ci memcpy(buffer, tmp, len); 10362306a36Sopenharmony_ci *lenp = len; 10462306a36Sopenharmony_ci *ppos += len; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic struct ctl_table_header *svcrdma_table_header; 11062306a36Sopenharmony_cistatic struct ctl_table svcrdma_parm_table[] = { 11162306a36Sopenharmony_ci { 11262306a36Sopenharmony_ci .procname = "max_requests", 11362306a36Sopenharmony_ci .data = &svcrdma_max_requests, 11462306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 11562306a36Sopenharmony_ci .mode = 0644, 11662306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 11762306a36Sopenharmony_ci .extra1 = &min_max_requests, 11862306a36Sopenharmony_ci .extra2 = &max_max_requests 11962306a36Sopenharmony_ci }, 12062306a36Sopenharmony_ci { 12162306a36Sopenharmony_ci .procname = "max_req_size", 12262306a36Sopenharmony_ci .data = &svcrdma_max_req_size, 12362306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 12462306a36Sopenharmony_ci .mode = 0644, 12562306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 12662306a36Sopenharmony_ci .extra1 = &min_max_inline, 12762306a36Sopenharmony_ci .extra2 = &max_max_inline 12862306a36Sopenharmony_ci }, 12962306a36Sopenharmony_ci { 13062306a36Sopenharmony_ci .procname = "max_outbound_read_requests", 13162306a36Sopenharmony_ci .data = &svcrdma_ord, 13262306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 13362306a36Sopenharmony_ci .mode = 0644, 13462306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 13562306a36Sopenharmony_ci .extra1 = &min_ord, 13662306a36Sopenharmony_ci .extra2 = &max_ord, 13762306a36Sopenharmony_ci }, 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci { 14062306a36Sopenharmony_ci .procname = "rdma_stat_read", 14162306a36Sopenharmony_ci .data = &svcrdma_stat_read, 14262306a36Sopenharmony_ci .maxlen = SVCRDMA_COUNTER_BUFSIZ, 14362306a36Sopenharmony_ci .mode = 0644, 14462306a36Sopenharmony_ci .proc_handler = svcrdma_counter_handler, 14562306a36Sopenharmony_ci }, 14662306a36Sopenharmony_ci { 14762306a36Sopenharmony_ci .procname = "rdma_stat_recv", 14862306a36Sopenharmony_ci .data = &svcrdma_stat_recv, 14962306a36Sopenharmony_ci .maxlen = SVCRDMA_COUNTER_BUFSIZ, 15062306a36Sopenharmony_ci .mode = 0644, 15162306a36Sopenharmony_ci .proc_handler = svcrdma_counter_handler, 15262306a36Sopenharmony_ci }, 15362306a36Sopenharmony_ci { 15462306a36Sopenharmony_ci .procname = "rdma_stat_write", 15562306a36Sopenharmony_ci .data = &svcrdma_stat_write, 15662306a36Sopenharmony_ci .maxlen = SVCRDMA_COUNTER_BUFSIZ, 15762306a36Sopenharmony_ci .mode = 0644, 15862306a36Sopenharmony_ci .proc_handler = svcrdma_counter_handler, 15962306a36Sopenharmony_ci }, 16062306a36Sopenharmony_ci { 16162306a36Sopenharmony_ci .procname = "rdma_stat_sq_starve", 16262306a36Sopenharmony_ci .data = &svcrdma_stat_sq_starve, 16362306a36Sopenharmony_ci .maxlen = SVCRDMA_COUNTER_BUFSIZ, 16462306a36Sopenharmony_ci .mode = 0644, 16562306a36Sopenharmony_ci .proc_handler = svcrdma_counter_handler, 16662306a36Sopenharmony_ci }, 16762306a36Sopenharmony_ci { 16862306a36Sopenharmony_ci .procname = "rdma_stat_rq_starve", 16962306a36Sopenharmony_ci .data = &svcrdma_stat_unused, 17062306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 17162306a36Sopenharmony_ci .mode = 0644, 17262306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 17362306a36Sopenharmony_ci .extra1 = &zero, 17462306a36Sopenharmony_ci .extra2 = &zero, 17562306a36Sopenharmony_ci }, 17662306a36Sopenharmony_ci { 17762306a36Sopenharmony_ci .procname = "rdma_stat_rq_poll", 17862306a36Sopenharmony_ci .data = &svcrdma_stat_unused, 17962306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 18062306a36Sopenharmony_ci .mode = 0644, 18162306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 18262306a36Sopenharmony_ci .extra1 = &zero, 18362306a36Sopenharmony_ci .extra2 = &zero, 18462306a36Sopenharmony_ci }, 18562306a36Sopenharmony_ci { 18662306a36Sopenharmony_ci .procname = "rdma_stat_rq_prod", 18762306a36Sopenharmony_ci .data = &svcrdma_stat_unused, 18862306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 18962306a36Sopenharmony_ci .mode = 0644, 19062306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 19162306a36Sopenharmony_ci .extra1 = &zero, 19262306a36Sopenharmony_ci .extra2 = &zero, 19362306a36Sopenharmony_ci }, 19462306a36Sopenharmony_ci { 19562306a36Sopenharmony_ci .procname = "rdma_stat_sq_poll", 19662306a36Sopenharmony_ci .data = &svcrdma_stat_unused, 19762306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 19862306a36Sopenharmony_ci .mode = 0644, 19962306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 20062306a36Sopenharmony_ci .extra1 = &zero, 20162306a36Sopenharmony_ci .extra2 = &zero, 20262306a36Sopenharmony_ci }, 20362306a36Sopenharmony_ci { 20462306a36Sopenharmony_ci .procname = "rdma_stat_sq_prod", 20562306a36Sopenharmony_ci .data = &svcrdma_stat_unused, 20662306a36Sopenharmony_ci .maxlen = sizeof(unsigned int), 20762306a36Sopenharmony_ci .mode = 0644, 20862306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 20962306a36Sopenharmony_ci .extra1 = &zero, 21062306a36Sopenharmony_ci .extra2 = &zero, 21162306a36Sopenharmony_ci }, 21262306a36Sopenharmony_ci { }, 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic void svc_rdma_proc_cleanup(void) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci if (!svcrdma_table_header) 21862306a36Sopenharmony_ci return; 21962306a36Sopenharmony_ci unregister_sysctl_table(svcrdma_table_header); 22062306a36Sopenharmony_ci svcrdma_table_header = NULL; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci percpu_counter_destroy(&svcrdma_stat_write); 22362306a36Sopenharmony_ci percpu_counter_destroy(&svcrdma_stat_sq_starve); 22462306a36Sopenharmony_ci percpu_counter_destroy(&svcrdma_stat_recv); 22562306a36Sopenharmony_ci percpu_counter_destroy(&svcrdma_stat_read); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int svc_rdma_proc_init(void) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci int rc; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (svcrdma_table_header) 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci rc = percpu_counter_init(&svcrdma_stat_read, 0, GFP_KERNEL); 23662306a36Sopenharmony_ci if (rc) 23762306a36Sopenharmony_ci goto out_err; 23862306a36Sopenharmony_ci rc = percpu_counter_init(&svcrdma_stat_recv, 0, GFP_KERNEL); 23962306a36Sopenharmony_ci if (rc) 24062306a36Sopenharmony_ci goto out_err; 24162306a36Sopenharmony_ci rc = percpu_counter_init(&svcrdma_stat_sq_starve, 0, GFP_KERNEL); 24262306a36Sopenharmony_ci if (rc) 24362306a36Sopenharmony_ci goto out_err; 24462306a36Sopenharmony_ci rc = percpu_counter_init(&svcrdma_stat_write, 0, GFP_KERNEL); 24562306a36Sopenharmony_ci if (rc) 24662306a36Sopenharmony_ci goto out_err; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci svcrdma_table_header = register_sysctl("sunrpc/svc_rdma", 24962306a36Sopenharmony_ci svcrdma_parm_table); 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ciout_err: 25362306a36Sopenharmony_ci percpu_counter_destroy(&svcrdma_stat_sq_starve); 25462306a36Sopenharmony_ci percpu_counter_destroy(&svcrdma_stat_recv); 25562306a36Sopenharmony_ci percpu_counter_destroy(&svcrdma_stat_read); 25662306a36Sopenharmony_ci return rc; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_civoid svc_rdma_cleanup(void) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n"); 26262306a36Sopenharmony_ci svc_unreg_xprt_class(&svc_rdma_class); 26362306a36Sopenharmony_ci svc_rdma_proc_cleanup(); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ciint svc_rdma_init(void) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci int rc; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci dprintk("SVCRDMA Module Init, register RPC RDMA transport\n"); 27162306a36Sopenharmony_ci dprintk("\tsvcrdma_ord : %d\n", svcrdma_ord); 27262306a36Sopenharmony_ci dprintk("\tmax_requests : %u\n", svcrdma_max_requests); 27362306a36Sopenharmony_ci dprintk("\tmax_bc_requests : %u\n", svcrdma_max_bc_requests); 27462306a36Sopenharmony_ci dprintk("\tmax_inline : %d\n", svcrdma_max_req_size); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci rc = svc_rdma_proc_init(); 27762306a36Sopenharmony_ci if (rc) 27862306a36Sopenharmony_ci return rc; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* Register RDMA with the SVC transport switch */ 28162306a36Sopenharmony_ci svc_reg_xprt_class(&svc_rdma_class); 28262306a36Sopenharmony_ci return 0; 28362306a36Sopenharmony_ci} 284