Whamcloud - gitweb
LU-6261 gnilnd: Add ability to bind scheduler threads to cpus.
[fs/lustre-release.git] / lnet / klnds / gnilnd / gnilnd_sysctl.c
1 /*
2  * Copyright (C) 2012 Cray, Inc.
3  *
4  * Copyright (c) 2014, Intel Corporation.
5  *
6  *   Author: Nic Henke <nic@cray.com>
7  *   Author: James Shimek <jshimek@cray.com>
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 /* this code liberated and modified from Lustre */
26
27 #define DEBUG_SUBSYSTEM S_LND
28
29 #include "gnilnd.h"
30
31 #define GNILND_PEERSTATE_STRLEN 16
32 typedef struct kgn_sysctl_data {
33         int                     ksd_pause_trigger;
34         int                     ksd_quiesce_secs;
35         int                     ksd_rdmaq_override;
36         char                    ksd_peer_state[GNILND_PEERSTATE_STRLEN];
37 } kgn_sysctl_data_t;
38
39 static kgn_sysctl_data_t        kgnilnd_sysctl;
40
41 #if defined(CONFIG_SYSCTL)
42
43 static struct ctl_table_header *kgnilnd_table_header = NULL;
44
45 static int
46 proc_toggle_thread_pause(struct ctl_table *table, int write,
47                          void __user *buffer, size_t *lenp, loff_t *ppos)
48 {
49         int  old_val = kgnilnd_sysctl.ksd_pause_trigger;
50         int  rc = 0;
51         ENTRY;
52
53         rc = proc_dointvec(table, write, buffer, lenp, ppos);
54         if (!write) {
55                 /* read */
56                 RETURN(rc);
57         }
58
59         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
60                 rc = -EINVAL;
61                 RETURN(rc);
62         }
63
64         if (old_val != kgnilnd_sysctl.ksd_pause_trigger) {
65                 mutex_lock(&kgnilnd_data.kgn_quiesce_mutex);
66                 CDEBUG(D_NET, "setting quiesce_trigger %d\n", old_val);
67                 kgnilnd_data.kgn_quiesce_trigger = kgnilnd_sysctl.ksd_pause_trigger;
68                 kgnilnd_quiesce_wait("admin sysctl");
69                 mutex_unlock(&kgnilnd_data.kgn_quiesce_mutex);
70         }
71
72         RETURN(rc);
73 }
74
75 static int
76 proc_hw_quiesce(struct ctl_table *table, int write, void __user *buffer,
77                 size_t *lenp, loff_t *ppos)
78 {
79         int              rc = 0;
80         kgn_device_t    *dev;
81         ENTRY;
82
83         rc = proc_dointvec(table, write, buffer, lenp, ppos);
84         if (!write) {
85                 /* read */
86                 RETURN(rc);
87         }
88
89         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
90                 rc = -EINVAL;
91                 RETURN(rc);
92         }
93
94
95         /* only device 0 gets the handle, see kgnilnd_dev_init */
96         dev = &kgnilnd_data.kgn_devices[0];
97
98         LASSERTF(dev != NULL, "dev 0 is NULL\n");
99
100         kgnilnd_quiesce_end_callback(dev->gnd_handle,
101                                      kgnilnd_sysctl.ksd_quiesce_secs * MSEC_PER_SEC);
102
103         RETURN(rc);
104 }
105
106 static int
107 proc_trigger_stack_reset(struct ctl_table *table, int write,
108                          void __user *buffer, size_t *lenp, loff_t *ppos)
109 {
110         int              rc = 0;
111         int              i = 1;
112         kgn_device_t    *dev;
113         ENTRY;
114
115         if (!write) {
116                 /* read */
117                 rc = proc_dointvec(table, write, buffer, lenp, ppos);
118                 RETURN(rc);
119         }
120
121         /* only device 0 gets the handle, see kgnilnd_dev_init */
122         dev = &kgnilnd_data.kgn_devices[0];
123
124         LASSERTF(dev != NULL, "dev 0 is NULL\n");
125
126         kgnilnd_critical_error(dev->gnd_err_handle);
127
128         /* Wait for the reset to complete.  This prevents any races in testing
129          * where we'd immediately try to send traffic again */
130         while (kgnilnd_data.kgn_needs_reset != 0) {
131                 i++;
132                 LCONSOLE((((i) & (-i)) == i) ? D_WARNING : D_NET,
133                                 "Waiting for stack reset request to clear\n");
134                 set_current_state(TASK_UNINTERRUPTIBLE);
135                 schedule_timeout(cfs_time_seconds(1 * i));
136         }
137
138         RETURN(rc);
139 }
140
141 static int
142 proc_toggle_rdmaq_override(struct ctl_table *table, int write,
143                            void __user *buffer, size_t *lenp, loff_t *ppos)
144 {
145         int  old_val = kgnilnd_sysctl.ksd_rdmaq_override;
146         int  rc = 0;
147         ENTRY;
148
149         rc = proc_dointvec(table, write, buffer, lenp, ppos);
150         if (!write) {
151                 /* read */
152                 RETURN(rc);
153         }
154
155         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
156                 rc = -EINVAL;
157                 RETURN(rc);
158         }
159
160         if (old_val != kgnilnd_sysctl.ksd_rdmaq_override) {
161                 long    new_mb = kgnilnd_sysctl.ksd_rdmaq_override * (long)(1024*1024);
162                 LCONSOLE_INFO("changing RDMAQ override to %d mbytes/sec\n",
163                               kgnilnd_sysctl.ksd_rdmaq_override);
164                 /* override proc is mbytes, but we calc in bytes */
165                 kgnilnd_data.kgn_rdmaq_override = new_mb;
166                 smp_wmb();
167         }
168
169         RETURN(rc);
170 }
171
172 /* /proc/sys entry point for injecting up/down nid event
173  * <up|down> <nid>
174  */
175 static int
176 proc_peer_state(struct ctl_table *table, int write, void __user *buffer,
177                 size_t *lenp, loff_t *ppos)
178 {
179         int             rc;
180         int             nid;
181         int             node_down;
182         char            command[10];
183         ENTRY;
184
185         rc = proc_dostring(table, write, buffer, lenp, ppos);
186
187         if (!write) {
188                 /* read */
189                 RETURN(rc);
190         }
191
192         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
193                 rc = -EINVAL;
194                 RETURN(rc);
195         }
196
197         /* convert to nid, up/down values */
198         rc = sscanf(kgnilnd_sysctl.ksd_peer_state, "%s %d", command, &nid);
199         CDEBUG(D_INFO, "command %s, nid %d\n", command, nid);
200
201         if (rc != 2) {
202                 CDEBUG(D_ERROR, "invalid parameter\n");
203                 RETURN(rc);
204         } else {
205                 switch (command[0]) {
206                 case 'd': /* down */
207                         node_down = 1;
208                         CDEBUG(D_INFO, "take node %d down\n", nid);
209                         break;
210                 case 'u': /* up */
211                         node_down = 0;
212                         CDEBUG(D_INFO, "bring node %d up\n", nid);
213                         break;
214                 default:
215                         CDEBUG(D_ERROR, "invalid command %s\n", command);
216                         RETURN(-EINVAL);
217                 }
218         }
219
220         CDEBUG(D_INFO, "proc_peer_state: reporting node_down %d, nid %d\n",
221                       node_down, nid);
222         rc = kgnilnd_report_node_state(nid, node_down);
223
224         if (rc) {
225                 rc = -EINVAL;
226         }
227
228         RETURN(rc);
229 }
230
231 static struct ctl_table kgnilnd_table[] = {
232         /*
233          * NB No .strategy entries have been provided since sysctl(8) prefers
234          * to go via /proc for portability.
235          */
236         {
237                 INIT_CTL_NAME
238                 .procname = "version",
239                 .data     = KGNILND_BUILD_REV,
240                 .maxlen   = sizeof(KGNILND_BUILD_REV),
241                 .mode     = 0444,
242                 .proc_handler = &proc_dostring
243         },
244         {
245                 INIT_CTL_NAME
246                 .procname = "thread_pause",
247                 .data     = &kgnilnd_sysctl.ksd_pause_trigger,
248                 .maxlen   = sizeof(int),
249                 .mode     = 0644,
250                 .proc_handler = &proc_toggle_thread_pause,
251         },
252         {
253                 INIT_CTL_NAME
254                 .procname = "hw_quiesce",
255                 .data     = &kgnilnd_sysctl.ksd_quiesce_secs,
256                 .maxlen   = sizeof(__u32),
257                 .mode     = 0644,
258                 .proc_handler = &proc_hw_quiesce,
259         },
260         {
261                 INIT_CTL_NAME
262                 .procname = "stack_reset",
263                 .data     = NULL,
264                 .maxlen   = sizeof(int),
265                 .mode     = 0600,
266                 .proc_handler = &proc_trigger_stack_reset,
267         },
268         {
269                 INIT_CTL_NAME
270                 .procname = "rdmaq_override",
271                 .data     = &kgnilnd_sysctl.ksd_rdmaq_override,
272                 .maxlen   = sizeof(int),
273                 .mode     = 0644,
274                 .proc_handler = &proc_toggle_rdmaq_override,
275         },
276         {
277                 INIT_CTL_NAME
278                 .procname = "peer_state",
279                 .data     = kgnilnd_sysctl.ksd_peer_state,
280                 .maxlen   = GNILND_PEERSTATE_STRLEN,
281                 .mode     = 0644,
282                 .proc_handler = &proc_peer_state,
283         },
284         { 0 }
285 };
286
287 static struct ctl_table kgnilnd_top_table[2] = {
288         {
289                 INIT_CTL_NAME
290                 .procname = "kgnilnd",
291                 .data     = NULL,
292                 .maxlen   = 0,
293                 .mode     = 0555,
294                 .child    = kgnilnd_table
295         },
296         { 0 }
297 };
298
299 void kgnilnd_insert_sysctl(void)
300 {
301         if (kgnilnd_table_header == NULL)
302                 kgnilnd_table_header = register_sysctl_table(kgnilnd_top_table);
303 }
304
305 void kgnilnd_remove_sysctl(void)
306 {
307         if (kgnilnd_table_header != NULL)
308                 unregister_sysctl_table(kgnilnd_table_header);
309
310         kgnilnd_table_header = NULL;
311 }
312
313 #else
314 void kgnilnd_insert_sysctl(void) {}
315 void kgnilnd_remove_sysctl(void) {}
316 #endif