Whamcloud - gitweb
aa08d80c7382a40b117e811648a1a0897a93a31a
[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 <libcfs/linux/linux-misc.h>
30
31 #include "gnilnd.h"
32
33 #define GNILND_PEERSTATE_STRLEN 16
34 typedef struct kgn_sysctl_data {
35         int                     ksd_pause_trigger;
36         int                     ksd_quiesce_secs;
37         int                     ksd_rdmaq_override;
38         char                    ksd_peer_state[GNILND_PEERSTATE_STRLEN];
39 } kgn_sysctl_data_t;
40
41 static kgn_sysctl_data_t        kgnilnd_sysctl;
42
43 #if defined(CONFIG_SYSCTL)
44
45 static struct ctl_table_header *kgnilnd_table_header = NULL;
46
47 static int
48 proc_toggle_thread_pause(struct ctl_table *table, int write,
49                          void __user *buffer, size_t *lenp, loff_t *ppos)
50 {
51         int  old_val = kgnilnd_sysctl.ksd_pause_trigger;
52         int  rc = 0;
53         ENTRY;
54
55         rc = proc_dointvec(table, write, buffer, lenp, ppos);
56         if (!write) {
57                 /* read */
58                 RETURN(rc);
59         }
60
61         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
62                 rc = -EINVAL;
63                 RETURN(rc);
64         }
65
66         if (old_val != kgnilnd_sysctl.ksd_pause_trigger) {
67                 mutex_lock(&kgnilnd_data.kgn_quiesce_mutex);
68                 CDEBUG(D_NET, "setting quiesce_trigger %d\n", old_val);
69                 kgnilnd_data.kgn_quiesce_trigger = kgnilnd_sysctl.ksd_pause_trigger;
70                 kgnilnd_quiesce_wait("admin sysctl");
71                 mutex_unlock(&kgnilnd_data.kgn_quiesce_mutex);
72         }
73
74         RETURN(rc);
75 }
76
77 static int
78 proc_hw_quiesce(struct ctl_table *table, int write, void __user *buffer,
79                 size_t *lenp, loff_t *ppos)
80 {
81         int              rc = 0;
82         kgn_device_t    *dev;
83         ENTRY;
84
85         rc = proc_dointvec(table, write, buffer, lenp, ppos);
86         if (!write) {
87                 /* read */
88                 RETURN(rc);
89         }
90
91         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
92                 rc = -EINVAL;
93                 RETURN(rc);
94         }
95
96
97         /* only device 0 gets the handle, see kgnilnd_dev_init */
98         dev = &kgnilnd_data.kgn_devices[0];
99
100         LASSERTF(dev != NULL, "dev 0 is NULL\n");
101
102         kgnilnd_quiesce_end_callback(dev->gnd_handle,
103                                      kgnilnd_sysctl.ksd_quiesce_secs * MSEC_PER_SEC);
104
105         RETURN(rc);
106 }
107
108 static int
109 proc_trigger_stack_reset(struct ctl_table *table, int write,
110                          void __user *buffer, size_t *lenp, loff_t *ppos)
111 {
112         int              rc = 0;
113         int              i = 1;
114         kgn_device_t    *dev;
115         ENTRY;
116
117         if (!write) {
118                 /* read */
119                 rc = proc_dointvec(table, write, buffer, lenp, ppos);
120                 RETURN(rc);
121         }
122
123         /* only device 0 gets the handle, see kgnilnd_dev_init */
124         dev = &kgnilnd_data.kgn_devices[0];
125
126         LASSERTF(dev != NULL, "dev 0 is NULL\n");
127
128         kgnilnd_critical_error(dev->gnd_err_handle);
129
130         /* Wait for the reset to complete.  This prevents any races in testing
131          * where we'd immediately try to send traffic again */
132         while (kgnilnd_data.kgn_needs_reset != 0) {
133                 i++;
134                 LCONSOLE((((i) & (-i)) == i) ? D_WARNING : D_NET,
135                                 "Waiting for stack reset request to clear\n");
136                 set_current_state(TASK_UNINTERRUPTIBLE);
137                 schedule_timeout(cfs_time_seconds(1 * i));
138         }
139
140         RETURN(rc);
141 }
142
143 static int
144 proc_toggle_rdmaq_override(struct ctl_table *table, int write,
145                            void __user *buffer, size_t *lenp, loff_t *ppos)
146 {
147         int  old_val = kgnilnd_sysctl.ksd_rdmaq_override;
148         int  rc = 0;
149         ENTRY;
150
151         rc = proc_dointvec(table, write, buffer, lenp, ppos);
152         if (!write) {
153                 /* read */
154                 RETURN(rc);
155         }
156
157         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
158                 rc = -EINVAL;
159                 RETURN(rc);
160         }
161
162         if (old_val != kgnilnd_sysctl.ksd_rdmaq_override) {
163                 long    new_mb = kgnilnd_sysctl.ksd_rdmaq_override * (long)(1024*1024);
164                 LCONSOLE_INFO("changing RDMAQ override to %d mbytes/sec\n",
165                               kgnilnd_sysctl.ksd_rdmaq_override);
166                 /* override proc is mbytes, but we calc in bytes */
167                 kgnilnd_data.kgn_rdmaq_override = new_mb;
168                 smp_wmb();
169         }
170
171         RETURN(rc);
172 }
173
174 /* /proc/sys entry point for injecting up/down nid event
175  * <up|down> <nid>
176  */
177 static int
178 proc_peer_state(struct ctl_table *table, int write, void __user *buffer,
179                 size_t *lenp, loff_t *ppos)
180 {
181         int             rc;
182         int             nid;
183         int             node_down;
184         char            command[10];
185         ENTRY;
186
187         rc = proc_dostring(table, write, buffer, lenp, ppos);
188
189         if (!write) {
190                 /* read */
191                 RETURN(rc);
192         }
193
194         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
195                 rc = -EINVAL;
196                 RETURN(rc);
197         }
198
199         /* convert to nid, up/down values */
200         rc = sscanf(kgnilnd_sysctl.ksd_peer_state, "%s %d", command, &nid);
201         CDEBUG(D_INFO, "command %s, nid %d\n", command, nid);
202
203         if (rc != 2) {
204                 CDEBUG(D_ERROR, "invalid parameter\n");
205                 RETURN(rc);
206         } else {
207                 switch (command[0]) {
208                 case 'd': /* down */
209                         node_down = 1;
210                         CDEBUG(D_INFO, "take node %d down\n", nid);
211                         break;
212                 case 'u': /* up */
213                         node_down = 0;
214                         CDEBUG(D_INFO, "bring node %d up\n", nid);
215                         break;
216                 default:
217                         CDEBUG(D_ERROR, "invalid command %s\n", command);
218                         RETURN(-EINVAL);
219                 }
220         }
221
222         CDEBUG(D_INFO, "proc_peer_state: reporting node_down %d, nid %d\n",
223                       node_down, nid);
224         rc = kgnilnd_report_node_state(nid, node_down);
225
226         if (rc) {
227                 rc = -EINVAL;
228         }
229
230         RETURN(rc);
231 }
232
233 static struct ctl_table kgnilnd_table[] = {
234         /*
235          * NB No .strategy entries have been provided since sysctl(8) prefers
236          * to go via /proc for portability.
237          */
238         {
239                 INIT_CTL_NAME
240                 .procname = "version",
241                 .data     = LUSTRE_VERSION_STRING,
242                 .maxlen   = sizeof(LUSTRE_VERSION_STRING),
243                 .mode     = 0444,
244                 .proc_handler = &proc_dostring
245         },
246         {
247                 INIT_CTL_NAME
248                 .procname = "thread_pause",
249                 .data     = &kgnilnd_sysctl.ksd_pause_trigger,
250                 .maxlen   = sizeof(int),
251                 .mode     = 0644,
252                 .proc_handler = &proc_toggle_thread_pause,
253         },
254         {
255                 INIT_CTL_NAME
256                 .procname = "hw_quiesce",
257                 .data     = &kgnilnd_sysctl.ksd_quiesce_secs,
258                 .maxlen   = sizeof(__u32),
259                 .mode     = 0644,
260                 .proc_handler = &proc_hw_quiesce,
261         },
262         {
263                 INIT_CTL_NAME
264                 .procname = "stack_reset",
265                 .data     = NULL,
266                 .maxlen   = sizeof(int),
267                 .mode     = 0600,
268                 .proc_handler = &proc_trigger_stack_reset,
269         },
270         {
271                 INIT_CTL_NAME
272                 .procname = "rdmaq_override",
273                 .data     = &kgnilnd_sysctl.ksd_rdmaq_override,
274                 .maxlen   = sizeof(int),
275                 .mode     = 0644,
276                 .proc_handler = &proc_toggle_rdmaq_override,
277         },
278         {
279                 INIT_CTL_NAME
280                 .procname = "peer_state",
281                 .data     = kgnilnd_sysctl.ksd_peer_state,
282                 .maxlen   = GNILND_PEERSTATE_STRLEN,
283                 .mode     = 0644,
284                 .proc_handler = &proc_peer_state,
285         },
286         { 0 }
287 };
288
289 static struct ctl_table kgnilnd_top_table[2] = {
290         {
291                 INIT_CTL_NAME
292                 .procname = "kgnilnd",
293                 .data     = NULL,
294                 .maxlen   = 0,
295                 .mode     = 0555,
296                 .child    = kgnilnd_table
297         },
298         { 0 }
299 };
300
301 void kgnilnd_insert_sysctl(void)
302 {
303         if (kgnilnd_table_header == NULL)
304                 kgnilnd_table_header = register_sysctl_table(kgnilnd_top_table);
305 }
306
307 void kgnilnd_remove_sysctl(void)
308 {
309         if (kgnilnd_table_header != NULL)
310                 unregister_sysctl_table(kgnilnd_table_header);
311
312         kgnilnd_table_header = NULL;
313 }
314
315 #else
316 void kgnilnd_insert_sysctl(void) {}
317 void kgnilnd_remove_sysctl(void) {}
318 #endif