Commit | Line | Data |
---|---|---|
d7e09d03 PT |
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.sun.com/software/products/lustre/docs/GPLv2.pdf | |
19 | * | |
20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
21 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
22 | * have any questions. | |
23 | * | |
24 | * GPL HEADER END | |
25 | */ | |
26 | /* | |
27 | * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
1dc563a6 | 30 | * Copyright (c) 2011, 2015, Intel Corporation. |
d7e09d03 PT |
31 | */ |
32 | /* | |
33 | * This file is part of Lustre, http://www.lustre.org/ | |
34 | * Lustre is a trademark of Sun Microsystems, Inc. | |
35 | */ | |
36 | ||
37 | #define DEBUG_SUBSYSTEM S_LNET | |
d7e09d03 | 38 | #include <linux/log2.h> |
9056be30 | 39 | #include <linux/ktime.h> |
d7e09d03 | 40 | |
db18b8e9 | 41 | #include "../../include/linux/lnet/lib-lnet.h" |
2e9a51bd | 42 | #include "../../include/linux/lnet/lib-dlc.h" |
db18b8e9 | 43 | |
d7e09d03 PT |
44 | #define D_LNI D_CONSOLE |
45 | ||
7e7ab095 | 46 | lnet_t the_lnet; /* THE state of the network */ |
d7e09d03 PT |
47 | EXPORT_SYMBOL(the_lnet); |
48 | ||
d7e09d03 | 49 | static char *ip2nets = ""; |
8cc7b4b9 PT |
50 | module_param(ip2nets, charp, 0444); |
51 | MODULE_PARM_DESC(ip2nets, "LNET network <- IP table"); | |
d7e09d03 PT |
52 | |
53 | static char *networks = ""; | |
8cc7b4b9 PT |
54 | module_param(networks, charp, 0444); |
55 | MODULE_PARM_DESC(networks, "local networks"); | |
d7e09d03 PT |
56 | |
57 | static char *routes = ""; | |
8cc7b4b9 PT |
58 | module_param(routes, charp, 0444); |
59 | MODULE_PARM_DESC(routes, "routes to non-local networks"); | |
d7e09d03 PT |
60 | |
61 | static int rnet_htable_size = LNET_REMOTE_NETS_HASH_DEFAULT; | |
8cc7b4b9 PT |
62 | module_param(rnet_htable_size, int, 0444); |
63 | MODULE_PARM_DESC(rnet_htable_size, "size of remote network hash table"); | |
d7e09d03 | 64 | |
fccfde7d | 65 | static int lnet_ping(lnet_process_id_t id, int timeout_ms, |
4eb53dfd | 66 | lnet_process_id_t __user *ids, int n_ids); |
fccfde7d | 67 | |
51bd8814 | 68 | static char * |
d7e09d03 PT |
69 | lnet_get_routes(void) |
70 | { | |
71 | return routes; | |
72 | } | |
73 | ||
51bd8814 | 74 | static char * |
d7e09d03 PT |
75 | lnet_get_networks(void) |
76 | { | |
7e7ab095 MS |
77 | char *nets; |
78 | int rc; | |
d7e09d03 | 79 | |
5fd88337 | 80 | if (*networks && *ip2nets) { |
8ad5360a | 81 | LCONSOLE_ERROR_MSG(0x101, "Please specify EITHER 'networks' or 'ip2nets' but not both at once\n"); |
d7e09d03 PT |
82 | return NULL; |
83 | } | |
84 | ||
5fd88337 | 85 | if (*ip2nets) { |
d7e09d03 | 86 | rc = lnet_parse_ip2nets(&nets, ip2nets); |
5fd88337 | 87 | return !rc ? nets : NULL; |
d7e09d03 PT |
88 | } |
89 | ||
5fd88337 | 90 | if (*networks) |
d7e09d03 PT |
91 | return networks; |
92 | ||
93 | return "tcp"; | |
94 | } | |
95 | ||
51bd8814 | 96 | static void |
d7e09d03 PT |
97 | lnet_init_locks(void) |
98 | { | |
99 | spin_lock_init(&the_lnet.ln_eq_wait_lock); | |
100 | init_waitqueue_head(&the_lnet.ln_eq_waitq); | |
101 | mutex_init(&the_lnet.ln_lnd_mutex); | |
102 | mutex_init(&the_lnet.ln_api_mutex); | |
103 | } | |
104 | ||
d7e09d03 PT |
105 | static int |
106 | lnet_create_remote_nets_table(void) | |
107 | { | |
7e7ab095 MS |
108 | int i; |
109 | struct list_head *hash; | |
d7e09d03 | 110 | |
06ace26e | 111 | LASSERT(!the_lnet.ln_remote_nets_hash); |
d7e09d03 PT |
112 | LASSERT(the_lnet.ln_remote_nets_hbits > 0); |
113 | LIBCFS_ALLOC(hash, LNET_REMOTE_NETS_HASH_SIZE * sizeof(*hash)); | |
06ace26e | 114 | if (!hash) { |
d7e09d03 PT |
115 | CERROR("Failed to create remote nets hash table\n"); |
116 | return -ENOMEM; | |
117 | } | |
118 | ||
119 | for (i = 0; i < LNET_REMOTE_NETS_HASH_SIZE; i++) | |
120 | INIT_LIST_HEAD(&hash[i]); | |
121 | the_lnet.ln_remote_nets_hash = hash; | |
122 | return 0; | |
123 | } | |
124 | ||
125 | static void | |
126 | lnet_destroy_remote_nets_table(void) | |
127 | { | |
1ae2bdb2 | 128 | int i; |
d7e09d03 | 129 | |
06ace26e | 130 | if (!the_lnet.ln_remote_nets_hash) |
d7e09d03 PT |
131 | return; |
132 | ||
133 | for (i = 0; i < LNET_REMOTE_NETS_HASH_SIZE; i++) | |
134 | LASSERT(list_empty(&the_lnet.ln_remote_nets_hash[i])); | |
135 | ||
136 | LIBCFS_FREE(the_lnet.ln_remote_nets_hash, | |
1ae2bdb2 DE |
137 | LNET_REMOTE_NETS_HASH_SIZE * |
138 | sizeof(the_lnet.ln_remote_nets_hash[0])); | |
d7e09d03 PT |
139 | the_lnet.ln_remote_nets_hash = NULL; |
140 | } | |
141 | ||
142 | static void | |
143 | lnet_destroy_locks(void) | |
144 | { | |
06ace26e | 145 | if (the_lnet.ln_res_lock) { |
d7e09d03 PT |
146 | cfs_percpt_lock_free(the_lnet.ln_res_lock); |
147 | the_lnet.ln_res_lock = NULL; | |
148 | } | |
149 | ||
06ace26e | 150 | if (the_lnet.ln_net_lock) { |
d7e09d03 PT |
151 | cfs_percpt_lock_free(the_lnet.ln_net_lock); |
152 | the_lnet.ln_net_lock = NULL; | |
153 | } | |
d7e09d03 PT |
154 | } |
155 | ||
156 | static int | |
157 | lnet_create_locks(void) | |
158 | { | |
159 | lnet_init_locks(); | |
160 | ||
161 | the_lnet.ln_res_lock = cfs_percpt_lock_alloc(lnet_cpt_table()); | |
06ace26e | 162 | if (!the_lnet.ln_res_lock) |
d7e09d03 PT |
163 | goto failed; |
164 | ||
165 | the_lnet.ln_net_lock = cfs_percpt_lock_alloc(lnet_cpt_table()); | |
06ace26e | 166 | if (!the_lnet.ln_net_lock) |
d7e09d03 PT |
167 | goto failed; |
168 | ||
169 | return 0; | |
170 | ||
171 | failed: | |
172 | lnet_destroy_locks(); | |
173 | return -ENOMEM; | |
174 | } | |
175 | ||
3b7566d9 | 176 | static void lnet_assert_wire_constants(void) |
d7e09d03 | 177 | { |
4420cfd3 JS |
178 | /* |
179 | * Wire protocol assertions generated by 'wirecheck' | |
d7e09d03 PT |
180 | * running on Linux robert.bartonsoftware.com 2.6.8-1.521 |
181 | * #1 Mon Aug 16 09:01:18 EDT 2004 i686 athlon i386 GNU/Linux | |
4420cfd3 JS |
182 | * with gcc version 3.3.3 20040412 (Red Hat Linux 3.3.3-7) |
183 | */ | |
d7e09d03 PT |
184 | |
185 | /* Constants... */ | |
3b7566d9 TP |
186 | CLASSERT(LNET_PROTO_TCP_MAGIC == 0xeebc0ded); |
187 | CLASSERT(LNET_PROTO_TCP_VERSION_MAJOR == 1); | |
188 | CLASSERT(LNET_PROTO_TCP_VERSION_MINOR == 0); | |
189 | CLASSERT(LNET_MSG_ACK == 0); | |
190 | CLASSERT(LNET_MSG_PUT == 1); | |
191 | CLASSERT(LNET_MSG_GET == 2); | |
192 | CLASSERT(LNET_MSG_REPLY == 3); | |
193 | CLASSERT(LNET_MSG_HELLO == 4); | |
d7e09d03 PT |
194 | |
195 | /* Checks for struct ptl_handle_wire_t */ | |
3b7566d9 TP |
196 | CLASSERT((int)sizeof(lnet_handle_wire_t) == 16); |
197 | CLASSERT((int)offsetof(lnet_handle_wire_t, wh_interface_cookie) == 0); | |
198 | CLASSERT((int)sizeof(((lnet_handle_wire_t *)0)->wh_interface_cookie) == 8); | |
199 | CLASSERT((int)offsetof(lnet_handle_wire_t, wh_object_cookie) == 8); | |
200 | CLASSERT((int)sizeof(((lnet_handle_wire_t *)0)->wh_object_cookie) == 8); | |
d7e09d03 PT |
201 | |
202 | /* Checks for struct lnet_magicversion_t */ | |
3b7566d9 TP |
203 | CLASSERT((int)sizeof(lnet_magicversion_t) == 8); |
204 | CLASSERT((int)offsetof(lnet_magicversion_t, magic) == 0); | |
205 | CLASSERT((int)sizeof(((lnet_magicversion_t *)0)->magic) == 4); | |
206 | CLASSERT((int)offsetof(lnet_magicversion_t, version_major) == 4); | |
207 | CLASSERT((int)sizeof(((lnet_magicversion_t *)0)->version_major) == 2); | |
208 | CLASSERT((int)offsetof(lnet_magicversion_t, version_minor) == 6); | |
209 | CLASSERT((int)sizeof(((lnet_magicversion_t *)0)->version_minor) == 2); | |
d7e09d03 PT |
210 | |
211 | /* Checks for struct lnet_hdr_t */ | |
3b7566d9 TP |
212 | CLASSERT((int)sizeof(lnet_hdr_t) == 72); |
213 | CLASSERT((int)offsetof(lnet_hdr_t, dest_nid) == 0); | |
214 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->dest_nid) == 8); | |
215 | CLASSERT((int)offsetof(lnet_hdr_t, src_nid) == 8); | |
216 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->src_nid) == 8); | |
217 | CLASSERT((int)offsetof(lnet_hdr_t, dest_pid) == 16); | |
218 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->dest_pid) == 4); | |
219 | CLASSERT((int)offsetof(lnet_hdr_t, src_pid) == 20); | |
220 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->src_pid) == 4); | |
221 | CLASSERT((int)offsetof(lnet_hdr_t, type) == 24); | |
222 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->type) == 4); | |
223 | CLASSERT((int)offsetof(lnet_hdr_t, payload_length) == 28); | |
224 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->payload_length) == 4); | |
225 | CLASSERT((int)offsetof(lnet_hdr_t, msg) == 32); | |
226 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg) == 40); | |
d7e09d03 PT |
227 | |
228 | /* Ack */ | |
3b7566d9 TP |
229 | CLASSERT((int)offsetof(lnet_hdr_t, msg.ack.dst_wmd) == 32); |
230 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.ack.dst_wmd) == 16); | |
231 | CLASSERT((int)offsetof(lnet_hdr_t, msg.ack.match_bits) == 48); | |
232 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.ack.match_bits) == 8); | |
233 | CLASSERT((int)offsetof(lnet_hdr_t, msg.ack.mlength) == 56); | |
234 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.ack.mlength) == 4); | |
d7e09d03 PT |
235 | |
236 | /* Put */ | |
3b7566d9 TP |
237 | CLASSERT((int)offsetof(lnet_hdr_t, msg.put.ack_wmd) == 32); |
238 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.ack_wmd) == 16); | |
239 | CLASSERT((int)offsetof(lnet_hdr_t, msg.put.match_bits) == 48); | |
240 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.match_bits) == 8); | |
241 | CLASSERT((int)offsetof(lnet_hdr_t, msg.put.hdr_data) == 56); | |
242 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.hdr_data) == 8); | |
243 | CLASSERT((int)offsetof(lnet_hdr_t, msg.put.ptl_index) == 64); | |
244 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.ptl_index) == 4); | |
245 | CLASSERT((int)offsetof(lnet_hdr_t, msg.put.offset) == 68); | |
246 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.offset) == 4); | |
d7e09d03 PT |
247 | |
248 | /* Get */ | |
3b7566d9 TP |
249 | CLASSERT((int)offsetof(lnet_hdr_t, msg.get.return_wmd) == 32); |
250 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.return_wmd) == 16); | |
251 | CLASSERT((int)offsetof(lnet_hdr_t, msg.get.match_bits) == 48); | |
252 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.match_bits) == 8); | |
253 | CLASSERT((int)offsetof(lnet_hdr_t, msg.get.ptl_index) == 56); | |
254 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.ptl_index) == 4); | |
255 | CLASSERT((int)offsetof(lnet_hdr_t, msg.get.src_offset) == 60); | |
256 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.src_offset) == 4); | |
257 | CLASSERT((int)offsetof(lnet_hdr_t, msg.get.sink_length) == 64); | |
258 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.sink_length) == 4); | |
d7e09d03 PT |
259 | |
260 | /* Reply */ | |
3b7566d9 TP |
261 | CLASSERT((int)offsetof(lnet_hdr_t, msg.reply.dst_wmd) == 32); |
262 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.reply.dst_wmd) == 16); | |
d7e09d03 PT |
263 | |
264 | /* Hello */ | |
3b7566d9 TP |
265 | CLASSERT((int)offsetof(lnet_hdr_t, msg.hello.incarnation) == 32); |
266 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.hello.incarnation) == 8); | |
267 | CLASSERT((int)offsetof(lnet_hdr_t, msg.hello.type) == 40); | |
268 | CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.hello.type) == 4); | |
d7e09d03 PT |
269 | } |
270 | ||
51bd8814 | 271 | static lnd_t * |
80feb1ef | 272 | lnet_find_lnd_by_type(__u32 type) |
d7e09d03 | 273 | { |
7e7ab095 MS |
274 | lnd_t *lnd; |
275 | struct list_head *tmp; | |
d7e09d03 PT |
276 | |
277 | /* holding lnd mutex */ | |
565f3d2f | 278 | list_for_each(tmp, &the_lnet.ln_lnds) { |
d7e09d03 PT |
279 | lnd = list_entry(tmp, lnd_t, lnd_list); |
280 | ||
80feb1ef | 281 | if (lnd->lnd_type == type) |
d7e09d03 PT |
282 | return lnd; |
283 | } | |
284 | ||
285 | return NULL; | |
286 | } | |
287 | ||
288 | void | |
3b7566d9 | 289 | lnet_register_lnd(lnd_t *lnd) |
d7e09d03 | 290 | { |
bdd84a6f | 291 | mutex_lock(&the_lnet.ln_lnd_mutex); |
d7e09d03 | 292 | |
3b7566d9 TP |
293 | LASSERT(the_lnet.ln_init); |
294 | LASSERT(libcfs_isknown_lnd(lnd->lnd_type)); | |
06ace26e | 295 | LASSERT(!lnet_find_lnd_by_type(lnd->lnd_type)); |
d7e09d03 | 296 | |
3b7566d9 | 297 | list_add_tail(&lnd->lnd_list, &the_lnet.ln_lnds); |
d7e09d03 PT |
298 | lnd->lnd_refcount = 0; |
299 | ||
300 | CDEBUG(D_NET, "%s LND registered\n", libcfs_lnd2str(lnd->lnd_type)); | |
301 | ||
bdd84a6f | 302 | mutex_unlock(&the_lnet.ln_lnd_mutex); |
d7e09d03 PT |
303 | } |
304 | EXPORT_SYMBOL(lnet_register_lnd); | |
305 | ||
306 | void | |
3b7566d9 | 307 | lnet_unregister_lnd(lnd_t *lnd) |
d7e09d03 | 308 | { |
bdd84a6f | 309 | mutex_lock(&the_lnet.ln_lnd_mutex); |
d7e09d03 | 310 | |
3b7566d9 TP |
311 | LASSERT(the_lnet.ln_init); |
312 | LASSERT(lnet_find_lnd_by_type(lnd->lnd_type) == lnd); | |
5fd88337 | 313 | LASSERT(!lnd->lnd_refcount); |
d7e09d03 | 314 | |
3b7566d9 | 315 | list_del(&lnd->lnd_list); |
d7e09d03 PT |
316 | CDEBUG(D_NET, "%s LND unregistered\n", libcfs_lnd2str(lnd->lnd_type)); |
317 | ||
bdd84a6f | 318 | mutex_unlock(&the_lnet.ln_lnd_mutex); |
d7e09d03 PT |
319 | } |
320 | EXPORT_SYMBOL(lnet_unregister_lnd); | |
321 | ||
322 | void | |
323 | lnet_counters_get(lnet_counters_t *counters) | |
324 | { | |
325 | lnet_counters_t *ctr; | |
7e7ab095 | 326 | int i; |
d7e09d03 PT |
327 | |
328 | memset(counters, 0, sizeof(*counters)); | |
329 | ||
330 | lnet_net_lock(LNET_LOCK_EX); | |
331 | ||
332 | cfs_percpt_for_each(ctr, i, the_lnet.ln_counters) { | |
333 | counters->msgs_max += ctr->msgs_max; | |
334 | counters->msgs_alloc += ctr->msgs_alloc; | |
335 | counters->errors += ctr->errors; | |
336 | counters->send_count += ctr->send_count; | |
337 | counters->recv_count += ctr->recv_count; | |
338 | counters->route_count += ctr->route_count; | |
b3d0dfe5 | 339 | counters->drop_count += ctr->drop_count; |
d7e09d03 PT |
340 | counters->send_length += ctr->send_length; |
341 | counters->recv_length += ctr->recv_length; | |
342 | counters->route_length += ctr->route_length; | |
343 | counters->drop_length += ctr->drop_length; | |
d7e09d03 PT |
344 | } |
345 | lnet_net_unlock(LNET_LOCK_EX); | |
346 | } | |
347 | EXPORT_SYMBOL(lnet_counters_get); | |
348 | ||
349 | void | |
350 | lnet_counters_reset(void) | |
351 | { | |
352 | lnet_counters_t *counters; | |
7e7ab095 | 353 | int i; |
d7e09d03 PT |
354 | |
355 | lnet_net_lock(LNET_LOCK_EX); | |
356 | ||
357 | cfs_percpt_for_each(counters, i, the_lnet.ln_counters) | |
358 | memset(counters, 0, sizeof(lnet_counters_t)); | |
359 | ||
360 | lnet_net_unlock(LNET_LOCK_EX); | |
361 | } | |
d7e09d03 | 362 | |
d7e09d03 PT |
363 | static char * |
364 | lnet_res_type2str(int type) | |
365 | { | |
366 | switch (type) { | |
367 | default: | |
368 | LBUG(); | |
369 | case LNET_COOKIE_TYPE_MD: | |
370 | return "MD"; | |
371 | case LNET_COOKIE_TYPE_ME: | |
372 | return "ME"; | |
373 | case LNET_COOKIE_TYPE_EQ: | |
374 | return "EQ"; | |
375 | } | |
376 | } | |
377 | ||
51bd8814 | 378 | static void |
d7e09d03 PT |
379 | lnet_res_container_cleanup(struct lnet_res_container *rec) |
380 | { | |
7e7ab095 | 381 | int count = 0; |
d7e09d03 | 382 | |
5fd88337 | 383 | if (!rec->rec_type) /* not set yet, it's uninitialized */ |
d7e09d03 PT |
384 | return; |
385 | ||
386 | while (!list_empty(&rec->rec_active)) { | |
387 | struct list_head *e = rec->rec_active.next; | |
388 | ||
389 | list_del_init(e); | |
390 | if (rec->rec_type == LNET_COOKIE_TYPE_EQ) { | |
391 | lnet_eq_free(list_entry(e, lnet_eq_t, eq_list)); | |
392 | ||
393 | } else if (rec->rec_type == LNET_COOKIE_TYPE_MD) { | |
394 | lnet_md_free(list_entry(e, lnet_libmd_t, md_list)); | |
395 | ||
396 | } else { /* NB: Active MEs should be attached on portals */ | |
397 | LBUG(); | |
398 | } | |
399 | count++; | |
400 | } | |
401 | ||
402 | if (count > 0) { | |
4420cfd3 JS |
403 | /* |
404 | * Found alive MD/ME/EQ, user really should unlink/free | |
d7e09d03 | 405 | * all of them before finalize LNet, but if someone didn't, |
4420cfd3 JS |
406 | * we have to recycle garbage for him |
407 | */ | |
d7e09d03 PT |
408 | CERROR("%d active elements on exit of %s container\n", |
409 | count, lnet_res_type2str(rec->rec_type)); | |
410 | } | |
411 | ||
06ace26e | 412 | if (rec->rec_lh_hash) { |
d7e09d03 PT |
413 | LIBCFS_FREE(rec->rec_lh_hash, |
414 | LNET_LH_HASH_SIZE * sizeof(rec->rec_lh_hash[0])); | |
415 | rec->rec_lh_hash = NULL; | |
416 | } | |
417 | ||
418 | rec->rec_type = 0; /* mark it as finalized */ | |
419 | } | |
420 | ||
51bd8814 | 421 | static int |
39445367 | 422 | lnet_res_container_setup(struct lnet_res_container *rec, int cpt, int type) |
d7e09d03 | 423 | { |
7e7ab095 MS |
424 | int rc = 0; |
425 | int i; | |
d7e09d03 | 426 | |
5fd88337 | 427 | LASSERT(!rec->rec_type); |
d7e09d03 PT |
428 | |
429 | rec->rec_type = type; | |
430 | INIT_LIST_HEAD(&rec->rec_active); | |
d7e09d03 PT |
431 | rec->rec_lh_cookie = (cpt << LNET_COOKIE_TYPE_BITS) | type; |
432 | ||
433 | /* Arbitrary choice of hash table size */ | |
434 | LIBCFS_CPT_ALLOC(rec->rec_lh_hash, lnet_cpt_table(), cpt, | |
435 | LNET_LH_HASH_SIZE * sizeof(rec->rec_lh_hash[0])); | |
06ace26e | 436 | if (!rec->rec_lh_hash) { |
d7e09d03 PT |
437 | rc = -ENOMEM; |
438 | goto out; | |
439 | } | |
440 | ||
441 | for (i = 0; i < LNET_LH_HASH_SIZE; i++) | |
442 | INIT_LIST_HEAD(&rec->rec_lh_hash[i]); | |
443 | ||
444 | return 0; | |
445 | ||
446 | out: | |
447 | CERROR("Failed to setup %s resource container\n", | |
448 | lnet_res_type2str(type)); | |
449 | lnet_res_container_cleanup(rec); | |
450 | return rc; | |
451 | } | |
452 | ||
453 | static void | |
454 | lnet_res_containers_destroy(struct lnet_res_container **recs) | |
455 | { | |
7e7ab095 MS |
456 | struct lnet_res_container *rec; |
457 | int i; | |
d7e09d03 PT |
458 | |
459 | cfs_percpt_for_each(rec, i, recs) | |
460 | lnet_res_container_cleanup(rec); | |
461 | ||
462 | cfs_percpt_free(recs); | |
463 | } | |
464 | ||
465 | static struct lnet_res_container ** | |
39445367 | 466 | lnet_res_containers_create(int type) |
d7e09d03 | 467 | { |
7e7ab095 MS |
468 | struct lnet_res_container **recs; |
469 | struct lnet_res_container *rec; | |
470 | int rc; | |
471 | int i; | |
d7e09d03 PT |
472 | |
473 | recs = cfs_percpt_alloc(lnet_cpt_table(), sizeof(*rec)); | |
06ace26e | 474 | if (!recs) { |
d7e09d03 PT |
475 | CERROR("Failed to allocate %s resource containers\n", |
476 | lnet_res_type2str(type)); | |
477 | return NULL; | |
478 | } | |
479 | ||
480 | cfs_percpt_for_each(rec, i, recs) { | |
39445367 | 481 | rc = lnet_res_container_setup(rec, i, type); |
5fd88337 | 482 | if (rc) { |
d7e09d03 PT |
483 | lnet_res_containers_destroy(recs); |
484 | return NULL; | |
485 | } | |
486 | } | |
487 | ||
488 | return recs; | |
489 | } | |
490 | ||
491 | lnet_libhandle_t * | |
492 | lnet_res_lh_lookup(struct lnet_res_container *rec, __u64 cookie) | |
493 | { | |
494 | /* ALWAYS called with lnet_res_lock held */ | |
7e7ab095 MS |
495 | struct list_head *head; |
496 | lnet_libhandle_t *lh; | |
497 | unsigned int hash; | |
d7e09d03 PT |
498 | |
499 | if ((cookie & LNET_COOKIE_MASK) != rec->rec_type) | |
500 | return NULL; | |
501 | ||
502 | hash = cookie >> (LNET_COOKIE_TYPE_BITS + LNET_CPT_BITS); | |
503 | head = &rec->rec_lh_hash[hash & LNET_LH_HASH_MASK]; | |
504 | ||
505 | list_for_each_entry(lh, head, lh_hash_chain) { | |
506 | if (lh->lh_cookie == cookie) | |
507 | return lh; | |
508 | } | |
509 | ||
510 | return NULL; | |
511 | } | |
512 | ||
513 | void | |
514 | lnet_res_lh_initialize(struct lnet_res_container *rec, lnet_libhandle_t *lh) | |
515 | { | |
516 | /* ALWAYS called with lnet_res_lock held */ | |
7e7ab095 MS |
517 | unsigned int ibits = LNET_COOKIE_TYPE_BITS + LNET_CPT_BITS; |
518 | unsigned int hash; | |
d7e09d03 PT |
519 | |
520 | lh->lh_cookie = rec->rec_lh_cookie; | |
521 | rec->rec_lh_cookie += 1 << ibits; | |
522 | ||
523 | hash = (lh->lh_cookie >> ibits) & LNET_LH_HASH_MASK; | |
524 | ||
525 | list_add(&lh->lh_hash_chain, &rec->rec_lh_hash[hash]); | |
526 | } | |
527 | ||
09f2f175 | 528 | static int lnet_unprepare(void); |
d7e09d03 | 529 | |
51bd8814 | 530 | static int |
d7e09d03 PT |
531 | lnet_prepare(lnet_pid_t requested_pid) |
532 | { | |
533 | /* Prepare to bring up the network */ | |
534 | struct lnet_res_container **recs; | |
7e7ab095 | 535 | int rc = 0; |
d7e09d03 | 536 | |
6c9e5a55 AS |
537 | if (requested_pid == LNET_PID_ANY) { |
538 | /* Don't instantiate LNET just for me */ | |
539 | return -ENETDOWN; | |
540 | } | |
541 | ||
5fd88337 | 542 | LASSERT(!the_lnet.ln_refcount); |
d7e09d03 PT |
543 | |
544 | the_lnet.ln_routing = 0; | |
545 | ||
5fd88337 | 546 | LASSERT(!(requested_pid & LNET_PID_USERFLAG)); |
d7e09d03 PT |
547 | the_lnet.ln_pid = requested_pid; |
548 | ||
549 | INIT_LIST_HEAD(&the_lnet.ln_test_peers); | |
550 | INIT_LIST_HEAD(&the_lnet.ln_nis); | |
551 | INIT_LIST_HEAD(&the_lnet.ln_nis_cpt); | |
552 | INIT_LIST_HEAD(&the_lnet.ln_nis_zombie); | |
553 | INIT_LIST_HEAD(&the_lnet.ln_routers); | |
554 | ||
555 | rc = lnet_create_remote_nets_table(); | |
5fd88337 | 556 | if (rc) |
d7e09d03 | 557 | goto failed; |
7bcd831b SB |
558 | /* |
559 | * NB the interface cookie in wire handles guards against delayed | |
560 | * replies and ACKs appearing valid after reboot. | |
561 | */ | |
562 | the_lnet.ln_interface_cookie = ktime_get_ns(); | |
d7e09d03 PT |
563 | |
564 | the_lnet.ln_counters = cfs_percpt_alloc(lnet_cpt_table(), | |
565 | sizeof(lnet_counters_t)); | |
06ace26e | 566 | if (!the_lnet.ln_counters) { |
d7e09d03 PT |
567 | CERROR("Failed to allocate counters for LNet\n"); |
568 | rc = -ENOMEM; | |
569 | goto failed; | |
570 | } | |
571 | ||
572 | rc = lnet_peer_tables_create(); | |
5fd88337 | 573 | if (rc) |
d7e09d03 PT |
574 | goto failed; |
575 | ||
576 | rc = lnet_msg_containers_create(); | |
5fd88337 | 577 | if (rc) |
d7e09d03 PT |
578 | goto failed; |
579 | ||
580 | rc = lnet_res_container_setup(&the_lnet.ln_eq_container, 0, | |
39445367 | 581 | LNET_COOKIE_TYPE_EQ); |
5fd88337 | 582 | if (rc) |
d7e09d03 PT |
583 | goto failed; |
584 | ||
39445367 | 585 | recs = lnet_res_containers_create(LNET_COOKIE_TYPE_ME); |
06ace26e | 586 | if (!recs) { |
a18ac314 | 587 | rc = -ENOMEM; |
d7e09d03 | 588 | goto failed; |
a18ac314 | 589 | } |
d7e09d03 PT |
590 | |
591 | the_lnet.ln_me_containers = recs; | |
592 | ||
39445367 | 593 | recs = lnet_res_containers_create(LNET_COOKIE_TYPE_MD); |
06ace26e | 594 | if (!recs) { |
a18ac314 | 595 | rc = -ENOMEM; |
d7e09d03 | 596 | goto failed; |
a18ac314 | 597 | } |
d7e09d03 PT |
598 | |
599 | the_lnet.ln_md_containers = recs; | |
600 | ||
601 | rc = lnet_portals_create(); | |
5fd88337 | 602 | if (rc) { |
d7e09d03 PT |
603 | CERROR("Failed to create portals for LNet: %d\n", rc); |
604 | goto failed; | |
605 | } | |
606 | ||
607 | return 0; | |
608 | ||
609 | failed: | |
610 | lnet_unprepare(); | |
611 | return rc; | |
612 | } | |
613 | ||
09f2f175 | 614 | static int |
3b7566d9 | 615 | lnet_unprepare(void) |
d7e09d03 | 616 | { |
4420cfd3 JS |
617 | /* |
618 | * NB no LNET_LOCK since this is the last reference. All LND instances | |
d7e09d03 PT |
619 | * have shut down already, so it is safe to unlink and free all |
620 | * descriptors, even those that appear committed to a network op (eg MD | |
4420cfd3 JS |
621 | * with non-zero pending count) |
622 | */ | |
d7e09d03 PT |
623 | lnet_fail_nid(LNET_NID_ANY, 0); |
624 | ||
5fd88337 | 625 | LASSERT(!the_lnet.ln_refcount); |
d7e09d03 PT |
626 | LASSERT(list_empty(&the_lnet.ln_test_peers)); |
627 | LASSERT(list_empty(&the_lnet.ln_nis)); | |
628 | LASSERT(list_empty(&the_lnet.ln_nis_cpt)); | |
629 | LASSERT(list_empty(&the_lnet.ln_nis_zombie)); | |
630 | ||
631 | lnet_portals_destroy(); | |
632 | ||
06ace26e | 633 | if (the_lnet.ln_md_containers) { |
d7e09d03 PT |
634 | lnet_res_containers_destroy(the_lnet.ln_md_containers); |
635 | the_lnet.ln_md_containers = NULL; | |
636 | } | |
637 | ||
06ace26e | 638 | if (the_lnet.ln_me_containers) { |
d7e09d03 PT |
639 | lnet_res_containers_destroy(the_lnet.ln_me_containers); |
640 | the_lnet.ln_me_containers = NULL; | |
641 | } | |
642 | ||
643 | lnet_res_container_cleanup(&the_lnet.ln_eq_container); | |
644 | ||
645 | lnet_msg_containers_destroy(); | |
646 | lnet_peer_tables_destroy(); | |
86ef6250 | 647 | lnet_rtrpools_free(0); |
d7e09d03 | 648 | |
06ace26e | 649 | if (the_lnet.ln_counters) { |
d7e09d03 PT |
650 | cfs_percpt_free(the_lnet.ln_counters); |
651 | the_lnet.ln_counters = NULL; | |
652 | } | |
653 | lnet_destroy_remote_nets_table(); | |
654 | ||
655 | return 0; | |
656 | } | |
657 | ||
658 | lnet_ni_t * | |
659 | lnet_net2ni_locked(__u32 net, int cpt) | |
660 | { | |
7e7ab095 MS |
661 | struct list_head *tmp; |
662 | lnet_ni_t *ni; | |
d7e09d03 PT |
663 | |
664 | LASSERT(cpt != LNET_LOCK_EX); | |
665 | ||
666 | list_for_each(tmp, &the_lnet.ln_nis) { | |
667 | ni = list_entry(tmp, lnet_ni_t, ni_list); | |
668 | ||
669 | if (LNET_NIDNET(ni->ni_nid) == net) { | |
670 | lnet_ni_addref_locked(ni, cpt); | |
671 | return ni; | |
672 | } | |
673 | } | |
674 | ||
675 | return NULL; | |
676 | } | |
677 | ||
678 | lnet_ni_t * | |
679 | lnet_net2ni(__u32 net) | |
680 | { | |
681 | lnet_ni_t *ni; | |
682 | ||
683 | lnet_net_lock(0); | |
684 | ni = lnet_net2ni_locked(net, 0); | |
685 | lnet_net_unlock(0); | |
686 | ||
687 | return ni; | |
688 | } | |
689 | EXPORT_SYMBOL(lnet_net2ni); | |
690 | ||
691 | static unsigned int | |
692 | lnet_nid_cpt_hash(lnet_nid_t nid, unsigned int number) | |
693 | { | |
7e7ab095 MS |
694 | __u64 key = nid; |
695 | unsigned int val; | |
d7e09d03 PT |
696 | |
697 | LASSERT(number >= 1 && number <= LNET_CPT_NUMBER); | |
698 | ||
699 | if (number == 1) | |
700 | return 0; | |
701 | ||
72c0824a | 702 | val = hash_long(key, LNET_CPT_BITS); |
d7e09d03 PT |
703 | /* NB: LNET_CP_NUMBER doesn't have to be PO2 */ |
704 | if (val < number) | |
705 | return val; | |
706 | ||
707 | return (unsigned int)(key + val + (val >> 1)) % number; | |
708 | } | |
709 | ||
710 | int | |
711 | lnet_cpt_of_nid_locked(lnet_nid_t nid) | |
712 | { | |
713 | struct lnet_ni *ni; | |
714 | ||
715 | /* must called with hold of lnet_net_lock */ | |
716 | if (LNET_CPT_NUMBER == 1) | |
717 | return 0; /* the only one */ | |
718 | ||
719 | /* take lnet_net_lock(any) would be OK */ | |
720 | if (!list_empty(&the_lnet.ln_nis_cpt)) { | |
721 | list_for_each_entry(ni, &the_lnet.ln_nis_cpt, ni_cptlist) { | |
722 | if (LNET_NIDNET(ni->ni_nid) != LNET_NIDNET(nid)) | |
723 | continue; | |
724 | ||
06ace26e | 725 | LASSERT(ni->ni_cpts); |
d7e09d03 PT |
726 | return ni->ni_cpts[lnet_nid_cpt_hash |
727 | (nid, ni->ni_ncpts)]; | |
728 | } | |
729 | } | |
730 | ||
731 | return lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER); | |
732 | } | |
733 | ||
734 | int | |
735 | lnet_cpt_of_nid(lnet_nid_t nid) | |
736 | { | |
7e7ab095 MS |
737 | int cpt; |
738 | int cpt2; | |
d7e09d03 PT |
739 | |
740 | if (LNET_CPT_NUMBER == 1) | |
741 | return 0; /* the only one */ | |
742 | ||
743 | if (list_empty(&the_lnet.ln_nis_cpt)) | |
744 | return lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER); | |
745 | ||
746 | cpt = lnet_net_lock_current(); | |
747 | cpt2 = lnet_cpt_of_nid_locked(nid); | |
748 | lnet_net_unlock(cpt); | |
749 | ||
750 | return cpt2; | |
751 | } | |
752 | EXPORT_SYMBOL(lnet_cpt_of_nid); | |
753 | ||
754 | int | |
755 | lnet_islocalnet(__u32 net) | |
756 | { | |
7e7ab095 MS |
757 | struct lnet_ni *ni; |
758 | int cpt; | |
d7e09d03 PT |
759 | |
760 | cpt = lnet_net_lock_current(); | |
761 | ||
762 | ni = lnet_net2ni_locked(net, cpt); | |
06ace26e | 763 | if (ni) |
d7e09d03 PT |
764 | lnet_ni_decref_locked(ni, cpt); |
765 | ||
766 | lnet_net_unlock(cpt); | |
767 | ||
06ace26e | 768 | return !!ni; |
d7e09d03 PT |
769 | } |
770 | ||
771 | lnet_ni_t * | |
772 | lnet_nid2ni_locked(lnet_nid_t nid, int cpt) | |
773 | { | |
7e7ab095 MS |
774 | struct lnet_ni *ni; |
775 | struct list_head *tmp; | |
d7e09d03 PT |
776 | |
777 | LASSERT(cpt != LNET_LOCK_EX); | |
778 | ||
779 | list_for_each(tmp, &the_lnet.ln_nis) { | |
780 | ni = list_entry(tmp, lnet_ni_t, ni_list); | |
781 | ||
782 | if (ni->ni_nid == nid) { | |
783 | lnet_ni_addref_locked(ni, cpt); | |
784 | return ni; | |
785 | } | |
786 | } | |
787 | ||
788 | return NULL; | |
789 | } | |
790 | ||
791 | int | |
792 | lnet_islocalnid(lnet_nid_t nid) | |
793 | { | |
7e7ab095 MS |
794 | struct lnet_ni *ni; |
795 | int cpt; | |
d7e09d03 PT |
796 | |
797 | cpt = lnet_net_lock_current(); | |
798 | ni = lnet_nid2ni_locked(nid, cpt); | |
06ace26e | 799 | if (ni) |
d7e09d03 PT |
800 | lnet_ni_decref_locked(ni, cpt); |
801 | lnet_net_unlock(cpt); | |
802 | ||
06ace26e | 803 | return !!ni; |
d7e09d03 PT |
804 | } |
805 | ||
806 | int | |
3b7566d9 | 807 | lnet_count_acceptor_nis(void) |
d7e09d03 PT |
808 | { |
809 | /* Return the # of NIs that need the acceptor. */ | |
7e7ab095 MS |
810 | int count = 0; |
811 | struct list_head *tmp; | |
812 | struct lnet_ni *ni; | |
813 | int cpt; | |
d7e09d03 PT |
814 | |
815 | cpt = lnet_net_lock_current(); | |
816 | list_for_each(tmp, &the_lnet.ln_nis) { | |
817 | ni = list_entry(tmp, lnet_ni_t, ni_list); | |
818 | ||
06ace26e | 819 | if (ni->ni_lnd->lnd_accept) |
d7e09d03 PT |
820 | count++; |
821 | } | |
822 | ||
823 | lnet_net_unlock(cpt); | |
824 | ||
825 | return count; | |
826 | } | |
827 | ||
6c9e5a55 AS |
828 | static lnet_ping_info_t * |
829 | lnet_ping_info_create(int num_ni) | |
830 | { | |
831 | lnet_ping_info_t *ping_info; | |
832 | unsigned int infosz; | |
833 | ||
834 | infosz = offsetof(lnet_ping_info_t, pi_ni[num_ni]); | |
835 | LIBCFS_ALLOC(ping_info, infosz); | |
836 | if (!ping_info) { | |
837 | CERROR("Can't allocate ping info[%d]\n", num_ni); | |
838 | return NULL; | |
839 | } | |
840 | ||
841 | ping_info->pi_nnis = num_ni; | |
842 | ping_info->pi_pid = the_lnet.ln_pid; | |
843 | ping_info->pi_magic = LNET_PROTO_PING_MAGIC; | |
844 | ping_info->pi_features = LNET_PING_FEAT_NI_STATUS; | |
845 | ||
846 | return ping_info; | |
847 | } | |
848 | ||
849 | static inline int | |
850 | lnet_get_ni_count(void) | |
851 | { | |
852 | struct lnet_ni *ni; | |
853 | int count = 0; | |
854 | ||
855 | lnet_net_lock(0); | |
856 | ||
857 | list_for_each_entry(ni, &the_lnet.ln_nis, ni_list) | |
858 | count++; | |
859 | ||
860 | lnet_net_unlock(0); | |
861 | ||
862 | return count; | |
863 | } | |
864 | ||
865 | static inline void | |
866 | lnet_ping_info_free(lnet_ping_info_t *pinfo) | |
867 | { | |
868 | LIBCFS_FREE(pinfo, | |
869 | offsetof(lnet_ping_info_t, | |
870 | pi_ni[pinfo->pi_nnis])); | |
871 | } | |
872 | ||
873 | static void | |
874 | lnet_ping_info_destroy(void) | |
875 | { | |
876 | struct lnet_ni *ni; | |
877 | ||
878 | lnet_net_lock(LNET_LOCK_EX); | |
879 | ||
880 | list_for_each_entry(ni, &the_lnet.ln_nis, ni_list) { | |
881 | lnet_ni_lock(ni); | |
882 | ni->ni_status = NULL; | |
883 | lnet_ni_unlock(ni); | |
884 | } | |
885 | ||
886 | lnet_ping_info_free(the_lnet.ln_ping_info); | |
887 | the_lnet.ln_ping_info = NULL; | |
888 | ||
889 | lnet_net_unlock(LNET_LOCK_EX); | |
890 | } | |
891 | ||
892 | static void | |
893 | lnet_ping_event_handler(lnet_event_t *event) | |
894 | { | |
895 | lnet_ping_info_t *pinfo = event->md.user_ptr; | |
896 | ||
897 | if (event->unlinked) | |
898 | pinfo->pi_features = LNET_PING_FEAT_INVAL; | |
899 | } | |
900 | ||
901 | static int | |
902 | lnet_ping_info_setup(lnet_ping_info_t **ppinfo, lnet_handle_md_t *md_handle, | |
903 | int ni_count, bool set_eq) | |
904 | { | |
905 | lnet_process_id_t id = {LNET_NID_ANY, LNET_PID_ANY}; | |
906 | lnet_handle_me_t me_handle; | |
907 | lnet_md_t md = {0}; | |
908 | int rc, rc2; | |
909 | ||
910 | if (set_eq) { | |
911 | rc = LNetEQAlloc(0, lnet_ping_event_handler, | |
912 | &the_lnet.ln_ping_target_eq); | |
913 | if (rc) { | |
914 | CERROR("Can't allocate ping EQ: %d\n", rc); | |
915 | return rc; | |
916 | } | |
917 | } | |
918 | ||
919 | *ppinfo = lnet_ping_info_create(ni_count); | |
920 | if (!*ppinfo) { | |
921 | rc = -ENOMEM; | |
922 | goto failed_0; | |
923 | } | |
924 | ||
925 | rc = LNetMEAttach(LNET_RESERVED_PORTAL, id, | |
926 | LNET_PROTO_PING_MATCHBITS, 0, | |
927 | LNET_UNLINK, LNET_INS_AFTER, | |
928 | &me_handle); | |
929 | if (rc) { | |
930 | CERROR("Can't create ping ME: %d\n", rc); | |
931 | goto failed_1; | |
932 | } | |
933 | ||
934 | /* initialize md content */ | |
935 | md.start = *ppinfo; | |
936 | md.length = offsetof(lnet_ping_info_t, | |
937 | pi_ni[(*ppinfo)->pi_nnis]); | |
938 | md.threshold = LNET_MD_THRESH_INF; | |
939 | md.max_size = 0; | |
940 | md.options = LNET_MD_OP_GET | LNET_MD_TRUNCATE | | |
941 | LNET_MD_MANAGE_REMOTE; | |
942 | md.user_ptr = NULL; | |
943 | md.eq_handle = the_lnet.ln_ping_target_eq; | |
944 | md.user_ptr = *ppinfo; | |
945 | ||
946 | rc = LNetMDAttach(me_handle, md, LNET_RETAIN, md_handle); | |
947 | if (rc) { | |
948 | CERROR("Can't attach ping MD: %d\n", rc); | |
949 | goto failed_2; | |
950 | } | |
951 | ||
952 | return 0; | |
953 | ||
954 | failed_2: | |
955 | rc2 = LNetMEUnlink(me_handle); | |
956 | LASSERT(!rc2); | |
957 | failed_1: | |
958 | lnet_ping_info_free(*ppinfo); | |
959 | *ppinfo = NULL; | |
960 | failed_0: | |
961 | if (set_eq) | |
962 | LNetEQFree(the_lnet.ln_ping_target_eq); | |
963 | return rc; | |
964 | } | |
965 | ||
966 | static void | |
967 | lnet_ping_md_unlink(lnet_ping_info_t *pinfo, lnet_handle_md_t *md_handle) | |
968 | { | |
969 | sigset_t blocked = cfs_block_allsigs(); | |
970 | ||
971 | LNetMDUnlink(*md_handle); | |
972 | LNetInvalidateHandle(md_handle); | |
973 | ||
974 | /* NB md could be busy; this just starts the unlink */ | |
975 | while (pinfo->pi_features != LNET_PING_FEAT_INVAL) { | |
976 | CDEBUG(D_NET, "Still waiting for ping MD to unlink\n"); | |
977 | set_current_state(TASK_UNINTERRUPTIBLE); | |
978 | schedule_timeout(cfs_time_seconds(1)); | |
979 | } | |
980 | ||
981 | cfs_restore_sigs(blocked); | |
982 | } | |
983 | ||
984 | static void | |
985 | lnet_ping_info_install_locked(lnet_ping_info_t *ping_info) | |
986 | { | |
987 | lnet_ni_status_t *ns; | |
988 | lnet_ni_t *ni; | |
989 | int i = 0; | |
990 | ||
991 | list_for_each_entry(ni, &the_lnet.ln_nis, ni_list) { | |
992 | LASSERT(i < ping_info->pi_nnis); | |
993 | ||
994 | ns = &ping_info->pi_ni[i]; | |
995 | ||
996 | ns->ns_nid = ni->ni_nid; | |
997 | ||
998 | lnet_ni_lock(ni); | |
999 | ns->ns_status = (ni->ni_status) ? | |
1000 | ni->ni_status->ns_status : LNET_NI_STATUS_UP; | |
1001 | ni->ni_status = ns; | |
1002 | lnet_ni_unlock(ni); | |
1003 | ||
1004 | i++; | |
1005 | } | |
1006 | } | |
1007 | ||
1008 | static void | |
1009 | lnet_ping_target_update(lnet_ping_info_t *pinfo, lnet_handle_md_t md_handle) | |
1010 | { | |
1011 | lnet_ping_info_t *old_pinfo = NULL; | |
1012 | lnet_handle_md_t old_md; | |
1013 | ||
1014 | /* switch the NIs to point to the new ping info created */ | |
1015 | lnet_net_lock(LNET_LOCK_EX); | |
1016 | ||
1017 | if (!the_lnet.ln_routing) | |
1018 | pinfo->pi_features |= LNET_PING_FEAT_RTE_DISABLED; | |
1019 | lnet_ping_info_install_locked(pinfo); | |
1020 | ||
1021 | if (the_lnet.ln_ping_info) { | |
1022 | old_pinfo = the_lnet.ln_ping_info; | |
1023 | old_md = the_lnet.ln_ping_target_md; | |
1024 | } | |
1025 | the_lnet.ln_ping_target_md = md_handle; | |
1026 | the_lnet.ln_ping_info = pinfo; | |
1027 | ||
1028 | lnet_net_unlock(LNET_LOCK_EX); | |
1029 | ||
1030 | if (old_pinfo) { | |
1031 | /* unlink the old ping info */ | |
1032 | lnet_ping_md_unlink(old_pinfo, &old_md); | |
1033 | lnet_ping_info_free(old_pinfo); | |
1034 | } | |
1035 | } | |
1036 | ||
1037 | static void | |
1038 | lnet_ping_target_fini(void) | |
1039 | { | |
1040 | int rc; | |
1041 | ||
1042 | lnet_ping_md_unlink(the_lnet.ln_ping_info, | |
1043 | &the_lnet.ln_ping_target_md); | |
1044 | ||
1045 | rc = LNetEQFree(the_lnet.ln_ping_target_eq); | |
1046 | LASSERT(!rc); | |
1047 | ||
1048 | lnet_ping_info_destroy(); | |
1049 | } | |
1050 | ||
d7e09d03 PT |
1051 | static int |
1052 | lnet_ni_tq_credits(lnet_ni_t *ni) | |
1053 | { | |
7e7ab095 | 1054 | int credits; |
d7e09d03 PT |
1055 | |
1056 | LASSERT(ni->ni_ncpts >= 1); | |
1057 | ||
1058 | if (ni->ni_ncpts == 1) | |
1059 | return ni->ni_maxtxcredits; | |
1060 | ||
1061 | credits = ni->ni_maxtxcredits / ni->ni_ncpts; | |
1062 | credits = max(credits, 8 * ni->ni_peertxcredits); | |
1063 | credits = min(credits, ni->ni_maxtxcredits); | |
1064 | ||
1065 | return credits; | |
1066 | } | |
1067 | ||
9c26b89d AS |
1068 | static void |
1069 | lnet_ni_unlink_locked(lnet_ni_t *ni) | |
1070 | { | |
1071 | if (!list_empty(&ni->ni_cptlist)) { | |
1072 | list_del_init(&ni->ni_cptlist); | |
1073 | lnet_ni_decref_locked(ni, 0); | |
1074 | } | |
1075 | ||
1076 | /* move it to zombie list and nobody can find it anymore */ | |
1077 | LASSERT(!list_empty(&ni->ni_list)); | |
1078 | list_move(&ni->ni_list, &the_lnet.ln_nis_zombie); | |
1079 | lnet_ni_decref_locked(ni, 0); /* drop ln_nis' ref */ | |
1080 | } | |
1081 | ||
51bd8814 | 1082 | static void |
6c9e5a55 | 1083 | lnet_clear_zombies_nis_locked(void) |
d7e09d03 | 1084 | { |
7e7ab095 MS |
1085 | int i; |
1086 | int islo; | |
1087 | lnet_ni_t *ni; | |
d7e09d03 | 1088 | |
6c9e5a55 AS |
1089 | /* |
1090 | * Now wait for the NI's I just nuked to show up on ln_zombie_nis | |
1091 | * and shut them down in guaranteed thread context | |
1092 | */ | |
1093 | i = 2; | |
1094 | while (!list_empty(&the_lnet.ln_nis_zombie)) { | |
1095 | int *ref; | |
1096 | int j; | |
1097 | ||
1098 | ni = list_entry(the_lnet.ln_nis_zombie.next, | |
1099 | lnet_ni_t, ni_list); | |
1100 | list_del_init(&ni->ni_list); | |
1101 | cfs_percpt_for_each(ref, j, ni->ni_refs) { | |
1102 | if (!*ref) | |
1103 | continue; | |
1104 | /* still busy, add it back to zombie list */ | |
1105 | list_add(&ni->ni_list, &the_lnet.ln_nis_zombie); | |
1106 | break; | |
1107 | } | |
1108 | ||
1109 | if (!list_empty(&ni->ni_list)) { | |
1110 | lnet_net_unlock(LNET_LOCK_EX); | |
1111 | ++i; | |
1112 | if ((i & (-i)) == i) { | |
1113 | CDEBUG(D_WARNING, "Waiting for zombie LNI %s\n", | |
1114 | libcfs_nid2str(ni->ni_nid)); | |
1115 | } | |
1116 | set_current_state(TASK_UNINTERRUPTIBLE); | |
1117 | schedule_timeout(cfs_time_seconds(1)); | |
1118 | lnet_net_lock(LNET_LOCK_EX); | |
1119 | continue; | |
1120 | } | |
1121 | ||
1122 | ni->ni_lnd->lnd_refcount--; | |
1123 | lnet_net_unlock(LNET_LOCK_EX); | |
1124 | ||
1125 | islo = ni->ni_lnd->lnd_type == LOLND; | |
1126 | ||
1127 | LASSERT(!in_interrupt()); | |
1128 | ni->ni_lnd->lnd_shutdown(ni); | |
1129 | ||
1130 | /* | |
1131 | * can't deref lnd anymore now; it might have unregistered | |
1132 | * itself... | |
1133 | */ | |
1134 | if (!islo) | |
1135 | CDEBUG(D_LNI, "Removed LNI %s\n", | |
1136 | libcfs_nid2str(ni->ni_nid)); | |
1137 | ||
1138 | lnet_ni_free(ni); | |
1139 | i = 2; | |
1140 | ||
1141 | lnet_net_lock(LNET_LOCK_EX); | |
1142 | } | |
1143 | } | |
1144 | ||
1145 | static void | |
1146 | lnet_shutdown_lndnis(void) | |
1147 | { | |
1148 | lnet_ni_t *ni; | |
1149 | int i; | |
1150 | ||
d7e09d03 PT |
1151 | /* NB called holding the global mutex */ |
1152 | ||
1153 | /* All quiet on the API front */ | |
1154 | LASSERT(!the_lnet.ln_shutdown); | |
5fd88337 | 1155 | LASSERT(!the_lnet.ln_refcount); |
d7e09d03 PT |
1156 | LASSERT(list_empty(&the_lnet.ln_nis_zombie)); |
1157 | ||
1158 | lnet_net_lock(LNET_LOCK_EX); | |
1159 | the_lnet.ln_shutdown = 1; /* flag shutdown */ | |
1160 | ||
1161 | /* Unlink NIs from the global table */ | |
1162 | while (!list_empty(&the_lnet.ln_nis)) { | |
1163 | ni = list_entry(the_lnet.ln_nis.next, | |
c314c319 | 1164 | lnet_ni_t, ni_list); |
9c26b89d | 1165 | lnet_ni_unlink_locked(ni); |
d7e09d03 PT |
1166 | } |
1167 | ||
1168 | /* Drop the cached eqwait NI. */ | |
06ace26e | 1169 | if (the_lnet.ln_eq_waitni) { |
d7e09d03 PT |
1170 | lnet_ni_decref_locked(the_lnet.ln_eq_waitni, 0); |
1171 | the_lnet.ln_eq_waitni = NULL; | |
1172 | } | |
1173 | ||
1174 | /* Drop the cached loopback NI. */ | |
06ace26e | 1175 | if (the_lnet.ln_loni) { |
d7e09d03 PT |
1176 | lnet_ni_decref_locked(the_lnet.ln_loni, 0); |
1177 | the_lnet.ln_loni = NULL; | |
1178 | } | |
1179 | ||
1180 | lnet_net_unlock(LNET_LOCK_EX); | |
1181 | ||
4420cfd3 JS |
1182 | /* |
1183 | * Clear lazy portals and drop delayed messages which hold refs | |
1184 | * on their lnet_msg_t::msg_rxpeer | |
1185 | */ | |
d7e09d03 PT |
1186 | for (i = 0; i < the_lnet.ln_nportals; i++) |
1187 | LNetClearLazyPortal(i); | |
1188 | ||
4420cfd3 JS |
1189 | /* |
1190 | * Clear the peer table and wait for all peers to go (they hold refs on | |
1191 | * their NIs) | |
1192 | */ | |
21602c7d | 1193 | lnet_peer_tables_cleanup(NULL); |
d7e09d03 PT |
1194 | |
1195 | lnet_net_lock(LNET_LOCK_EX); | |
d7e09d03 | 1196 | |
6c9e5a55 AS |
1197 | lnet_clear_zombies_nis_locked(); |
1198 | the_lnet.ln_shutdown = 0; | |
1199 | lnet_net_unlock(LNET_LOCK_EX); | |
1200 | } | |
d7e09d03 | 1201 | |
9c26b89d AS |
1202 | /* shutdown down the NI and release refcount */ |
1203 | static void | |
1204 | lnet_shutdown_lndni(struct lnet_ni *ni) | |
6c9e5a55 | 1205 | { |
6c9e5a55 | 1206 | lnet_net_lock(LNET_LOCK_EX); |
9c26b89d | 1207 | lnet_ni_unlink_locked(ni); |
d7e09d03 | 1208 | lnet_net_unlock(LNET_LOCK_EX); |
6c9e5a55 AS |
1209 | |
1210 | /* Do peer table cleanup for this ni */ | |
9c26b89d | 1211 | lnet_peer_tables_cleanup(ni); |
6c9e5a55 AS |
1212 | |
1213 | lnet_net_lock(LNET_LOCK_EX); | |
1214 | lnet_clear_zombies_nis_locked(); | |
1215 | lnet_net_unlock(LNET_LOCK_EX); | |
d7e09d03 PT |
1216 | } |
1217 | ||
51bd8814 | 1218 | static int |
9c26b89d AS |
1219 | lnet_startup_lndni(struct lnet_ni *ni, __s32 peer_timeout, |
1220 | __s32 peer_cr, __s32 peer_buf_cr, __s32 credits) | |
d7e09d03 | 1221 | { |
9c26b89d AS |
1222 | int rc = 0; |
1223 | int lnd_type; | |
7e7ab095 | 1224 | lnd_t *lnd; |
7e7ab095 | 1225 | struct lnet_tx_queue *tq; |
7e7ab095 | 1226 | int i; |
d7e09d03 | 1227 | |
9c26b89d | 1228 | lnd_type = LNET_NETTYP(LNET_NIDNET(ni->ni_nid)); |
d7e09d03 | 1229 | |
9c26b89d | 1230 | LASSERT(libcfs_isknown_lnd(lnd_type)); |
d7e09d03 | 1231 | |
9c26b89d AS |
1232 | if (lnd_type == CIBLND || lnd_type == OPENIBLND || |
1233 | lnd_type == IIBLND || lnd_type == VIBLND) { | |
1234 | CERROR("LND %s obsoleted\n", libcfs_lnd2str(lnd_type)); | |
1235 | goto failed0; | |
1236 | } | |
6c9e5a55 | 1237 | |
9c26b89d AS |
1238 | /* Make sure this new NI is unique. */ |
1239 | lnet_net_lock(LNET_LOCK_EX); | |
1240 | if (!lnet_net_unique(LNET_NIDNET(ni->ni_nid), &the_lnet.ln_nis)) { | |
1241 | if (lnd_type == LOLND) { | |
6c9e5a55 | 1242 | lnet_net_unlock(LNET_LOCK_EX); |
9c26b89d AS |
1243 | lnet_ni_free(ni); |
1244 | return 0; | |
6c9e5a55 AS |
1245 | } |
1246 | lnet_net_unlock(LNET_LOCK_EX); | |
1247 | ||
9c26b89d AS |
1248 | CERROR("Net %s is not unique\n", |
1249 | libcfs_net2str(LNET_NIDNET(ni->ni_nid))); | |
1250 | goto failed0; | |
1251 | } | |
1252 | lnet_net_unlock(LNET_LOCK_EX); | |
1253 | ||
1254 | mutex_lock(&the_lnet.ln_lnd_mutex); | |
1255 | lnd = lnet_find_lnd_by_type(lnd_type); | |
1256 | ||
1257 | if (!lnd) { | |
1258 | mutex_unlock(&the_lnet.ln_lnd_mutex); | |
1259 | rc = request_module("%s", libcfs_lnd2modname(lnd_type)); | |
bdd84a6f | 1260 | mutex_lock(&the_lnet.ln_lnd_mutex); |
d7e09d03 | 1261 | |
9c26b89d | 1262 | lnd = lnet_find_lnd_by_type(lnd_type); |
06ace26e | 1263 | if (!lnd) { |
bdd84a6f | 1264 | mutex_unlock(&the_lnet.ln_lnd_mutex); |
9c26b89d AS |
1265 | CERROR("Can't load LND %s, module %s, rc=%d\n", |
1266 | libcfs_lnd2str(lnd_type), | |
1267 | libcfs_lnd2modname(lnd_type), rc); | |
1268 | goto failed0; | |
d7e09d03 | 1269 | } |
9c26b89d AS |
1270 | } |
1271 | ||
1272 | lnet_net_lock(LNET_LOCK_EX); | |
1273 | lnd->lnd_refcount++; | |
1274 | lnet_net_unlock(LNET_LOCK_EX); | |
1275 | ||
1276 | ni->ni_lnd = lnd; | |
1277 | ||
1278 | rc = lnd->lnd_startup(ni); | |
1279 | ||
1280 | mutex_unlock(&the_lnet.ln_lnd_mutex); | |
d7e09d03 | 1281 | |
9c26b89d AS |
1282 | if (rc) { |
1283 | LCONSOLE_ERROR_MSG(0x105, "Error %d starting up LNI %s\n", | |
1284 | rc, libcfs_lnd2str(lnd->lnd_type)); | |
d7e09d03 | 1285 | lnet_net_lock(LNET_LOCK_EX); |
9c26b89d | 1286 | lnd->lnd_refcount--; |
d7e09d03 | 1287 | lnet_net_unlock(LNET_LOCK_EX); |
9c26b89d AS |
1288 | goto failed0; |
1289 | } | |
d7e09d03 | 1290 | |
9c26b89d AS |
1291 | /* |
1292 | * If given some LND tunable parameters, parse those now to | |
1293 | * override the values in the NI structure. | |
1294 | */ | |
1295 | if (peer_buf_cr >= 0) | |
1296 | ni->ni_peerrtrcredits = peer_buf_cr; | |
1297 | if (peer_timeout >= 0) | |
1298 | ni->ni_peertimeout = peer_timeout; | |
1299 | /* | |
1300 | * TODO | |
1301 | * Note: For now, don't allow the user to change | |
1302 | * peertxcredits as this number is used in the | |
1303 | * IB LND to control queue depth. | |
1304 | * if (peer_cr != -1) | |
1305 | * ni->ni_peertxcredits = peer_cr; | |
1306 | */ | |
1307 | if (credits >= 0) | |
1308 | ni->ni_maxtxcredits = credits; | |
d7e09d03 | 1309 | |
9c26b89d | 1310 | LASSERT(ni->ni_peertimeout <= 0 || lnd->lnd_query); |
d7e09d03 | 1311 | |
9c26b89d AS |
1312 | lnet_net_lock(LNET_LOCK_EX); |
1313 | /* refcount for ln_nis */ | |
1314 | lnet_ni_addref_locked(ni, 0); | |
1315 | list_add_tail(&ni->ni_list, &the_lnet.ln_nis); | |
1316 | if (ni->ni_cpts) { | |
1317 | lnet_ni_addref_locked(ni, 0); | |
1318 | list_add_tail(&ni->ni_cptlist, &the_lnet.ln_nis_cpt); | |
1319 | } | |
d7e09d03 | 1320 | |
9c26b89d | 1321 | lnet_net_unlock(LNET_LOCK_EX); |
d7e09d03 | 1322 | |
9c26b89d AS |
1323 | if (lnd->lnd_type == LOLND) { |
1324 | lnet_ni_addref(ni); | |
1325 | LASSERT(!the_lnet.ln_loni); | |
1326 | the_lnet.ln_loni = ni; | |
1327 | return 0; | |
1328 | } | |
1329 | ||
1330 | if (!ni->ni_peertxcredits || !ni->ni_maxtxcredits) { | |
1331 | LCONSOLE_ERROR_MSG(0x107, "LNI %s has no %scredits\n", | |
1332 | libcfs_lnd2str(lnd->lnd_type), | |
1333 | !ni->ni_peertxcredits ? | |
1334 | "" : "per-peer "); | |
6c9e5a55 | 1335 | /* |
9c26b89d AS |
1336 | * shutdown the NI since if we get here then it must've already |
1337 | * been started | |
6c9e5a55 | 1338 | */ |
9c26b89d AS |
1339 | lnet_shutdown_lndni(ni); |
1340 | return -EINVAL; | |
1341 | } | |
d7e09d03 | 1342 | |
9c26b89d AS |
1343 | cfs_percpt_for_each(tq, i, ni->ni_tx_queues) { |
1344 | tq->tq_credits_min = | |
1345 | tq->tq_credits_max = | |
1346 | tq->tq_credits = lnet_ni_tq_credits(ni); | |
1347 | } | |
d7e09d03 | 1348 | |
9c26b89d AS |
1349 | CDEBUG(D_LNI, "Added LNI %s [%d/%d/%d/%d]\n", |
1350 | libcfs_nid2str(ni->ni_nid), ni->ni_peertxcredits, | |
1351 | lnet_ni_tq_credits(ni) * LNET_CPT_NUMBER, | |
1352 | ni->ni_peerrtrcredits, ni->ni_peertimeout); | |
d7e09d03 | 1353 | |
9c26b89d AS |
1354 | return 0; |
1355 | failed0: | |
1356 | lnet_ni_free(ni); | |
1357 | return -EINVAL; | |
1358 | } | |
d7e09d03 | 1359 | |
9c26b89d AS |
1360 | static int |
1361 | lnet_startup_lndnis(struct list_head *nilist) | |
1362 | { | |
1363 | struct lnet_ni *ni; | |
1364 | int rc; | |
1365 | int lnd_type; | |
1366 | int ni_count = 0; | |
6c9e5a55 | 1367 | |
9c26b89d AS |
1368 | while (!list_empty(nilist)) { |
1369 | ni = list_entry(nilist->next, lnet_ni_t, ni_list); | |
1370 | list_del(&ni->ni_list); | |
1371 | rc = lnet_startup_lndni(ni, -1, -1, -1, -1); | |
d7e09d03 | 1372 | |
9c26b89d | 1373 | if (rc < 0) |
d7e09d03 | 1374 | goto failed; |
d7e09d03 | 1375 | |
9c26b89d AS |
1376 | ni_count++; |
1377 | } | |
d7e09d03 | 1378 | |
9c26b89d AS |
1379 | if (the_lnet.ln_eq_waitni && ni_count > 1) { |
1380 | lnd_type = the_lnet.ln_eq_waitni->ni_lnd->lnd_type; | |
1381 | LCONSOLE_ERROR_MSG(0x109, "LND %s can only run single-network\n", | |
1382 | libcfs_lnd2str(lnd_type)); | |
1383 | rc = -EINVAL; | |
1384 | goto failed; | |
d7e09d03 PT |
1385 | } |
1386 | ||
9c26b89d | 1387 | return ni_count; |
6c9e5a55 | 1388 | failed: |
9c26b89d AS |
1389 | lnet_shutdown_lndnis(); |
1390 | ||
1391 | return rc; | |
d7e09d03 PT |
1392 | } |
1393 | ||
1394 | /** | |
1395 | * Initialize LNet library. | |
1396 | * | |
1397 | * Only userspace program needs to call this function - it's automatically | |
a9cf72b6 JS |
1398 | * called in the kernel at module loading time. Caller has to call lnet_fini() |
1399 | * after a call to lnet_init(), if and only if the latter returned 0. It must | |
d7e09d03 PT |
1400 | * be called exactly once. |
1401 | * | |
1402 | * \return 0 on success, and -ve on failures. | |
1403 | */ | |
1404 | int | |
a9cf72b6 | 1405 | lnet_init(void) |
d7e09d03 | 1406 | { |
7e7ab095 | 1407 | int rc; |
d7e09d03 PT |
1408 | |
1409 | lnet_assert_wire_constants(); | |
1410 | LASSERT(!the_lnet.ln_init); | |
1411 | ||
1412 | memset(&the_lnet, 0, sizeof(the_lnet)); | |
1413 | ||
1414 | /* refer to global cfs_cpt_table for now */ | |
1415 | the_lnet.ln_cpt_table = cfs_cpt_table; | |
1416 | the_lnet.ln_cpt_number = cfs_cpt_number(cfs_cpt_table); | |
1417 | ||
1418 | LASSERT(the_lnet.ln_cpt_number > 0); | |
1419 | if (the_lnet.ln_cpt_number > LNET_CPT_MAX) { | |
1420 | /* we are under risk of consuming all lh_cookie */ | |
8ad5360a | 1421 | CERROR("Can't have %d CPTs for LNet (max allowed is %d), please change setting of CPT-table and retry\n", |
d7e09d03 PT |
1422 | the_lnet.ln_cpt_number, LNET_CPT_MAX); |
1423 | return -1; | |
1424 | } | |
1425 | ||
1426 | while ((1 << the_lnet.ln_cpt_bits) < the_lnet.ln_cpt_number) | |
1427 | the_lnet.ln_cpt_bits++; | |
1428 | ||
1429 | rc = lnet_create_locks(); | |
5fd88337 | 1430 | if (rc) { |
d7e09d03 PT |
1431 | CERROR("Can't create LNet global locks: %d\n", rc); |
1432 | return -1; | |
1433 | } | |
1434 | ||
1435 | the_lnet.ln_refcount = 0; | |
1436 | the_lnet.ln_init = 1; | |
1437 | LNetInvalidateHandle(&the_lnet.ln_rc_eqh); | |
1438 | INIT_LIST_HEAD(&the_lnet.ln_lnds); | |
1439 | INIT_LIST_HEAD(&the_lnet.ln_rcd_zombie); | |
1440 | INIT_LIST_HEAD(&the_lnet.ln_rcd_deathrow); | |
1441 | ||
4420cfd3 JS |
1442 | /* |
1443 | * The hash table size is the number of bits it takes to express the set | |
d7e09d03 | 1444 | * ln_num_routes, minus 1 (better to under estimate than over so we |
4420cfd3 JS |
1445 | * don't waste memory). |
1446 | */ | |
d7e09d03 PT |
1447 | if (rnet_htable_size <= 0) |
1448 | rnet_htable_size = LNET_REMOTE_NETS_HASH_DEFAULT; | |
1449 | else if (rnet_htable_size > LNET_REMOTE_NETS_HASH_MAX) | |
1450 | rnet_htable_size = LNET_REMOTE_NETS_HASH_MAX; | |
1451 | the_lnet.ln_remote_nets_hbits = max_t(int, 1, | |
1452 | order_base_2(rnet_htable_size) - 1); | |
1453 | ||
4420cfd3 JS |
1454 | /* |
1455 | * All LNDs apart from the LOLND are in separate modules. They | |
d7e09d03 | 1456 | * register themselves when their module loads, and unregister |
4420cfd3 JS |
1457 | * themselves when their module is unloaded. |
1458 | */ | |
d7e09d03 PT |
1459 | lnet_register_lnd(&the_lolnd); |
1460 | return 0; | |
1461 | } | |
d7e09d03 PT |
1462 | |
1463 | /** | |
1464 | * Finalize LNet library. | |
1465 | * | |
1466 | * Only userspace program needs to call this function. It can be called | |
1467 | * at most once. | |
1468 | * | |
a9cf72b6 | 1469 | * \pre lnet_init() called with success. |
d7e09d03 PT |
1470 | * \pre All LNet users called LNetNIFini() for matching LNetNIInit() calls. |
1471 | */ | |
1472 | void | |
a9cf72b6 | 1473 | lnet_fini(void) |
d7e09d03 PT |
1474 | { |
1475 | LASSERT(the_lnet.ln_init); | |
5fd88337 | 1476 | LASSERT(!the_lnet.ln_refcount); |
d7e09d03 PT |
1477 | |
1478 | while (!list_empty(&the_lnet.ln_lnds)) | |
1479 | lnet_unregister_lnd(list_entry(the_lnet.ln_lnds.next, | |
c314c319 | 1480 | lnd_t, lnd_list)); |
d7e09d03 PT |
1481 | lnet_destroy_locks(); |
1482 | ||
1483 | the_lnet.ln_init = 0; | |
1484 | } | |
d7e09d03 PT |
1485 | |
1486 | /** | |
1487 | * Set LNet PID and start LNet interfaces, routing, and forwarding. | |
1488 | * | |
a9cf72b6 | 1489 | * Userspace program should call this after a successful call to lnet_init(). |
d7e09d03 PT |
1490 | * Users must call this function at least once before any other functions. |
1491 | * For each successful call there must be a corresponding call to | |
1492 | * LNetNIFini(). For subsequent calls to LNetNIInit(), \a requested_pid is | |
1493 | * ignored. | |
1494 | * | |
1495 | * The PID used by LNet may be different from the one requested. | |
1496 | * See LNetGetId(). | |
1497 | * | |
1498 | * \param requested_pid PID requested by the caller. | |
1499 | * | |
1500 | * \return >= 0 on success, and < 0 error code on failures. | |
1501 | */ | |
1502 | int | |
1503 | LNetNIInit(lnet_pid_t requested_pid) | |
1504 | { | |
7e7ab095 | 1505 | int im_a_router = 0; |
9c26b89d AS |
1506 | int rc, rc2; |
1507 | int ni_count; | |
6c9e5a55 AS |
1508 | lnet_ping_info_t *pinfo; |
1509 | lnet_handle_md_t md_handle; | |
1510 | struct list_head net_head; | |
6c9e5a55 AS |
1511 | |
1512 | INIT_LIST_HEAD(&net_head); | |
d7e09d03 | 1513 | |
bdd84a6f | 1514 | mutex_lock(&the_lnet.ln_api_mutex); |
d7e09d03 | 1515 | |
3b7566d9 | 1516 | LASSERT(the_lnet.ln_init); |
d7e09d03 PT |
1517 | CDEBUG(D_OTHER, "refs %d\n", the_lnet.ln_refcount); |
1518 | ||
1519 | if (the_lnet.ln_refcount > 0) { | |
1520 | rc = the_lnet.ln_refcount++; | |
6c9e5a55 AS |
1521 | mutex_unlock(&the_lnet.ln_api_mutex); |
1522 | return rc; | |
d7e09d03 PT |
1523 | } |
1524 | ||
d7e09d03 | 1525 | rc = lnet_prepare(requested_pid); |
9c26b89d AS |
1526 | if (rc) { |
1527 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1528 | return rc; | |
1529 | } | |
d7e09d03 | 1530 | |
9c26b89d AS |
1531 | /* Add in the loopback network */ |
1532 | if (!lnet_ni_alloc(LNET_MKNET(LOLND, 0), NULL, &net_head)) { | |
1533 | rc = -ENOMEM; | |
1534 | goto err_empty_list; | |
1535 | } | |
6c9e5a55 | 1536 | |
9c26b89d AS |
1537 | /* |
1538 | * If LNet is being initialized via DLC it is possible | |
1539 | * that the user requests not to load module parameters (ones which | |
1540 | * are supported by DLC) on initialization. Therefore, make sure not | |
1541 | * to load networks, routes and forwarding from module parameters | |
1542 | * in this case. On cleanup in case of failure only clean up | |
1543 | * routes if it has been loaded | |
1544 | */ | |
1545 | if (!the_lnet.ln_nis_from_mod_params) { | |
1546 | rc = lnet_parse_networks(&net_head, lnet_get_networks()); | |
1547 | if (rc < 0) | |
1548 | goto err_empty_list; | |
1549 | } | |
d7e09d03 | 1550 | |
9c26b89d AS |
1551 | ni_count = lnet_startup_lndnis(&net_head); |
1552 | if (ni_count < 0) { | |
1553 | rc = ni_count; | |
1554 | goto err_empty_list; | |
6c9e5a55 AS |
1555 | } |
1556 | ||
9c26b89d AS |
1557 | if (!the_lnet.ln_nis_from_mod_params) { |
1558 | rc = lnet_parse_routes(lnet_get_routes(), &im_a_router); | |
1559 | if (rc) | |
1560 | goto err_shutdown_lndnis; | |
d7e09d03 | 1561 | |
9c26b89d AS |
1562 | rc = lnet_check_routes(); |
1563 | if (rc) | |
1564 | goto err_destory_routes; | |
d7e09d03 | 1565 | |
9c26b89d AS |
1566 | rc = lnet_rtrpools_alloc(im_a_router); |
1567 | if (rc) | |
1568 | goto err_destory_routes; | |
1569 | } | |
d7e09d03 PT |
1570 | |
1571 | rc = lnet_acceptor_start(); | |
5fd88337 | 1572 | if (rc) |
9c26b89d | 1573 | goto err_destory_routes; |
d7e09d03 PT |
1574 | |
1575 | the_lnet.ln_refcount = 1; | |
1576 | /* Now I may use my own API functions... */ | |
1577 | ||
6c9e5a55 | 1578 | rc = lnet_ping_info_setup(&pinfo, &md_handle, ni_count, true); |
5fd88337 | 1579 | if (rc) |
9c26b89d | 1580 | goto err_acceptor_stop; |
d7e09d03 | 1581 | |
6c9e5a55 AS |
1582 | lnet_ping_target_update(pinfo, md_handle); |
1583 | ||
d7e09d03 | 1584 | rc = lnet_router_checker_start(); |
5fd88337 | 1585 | if (rc) |
9c26b89d | 1586 | goto err_stop_ping; |
d7e09d03 | 1587 | |
b03f395a | 1588 | lnet_router_debugfs_init(); |
6c9e5a55 AS |
1589 | |
1590 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1591 | ||
1592 | return 0; | |
d7e09d03 | 1593 | |
9c26b89d | 1594 | err_stop_ping: |
6c9e5a55 AS |
1595 | lnet_ping_md_unlink(pinfo, &md_handle); |
1596 | lnet_ping_info_free(pinfo); | |
9c26b89d AS |
1597 | rc2 = LNetEQFree(the_lnet.ln_ping_target_eq); |
1598 | LASSERT(!rc2); | |
1599 | err_acceptor_stop: | |
1600 | the_lnet.ln_refcount = 0; | |
d7e09d03 | 1601 | lnet_acceptor_stop(); |
9c26b89d AS |
1602 | err_destory_routes: |
1603 | if (!the_lnet.ln_nis_from_mod_params) | |
1604 | lnet_destroy_routes(); | |
1605 | err_shutdown_lndnis: | |
d7e09d03 | 1606 | lnet_shutdown_lndnis(); |
9c26b89d | 1607 | err_empty_list: |
d7e09d03 | 1608 | lnet_unprepare(); |
3b7566d9 | 1609 | LASSERT(rc < 0); |
bdd84a6f | 1610 | mutex_unlock(&the_lnet.ln_api_mutex); |
6c9e5a55 | 1611 | while (!list_empty(&net_head)) { |
9c26b89d AS |
1612 | struct lnet_ni *ni; |
1613 | ||
6c9e5a55 AS |
1614 | ni = list_entry(net_head.next, struct lnet_ni, ni_list); |
1615 | list_del_init(&ni->ni_list); | |
1616 | lnet_ni_free(ni); | |
1617 | } | |
d7e09d03 PT |
1618 | return rc; |
1619 | } | |
1620 | EXPORT_SYMBOL(LNetNIInit); | |
1621 | ||
1622 | /** | |
1623 | * Stop LNet interfaces, routing, and forwarding. | |
1624 | * | |
1625 | * Users must call this function once for each successful call to LNetNIInit(). | |
1626 | * Once the LNetNIFini() operation has been started, the results of pending | |
1627 | * API operations are undefined. | |
1628 | * | |
1629 | * \return always 0 for current implementation. | |
1630 | */ | |
1631 | int | |
7d46a21a | 1632 | LNetNIFini(void) |
d7e09d03 | 1633 | { |
bdd84a6f | 1634 | mutex_lock(&the_lnet.ln_api_mutex); |
d7e09d03 | 1635 | |
3b7566d9 TP |
1636 | LASSERT(the_lnet.ln_init); |
1637 | LASSERT(the_lnet.ln_refcount > 0); | |
d7e09d03 PT |
1638 | |
1639 | if (the_lnet.ln_refcount != 1) { | |
1640 | the_lnet.ln_refcount--; | |
1641 | } else { | |
3b7566d9 | 1642 | LASSERT(!the_lnet.ln_niinit_self); |
d7e09d03 | 1643 | |
b03f395a | 1644 | lnet_router_debugfs_fini(); |
d7e09d03 PT |
1645 | lnet_router_checker_stop(); |
1646 | lnet_ping_target_fini(); | |
1647 | ||
1648 | /* Teardown fns that use my own API functions BEFORE here */ | |
1649 | the_lnet.ln_refcount = 0; | |
1650 | ||
1651 | lnet_acceptor_stop(); | |
1652 | lnet_destroy_routes(); | |
1653 | lnet_shutdown_lndnis(); | |
1654 | lnet_unprepare(); | |
1655 | } | |
1656 | ||
bdd84a6f | 1657 | mutex_unlock(&the_lnet.ln_api_mutex); |
d7e09d03 PT |
1658 | return 0; |
1659 | } | |
1660 | EXPORT_SYMBOL(LNetNIFini); | |
1661 | ||
edeb5d8c AS |
1662 | /** |
1663 | * Grabs the ni data from the ni structure and fills the out | |
1664 | * parameters | |
1665 | * | |
1666 | * \param[in] ni network interface structure | |
1667 | * \param[out] cpt_count the number of cpts the ni is on | |
1668 | * \param[out] nid Network Interface ID | |
1669 | * \param[out] peer_timeout NI peer timeout | |
1670 | * \param[out] peer_tx_crdits NI peer transmit credits | |
1671 | * \param[out] peer_rtr_credits NI peer router credits | |
1672 | * \param[out] max_tx_credits NI max transmit credit | |
1673 | * \param[out] net_config Network configuration | |
1674 | */ | |
1675 | static void | |
1676 | lnet_fill_ni_info(struct lnet_ni *ni, __u32 *cpt_count, __u64 *nid, | |
1677 | int *peer_timeout, int *peer_tx_credits, | |
1678 | int *peer_rtr_credits, int *max_tx_credits, | |
1679 | struct lnet_ioctl_net_config *net_config) | |
1680 | { | |
1681 | int i; | |
1682 | ||
1683 | if (!ni) | |
1684 | return; | |
1685 | ||
1686 | if (!net_config) | |
1687 | return; | |
1688 | ||
1689 | BUILD_BUG_ON(ARRAY_SIZE(ni->ni_interfaces) != | |
1690 | ARRAY_SIZE(net_config->ni_interfaces)); | |
1691 | ||
1692 | for (i = 0; i < ARRAY_SIZE(ni->ni_interfaces); i++) { | |
1693 | if (!ni->ni_interfaces[i]) | |
1694 | break; | |
1695 | ||
1696 | strncpy(net_config->ni_interfaces[i], | |
1697 | ni->ni_interfaces[i], | |
1698 | sizeof(net_config->ni_interfaces[i])); | |
1699 | } | |
1700 | ||
1701 | *nid = ni->ni_nid; | |
1702 | *peer_timeout = ni->ni_peertimeout; | |
1703 | *peer_tx_credits = ni->ni_peertxcredits; | |
1704 | *peer_rtr_credits = ni->ni_peerrtrcredits; | |
1705 | *max_tx_credits = ni->ni_maxtxcredits; | |
1706 | ||
1707 | net_config->ni_status = ni->ni_status->ns_status; | |
1708 | ||
1709 | if (ni->ni_cpts) { | |
1710 | int num_cpts = min(ni->ni_ncpts, LNET_MAX_SHOW_NUM_CPT); | |
1711 | ||
1712 | for (i = 0; i < num_cpts; i++) | |
1713 | net_config->ni_cpts[i] = ni->ni_cpts[i]; | |
1714 | ||
1715 | *cpt_count = num_cpts; | |
1716 | } | |
1717 | } | |
1718 | ||
1719 | int | |
1720 | lnet_get_net_config(int idx, __u32 *cpt_count, __u64 *nid, int *peer_timeout, | |
1721 | int *peer_tx_credits, int *peer_rtr_credits, | |
1722 | int *max_tx_credits, | |
1723 | struct lnet_ioctl_net_config *net_config) | |
1724 | { | |
1725 | struct lnet_ni *ni; | |
1726 | struct list_head *tmp; | |
1727 | int cpt, i = 0; | |
1728 | int rc = -ENOENT; | |
1729 | ||
1730 | cpt = lnet_net_lock_current(); | |
1731 | ||
1732 | list_for_each(tmp, &the_lnet.ln_nis) { | |
1733 | if (i++ != idx) | |
1734 | continue; | |
1735 | ||
1736 | ni = list_entry(tmp, lnet_ni_t, ni_list); | |
1737 | lnet_ni_lock(ni); | |
1738 | lnet_fill_ni_info(ni, cpt_count, nid, peer_timeout, | |
1739 | peer_tx_credits, peer_rtr_credits, | |
1740 | max_tx_credits, net_config); | |
1741 | lnet_ni_unlock(ni); | |
1742 | rc = 0; | |
1743 | break; | |
1744 | } | |
1745 | ||
1746 | lnet_net_unlock(cpt); | |
1747 | return rc; | |
1748 | } | |
1749 | ||
6c9e5a55 AS |
1750 | int |
1751 | lnet_dyn_add_ni(lnet_pid_t requested_pid, char *nets, | |
1752 | __s32 peer_timeout, __s32 peer_cr, __s32 peer_buf_cr, | |
1753 | __s32 credits) | |
1754 | { | |
1755 | lnet_ping_info_t *pinfo; | |
1756 | lnet_handle_md_t md_handle; | |
1757 | struct lnet_ni *ni; | |
1758 | struct list_head net_head; | |
1759 | int rc; | |
1760 | ||
1761 | INIT_LIST_HEAD(&net_head); | |
1762 | ||
1763 | /* Create a ni structure for the network string */ | |
1764 | rc = lnet_parse_networks(&net_head, nets); | |
9c26b89d AS |
1765 | if (rc <= 0) |
1766 | return !rc ? -EINVAL : rc; | |
6c9e5a55 AS |
1767 | |
1768 | mutex_lock(&the_lnet.ln_api_mutex); | |
1769 | ||
1770 | if (rc > 1) { | |
1771 | rc = -EINVAL; /* only add one interface per call */ | |
1772 | goto failed0; | |
1773 | } | |
1774 | ||
1775 | rc = lnet_ping_info_setup(&pinfo, &md_handle, 1 + lnet_get_ni_count(), | |
1776 | false); | |
1777 | if (rc) | |
1778 | goto failed0; | |
1779 | ||
9c26b89d AS |
1780 | ni = list_entry(net_head.next, struct lnet_ni, ni_list); |
1781 | list_del_init(&ni->ni_list); | |
1782 | ||
1783 | rc = lnet_startup_lndni(ni, peer_timeout, peer_cr, | |
1784 | peer_buf_cr, credits); | |
6c9e5a55 AS |
1785 | if (rc) |
1786 | goto failed1; | |
1787 | ||
1788 | lnet_ping_target_update(pinfo, md_handle); | |
1789 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1790 | ||
1791 | return 0; | |
1792 | ||
1793 | failed1: | |
1794 | lnet_ping_md_unlink(pinfo, &md_handle); | |
1795 | lnet_ping_info_free(pinfo); | |
1796 | failed0: | |
1797 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1798 | while (!list_empty(&net_head)) { | |
1799 | ni = list_entry(net_head.next, struct lnet_ni, ni_list); | |
1800 | list_del_init(&ni->ni_list); | |
1801 | lnet_ni_free(ni); | |
1802 | } | |
1803 | return rc; | |
1804 | } | |
1805 | ||
1806 | int | |
1807 | lnet_dyn_del_ni(__u32 net) | |
1808 | { | |
9c26b89d AS |
1809 | lnet_ni_t *ni; |
1810 | lnet_ping_info_t *pinfo; | |
1811 | lnet_handle_md_t md_handle; | |
6c9e5a55 AS |
1812 | int rc; |
1813 | ||
9c26b89d AS |
1814 | /* don't allow userspace to shutdown the LOLND */ |
1815 | if (LNET_NETTYP(net) == LOLND) | |
1816 | return -EINVAL; | |
1817 | ||
6c9e5a55 | 1818 | mutex_lock(&the_lnet.ln_api_mutex); |
9c26b89d AS |
1819 | /* create and link a new ping info, before removing the old one */ |
1820 | rc = lnet_ping_info_setup(&pinfo, &md_handle, | |
1821 | lnet_get_ni_count() - 1, false); | |
1822 | if (rc) | |
1823 | goto out; | |
1824 | ||
1825 | ni = lnet_net2ni(net); | |
1826 | if (!ni) { | |
1827 | rc = -EINVAL; | |
1828 | goto failed; | |
1829 | } | |
1830 | ||
1831 | /* decrement the reference counter taken by lnet_net2ni() */ | |
1832 | lnet_ni_decref_locked(ni, 0); | |
1833 | ||
1834 | lnet_shutdown_lndni(ni); | |
1835 | lnet_ping_target_update(pinfo, md_handle); | |
1836 | goto out; | |
1837 | failed: | |
1838 | lnet_ping_md_unlink(pinfo, &md_handle); | |
1839 | lnet_ping_info_free(pinfo); | |
1840 | out: | |
6c9e5a55 AS |
1841 | mutex_unlock(&the_lnet.ln_api_mutex); |
1842 | ||
1843 | return rc; | |
1844 | } | |
1845 | ||
d7e09d03 | 1846 | /** |
71c36dd7 | 1847 | * LNet ioctl handler. |
d7e09d03 | 1848 | * |
d7e09d03 PT |
1849 | */ |
1850 | int | |
1851 | LNetCtl(unsigned int cmd, void *arg) | |
1852 | { | |
1853 | struct libcfs_ioctl_data *data = arg; | |
2e9a51bd | 1854 | struct lnet_ioctl_config_data *config; |
7e7ab095 MS |
1855 | lnet_process_id_t id = {0}; |
1856 | lnet_ni_t *ni; | |
1857 | int rc; | |
5e50efea | 1858 | unsigned long secs_passed; |
d7e09d03 | 1859 | |
3b7566d9 | 1860 | LASSERT(the_lnet.ln_init); |
d7e09d03 PT |
1861 | |
1862 | switch (cmd) { | |
1863 | case IOC_LIBCFS_GET_NI: | |
1864 | rc = LNetGetId(data->ioc_count, &id); | |
1865 | data->ioc_nid = id.nid; | |
1866 | return rc; | |
1867 | ||
1868 | case IOC_LIBCFS_FAIL_NID: | |
1869 | return lnet_fail_nid(data->ioc_nid, data->ioc_count); | |
1870 | ||
1871 | case IOC_LIBCFS_ADD_ROUTE: | |
edeb5d8c AS |
1872 | config = arg; |
1873 | ||
1874 | if (config->cfg_hdr.ioc_len < sizeof(*config)) | |
1875 | return -EINVAL; | |
1876 | ||
6c9e5a55 | 1877 | mutex_lock(&the_lnet.ln_api_mutex); |
edeb5d8c AS |
1878 | rc = lnet_add_route(config->cfg_net, |
1879 | config->cfg_config_u.cfg_route.rtr_hop, | |
1880 | config->cfg_nid, | |
1881 | config->cfg_config_u.cfg_route.rtr_priority); | |
6c9e5a55 AS |
1882 | mutex_unlock(&the_lnet.ln_api_mutex); |
1883 | return rc ? rc : lnet_check_routes(); | |
d7e09d03 PT |
1884 | |
1885 | case IOC_LIBCFS_DEL_ROUTE: | |
2e9a51bd AS |
1886 | config = arg; |
1887 | ||
1888 | if (config->cfg_hdr.ioc_len < sizeof(*config)) | |
1889 | return -EINVAL; | |
1890 | ||
6c9e5a55 | 1891 | mutex_lock(&the_lnet.ln_api_mutex); |
2e9a51bd | 1892 | rc = lnet_del_route(config->cfg_net, config->cfg_nid); |
6c9e5a55 AS |
1893 | mutex_unlock(&the_lnet.ln_api_mutex); |
1894 | return rc; | |
d7e09d03 PT |
1895 | |
1896 | case IOC_LIBCFS_GET_ROUTE: | |
2e9a51bd AS |
1897 | config = arg; |
1898 | ||
1899 | if (config->cfg_hdr.ioc_len < sizeof(*config)) | |
1900 | return -EINVAL; | |
1901 | ||
1902 | return lnet_get_route(config->cfg_count, | |
1903 | &config->cfg_net, | |
1904 | &config->cfg_config_u.cfg_route.rtr_hop, | |
1905 | &config->cfg_nid, | |
1906 | &config->cfg_config_u.cfg_route.rtr_flags, | |
1907 | &config->cfg_config_u.cfg_route.rtr_priority); | |
1908 | ||
edeb5d8c AS |
1909 | case IOC_LIBCFS_GET_NET: { |
1910 | struct lnet_ioctl_net_config *net_config; | |
1911 | size_t total = sizeof(*config) + sizeof(*net_config); | |
2e9a51bd | 1912 | |
edeb5d8c | 1913 | config = arg; |
2e9a51bd | 1914 | |
edeb5d8c AS |
1915 | if (config->cfg_hdr.ioc_len < total) |
1916 | return -EINVAL; | |
1917 | ||
1918 | net_config = (struct lnet_ioctl_net_config *) | |
1919 | config->cfg_bulk; | |
1920 | if (!net_config) | |
1921 | return -EINVAL; | |
1922 | ||
1923 | return lnet_get_net_config(config->cfg_count, | |
1924 | &config->cfg_ncpts, | |
1925 | &config->cfg_nid, | |
1926 | &config->cfg_config_u.cfg_net.net_peer_timeout, | |
1927 | &config->cfg_config_u.cfg_net.net_peer_tx_credits, | |
1928 | &config->cfg_config_u.cfg_net.net_peer_rtr_credits, | |
1929 | &config->cfg_config_u.cfg_net.net_max_tx_credits, | |
1930 | net_config); | |
1931 | } | |
2e9a51bd AS |
1932 | |
1933 | case IOC_LIBCFS_GET_LNET_STATS: { | |
1934 | struct lnet_ioctl_lnet_stats *lnet_stats = arg; | |
1935 | ||
1936 | if (lnet_stats->st_hdr.ioc_len < sizeof(*lnet_stats)) | |
1937 | return -EINVAL; | |
1938 | ||
1939 | lnet_counters_get(&lnet_stats->st_cntrs); | |
1940 | return 0; | |
1941 | } | |
1942 | ||
1943 | case IOC_LIBCFS_CONFIG_RTR: | |
edeb5d8c AS |
1944 | config = arg; |
1945 | ||
1946 | if (config->cfg_hdr.ioc_len < sizeof(*config)) | |
1947 | return -EINVAL; | |
1948 | ||
1949 | mutex_lock(&the_lnet.ln_api_mutex); | |
1950 | if (config->cfg_config_u.cfg_buffers.buf_enable) { | |
1951 | rc = lnet_rtrpools_enable(); | |
1952 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1953 | return rc; | |
1954 | } | |
1955 | lnet_rtrpools_disable(); | |
1956 | mutex_unlock(&the_lnet.ln_api_mutex); | |
2e9a51bd AS |
1957 | return 0; |
1958 | ||
1959 | case IOC_LIBCFS_ADD_BUF: | |
edeb5d8c | 1960 | config = arg; |
2e9a51bd | 1961 | |
edeb5d8c AS |
1962 | if (config->cfg_hdr.ioc_len < sizeof(*config)) |
1963 | return -EINVAL; | |
2e9a51bd | 1964 | |
edeb5d8c AS |
1965 | mutex_lock(&the_lnet.ln_api_mutex); |
1966 | rc = lnet_rtrpools_adjust(config->cfg_config_u.cfg_buffers.buf_tiny, | |
1967 | config->cfg_config_u.cfg_buffers.buf_small, | |
1968 | config->cfg_config_u.cfg_buffers.buf_large); | |
1969 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1970 | return rc; | |
1971 | ||
1972 | case IOC_LIBCFS_GET_BUF: { | |
1973 | struct lnet_ioctl_pool_cfg *pool_cfg; | |
1974 | size_t total = sizeof(*config) + sizeof(*pool_cfg); | |
1975 | ||
1976 | config = arg; | |
1977 | ||
1978 | if (config->cfg_hdr.ioc_len < total) | |
1979 | return -EINVAL; | |
1980 | ||
1981 | pool_cfg = (struct lnet_ioctl_pool_cfg *)config->cfg_bulk; | |
1982 | return lnet_get_rtr_pool_cfg(config->cfg_count, pool_cfg); | |
1983 | } | |
1984 | ||
1985 | case IOC_LIBCFS_GET_PEER_INFO: { | |
1986 | struct lnet_ioctl_peer *peer_info = arg; | |
1987 | ||
1988 | if (peer_info->pr_hdr.ioc_len < sizeof(*peer_info)) | |
1989 | return -EINVAL; | |
1990 | ||
1991 | return lnet_get_peer_info(peer_info->pr_count, | |
1992 | &peer_info->pr_nid, | |
1993 | peer_info->pr_lnd_u.pr_peer_credits.cr_aliveness, | |
1994 | &peer_info->pr_lnd_u.pr_peer_credits.cr_ncpt, | |
1995 | &peer_info->pr_lnd_u.pr_peer_credits.cr_refcount, | |
1996 | &peer_info->pr_lnd_u.pr_peer_credits.cr_ni_peer_tx_credits, | |
1997 | &peer_info->pr_lnd_u.pr_peer_credits.cr_peer_tx_credits, | |
1998 | &peer_info->pr_lnd_u.pr_peer_credits.cr_peer_rtr_credits, | |
1999 | &peer_info->pr_lnd_u.pr_peer_credits.cr_peer_min_rtr_credits, | |
2000 | &peer_info->pr_lnd_u.pr_peer_credits.cr_peer_tx_qnob); | |
2001 | } | |
2e9a51bd | 2002 | |
d7e09d03 | 2003 | case IOC_LIBCFS_NOTIFY_ROUTER: |
5e50efea | 2004 | secs_passed = (ktime_get_real_seconds() - data->ioc_u64[0]); |
d7e09d03 | 2005 | return lnet_notify(NULL, data->ioc_nid, data->ioc_flags, |
5e50efea | 2006 | jiffies - secs_passed * HZ); |
d7e09d03 | 2007 | |
d7e09d03 PT |
2008 | case IOC_LIBCFS_LNET_DIST: |
2009 | rc = LNetDist(data->ioc_nid, &data->ioc_nid, &data->ioc_u32[1]); | |
2010 | if (rc < 0 && rc != -EHOSTUNREACH) | |
2011 | return rc; | |
2012 | ||
2013 | data->ioc_u32[0] = rc; | |
2014 | return 0; | |
2015 | ||
2016 | case IOC_LIBCFS_TESTPROTOCOMPAT: | |
2017 | lnet_net_lock(LNET_LOCK_EX); | |
2018 | the_lnet.ln_testprotocompat = data->ioc_flags; | |
2019 | lnet_net_unlock(LNET_LOCK_EX); | |
2020 | return 0; | |
2021 | ||
2022 | case IOC_LIBCFS_PING: | |
2023 | id.nid = data->ioc_nid; | |
2024 | id.pid = data->ioc_u32[0]; | |
2025 | rc = lnet_ping(id, data->ioc_u32[1], /* timeout */ | |
4eb53dfd | 2026 | data->ioc_pbuf1, |
51078e25 | 2027 | data->ioc_plen1 / sizeof(lnet_process_id_t)); |
d7e09d03 PT |
2028 | if (rc < 0) |
2029 | return rc; | |
2030 | data->ioc_count = rc; | |
2031 | return 0; | |
2032 | ||
d7e09d03 PT |
2033 | default: |
2034 | ni = lnet_net2ni(data->ioc_net); | |
06ace26e | 2035 | if (!ni) |
d7e09d03 PT |
2036 | return -EINVAL; |
2037 | ||
06ace26e | 2038 | if (!ni->ni_lnd->lnd_ctl) |
d7e09d03 PT |
2039 | rc = -EINVAL; |
2040 | else | |
2041 | rc = ni->ni_lnd->lnd_ctl(ni, cmd, arg); | |
2042 | ||
2043 | lnet_ni_decref(ni); | |
2044 | return rc; | |
2045 | } | |
2046 | /* not reached */ | |
2047 | } | |
2048 | EXPORT_SYMBOL(LNetCtl); | |
2049 | ||
71c36dd7 OD |
2050 | void LNetDebugPeer(lnet_process_id_t id) |
2051 | { | |
2052 | lnet_debug_peer(id.nid); | |
2053 | } | |
2054 | EXPORT_SYMBOL(LNetDebugPeer); | |
2055 | ||
d7e09d03 PT |
2056 | /** |
2057 | * Retrieve the lnet_process_id_t ID of LNet interface at \a index. Note that | |
2058 | * all interfaces share a same PID, as requested by LNetNIInit(). | |
2059 | * | |
2060 | * \param index Index of the interface to look up. | |
2061 | * \param id On successful return, this location will hold the | |
2062 | * lnet_process_id_t ID of the interface. | |
2063 | * | |
2064 | * \retval 0 If an interface exists at \a index. | |
2065 | * \retval -ENOENT If no interface has been found. | |
2066 | */ | |
2067 | int | |
2068 | LNetGetId(unsigned int index, lnet_process_id_t *id) | |
2069 | { | |
7e7ab095 MS |
2070 | struct lnet_ni *ni; |
2071 | struct list_head *tmp; | |
2072 | int cpt; | |
2073 | int rc = -ENOENT; | |
d7e09d03 PT |
2074 | |
2075 | LASSERT(the_lnet.ln_init); | |
4b1e84ed PT |
2076 | |
2077 | /* LNetNI initilization failed? */ | |
5fd88337 | 2078 | if (!the_lnet.ln_refcount) |
4b1e84ed | 2079 | return rc; |
d7e09d03 PT |
2080 | |
2081 | cpt = lnet_net_lock_current(); | |
2082 | ||
2083 | list_for_each(tmp, &the_lnet.ln_nis) { | |
5fd88337 | 2084 | if (index--) |
d7e09d03 PT |
2085 | continue; |
2086 | ||
2087 | ni = list_entry(tmp, lnet_ni_t, ni_list); | |
2088 | ||
2089 | id->nid = ni->ni_nid; | |
2090 | id->pid = the_lnet.ln_pid; | |
2091 | rc = 0; | |
2092 | break; | |
2093 | } | |
2094 | ||
2095 | lnet_net_unlock(cpt); | |
2096 | return rc; | |
2097 | } | |
2098 | EXPORT_SYMBOL(LNetGetId); | |
2099 | ||
2100 | /** | |
2101 | * Print a string representation of handle \a h into buffer \a str of | |
2102 | * \a len bytes. | |
2103 | */ | |
2104 | void | |
2105 | LNetSnprintHandle(char *str, int len, lnet_handle_any_t h) | |
2106 | { | |
55f5a824 | 2107 | snprintf(str, len, "%#llx", h.cookie); |
d7e09d03 PT |
2108 | } |
2109 | EXPORT_SYMBOL(LNetSnprintHandle); | |
2110 | ||
fccfde7d | 2111 | static int lnet_ping(lnet_process_id_t id, int timeout_ms, |
4eb53dfd | 2112 | lnet_process_id_t __user *ids, int n_ids) |
d7e09d03 | 2113 | { |
7e7ab095 MS |
2114 | lnet_handle_eq_t eqh; |
2115 | lnet_handle_md_t mdh; | |
2116 | lnet_event_t event; | |
2117 | lnet_md_t md = { NULL }; | |
2118 | int which; | |
2119 | int unlinked = 0; | |
2120 | int replied = 0; | |
2121 | const int a_long_time = 60000; /* mS */ | |
6c9e5a55 | 2122 | int infosz; |
7e7ab095 MS |
2123 | lnet_ping_info_t *info; |
2124 | lnet_process_id_t tmpid; | |
2125 | int i; | |
2126 | int nob; | |
2127 | int rc; | |
2128 | int rc2; | |
2129 | sigset_t blocked; | |
d7e09d03 | 2130 | |
6c9e5a55 AS |
2131 | infosz = offsetof(lnet_ping_info_t, pi_ni[n_ids]); |
2132 | ||
d7e09d03 PT |
2133 | if (n_ids <= 0 || |
2134 | id.nid == LNET_NID_ANY || | |
2135 | timeout_ms > 500000 || /* arbitrary limit! */ | |
2136 | n_ids > 20) /* arbitrary limit! */ | |
2137 | return -EINVAL; | |
2138 | ||
2139 | if (id.pid == LNET_PID_ANY) | |
fe7cb65d | 2140 | id.pid = LNET_PID_LUSTRE; |
d7e09d03 PT |
2141 | |
2142 | LIBCFS_ALLOC(info, infosz); | |
06ace26e | 2143 | if (!info) |
d7e09d03 PT |
2144 | return -ENOMEM; |
2145 | ||
2146 | /* NB 2 events max (including any unlink event) */ | |
2147 | rc = LNetEQAlloc(2, LNET_EQ_HANDLER_NONE, &eqh); | |
5fd88337 | 2148 | if (rc) { |
d7e09d03 PT |
2149 | CERROR("Can't allocate EQ: %d\n", rc); |
2150 | goto out_0; | |
2151 | } | |
2152 | ||
2153 | /* initialize md content */ | |
2154 | md.start = info; | |
2155 | md.length = infosz; | |
2156 | md.threshold = 2; /*GET/REPLY*/ | |
2157 | md.max_size = 0; | |
2158 | md.options = LNET_MD_TRUNCATE; | |
2159 | md.user_ptr = NULL; | |
2160 | md.eq_handle = eqh; | |
2161 | ||
2162 | rc = LNetMDBind(md, LNET_UNLINK, &mdh); | |
5fd88337 | 2163 | if (rc) { |
d7e09d03 PT |
2164 | CERROR("Can't bind MD: %d\n", rc); |
2165 | goto out_1; | |
2166 | } | |
2167 | ||
2168 | rc = LNetGet(LNET_NID_ANY, mdh, id, | |
2169 | LNET_RESERVED_PORTAL, | |
2170 | LNET_PROTO_PING_MATCHBITS, 0); | |
2171 | ||
5fd88337 | 2172 | if (rc) { |
d7e09d03 PT |
2173 | /* Don't CERROR; this could be deliberate! */ |
2174 | ||
2175 | rc2 = LNetMDUnlink(mdh); | |
5fd88337 | 2176 | LASSERT(!rc2); |
d7e09d03 PT |
2177 | |
2178 | /* NB must wait for the UNLINK event below... */ | |
2179 | unlinked = 1; | |
2180 | timeout_ms = a_long_time; | |
2181 | } | |
2182 | ||
2183 | do { | |
2184 | /* MUST block for unlink to complete */ | |
2185 | if (unlinked) | |
2186 | blocked = cfs_block_allsigs(); | |
2187 | ||
2188 | rc2 = LNetEQPoll(&eqh, 1, timeout_ms, &event, &which); | |
2189 | ||
2190 | if (unlinked) | |
2191 | cfs_restore_sigs(blocked); | |
2192 | ||
2193 | CDEBUG(D_NET, "poll %d(%d %d)%s\n", rc2, | |
2194 | (rc2 <= 0) ? -1 : event.type, | |
2195 | (rc2 <= 0) ? -1 : event.status, | |
2196 | (rc2 > 0 && event.unlinked) ? " unlinked" : ""); | |
2197 | ||
3b7566d9 | 2198 | LASSERT(rc2 != -EOVERFLOW); /* can't miss anything */ |
d7e09d03 | 2199 | |
5fd88337 | 2200 | if (rc2 <= 0 || event.status) { |
d7e09d03 | 2201 | /* timeout or error */ |
5fd88337 | 2202 | if (!replied && !rc) |
d7e09d03 | 2203 | rc = (rc2 < 0) ? rc2 : |
5fd88337 | 2204 | !rc2 ? -ETIMEDOUT : |
d7e09d03 PT |
2205 | event.status; |
2206 | ||
2207 | if (!unlinked) { | |
2208 | /* Ensure completion in finite time... */ | |
2209 | LNetMDUnlink(mdh); | |
2210 | /* No assertion (racing with network) */ | |
2211 | unlinked = 1; | |
2212 | timeout_ms = a_long_time; | |
5fd88337 | 2213 | } else if (!rc2) { |
d7e09d03 PT |
2214 | /* timed out waiting for unlink */ |
2215 | CWARN("ping %s: late network completion\n", | |
2216 | libcfs_id2str(id)); | |
2217 | } | |
2218 | } else if (event.type == LNET_EVENT_REPLY) { | |
2219 | replied = 1; | |
2220 | rc = event.mlength; | |
2221 | } | |
2222 | ||
2223 | } while (rc2 <= 0 || !event.unlinked); | |
2224 | ||
2225 | if (!replied) { | |
2226 | if (rc >= 0) | |
2227 | CWARN("%s: Unexpected rc >= 0 but no reply!\n", | |
2228 | libcfs_id2str(id)); | |
2229 | rc = -EIO; | |
2230 | goto out_1; | |
2231 | } | |
2232 | ||
2233 | nob = rc; | |
3b7566d9 | 2234 | LASSERT(nob >= 0 && nob <= infosz); |
d7e09d03 PT |
2235 | |
2236 | rc = -EPROTO; /* if I can't parse... */ | |
2237 | ||
2238 | if (nob < 8) { | |
2239 | /* can't check magic/version */ | |
2240 | CERROR("%s: ping info too short %d\n", | |
2241 | libcfs_id2str(id), nob); | |
2242 | goto out_1; | |
2243 | } | |
2244 | ||
2245 | if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) { | |
2246 | lnet_swap_pinginfo(info); | |
2247 | } else if (info->pi_magic != LNET_PROTO_PING_MAGIC) { | |
2248 | CERROR("%s: Unexpected magic %08x\n", | |
2249 | libcfs_id2str(id), info->pi_magic); | |
2250 | goto out_1; | |
2251 | } | |
2252 | ||
5fd88337 | 2253 | if (!(info->pi_features & LNET_PING_FEAT_NI_STATUS)) { |
d7e09d03 PT |
2254 | CERROR("%s: ping w/o NI status: 0x%x\n", |
2255 | libcfs_id2str(id), info->pi_features); | |
2256 | goto out_1; | |
2257 | } | |
2258 | ||
2259 | if (nob < offsetof(lnet_ping_info_t, pi_ni[0])) { | |
2260 | CERROR("%s: Short reply %d(%d min)\n", libcfs_id2str(id), | |
2261 | nob, (int)offsetof(lnet_ping_info_t, pi_ni[0])); | |
2262 | goto out_1; | |
2263 | } | |
2264 | ||
2265 | if (info->pi_nnis < n_ids) | |
2266 | n_ids = info->pi_nnis; | |
2267 | ||
2268 | if (nob < offsetof(lnet_ping_info_t, pi_ni[n_ids])) { | |
2269 | CERROR("%s: Short reply %d(%d expected)\n", libcfs_id2str(id), | |
2270 | nob, (int)offsetof(lnet_ping_info_t, pi_ni[n_ids])); | |
2271 | goto out_1; | |
2272 | } | |
2273 | ||
2274 | rc = -EFAULT; /* If I SEGV... */ | |
2275 | ||
751a624a | 2276 | memset(&tmpid, 0, sizeof(tmpid)); |
d7e09d03 PT |
2277 | for (i = 0; i < n_ids; i++) { |
2278 | tmpid.pid = info->pi_pid; | |
2279 | tmpid.nid = info->pi_ni[i].ns_nid; | |
2280 | if (copy_to_user(&ids[i], &tmpid, sizeof(tmpid))) | |
2281 | goto out_1; | |
2282 | } | |
2283 | rc = info->pi_nnis; | |
2284 | ||
2285 | out_1: | |
2286 | rc2 = LNetEQFree(eqh); | |
5fd88337 | 2287 | if (rc2) |
d7e09d03 | 2288 | CERROR("rc2 %d\n", rc2); |
5fd88337 | 2289 | LASSERT(!rc2); |
d7e09d03 PT |
2290 | |
2291 | out_0: | |
2292 | LIBCFS_FREE(info, infosz); | |
2293 | return rc; | |
2294 | } |