Whamcloud - gitweb
LU-10003 lnet: use Netlink to support old and new NI APIs.
[fs/lustre-release.git] / lnet / lnet / module.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31
32 #define DEBUG_SUBSYSTEM S_LNET
33
34 #include <lnet/lib-lnet.h>
35 #include <uapi/linux/lnet/lnet-dlc.h>
36
37 static int config_on_load = 0;
38 module_param(config_on_load, int, 0444);
39 MODULE_PARM_DESC(config_on_load, "configure network at module load");
40
41 static DEFINE_MUTEX(lnet_config_mutex);
42
43 int lnet_configure(void *arg)
44 {
45         /* 'arg' only there so I can be passed to cfs_create_thread() */
46         int    rc = 0;
47
48         mutex_lock(&lnet_config_mutex);
49
50         if (!the_lnet.ln_niinit_self) {
51                 rc = try_module_get(THIS_MODULE);
52
53                 if (rc != 1)
54                         goto out;
55
56                 rc = LNetNIInit(LNET_PID_LUSTRE);
57                 if (rc >= 0) {
58                         the_lnet.ln_niinit_self = 1;
59                         rc = 0;
60                 } else {
61                         module_put(THIS_MODULE);
62                 }
63         }
64
65 out:
66         mutex_unlock(&lnet_config_mutex);
67         return rc;
68 }
69
70 int lnet_unconfigure(void)
71 {
72         int refcount;
73
74         mutex_lock(&lnet_config_mutex);
75
76         if (the_lnet.ln_niinit_self) {
77                 the_lnet.ln_niinit_self = 0;
78                 LNetNIFini();
79                 module_put(THIS_MODULE);
80         }
81
82         mutex_lock(&the_lnet.ln_api_mutex);
83         refcount = the_lnet.ln_refcount;
84         mutex_unlock(&the_lnet.ln_api_mutex);
85
86         mutex_unlock(&lnet_config_mutex);
87
88         return (refcount == 0) ? 0 : -EBUSY;
89 }
90
91 static int
92 lnet_dyn_configure_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_add_net(conf);
104         else
105                 rc = -EINVAL;
106         mutex_unlock(&lnet_config_mutex);
107
108         return rc;
109 }
110
111 static int
112 lnet_dyn_unconfigure_net(struct libcfs_ioctl_hdr *hdr)
113 {
114         struct lnet_ioctl_config_data *conf =
115           (struct lnet_ioctl_config_data *) hdr;
116         int                           rc;
117
118         if (conf->cfg_hdr.ioc_len < sizeof(*conf))
119                 return -EINVAL;
120
121         mutex_lock(&lnet_config_mutex);
122         if (the_lnet.ln_niinit_self)
123                 rc = lnet_dyn_del_net(conf->cfg_net);
124         else
125                 rc = -EINVAL;
126         mutex_unlock(&lnet_config_mutex);
127
128         return rc;
129 }
130
131 static int
132 lnet_dyn_configure_ni(struct libcfs_ioctl_hdr *hdr)
133 {
134         struct lnet_ioctl_config_ni *conf =
135           (struct lnet_ioctl_config_ni *)hdr;
136         int rc = -EINVAL;
137
138         if (conf->lic_cfg_hdr.ioc_len < sizeof(*conf))
139                 return rc;
140
141         mutex_lock(&lnet_config_mutex);
142         if (the_lnet.ln_niinit_self) {
143                 struct lnet_ioctl_config_lnd_tunables *tun = NULL;
144                 struct lnet_nid nid;
145                 u32 net_id;
146
147                 /* get the tunables if they are available */
148                 if (conf->lic_cfg_hdr.ioc_len >=
149                     sizeof(*conf) + sizeof(*tun))
150                         tun = (struct lnet_ioctl_config_lnd_tunables *) conf->lic_bulk;
151
152                 lnet_nid4_to_nid(conf->lic_nid, &nid);
153                 net_id = LNET_NID_NET(&nid);
154                 rc = lnet_dyn_add_ni(conf, net_id, tun);
155         }
156         mutex_unlock(&lnet_config_mutex);
157
158         return rc;
159 }
160
161 static int
162 lnet_dyn_unconfigure_ni(struct libcfs_ioctl_hdr *hdr)
163 {
164         struct lnet_ioctl_config_ni *conf =
165           (struct lnet_ioctl_config_ni *) hdr;
166         struct lnet_nid nid;
167         int rc = -EINVAL;
168
169         if (conf->lic_cfg_hdr.ioc_len < sizeof(*conf) ||
170             !the_lnet.ln_niinit_self)
171                 return rc;
172
173         lnet_nid4_to_nid(conf->lic_nid, &nid);
174         mutex_lock(&lnet_config_mutex);
175         if (the_lnet.ln_niinit_self)
176                 rc = lnet_dyn_del_ni(&nid);
177         else
178                 rc = -EINVAL;
179         mutex_unlock(&lnet_config_mutex);
180
181         return rc;
182 }
183
184 static int
185 lnet_ioctl(struct notifier_block *nb,
186            unsigned long cmd, void *vdata)
187 {
188         struct libcfs_ioctl_hdr *hdr = vdata;
189         int rc;
190
191         switch (cmd) {
192         case IOC_LIBCFS_CONFIGURE: {
193                 struct libcfs_ioctl_data *data =
194                   (struct libcfs_ioctl_data *)hdr;
195
196                 if (data->ioc_hdr.ioc_len < sizeof(*data)) {
197                         rc = -EINVAL;
198                 } else {
199                         the_lnet.ln_nis_from_mod_params = data->ioc_flags;
200                         rc = lnet_configure(NULL);
201                 }
202                 break;
203         }
204
205         case IOC_LIBCFS_UNCONFIGURE:
206                 rc = lnet_unconfigure();
207                 break;
208
209         case IOC_LIBCFS_ADD_NET:
210                 rc = lnet_dyn_configure_net(hdr);
211                 break;
212
213         case IOC_LIBCFS_DEL_NET:
214                 rc = lnet_dyn_unconfigure_net(hdr);
215                 break;
216
217         case IOC_LIBCFS_ADD_LOCAL_NI:
218                 rc = lnet_dyn_configure_ni(hdr);
219                 break;
220
221         case IOC_LIBCFS_DEL_LOCAL_NI:
222                 rc = lnet_dyn_unconfigure_ni(hdr);
223                 break;
224
225         default:
226                 /* Passing LNET_PID_ANY only gives me a ref if the net is up
227                  * already; I'll need it to ensure the net can't go down while
228                  * I'm called into it */
229                 rc = LNetNIInit(LNET_PID_ANY);
230                 if (rc >= 0) {
231                         rc = LNetCtl(cmd, hdr);
232                         LNetNIFini();
233                 }
234                 break;
235         }
236         return notifier_from_ioctl_errno(rc);
237 }
238
239 static struct notifier_block lnet_ioctl_handler = {
240         .notifier_call = lnet_ioctl,
241 };
242
243 static int __init lnet_init(void)
244 {
245         int rc;
246         ENTRY;
247
248         rc = lnet_lib_init();
249         if (rc != 0) {
250                 CERROR("lnet_lib_init: error %d\n", rc);
251                 RETURN(rc);
252         }
253
254         if (live_router_check_interval != INT_MIN ||
255             dead_router_check_interval != INT_MIN)
256                 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");
257
258         rc = blocking_notifier_chain_register(&libcfs_ioctl_list,
259                                               &lnet_ioctl_handler);
260         LASSERT(rc == 0);
261
262         if (config_on_load) {
263                 /* Have to schedule a separate thread to avoid deadlocking
264                  * in modload */
265                 (void)kthread_run(lnet_configure, NULL, "lnet_initd");
266         }
267
268         RETURN(0);
269 }
270
271 static void __exit lnet_exit(void)
272 {
273         int rc;
274
275         rc = blocking_notifier_chain_unregister(&libcfs_ioctl_list,
276                                                 &lnet_ioctl_handler);
277         LASSERT(rc == 0);
278
279         lnet_router_exit();
280         lnet_lib_exit();
281 }
282
283 MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
284 MODULE_DESCRIPTION("Lustre Networking layer");
285 MODULE_VERSION(LNET_VERSION);
286 MODULE_LICENSE("GPL");
287
288 module_init(lnet_init);
289 module_exit(lnet_exit);