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