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