Viewing: gnilnd_sysctl.c
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2012 Cray, Inc.
*
* Copyright (c) 2014, Intel Corporation.
*/
/* This file is part of Lustre, http://www.lustre.org.
*
* Author: Nic Henke <nic@cray.com>
* Author: James Shimek <jshimek@cray.com>
*/
/* this code liberated and modified from Lustre */
#define DEBUG_SUBSYSTEM S_LND
#include <lustre_compat/linux/linux-misc.h>
#include "gnilnd.h"
#define GNILND_PEERSTATE_STRLEN 16
typedef struct kgn_sysctl_data {
int ksd_pause_trigger;
int ksd_quiesce_secs;
int ksd_rdmaq_override;
char ksd_peer_state[GNILND_PEERSTATE_STRLEN];
} kgn_sysctl_data_t;
static kgn_sysctl_data_t kgnilnd_sysctl;
#if defined(CONFIG_SYSCTL)
static struct ctl_table_header *kgnilnd_table_header = NULL;
static int
proc_toggle_thread_pause(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int old_val = kgnilnd_sysctl.ksd_pause_trigger;
int rc = 0;
ENTRY;
rc = proc_dointvec(table, write, buffer, lenp, ppos);
if (!write) {
/* read */
RETURN(rc);
}
if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
rc = -EINVAL;
RETURN(rc);
}
if (old_val != kgnilnd_sysctl.ksd_pause_trigger) {
mutex_lock(&kgnilnd_data.kgn_quiesce_mutex);
CDEBUG(D_NET, "setting quiesce_trigger %d\n", old_val);
kgnilnd_data.kgn_quiesce_trigger = kgnilnd_sysctl.ksd_pause_trigger;
kgnilnd_quiesce_wait("admin sysctl");
mutex_unlock(&kgnilnd_data.kgn_quiesce_mutex);
}
RETURN(rc);
}
static int
proc_hw_quiesce(struct ctl_table *table, int write, void __user *buffer,
size_t *lenp, loff_t *ppos)
{
int rc = 0;
kgn_device_t *dev;
ENTRY;
rc = proc_dointvec(table, write, buffer, lenp, ppos);
if (!write) {
/* read */
RETURN(rc);
}
if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
rc = -EINVAL;
RETURN(rc);
}
/* only device 0 gets the handle, see kgnilnd_dev_init */
dev = &kgnilnd_data.kgn_devices[0];
LASSERTF(dev != NULL, "dev 0 is NULL\n");
kgnilnd_quiesce_end_callback(dev->gnd_handle,
kgnilnd_sysctl.ksd_quiesce_secs * MSEC_PER_SEC);
RETURN(rc);
}
static int
proc_trigger_stack_reset(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int rc = 0;
int i = 1;
kgn_device_t *dev;
ENTRY;
if (!write) {
/* read */
rc = proc_dointvec(table, write, buffer, lenp, ppos);
RETURN(rc);
}
/* only device 0 gets the handle, see kgnilnd_dev_init */
dev = &kgnilnd_data.kgn_devices[0];
LASSERTF(dev != NULL, "dev 0 is NULL\n");
kgnilnd_critical_error(dev->gnd_err_handle);
/* Wait for the reset to complete. This prevents any races in testing
* where we'd immediately try to send traffic again */
while (kgnilnd_data.kgn_needs_reset != 0) {
i++;
LCONSOLE((((i) & (-i)) == i) ? D_WARNING : D_NET,
"Waiting for stack reset request to clear\n");
schedule_timeout_uninterruptible(cfs_time_seconds(i));
}
RETURN(rc);
}
static int
proc_toggle_rdmaq_override(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int old_val = kgnilnd_sysctl.ksd_rdmaq_override;
int rc = 0;
ENTRY;
rc = proc_dointvec(table, write, buffer, lenp, ppos);
if (!write) {
/* read */
RETURN(rc);
}
if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
rc = -EINVAL;
RETURN(rc);
}
if (old_val != kgnilnd_sysctl.ksd_rdmaq_override) {
long new_mb = kgnilnd_sysctl.ksd_rdmaq_override * (long)(1024*1024);
LCONSOLE_INFO("changing RDMAQ override to %d mbytes/sec\n",
kgnilnd_sysctl.ksd_rdmaq_override);
/* override proc is mbytes, but we calc in bytes */
kgnilnd_data.kgn_rdmaq_override = new_mb;
smp_wmb();
}
RETURN(rc);
}
/* /proc/sys entry point for injecting up/down nid event
* <up|down> <nid>
*/
static int
proc_peer_state(struct ctl_table *table, int write, void __user *buffer,
size_t *lenp, loff_t *ppos)
{
int rc;
int nid;
int node_down;
char command[10];
ENTRY;
rc = proc_dostring(table, write, buffer, lenp, ppos);
if (!write) {
/* read */
RETURN(rc);
}
if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
rc = -EINVAL;
RETURN(rc);
}
/* convert to nid, up/down values */
rc = sscanf(kgnilnd_sysctl.ksd_peer_state, "%s %d", command, &nid);
CDEBUG(D_INFO, "command %s, nid %d\n", command, nid);
if (rc != 2) {
CDEBUG(D_ERROR, "invalid parameter\n");
RETURN(rc);
} else {
switch (command[0]) {
case 'd': /* down */
node_down = 1;
CDEBUG(D_INFO, "take node %d down\n", nid);
break;
case 'u': /* up */
node_down = 0;
CDEBUG(D_INFO, "bring node %d up\n", nid);
break;
default:
CDEBUG(D_ERROR, "invalid command %s\n", command);
RETURN(-EINVAL);
}
}
CDEBUG(D_INFO, "proc_peer_state: reporting node_down %d, nid %d\n",
node_down, nid);
rc = kgnilnd_report_node_state(nid, node_down);
if (rc) {
rc = -EINVAL;
}
RETURN(rc);
}
static struct ctl_table kgnilnd_table[] = {
/*
* NB No .strategy entries have been provided since sysctl(8) prefers
* to go via /proc for portability.
*/
{
.procname = "version",
.data = LUSTRE_VERSION_STRING,
.maxlen = sizeof(LUSTRE_VERSION_STRING),
.mode = 0444,
.proc_handler = &proc_dostring
},
{
.procname = "thread_pause",
.data = &kgnilnd_sysctl.ksd_pause_trigger,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_toggle_thread_pause,
},
{
.procname = "hw_quiesce",
.data = &kgnilnd_sysctl.ksd_quiesce_secs,
.maxlen = sizeof(__u32),
.mode = 0644,
.proc_handler = &proc_hw_quiesce,
},
{
.procname = "stack_reset",
.data = NULL,
.maxlen = sizeof(int),
.mode = 0600,
.proc_handler = &proc_trigger_stack_reset,
},
{
.procname = "rdmaq_override",
.data = &kgnilnd_sysctl.ksd_rdmaq_override,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_toggle_rdmaq_override,
},
{
.procname = "peer_state",
.data = kgnilnd_sysctl.ksd_peer_state,
.maxlen = GNILND_PEERSTATE_STRLEN,
.mode = 0644,
.proc_handler = &proc_peer_state,
},
{ .procname = NULL }
};
static struct ctl_table kgnilnd_top_table[2] = {
{
.procname = "kgnilnd",
.data = NULL,
.maxlen = 0,
.mode = 0555,
.child = kgnilnd_table
},
{ .procname = NULL }
};
void kgnilnd_insert_sysctl(void)
{
if (kgnilnd_table_header == NULL)
kgnilnd_table_header = register_sysctl_table(kgnilnd_top_table);
}
void kgnilnd_remove_sysctl(void)
{
if (kgnilnd_table_header != NULL)
unregister_sysctl_table(kgnilnd_table_header);
kgnilnd_table_header = NULL;
}
#else
void kgnilnd_insert_sysctl(void) {}
void kgnilnd_remove_sysctl(void) {}
#endif