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