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