Whamcloud - gitweb
LU-12930 various: use schedule_timeout_*interruptible
[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                 schedule_timeout_uninterruptible(cfs_time_seconds(i));
137         }
138
139         RETURN(rc);
140 }
141
142 static int
143 proc_toggle_rdmaq_override(struct ctl_table *table, int write,
144                            void __user *buffer, size_t *lenp, loff_t *ppos)
145 {
146         int  old_val = kgnilnd_sysctl.ksd_rdmaq_override;
147         int  rc = 0;
148         ENTRY;
149
150         rc = proc_dointvec(table, write, buffer, lenp, ppos);
151         if (!write) {
152                 /* read */
153                 RETURN(rc);
154         }
155
156         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
157                 rc = -EINVAL;
158                 RETURN(rc);
159         }
160
161         if (old_val != kgnilnd_sysctl.ksd_rdmaq_override) {
162                 long    new_mb = kgnilnd_sysctl.ksd_rdmaq_override * (long)(1024*1024);
163                 LCONSOLE_INFO("changing RDMAQ override to %d mbytes/sec\n",
164                               kgnilnd_sysctl.ksd_rdmaq_override);
165                 /* override proc is mbytes, but we calc in bytes */
166                 kgnilnd_data.kgn_rdmaq_override = new_mb;
167                 smp_wmb();
168         }
169
170         RETURN(rc);
171 }
172
173 /* /proc/sys entry point for injecting up/down nid event
174  * <up|down> <nid>
175  */
176 static int
177 proc_peer_state(struct ctl_table *table, int write, void __user *buffer,
178                 size_t *lenp, loff_t *ppos)
179 {
180         int             rc;
181         int             nid;
182         int             node_down;
183         char            command[10];
184         ENTRY;
185
186         rc = proc_dostring(table, write, buffer, lenp, ppos);
187
188         if (!write) {
189                 /* read */
190                 RETURN(rc);
191         }
192
193         if (kgnilnd_data.kgn_init != GNILND_INIT_ALL) {
194                 rc = -EINVAL;
195                 RETURN(rc);
196         }
197
198         /* convert to nid, up/down values */
199         rc = sscanf(kgnilnd_sysctl.ksd_peer_state, "%s %d", command, &nid);
200         CDEBUG(D_INFO, "command %s, nid %d\n", command, nid);
201
202         if (rc != 2) {
203                 CDEBUG(D_ERROR, "invalid parameter\n");
204                 RETURN(rc);
205         } else {
206                 switch (command[0]) {
207                 case 'd': /* down */
208                         node_down = 1;
209                         CDEBUG(D_INFO, "take node %d down\n", nid);
210                         break;
211                 case 'u': /* up */
212                         node_down = 0;
213                         CDEBUG(D_INFO, "bring node %d up\n", nid);
214                         break;
215                 default:
216                         CDEBUG(D_ERROR, "invalid command %s\n", command);
217                         RETURN(-EINVAL);
218                 }
219         }
220
221         CDEBUG(D_INFO, "proc_peer_state: reporting node_down %d, nid %d\n",
222                       node_down, nid);
223         rc = kgnilnd_report_node_state(nid, node_down);
224
225         if (rc) {
226                 rc = -EINVAL;
227         }
228
229         RETURN(rc);
230 }
231
232 static struct ctl_table kgnilnd_table[] = {
233         /*
234          * NB No .strategy entries have been provided since sysctl(8) prefers
235          * to go via /proc for portability.
236          */
237         {
238                 .procname = "version",
239                 .data     = LUSTRE_VERSION_STRING,
240                 .maxlen   = sizeof(LUSTRE_VERSION_STRING),
241                 .mode     = 0444,
242                 .proc_handler = &proc_dostring
243         },
244         {
245                 .procname = "thread_pause",
246                 .data     = &kgnilnd_sysctl.ksd_pause_trigger,
247                 .maxlen   = sizeof(int),
248                 .mode     = 0644,
249                 .proc_handler = &proc_toggle_thread_pause,
250         },
251         {
252                 .procname = "hw_quiesce",
253                 .data     = &kgnilnd_sysctl.ksd_quiesce_secs,
254                 .maxlen   = sizeof(__u32),
255                 .mode     = 0644,
256                 .proc_handler = &proc_hw_quiesce,
257         },
258         {
259                 .procname = "stack_reset",
260                 .data     = NULL,
261                 .maxlen   = sizeof(int),
262                 .mode     = 0600,
263                 .proc_handler = &proc_trigger_stack_reset,
264         },
265         {
266                 .procname = "rdmaq_override",
267                 .data     = &kgnilnd_sysctl.ksd_rdmaq_override,
268                 .maxlen   = sizeof(int),
269                 .mode     = 0644,
270                 .proc_handler = &proc_toggle_rdmaq_override,
271         },
272         {
273                 .procname = "peer_state",
274                 .data     = kgnilnd_sysctl.ksd_peer_state,
275                 .maxlen   = GNILND_PEERSTATE_STRLEN,
276                 .mode     = 0644,
277                 .proc_handler = &proc_peer_state,
278         },
279         { 0 }
280 };
281
282 static struct ctl_table kgnilnd_top_table[2] = {
283         {
284                 .procname = "kgnilnd",
285                 .data     = NULL,
286                 .maxlen   = 0,
287                 .mode     = 0555,
288                 .child    = kgnilnd_table
289         },
290         { 0 }
291 };
292
293 void kgnilnd_insert_sysctl(void)
294 {
295         if (kgnilnd_table_header == NULL)
296                 kgnilnd_table_header = register_sysctl_table(kgnilnd_top_table);
297 }
298
299 void kgnilnd_remove_sysctl(void)
300 {
301         if (kgnilnd_table_header != NULL)
302                 unregister_sysctl_table(kgnilnd_table_header);
303
304         kgnilnd_table_header = NULL;
305 }
306
307 #else
308 void kgnilnd_insert_sysctl(void) {}
309 void kgnilnd_remove_sysctl(void) {}
310 #endif