Whamcloud - gitweb
LU-6142 lnet: SPDX for lnet/lnet/
[fs/lustre-release.git] / lnet / lnet / module.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
4  * Use is subject to license terms.
5  *
6  * Copyright (c) 2012, 2017, Intel Corporation.
7  */
8
9 /* This file is part of Lustre, http://www.lustre.org/ */
10
11 #define DEBUG_SUBSYSTEM S_LNET
12
13 #include <linux/miscdevice.h>
14 #include <lnet/lib-lnet.h>
15 #include <uapi/linux/lnet/lnet-dlc.h>
16
17 static int config_on_load = 0;
18 module_param(config_on_load, int, 0444);
19 MODULE_PARM_DESC(config_on_load, "configure network at module load");
20
21 static DEFINE_MUTEX(lnet_config_mutex);
22
23 int lnet_configure(void *arg)
24 {
25         /* 'arg' only there so I can be passed to cfs_create_thread() */
26         int    rc = 0;
27
28         mutex_lock(&lnet_config_mutex);
29
30         if (!the_lnet.ln_niinit_self) {
31                 rc = try_module_get(THIS_MODULE);
32
33                 if (rc != 1)
34                         goto out;
35
36                 rc = LNetNIInit(LNET_PID_LUSTRE);
37                 if (rc >= 0) {
38                         the_lnet.ln_niinit_self = 1;
39                         rc = 0;
40                 } else {
41                         module_put(THIS_MODULE);
42                 }
43         }
44
45 out:
46         mutex_unlock(&lnet_config_mutex);
47         return rc;
48 }
49
50 int lnet_unconfigure(void)
51 {
52         int refcount;
53
54         mutex_lock(&lnet_config_mutex);
55
56         if (the_lnet.ln_niinit_self) {
57                 the_lnet.ln_niinit_self = 0;
58                 LNetNIFini();
59                 module_put(THIS_MODULE);
60         }
61
62         mutex_lock(&the_lnet.ln_api_mutex);
63         refcount = the_lnet.ln_refcount;
64         mutex_unlock(&the_lnet.ln_api_mutex);
65
66         mutex_unlock(&lnet_config_mutex);
67
68         return (refcount == 0) ? 0 : -EBUSY;
69 }
70
71 static int
72 lnet_dyn_configure_net(struct libcfs_ioctl_hdr *hdr)
73 {
74         struct lnet_ioctl_config_data *conf =
75           (struct lnet_ioctl_config_data *)hdr;
76         int                           rc;
77
78         if (conf->cfg_hdr.ioc_len < sizeof(*conf))
79                 return -EINVAL;
80
81         mutex_lock(&lnet_config_mutex);
82         if (the_lnet.ln_niinit_self)
83                 rc = lnet_dyn_add_net(conf);
84         else
85                 rc = -EINVAL;
86         mutex_unlock(&lnet_config_mutex);
87
88         return rc;
89 }
90
91 static int
92 lnet_dyn_unconfigure_net(struct libcfs_ioctl_hdr *hdr)
93 {
94         struct lnet_ioctl_config_data *conf =
95           (struct lnet_ioctl_config_data *) hdr;
96         int                           rc;
97
98         if (conf->cfg_hdr.ioc_len < sizeof(*conf))
99                 return -EINVAL;
100
101         mutex_lock(&lnet_config_mutex);
102         if (the_lnet.ln_niinit_self)
103                 rc = lnet_dyn_del_net(conf->cfg_net);
104         else
105                 rc = -EINVAL;
106         mutex_unlock(&lnet_config_mutex);
107
108         return rc;
109 }
110
111 static int
112 lnet_dyn_configure_ni(struct libcfs_ioctl_hdr *hdr)
113 {
114         struct lnet_ioctl_config_ni *conf =
115           (struct lnet_ioctl_config_ni *)hdr;
116         int rc = -EINVAL;
117
118         if (conf->lic_cfg_hdr.ioc_len < sizeof(*conf))
119                 return rc;
120
121         mutex_lock(&lnet_config_mutex);
122         if (the_lnet.ln_niinit_self) {
123                 struct lnet_ioctl_config_lnd_tunables *tun = NULL;
124                 struct lnet_nid nid;
125                 u32 net_id;
126
127                 /* get the tunables if they are available */
128                 if (conf->lic_cfg_hdr.ioc_len >=
129                     sizeof(*conf) + sizeof(*tun))
130                         tun = (struct lnet_ioctl_config_lnd_tunables *) conf->lic_bulk;
131
132                 lnet_nid4_to_nid(conf->lic_nid, &nid);
133                 net_id = LNET_NID_NET(&nid);
134                 rc = lnet_dyn_add_ni(conf, net_id, &LNET_ANY_NID, tun);
135         }
136         mutex_unlock(&lnet_config_mutex);
137
138         return rc;
139 }
140
141 static int
142 lnet_dyn_unconfigure_ni(struct libcfs_ioctl_hdr *hdr)
143 {
144         struct lnet_ioctl_config_ni *conf =
145           (struct lnet_ioctl_config_ni *) hdr;
146         struct lnet_nid nid;
147         int rc = -EINVAL;
148
149         if (conf->lic_cfg_hdr.ioc_len < sizeof(*conf) ||
150             !the_lnet.ln_niinit_self)
151                 return rc;
152
153         lnet_nid4_to_nid(conf->lic_nid, &nid);
154         mutex_lock(&lnet_config_mutex);
155         if (the_lnet.ln_niinit_self)
156                 rc = lnet_dyn_del_ni(&nid);
157         else
158                 rc = -EINVAL;
159         mutex_unlock(&lnet_config_mutex);
160
161         return rc;
162 }
163
164 static int
165 lnet_ioctl(unsigned int cmd, struct libcfs_ioctl_hdr *hdr)
166 {
167         int rc;
168
169         switch (cmd) {
170         case IOC_LIBCFS_CONFIGURE: {
171                 struct libcfs_ioctl_data *data =
172                   (struct libcfs_ioctl_data *)hdr;
173
174                 if (data->ioc_hdr.ioc_len < sizeof(*data)) {
175                         rc = -EINVAL;
176                 } else {
177                         the_lnet.ln_nis_from_mod_params = data->ioc_flags;
178                         rc = lnet_configure(NULL);
179                 }
180                 break;
181         }
182
183         case IOC_LIBCFS_UNCONFIGURE:
184                 rc = lnet_unconfigure();
185                 break;
186
187         case IOC_LIBCFS_ADD_NET:
188                 rc = lnet_dyn_configure_net(hdr);
189                 break;
190
191         case IOC_LIBCFS_DEL_NET:
192                 rc = lnet_dyn_unconfigure_net(hdr);
193                 break;
194
195         case IOC_LIBCFS_ADD_LOCAL_NI:
196                 rc = lnet_dyn_configure_ni(hdr);
197                 break;
198
199         case IOC_LIBCFS_DEL_LOCAL_NI:
200                 rc = lnet_dyn_unconfigure_ni(hdr);
201                 break;
202
203         default:
204                 /* Passing LNET_PID_ANY only gives me a ref if the net is up
205                  * already; I'll need it to ensure the net can't go down while
206                  * I'm called into it */
207                 rc = LNetNIInit(LNET_PID_ANY);
208                 if (rc >= 0) {
209                         rc = LNetCtl(cmd, hdr);
210                         LNetNIFini();
211                 }
212                 break;
213         }
214         return rc;
215 }
216 BLOCKING_NOTIFIER_HEAD(lnet_ioctl_list);
217 EXPORT_SYMBOL(lnet_ioctl_list);
218
219 static inline size_t lnet_ioctl_packlen(struct libcfs_ioctl_data *data)
220 {
221         size_t len = sizeof(*data);
222
223         len += (data->ioc_inllen1 + 7) & ~7;
224         len += (data->ioc_inllen2 + 7) & ~7;
225         return len;
226 }
227
228 static bool lnet_ioctl_is_invalid(struct libcfs_ioctl_data *data)
229 {
230         const int maxlen = 1 << 30;
231
232         if (data->ioc_hdr.ioc_len > maxlen)
233                 return true;
234
235         if (data->ioc_inllen1 > maxlen)
236                 return true;
237
238         if (data->ioc_inllen2 > maxlen)
239                 return true;
240
241         if (data->ioc_inlbuf1 && !data->ioc_inllen1)
242                 return true;
243
244         if (data->ioc_inlbuf2 && !data->ioc_inllen2)
245                 return true;
246
247         if (data->ioc_pbuf1 && !data->ioc_plen1)
248                 return true;
249
250         if (data->ioc_pbuf2 && !data->ioc_plen2)
251                 return true;
252
253         if (data->ioc_plen1 && !data->ioc_pbuf1)
254                 return true;
255
256         if (data->ioc_plen2 && !data->ioc_pbuf2)
257                 return true;
258
259         if (lnet_ioctl_packlen(data) != data->ioc_hdr.ioc_len)
260                 return true;
261
262         if (data->ioc_inllen1 &&
263                 data->ioc_bulk[((data->ioc_inllen1 + 7) & ~7) +
264                                data->ioc_inllen2 - 1] != '\0')
265                 return true;
266
267         return false;
268 }
269
270 static int lnet_ioctl_data_adjust(struct libcfs_ioctl_data *data)
271 {
272         ENTRY;
273
274         if (lnet_ioctl_is_invalid(data)) {
275                 CERROR("lnet ioctl: parameter not correctly formatted\n");
276                 RETURN(-EINVAL);
277         }
278
279         if (data->ioc_inllen1 != 0)
280                 data->ioc_inlbuf1 = &data->ioc_bulk[0];
281
282         if (data->ioc_inllen2 != 0)
283                 data->ioc_inlbuf2 = (&data->ioc_bulk[0] +
284                                      round_up(data->ioc_inllen1, 8));
285
286         RETURN(0);
287 }
288
289 static int lnet_ioctl_getdata(struct libcfs_ioctl_hdr **hdr_pp,
290                               struct libcfs_ioctl_hdr __user *uhdr)
291 {
292         struct libcfs_ioctl_hdr hdr;
293         int err;
294
295         ENTRY;
296         if (copy_from_user(&hdr, uhdr, sizeof(hdr)))
297                 RETURN(-EFAULT);
298
299         if (hdr.ioc_version != LNET_IOCTL_VERSION &&
300             hdr.ioc_version != LNET_IOCTL_VERSION2) {
301                 CERROR("lnet ioctl: version mismatch expected %#x, got %#x\n",
302                        LNET_IOCTL_VERSION, hdr.ioc_version);
303                 RETURN(-EINVAL);
304         }
305
306         if (hdr.ioc_len < sizeof(struct libcfs_ioctl_hdr)) {
307                 CERROR("lnet ioctl: user buffer too small for ioctl\n");
308                 RETURN(-EINVAL);
309         }
310
311         if (hdr.ioc_len > LIBCFS_IOC_DATA_MAX) {
312                 CERROR("lnet ioctl: user buffer is too large %d/%d\n",
313                        hdr.ioc_len, LIBCFS_IOC_DATA_MAX);
314                 RETURN(-EINVAL);
315         }
316
317         LIBCFS_ALLOC(*hdr_pp, hdr.ioc_len);
318         if (*hdr_pp == NULL)
319                 RETURN(-ENOMEM);
320
321         if (copy_from_user(*hdr_pp, uhdr, hdr.ioc_len))
322                 GOTO(free, err = -EFAULT);
323
324         if ((*hdr_pp)->ioc_version != hdr.ioc_version ||
325                 (*hdr_pp)->ioc_len != hdr.ioc_len) {
326                 GOTO(free, err = -EINVAL);
327         }
328
329         RETURN(0);
330
331 free:
332         LIBCFS_FREE(*hdr_pp, hdr.ioc_len);
333         RETURN(err);
334 }
335
336 static long
337 lnet_psdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
338 {
339         struct libcfs_ioctl_data *data = NULL;
340         struct libcfs_ioctl_hdr  *hdr;
341         int                       err;
342         void __user              *uparam = (void __user *)arg;
343
344         ENTRY;
345         if (!capable(CAP_SYS_ADMIN))
346                 return -EACCES;
347
348         if (_IOC_TYPE(cmd) != IOC_LIBCFS_TYPE ||
349             _IOC_NR(cmd) < IOC_LIBCFS_MIN_NR  ||
350             _IOC_NR(cmd) > IOC_LIBCFS_MAX_NR) {
351                 CDEBUG(D_IOCTL, "invalid ioctl ( type %d, nr %d, size %d )\n",
352                        _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd));
353                 return -EINVAL;
354         }
355
356         /* 'cmd' and permissions get checked in our arch-specific caller */
357         err = lnet_ioctl_getdata(&hdr, uparam);
358         if (err != 0) {
359                 CDEBUG_LIMIT(D_ERROR,
360                              "lnet ioctl: data header error %d\n", err);
361                 RETURN(err);
362         }
363
364         if (hdr->ioc_version == LNET_IOCTL_VERSION) {
365                 /* The lnet_ioctl_data_adjust() function performs adjustment
366                  * operations on the libcfs_ioctl_data structure to make
367                  * it usable by the code.  This doesn't need to be called
368                  * for new data structures added.
369                  */
370                 data = container_of(hdr, struct libcfs_ioctl_data, ioc_hdr);
371                 err = lnet_ioctl_data_adjust(data);
372                 if (err != 0)
373                         GOTO(out, err);
374         }
375
376         CDEBUG(D_IOCTL, "lnet ioctl cmd %u\n", cmd);
377
378         err = libcfs_ioctl(cmd, data);
379         if (err == -EINVAL)
380                 err = lnet_ioctl(cmd, hdr);
381         if (err == -EINVAL) {
382                 err = blocking_notifier_call_chain(&lnet_ioctl_list,
383                                                    cmd, hdr);
384                 if (!(err & NOTIFY_STOP_MASK))
385                         /* No-one claimed the ioctl */
386                         err = -EINVAL;
387                 else
388                         err = notifier_to_errno(err);
389         }
390         if (copy_to_user(uparam, hdr, hdr->ioc_len) && !err)
391                 err = -EFAULT;
392 out:
393         LIBCFS_FREE(hdr, hdr->ioc_len);
394         RETURN(err);
395 }
396
397 static const struct file_operations lnet_fops = {
398         .owner                  = THIS_MODULE,
399         .unlocked_ioctl         = lnet_psdev_ioctl,
400 };
401
402 static struct miscdevice lnet_dev = {
403         .minor                  = MISC_DYNAMIC_MINOR,
404         .name                   = "lnet",
405         .fops                   = &lnet_fops,
406 };
407
408 static int __init lnet_init(void)
409 {
410         int rc;
411
412         ENTRY;
413         rc = libcfs_setup();
414         if (rc)
415                 return rc;
416
417         rc = cfs_cpu_init();
418         if (rc < 0) {
419                 CERROR("cfs_cpu_init: rc = %d\n", rc);
420                 RETURN(rc);
421         }
422
423         rc = lnet_lib_init();
424         if (rc != 0) {
425                 CERROR("lnet_lib_init: rc = %d\n", rc);
426                 cfs_cpu_fini();
427                 RETURN(rc);
428         }
429
430         rc = misc_register(&lnet_dev);
431         if (rc) {
432                 CERROR("misc_register: rc = %d\n", rc);
433                 cfs_cpu_fini();
434                 RETURN(rc);
435         }
436
437         if (live_router_check_interval != INT_MIN ||
438             dead_router_check_interval != INT_MIN)
439                 LCONSOLE_WARN("live_router_check_interval and dead_router_check_interval have been deprecated. Use alive_router_check_interval instead. Ignoring these deprecated parameters.\n");
440
441         if (config_on_load) {
442                 /* Have to schedule a separate thread to avoid deadlocking
443                  * in modload */
444                 (void)kthread_run(lnet_configure, NULL, "lnet_initd");
445         }
446
447         RETURN(0);
448 }
449
450 static void __exit lnet_exit(void)
451 {
452         misc_deregister(&lnet_dev);
453
454         lnet_router_exit();
455         lnet_lib_exit();
456         cfs_cpu_fini();
457 }
458
459 MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
460 MODULE_DESCRIPTION("Lustre Networking layer");
461 MODULE_VERSION(LNET_VERSION);
462 MODULE_LICENSE("GPL");
463
464 module_init(lnet_init);
465 module_exit(lnet_exit);