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 | ||
d7e09d03 PT |
528 | int lnet_unprepare(void); |
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 | ||
614 | 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 | ||
51bd8814 | 1068 | static void |
6c9e5a55 | 1069 | lnet_clear_zombies_nis_locked(void) |
d7e09d03 | 1070 | { |
7e7ab095 MS |
1071 | int i; |
1072 | int islo; | |
1073 | lnet_ni_t *ni; | |
d7e09d03 | 1074 | |
6c9e5a55 AS |
1075 | /* |
1076 | * Now wait for the NI's I just nuked to show up on ln_zombie_nis | |
1077 | * and shut them down in guaranteed thread context | |
1078 | */ | |
1079 | i = 2; | |
1080 | while (!list_empty(&the_lnet.ln_nis_zombie)) { | |
1081 | int *ref; | |
1082 | int j; | |
1083 | ||
1084 | ni = list_entry(the_lnet.ln_nis_zombie.next, | |
1085 | lnet_ni_t, ni_list); | |
1086 | list_del_init(&ni->ni_list); | |
1087 | cfs_percpt_for_each(ref, j, ni->ni_refs) { | |
1088 | if (!*ref) | |
1089 | continue; | |
1090 | /* still busy, add it back to zombie list */ | |
1091 | list_add(&ni->ni_list, &the_lnet.ln_nis_zombie); | |
1092 | break; | |
1093 | } | |
1094 | ||
1095 | if (!list_empty(&ni->ni_list)) { | |
1096 | lnet_net_unlock(LNET_LOCK_EX); | |
1097 | ++i; | |
1098 | if ((i & (-i)) == i) { | |
1099 | CDEBUG(D_WARNING, "Waiting for zombie LNI %s\n", | |
1100 | libcfs_nid2str(ni->ni_nid)); | |
1101 | } | |
1102 | set_current_state(TASK_UNINTERRUPTIBLE); | |
1103 | schedule_timeout(cfs_time_seconds(1)); | |
1104 | lnet_net_lock(LNET_LOCK_EX); | |
1105 | continue; | |
1106 | } | |
1107 | ||
1108 | ni->ni_lnd->lnd_refcount--; | |
1109 | lnet_net_unlock(LNET_LOCK_EX); | |
1110 | ||
1111 | islo = ni->ni_lnd->lnd_type == LOLND; | |
1112 | ||
1113 | LASSERT(!in_interrupt()); | |
1114 | ni->ni_lnd->lnd_shutdown(ni); | |
1115 | ||
1116 | /* | |
1117 | * can't deref lnd anymore now; it might have unregistered | |
1118 | * itself... | |
1119 | */ | |
1120 | if (!islo) | |
1121 | CDEBUG(D_LNI, "Removed LNI %s\n", | |
1122 | libcfs_nid2str(ni->ni_nid)); | |
1123 | ||
1124 | lnet_ni_free(ni); | |
1125 | i = 2; | |
1126 | ||
1127 | lnet_net_lock(LNET_LOCK_EX); | |
1128 | } | |
1129 | } | |
1130 | ||
1131 | static void | |
1132 | lnet_shutdown_lndnis(void) | |
1133 | { | |
1134 | lnet_ni_t *ni; | |
1135 | int i; | |
1136 | ||
d7e09d03 PT |
1137 | /* NB called holding the global mutex */ |
1138 | ||
1139 | /* All quiet on the API front */ | |
1140 | LASSERT(!the_lnet.ln_shutdown); | |
5fd88337 | 1141 | LASSERT(!the_lnet.ln_refcount); |
d7e09d03 PT |
1142 | LASSERT(list_empty(&the_lnet.ln_nis_zombie)); |
1143 | ||
1144 | lnet_net_lock(LNET_LOCK_EX); | |
1145 | the_lnet.ln_shutdown = 1; /* flag shutdown */ | |
1146 | ||
1147 | /* Unlink NIs from the global table */ | |
1148 | while (!list_empty(&the_lnet.ln_nis)) { | |
1149 | ni = list_entry(the_lnet.ln_nis.next, | |
c314c319 | 1150 | lnet_ni_t, ni_list); |
d7e09d03 PT |
1151 | /* move it to zombie list and nobody can find it anymore */ |
1152 | list_move(&ni->ni_list, &the_lnet.ln_nis_zombie); | |
1153 | lnet_ni_decref_locked(ni, 0); /* drop ln_nis' ref */ | |
1154 | ||
1155 | if (!list_empty(&ni->ni_cptlist)) { | |
1156 | list_del_init(&ni->ni_cptlist); | |
1157 | lnet_ni_decref_locked(ni, 0); | |
1158 | } | |
1159 | } | |
1160 | ||
1161 | /* Drop the cached eqwait NI. */ | |
06ace26e | 1162 | if (the_lnet.ln_eq_waitni) { |
d7e09d03 PT |
1163 | lnet_ni_decref_locked(the_lnet.ln_eq_waitni, 0); |
1164 | the_lnet.ln_eq_waitni = NULL; | |
1165 | } | |
1166 | ||
1167 | /* Drop the cached loopback NI. */ | |
06ace26e | 1168 | if (the_lnet.ln_loni) { |
d7e09d03 PT |
1169 | lnet_ni_decref_locked(the_lnet.ln_loni, 0); |
1170 | the_lnet.ln_loni = NULL; | |
1171 | } | |
1172 | ||
1173 | lnet_net_unlock(LNET_LOCK_EX); | |
1174 | ||
4420cfd3 JS |
1175 | /* |
1176 | * Clear lazy portals and drop delayed messages which hold refs | |
1177 | * on their lnet_msg_t::msg_rxpeer | |
1178 | */ | |
d7e09d03 PT |
1179 | for (i = 0; i < the_lnet.ln_nportals; i++) |
1180 | LNetClearLazyPortal(i); | |
1181 | ||
4420cfd3 JS |
1182 | /* |
1183 | * Clear the peer table and wait for all peers to go (they hold refs on | |
1184 | * their NIs) | |
1185 | */ | |
21602c7d | 1186 | lnet_peer_tables_cleanup(NULL); |
d7e09d03 PT |
1187 | |
1188 | lnet_net_lock(LNET_LOCK_EX); | |
d7e09d03 | 1189 | |
6c9e5a55 AS |
1190 | lnet_clear_zombies_nis_locked(); |
1191 | the_lnet.ln_shutdown = 0; | |
1192 | lnet_net_unlock(LNET_LOCK_EX); | |
1193 | } | |
d7e09d03 | 1194 | |
6c9e5a55 AS |
1195 | int |
1196 | lnet_shutdown_lndni(__u32 net) | |
1197 | { | |
1198 | lnet_ping_info_t *pinfo; | |
1199 | lnet_handle_md_t md_handle; | |
1200 | lnet_ni_t *found_ni = NULL; | |
1201 | int ni_count; | |
1202 | int rc; | |
d7e09d03 | 1203 | |
6c9e5a55 AS |
1204 | if (LNET_NETTYP(net) == LOLND) |
1205 | return -EINVAL; | |
d7e09d03 | 1206 | |
6c9e5a55 | 1207 | ni_count = lnet_get_ni_count(); |
d7e09d03 | 1208 | |
6c9e5a55 AS |
1209 | /* create and link a new ping info, before removing the old one */ |
1210 | rc = lnet_ping_info_setup(&pinfo, &md_handle, ni_count - 1, false); | |
1211 | if (rc) | |
1212 | return rc; | |
d7e09d03 | 1213 | |
6c9e5a55 AS |
1214 | /* proceed with shutting down the NI */ |
1215 | lnet_net_lock(LNET_LOCK_EX); | |
d7e09d03 | 1216 | |
6c9e5a55 AS |
1217 | found_ni = lnet_net2ni_locked(net, 0); |
1218 | if (!found_ni) { | |
1219 | lnet_net_unlock(LNET_LOCK_EX); | |
1220 | lnet_ping_md_unlink(pinfo, &md_handle); | |
1221 | lnet_ping_info_free(pinfo); | |
1222 | return -EINVAL; | |
1223 | } | |
526cdb4f | 1224 | |
6c9e5a55 AS |
1225 | /* |
1226 | * decrement the reference counter on found_ni which was | |
1227 | * incremented when we called lnet_net2ni_locked() | |
1228 | */ | |
1229 | lnet_ni_decref_locked(found_ni, 0); | |
1230 | /* Move ni to zombie list so nobody can find it anymore */ | |
1231 | list_move(&found_ni->ni_list, &the_lnet.ln_nis_zombie); | |
1232 | ||
1233 | /* Drop the lock reference for the ln_nis ref. */ | |
1234 | lnet_ni_decref_locked(found_ni, 0); | |
1235 | ||
1236 | if (!list_empty(&found_ni->ni_cptlist)) { | |
1237 | list_del_init(&found_ni->ni_cptlist); | |
1238 | lnet_ni_decref_locked(found_ni, 0); | |
d7e09d03 PT |
1239 | } |
1240 | ||
d7e09d03 | 1241 | lnet_net_unlock(LNET_LOCK_EX); |
6c9e5a55 AS |
1242 | |
1243 | /* Do peer table cleanup for this ni */ | |
1244 | lnet_peer_tables_cleanup(found_ni); | |
1245 | ||
1246 | lnet_net_lock(LNET_LOCK_EX); | |
1247 | lnet_clear_zombies_nis_locked(); | |
1248 | lnet_net_unlock(LNET_LOCK_EX); | |
1249 | ||
1250 | lnet_ping_target_update(pinfo, md_handle); | |
1251 | ||
1252 | return 0; | |
d7e09d03 PT |
1253 | } |
1254 | ||
51bd8814 | 1255 | static int |
6c9e5a55 AS |
1256 | lnet_startup_lndnis(struct list_head *nilist, __s32 peer_timeout, |
1257 | __s32 peer_cr, __s32 peer_buf_cr, __s32 credits, | |
1258 | int *ni_count) | |
d7e09d03 | 1259 | { |
7e7ab095 MS |
1260 | lnd_t *lnd; |
1261 | struct lnet_ni *ni; | |
1262 | struct lnet_tx_queue *tq; | |
7e7ab095 MS |
1263 | int i; |
1264 | int rc = 0; | |
80feb1ef | 1265 | __u32 lnd_type; |
d7e09d03 | 1266 | |
6c9e5a55 AS |
1267 | while (!list_empty(nilist)) { |
1268 | ni = list_entry(nilist->next, lnet_ni_t, ni_list); | |
d7e09d03 PT |
1269 | lnd_type = LNET_NETTYP(LNET_NIDNET(ni->ni_nid)); |
1270 | ||
6c9e5a55 AS |
1271 | if (!libcfs_isknown_lnd(lnd_type)) |
1272 | goto failed; | |
d7e09d03 PT |
1273 | |
1274 | if (lnd_type == CIBLND || | |
1275 | lnd_type == OPENIBLND || | |
1276 | lnd_type == IIBLND || | |
1277 | lnd_type == VIBLND) { | |
1278 | CERROR("LND %s obsoleted\n", | |
1279 | libcfs_lnd2str(lnd_type)); | |
1280 | goto failed; | |
1281 | } | |
1282 | ||
6c9e5a55 AS |
1283 | /* Make sure this new NI is unique. */ |
1284 | lnet_net_lock(LNET_LOCK_EX); | |
1285 | if (!lnet_net_unique(LNET_NIDNET(ni->ni_nid), | |
1286 | &the_lnet.ln_nis)) { | |
1287 | if (lnd_type == LOLND) { | |
1288 | lnet_net_unlock(LNET_LOCK_EX); | |
1289 | list_del(&ni->ni_list); | |
1290 | lnet_ni_free(ni); | |
1291 | continue; | |
1292 | } | |
1293 | ||
1294 | CERROR("Net %s is not unique\n", | |
1295 | libcfs_net2str(LNET_NIDNET(ni->ni_nid))); | |
1296 | lnet_net_unlock(LNET_LOCK_EX); | |
1297 | goto failed; | |
1298 | } | |
1299 | lnet_net_unlock(LNET_LOCK_EX); | |
1300 | ||
bdd84a6f | 1301 | mutex_lock(&the_lnet.ln_lnd_mutex); |
d7e09d03 PT |
1302 | lnd = lnet_find_lnd_by_type(lnd_type); |
1303 | ||
06ace26e | 1304 | if (!lnd) { |
bdd84a6f | 1305 | mutex_unlock(&the_lnet.ln_lnd_mutex); |
d7e09d03 | 1306 | rc = request_module("%s", |
c314c319 | 1307 | libcfs_lnd2modname(lnd_type)); |
bdd84a6f | 1308 | mutex_lock(&the_lnet.ln_lnd_mutex); |
d7e09d03 PT |
1309 | |
1310 | lnd = lnet_find_lnd_by_type(lnd_type); | |
06ace26e | 1311 | if (!lnd) { |
bdd84a6f | 1312 | mutex_unlock(&the_lnet.ln_lnd_mutex); |
d7e09d03 PT |
1313 | CERROR("Can't load LND %s, module %s, rc=%d\n", |
1314 | libcfs_lnd2str(lnd_type), | |
1315 | libcfs_lnd2modname(lnd_type), rc); | |
1316 | goto failed; | |
1317 | } | |
1318 | } | |
1319 | ||
1320 | lnet_net_lock(LNET_LOCK_EX); | |
1321 | lnd->lnd_refcount++; | |
1322 | lnet_net_unlock(LNET_LOCK_EX); | |
1323 | ||
1324 | ni->ni_lnd = lnd; | |
1325 | ||
0eee6778 | 1326 | rc = lnd->lnd_startup(ni); |
d7e09d03 | 1327 | |
bdd84a6f | 1328 | mutex_unlock(&the_lnet.ln_lnd_mutex); |
d7e09d03 | 1329 | |
5fd88337 | 1330 | if (rc) { |
8ad5360a | 1331 | LCONSOLE_ERROR_MSG(0x105, "Error %d starting up LNI %s\n", |
d7e09d03 PT |
1332 | rc, libcfs_lnd2str(lnd->lnd_type)); |
1333 | lnet_net_lock(LNET_LOCK_EX); | |
1334 | lnd->lnd_refcount--; | |
1335 | lnet_net_unlock(LNET_LOCK_EX); | |
1336 | goto failed; | |
1337 | } | |
1338 | ||
6c9e5a55 AS |
1339 | /* |
1340 | * If given some LND tunable parameters, parse those now to | |
1341 | * override the values in the NI structure. | |
1342 | */ | |
1343 | if (peer_buf_cr >= 0) | |
1344 | ni->ni_peerrtrcredits = peer_buf_cr; | |
1345 | if (peer_timeout >= 0) | |
1346 | ni->ni_peertimeout = peer_timeout; | |
1347 | /* | |
1348 | * TODO | |
1349 | * Note: For now, don't allow the user to change | |
1350 | * peertxcredits as this number is used in the | |
1351 | * IB LND to control queue depth. | |
1352 | * if (peer_cr != -1) | |
1353 | * ni->ni_peertxcredits = peer_cr; | |
1354 | */ | |
1355 | if (credits >= 0) | |
1356 | ni->ni_maxtxcredits = credits; | |
1357 | ||
06ace26e | 1358 | LASSERT(ni->ni_peertimeout <= 0 || lnd->lnd_query); |
d7e09d03 PT |
1359 | |
1360 | list_del(&ni->ni_list); | |
1361 | ||
1362 | lnet_net_lock(LNET_LOCK_EX); | |
1363 | /* refcount for ln_nis */ | |
1364 | lnet_ni_addref_locked(ni, 0); | |
1365 | list_add_tail(&ni->ni_list, &the_lnet.ln_nis); | |
06ace26e | 1366 | if (ni->ni_cpts) { |
d7e09d03 | 1367 | list_add_tail(&ni->ni_cptlist, |
c314c319 | 1368 | &the_lnet.ln_nis_cpt); |
d7e09d03 PT |
1369 | lnet_ni_addref_locked(ni, 0); |
1370 | } | |
1371 | ||
1372 | lnet_net_unlock(LNET_LOCK_EX); | |
1373 | ||
6c9e5a55 AS |
1374 | /* increment the ni_count here to account for the LOLND as |
1375 | * well. If we increment past this point then the number | |
1376 | * of count will be missing the LOLND, and then ping and | |
1377 | * will not report the LOLND | |
1378 | */ | |
1379 | if (ni_count) | |
1380 | (*ni_count)++; | |
1381 | ||
d7e09d03 PT |
1382 | if (lnd->lnd_type == LOLND) { |
1383 | lnet_ni_addref(ni); | |
06ace26e | 1384 | LASSERT(!the_lnet.ln_loni); |
d7e09d03 PT |
1385 | the_lnet.ln_loni = ni; |
1386 | continue; | |
1387 | } | |
1388 | ||
5fd88337 | 1389 | if (!ni->ni_peertxcredits || !ni->ni_maxtxcredits) { |
d7e09d03 PT |
1390 | LCONSOLE_ERROR_MSG(0x107, "LNI %s has no %scredits\n", |
1391 | libcfs_lnd2str(lnd->lnd_type), | |
5fd88337 | 1392 | !ni->ni_peertxcredits ? |
d7e09d03 PT |
1393 | "" : "per-peer "); |
1394 | goto failed; | |
1395 | } | |
1396 | ||
1397 | cfs_percpt_for_each(tq, i, ni->ni_tx_queues) { | |
1398 | tq->tq_credits_min = | |
1399 | tq->tq_credits_max = | |
1400 | tq->tq_credits = lnet_ni_tq_credits(ni); | |
1401 | } | |
1402 | ||
1403 | CDEBUG(D_LNI, "Added LNI %s [%d/%d/%d/%d]\n", | |
1404 | libcfs_nid2str(ni->ni_nid), ni->ni_peertxcredits, | |
1405 | lnet_ni_tq_credits(ni) * LNET_CPT_NUMBER, | |
1406 | ni->ni_peerrtrcredits, ni->ni_peertimeout); | |
d7e09d03 PT |
1407 | } |
1408 | ||
1409 | return 0; | |
6c9e5a55 AS |
1410 | failed: |
1411 | while (!list_empty(nilist)) { | |
1412 | ni = list_entry(nilist->next, lnet_ni_t, ni_list); | |
d7e09d03 PT |
1413 | list_del(&ni->ni_list); |
1414 | lnet_ni_free(ni); | |
1415 | } | |
6c9e5a55 | 1416 | return -EINVAL; |
d7e09d03 PT |
1417 | } |
1418 | ||
1419 | /** | |
1420 | * Initialize LNet library. | |
1421 | * | |
1422 | * Only userspace program needs to call this function - it's automatically | |
a9cf72b6 JS |
1423 | * called in the kernel at module loading time. Caller has to call lnet_fini() |
1424 | * after a call to lnet_init(), if and only if the latter returned 0. It must | |
d7e09d03 PT |
1425 | * be called exactly once. |
1426 | * | |
1427 | * \return 0 on success, and -ve on failures. | |
1428 | */ | |
1429 | int | |
a9cf72b6 | 1430 | lnet_init(void) |
d7e09d03 | 1431 | { |
7e7ab095 | 1432 | int rc; |
d7e09d03 PT |
1433 | |
1434 | lnet_assert_wire_constants(); | |
1435 | LASSERT(!the_lnet.ln_init); | |
1436 | ||
1437 | memset(&the_lnet, 0, sizeof(the_lnet)); | |
1438 | ||
1439 | /* refer to global cfs_cpt_table for now */ | |
1440 | the_lnet.ln_cpt_table = cfs_cpt_table; | |
1441 | the_lnet.ln_cpt_number = cfs_cpt_number(cfs_cpt_table); | |
1442 | ||
1443 | LASSERT(the_lnet.ln_cpt_number > 0); | |
1444 | if (the_lnet.ln_cpt_number > LNET_CPT_MAX) { | |
1445 | /* we are under risk of consuming all lh_cookie */ | |
8ad5360a | 1446 | CERROR("Can't have %d CPTs for LNet (max allowed is %d), please change setting of CPT-table and retry\n", |
d7e09d03 PT |
1447 | the_lnet.ln_cpt_number, LNET_CPT_MAX); |
1448 | return -1; | |
1449 | } | |
1450 | ||
1451 | while ((1 << the_lnet.ln_cpt_bits) < the_lnet.ln_cpt_number) | |
1452 | the_lnet.ln_cpt_bits++; | |
1453 | ||
1454 | rc = lnet_create_locks(); | |
5fd88337 | 1455 | if (rc) { |
d7e09d03 PT |
1456 | CERROR("Can't create LNet global locks: %d\n", rc); |
1457 | return -1; | |
1458 | } | |
1459 | ||
1460 | the_lnet.ln_refcount = 0; | |
1461 | the_lnet.ln_init = 1; | |
1462 | LNetInvalidateHandle(&the_lnet.ln_rc_eqh); | |
1463 | INIT_LIST_HEAD(&the_lnet.ln_lnds); | |
1464 | INIT_LIST_HEAD(&the_lnet.ln_rcd_zombie); | |
1465 | INIT_LIST_HEAD(&the_lnet.ln_rcd_deathrow); | |
1466 | ||
4420cfd3 JS |
1467 | /* |
1468 | * The hash table size is the number of bits it takes to express the set | |
d7e09d03 | 1469 | * ln_num_routes, minus 1 (better to under estimate than over so we |
4420cfd3 JS |
1470 | * don't waste memory). |
1471 | */ | |
d7e09d03 PT |
1472 | if (rnet_htable_size <= 0) |
1473 | rnet_htable_size = LNET_REMOTE_NETS_HASH_DEFAULT; | |
1474 | else if (rnet_htable_size > LNET_REMOTE_NETS_HASH_MAX) | |
1475 | rnet_htable_size = LNET_REMOTE_NETS_HASH_MAX; | |
1476 | the_lnet.ln_remote_nets_hbits = max_t(int, 1, | |
1477 | order_base_2(rnet_htable_size) - 1); | |
1478 | ||
4420cfd3 JS |
1479 | /* |
1480 | * All LNDs apart from the LOLND are in separate modules. They | |
d7e09d03 | 1481 | * register themselves when their module loads, and unregister |
4420cfd3 JS |
1482 | * themselves when their module is unloaded. |
1483 | */ | |
d7e09d03 PT |
1484 | lnet_register_lnd(&the_lolnd); |
1485 | return 0; | |
1486 | } | |
d7e09d03 PT |
1487 | |
1488 | /** | |
1489 | * Finalize LNet library. | |
1490 | * | |
1491 | * Only userspace program needs to call this function. It can be called | |
1492 | * at most once. | |
1493 | * | |
a9cf72b6 | 1494 | * \pre lnet_init() called with success. |
d7e09d03 PT |
1495 | * \pre All LNet users called LNetNIFini() for matching LNetNIInit() calls. |
1496 | */ | |
1497 | void | |
a9cf72b6 | 1498 | lnet_fini(void) |
d7e09d03 PT |
1499 | { |
1500 | LASSERT(the_lnet.ln_init); | |
5fd88337 | 1501 | LASSERT(!the_lnet.ln_refcount); |
d7e09d03 PT |
1502 | |
1503 | while (!list_empty(&the_lnet.ln_lnds)) | |
1504 | lnet_unregister_lnd(list_entry(the_lnet.ln_lnds.next, | |
c314c319 | 1505 | lnd_t, lnd_list)); |
d7e09d03 PT |
1506 | lnet_destroy_locks(); |
1507 | ||
1508 | the_lnet.ln_init = 0; | |
1509 | } | |
d7e09d03 PT |
1510 | |
1511 | /** | |
1512 | * Set LNet PID and start LNet interfaces, routing, and forwarding. | |
1513 | * | |
a9cf72b6 | 1514 | * Userspace program should call this after a successful call to lnet_init(). |
d7e09d03 PT |
1515 | * Users must call this function at least once before any other functions. |
1516 | * For each successful call there must be a corresponding call to | |
1517 | * LNetNIFini(). For subsequent calls to LNetNIInit(), \a requested_pid is | |
1518 | * ignored. | |
1519 | * | |
1520 | * The PID used by LNet may be different from the one requested. | |
1521 | * See LNetGetId(). | |
1522 | * | |
1523 | * \param requested_pid PID requested by the caller. | |
1524 | * | |
1525 | * \return >= 0 on success, and < 0 error code on failures. | |
1526 | */ | |
1527 | int | |
1528 | LNetNIInit(lnet_pid_t requested_pid) | |
1529 | { | |
7e7ab095 MS |
1530 | int im_a_router = 0; |
1531 | int rc; | |
6c9e5a55 AS |
1532 | int ni_count = 0; |
1533 | int lnd_type; | |
1534 | struct lnet_ni *ni; | |
1535 | lnet_ping_info_t *pinfo; | |
1536 | lnet_handle_md_t md_handle; | |
1537 | struct list_head net_head; | |
6c9e5a55 AS |
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 | ||
d7e09d03 | 1552 | rc = lnet_prepare(requested_pid); |
5fd88337 | 1553 | if (rc) |
d7e09d03 PT |
1554 | goto failed0; |
1555 | ||
8766cd12 | 1556 | rc = lnet_parse_networks(&net_head, lnet_get_networks()); |
6c9e5a55 AS |
1557 | if (rc < 0) |
1558 | goto failed1; | |
1559 | ||
1560 | rc = lnet_startup_lndnis(&net_head, -1, -1, -1, -1, &ni_count); | |
5fd88337 | 1561 | if (rc) |
d7e09d03 PT |
1562 | goto failed1; |
1563 | ||
6c9e5a55 AS |
1564 | if (the_lnet.ln_eq_waitni && ni_count > 1) { |
1565 | lnd_type = the_lnet.ln_eq_waitni->ni_lnd->lnd_type; | |
1566 | LCONSOLE_ERROR_MSG(0x109, "LND %s can only run single-network\n", | |
1567 | libcfs_lnd2str(lnd_type)); | |
1568 | goto failed2; | |
1569 | } | |
1570 | ||
d7e09d03 | 1571 | rc = lnet_parse_routes(lnet_get_routes(), &im_a_router); |
5fd88337 | 1572 | if (rc) |
d7e09d03 PT |
1573 | goto failed2; |
1574 | ||
1575 | rc = lnet_check_routes(); | |
5fd88337 | 1576 | if (rc) |
d7e09d03 PT |
1577 | goto failed2; |
1578 | ||
1579 | rc = lnet_rtrpools_alloc(im_a_router); | |
5fd88337 | 1580 | if (rc) |
d7e09d03 PT |
1581 | goto failed2; |
1582 | ||
1583 | rc = lnet_acceptor_start(); | |
5fd88337 | 1584 | if (rc) |
d7e09d03 PT |
1585 | goto failed2; |
1586 | ||
1587 | the_lnet.ln_refcount = 1; | |
1588 | /* Now I may use my own API functions... */ | |
1589 | ||
6c9e5a55 | 1590 | rc = lnet_ping_info_setup(&pinfo, &md_handle, ni_count, true); |
5fd88337 | 1591 | if (rc) |
d7e09d03 PT |
1592 | goto failed3; |
1593 | ||
6c9e5a55 AS |
1594 | lnet_ping_target_update(pinfo, md_handle); |
1595 | ||
d7e09d03 | 1596 | rc = lnet_router_checker_start(); |
5fd88337 | 1597 | if (rc) |
d7e09d03 PT |
1598 | goto failed4; |
1599 | ||
b03f395a | 1600 | lnet_router_debugfs_init(); |
6c9e5a55 AS |
1601 | |
1602 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1603 | ||
1604 | return 0; | |
d7e09d03 PT |
1605 | |
1606 | failed4: | |
d7e09d03 | 1607 | the_lnet.ln_refcount = 0; |
6c9e5a55 AS |
1608 | lnet_ping_md_unlink(pinfo, &md_handle); |
1609 | lnet_ping_info_free(pinfo); | |
1610 | failed3: | |
d7e09d03 | 1611 | lnet_acceptor_stop(); |
6c9e5a55 AS |
1612 | rc = LNetEQFree(the_lnet.ln_ping_target_eq); |
1613 | LASSERT(!rc); | |
d7e09d03 PT |
1614 | failed2: |
1615 | lnet_destroy_routes(); | |
1616 | lnet_shutdown_lndnis(); | |
1617 | failed1: | |
1618 | lnet_unprepare(); | |
1619 | failed0: | |
3b7566d9 | 1620 | LASSERT(rc < 0); |
bdd84a6f | 1621 | mutex_unlock(&the_lnet.ln_api_mutex); |
6c9e5a55 AS |
1622 | while (!list_empty(&net_head)) { |
1623 | ni = list_entry(net_head.next, struct lnet_ni, ni_list); | |
1624 | list_del_init(&ni->ni_list); | |
1625 | lnet_ni_free(ni); | |
1626 | } | |
d7e09d03 PT |
1627 | return rc; |
1628 | } | |
1629 | EXPORT_SYMBOL(LNetNIInit); | |
1630 | ||
1631 | /** | |
1632 | * Stop LNet interfaces, routing, and forwarding. | |
1633 | * | |
1634 | * Users must call this function once for each successful call to LNetNIInit(). | |
1635 | * Once the LNetNIFini() operation has been started, the results of pending | |
1636 | * API operations are undefined. | |
1637 | * | |
1638 | * \return always 0 for current implementation. | |
1639 | */ | |
1640 | int | |
7d46a21a | 1641 | LNetNIFini(void) |
d7e09d03 | 1642 | { |
bdd84a6f | 1643 | mutex_lock(&the_lnet.ln_api_mutex); |
d7e09d03 | 1644 | |
3b7566d9 TP |
1645 | LASSERT(the_lnet.ln_init); |
1646 | LASSERT(the_lnet.ln_refcount > 0); | |
d7e09d03 PT |
1647 | |
1648 | if (the_lnet.ln_refcount != 1) { | |
1649 | the_lnet.ln_refcount--; | |
1650 | } else { | |
3b7566d9 | 1651 | LASSERT(!the_lnet.ln_niinit_self); |
d7e09d03 | 1652 | |
b03f395a | 1653 | lnet_router_debugfs_fini(); |
d7e09d03 PT |
1654 | lnet_router_checker_stop(); |
1655 | lnet_ping_target_fini(); | |
1656 | ||
1657 | /* Teardown fns that use my own API functions BEFORE here */ | |
1658 | the_lnet.ln_refcount = 0; | |
1659 | ||
1660 | lnet_acceptor_stop(); | |
1661 | lnet_destroy_routes(); | |
1662 | lnet_shutdown_lndnis(); | |
1663 | lnet_unprepare(); | |
1664 | } | |
1665 | ||
bdd84a6f | 1666 | mutex_unlock(&the_lnet.ln_api_mutex); |
d7e09d03 PT |
1667 | return 0; |
1668 | } | |
1669 | EXPORT_SYMBOL(LNetNIFini); | |
1670 | ||
6c9e5a55 AS |
1671 | int |
1672 | lnet_dyn_add_ni(lnet_pid_t requested_pid, char *nets, | |
1673 | __s32 peer_timeout, __s32 peer_cr, __s32 peer_buf_cr, | |
1674 | __s32 credits) | |
1675 | { | |
1676 | lnet_ping_info_t *pinfo; | |
1677 | lnet_handle_md_t md_handle; | |
1678 | struct lnet_ni *ni; | |
1679 | struct list_head net_head; | |
1680 | int rc; | |
1681 | ||
1682 | INIT_LIST_HEAD(&net_head); | |
1683 | ||
1684 | /* Create a ni structure for the network string */ | |
1685 | rc = lnet_parse_networks(&net_head, nets); | |
1686 | if (rc < 0) | |
1687 | return rc; | |
1688 | ||
1689 | mutex_lock(&the_lnet.ln_api_mutex); | |
1690 | ||
1691 | if (rc > 1) { | |
1692 | rc = -EINVAL; /* only add one interface per call */ | |
1693 | goto failed0; | |
1694 | } | |
1695 | ||
1696 | rc = lnet_ping_info_setup(&pinfo, &md_handle, 1 + lnet_get_ni_count(), | |
1697 | false); | |
1698 | if (rc) | |
1699 | goto failed0; | |
1700 | ||
1701 | rc = lnet_startup_lndnis(&net_head, peer_timeout, peer_cr, | |
1702 | peer_buf_cr, credits, NULL); | |
1703 | if (rc) | |
1704 | goto failed1; | |
1705 | ||
1706 | lnet_ping_target_update(pinfo, md_handle); | |
1707 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1708 | ||
1709 | return 0; | |
1710 | ||
1711 | failed1: | |
1712 | lnet_ping_md_unlink(pinfo, &md_handle); | |
1713 | lnet_ping_info_free(pinfo); | |
1714 | failed0: | |
1715 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1716 | while (!list_empty(&net_head)) { | |
1717 | ni = list_entry(net_head.next, struct lnet_ni, ni_list); | |
1718 | list_del_init(&ni->ni_list); | |
1719 | lnet_ni_free(ni); | |
1720 | } | |
1721 | return rc; | |
1722 | } | |
1723 | ||
1724 | int | |
1725 | lnet_dyn_del_ni(__u32 net) | |
1726 | { | |
1727 | int rc; | |
1728 | ||
1729 | mutex_lock(&the_lnet.ln_api_mutex); | |
1730 | rc = lnet_shutdown_lndni(net); | |
1731 | mutex_unlock(&the_lnet.ln_api_mutex); | |
1732 | ||
1733 | return rc; | |
1734 | } | |
1735 | ||
d7e09d03 | 1736 | /** |
71c36dd7 | 1737 | * LNet ioctl handler. |
d7e09d03 | 1738 | * |
d7e09d03 PT |
1739 | */ |
1740 | int | |
1741 | LNetCtl(unsigned int cmd, void *arg) | |
1742 | { | |
1743 | struct libcfs_ioctl_data *data = arg; | |
2e9a51bd | 1744 | struct lnet_ioctl_config_data *config; |
7e7ab095 MS |
1745 | lnet_process_id_t id = {0}; |
1746 | lnet_ni_t *ni; | |
1747 | int rc; | |
5e50efea | 1748 | unsigned long secs_passed; |
d7e09d03 | 1749 | |
3b7566d9 | 1750 | LASSERT(the_lnet.ln_init); |
d7e09d03 PT |
1751 | |
1752 | switch (cmd) { | |
1753 | case IOC_LIBCFS_GET_NI: | |
1754 | rc = LNetGetId(data->ioc_count, &id); | |
1755 | data->ioc_nid = id.nid; | |
1756 | return rc; | |
1757 | ||
1758 | case IOC_LIBCFS_FAIL_NID: | |
1759 | return lnet_fail_nid(data->ioc_nid, data->ioc_count); | |
1760 | ||
1761 | case IOC_LIBCFS_ADD_ROUTE: | |
6c9e5a55 | 1762 | mutex_lock(&the_lnet.ln_api_mutex); |
d7e09d03 | 1763 | rc = lnet_add_route(data->ioc_net, data->ioc_count, |
e75fb87f | 1764 | data->ioc_nid, data->ioc_priority); |
6c9e5a55 AS |
1765 | mutex_unlock(&the_lnet.ln_api_mutex); |
1766 | return rc ? rc : lnet_check_routes(); | |
d7e09d03 PT |
1767 | |
1768 | case IOC_LIBCFS_DEL_ROUTE: | |
2e9a51bd AS |
1769 | config = arg; |
1770 | ||
1771 | if (config->cfg_hdr.ioc_len < sizeof(*config)) | |
1772 | return -EINVAL; | |
1773 | ||
6c9e5a55 | 1774 | mutex_lock(&the_lnet.ln_api_mutex); |
2e9a51bd | 1775 | rc = lnet_del_route(config->cfg_net, config->cfg_nid); |
6c9e5a55 AS |
1776 | mutex_unlock(&the_lnet.ln_api_mutex); |
1777 | return rc; | |
d7e09d03 PT |
1778 | |
1779 | case IOC_LIBCFS_GET_ROUTE: | |
2e9a51bd AS |
1780 | config = arg; |
1781 | ||
1782 | if (config->cfg_hdr.ioc_len < sizeof(*config)) | |
1783 | return -EINVAL; | |
1784 | ||
1785 | return lnet_get_route(config->cfg_count, | |
1786 | &config->cfg_net, | |
1787 | &config->cfg_config_u.cfg_route.rtr_hop, | |
1788 | &config->cfg_nid, | |
1789 | &config->cfg_config_u.cfg_route.rtr_flags, | |
1790 | &config->cfg_config_u.cfg_route.rtr_priority); | |
1791 | ||
1792 | case IOC_LIBCFS_ADD_NET: | |
1793 | return 0; | |
1794 | ||
1795 | case IOC_LIBCFS_DEL_NET: | |
1796 | return 0; | |
1797 | ||
1798 | case IOC_LIBCFS_GET_NET: | |
1799 | return 0; | |
1800 | ||
1801 | case IOC_LIBCFS_GET_LNET_STATS: { | |
1802 | struct lnet_ioctl_lnet_stats *lnet_stats = arg; | |
1803 | ||
1804 | if (lnet_stats->st_hdr.ioc_len < sizeof(*lnet_stats)) | |
1805 | return -EINVAL; | |
1806 | ||
1807 | lnet_counters_get(&lnet_stats->st_cntrs); | |
1808 | return 0; | |
1809 | } | |
1810 | ||
1811 | case IOC_LIBCFS_CONFIG_RTR: | |
1812 | return 0; | |
1813 | ||
1814 | case IOC_LIBCFS_ADD_BUF: | |
1815 | return 0; | |
1816 | ||
1817 | case IOC_LIBCFS_GET_BUF: | |
1818 | return 0; | |
1819 | ||
1820 | case IOC_LIBCFS_GET_PEER_INFO: | |
1821 | return 0; | |
1822 | ||
d7e09d03 | 1823 | case IOC_LIBCFS_NOTIFY_ROUTER: |
5e50efea | 1824 | secs_passed = (ktime_get_real_seconds() - data->ioc_u64[0]); |
d7e09d03 | 1825 | return lnet_notify(NULL, data->ioc_nid, data->ioc_flags, |
5e50efea | 1826 | jiffies - secs_passed * HZ); |
d7e09d03 | 1827 | |
d7e09d03 PT |
1828 | case IOC_LIBCFS_LNET_DIST: |
1829 | rc = LNetDist(data->ioc_nid, &data->ioc_nid, &data->ioc_u32[1]); | |
1830 | if (rc < 0 && rc != -EHOSTUNREACH) | |
1831 | return rc; | |
1832 | ||
1833 | data->ioc_u32[0] = rc; | |
1834 | return 0; | |
1835 | ||
1836 | case IOC_LIBCFS_TESTPROTOCOMPAT: | |
1837 | lnet_net_lock(LNET_LOCK_EX); | |
1838 | the_lnet.ln_testprotocompat = data->ioc_flags; | |
1839 | lnet_net_unlock(LNET_LOCK_EX); | |
1840 | return 0; | |
1841 | ||
1842 | case IOC_LIBCFS_PING: | |
1843 | id.nid = data->ioc_nid; | |
1844 | id.pid = data->ioc_u32[0]; | |
1845 | rc = lnet_ping(id, data->ioc_u32[1], /* timeout */ | |
4eb53dfd | 1846 | data->ioc_pbuf1, |
51078e25 | 1847 | data->ioc_plen1 / sizeof(lnet_process_id_t)); |
d7e09d03 PT |
1848 | if (rc < 0) |
1849 | return rc; | |
1850 | data->ioc_count = rc; | |
1851 | return 0; | |
1852 | ||
d7e09d03 PT |
1853 | default: |
1854 | ni = lnet_net2ni(data->ioc_net); | |
06ace26e | 1855 | if (!ni) |
d7e09d03 PT |
1856 | return -EINVAL; |
1857 | ||
06ace26e | 1858 | if (!ni->ni_lnd->lnd_ctl) |
d7e09d03 PT |
1859 | rc = -EINVAL; |
1860 | else | |
1861 | rc = ni->ni_lnd->lnd_ctl(ni, cmd, arg); | |
1862 | ||
1863 | lnet_ni_decref(ni); | |
1864 | return rc; | |
1865 | } | |
1866 | /* not reached */ | |
1867 | } | |
1868 | EXPORT_SYMBOL(LNetCtl); | |
1869 | ||
71c36dd7 OD |
1870 | void LNetDebugPeer(lnet_process_id_t id) |
1871 | { | |
1872 | lnet_debug_peer(id.nid); | |
1873 | } | |
1874 | EXPORT_SYMBOL(LNetDebugPeer); | |
1875 | ||
d7e09d03 PT |
1876 | /** |
1877 | * Retrieve the lnet_process_id_t ID of LNet interface at \a index. Note that | |
1878 | * all interfaces share a same PID, as requested by LNetNIInit(). | |
1879 | * | |
1880 | * \param index Index of the interface to look up. | |
1881 | * \param id On successful return, this location will hold the | |
1882 | * lnet_process_id_t ID of the interface. | |
1883 | * | |
1884 | * \retval 0 If an interface exists at \a index. | |
1885 | * \retval -ENOENT If no interface has been found. | |
1886 | */ | |
1887 | int | |
1888 | LNetGetId(unsigned int index, lnet_process_id_t *id) | |
1889 | { | |
7e7ab095 MS |
1890 | struct lnet_ni *ni; |
1891 | struct list_head *tmp; | |
1892 | int cpt; | |
1893 | int rc = -ENOENT; | |
d7e09d03 PT |
1894 | |
1895 | LASSERT(the_lnet.ln_init); | |
4b1e84ed PT |
1896 | |
1897 | /* LNetNI initilization failed? */ | |
5fd88337 | 1898 | if (!the_lnet.ln_refcount) |
4b1e84ed | 1899 | return rc; |
d7e09d03 PT |
1900 | |
1901 | cpt = lnet_net_lock_current(); | |
1902 | ||
1903 | list_for_each(tmp, &the_lnet.ln_nis) { | |
5fd88337 | 1904 | if (index--) |
d7e09d03 PT |
1905 | continue; |
1906 | ||
1907 | ni = list_entry(tmp, lnet_ni_t, ni_list); | |
1908 | ||
1909 | id->nid = ni->ni_nid; | |
1910 | id->pid = the_lnet.ln_pid; | |
1911 | rc = 0; | |
1912 | break; | |
1913 | } | |
1914 | ||
1915 | lnet_net_unlock(cpt); | |
1916 | return rc; | |
1917 | } | |
1918 | EXPORT_SYMBOL(LNetGetId); | |
1919 | ||
1920 | /** | |
1921 | * Print a string representation of handle \a h into buffer \a str of | |
1922 | * \a len bytes. | |
1923 | */ | |
1924 | void | |
1925 | LNetSnprintHandle(char *str, int len, lnet_handle_any_t h) | |
1926 | { | |
55f5a824 | 1927 | snprintf(str, len, "%#llx", h.cookie); |
d7e09d03 PT |
1928 | } |
1929 | EXPORT_SYMBOL(LNetSnprintHandle); | |
1930 | ||
fccfde7d | 1931 | static int lnet_ping(lnet_process_id_t id, int timeout_ms, |
4eb53dfd | 1932 | lnet_process_id_t __user *ids, int n_ids) |
d7e09d03 | 1933 | { |
7e7ab095 MS |
1934 | lnet_handle_eq_t eqh; |
1935 | lnet_handle_md_t mdh; | |
1936 | lnet_event_t event; | |
1937 | lnet_md_t md = { NULL }; | |
1938 | int which; | |
1939 | int unlinked = 0; | |
1940 | int replied = 0; | |
1941 | const int a_long_time = 60000; /* mS */ | |
6c9e5a55 | 1942 | int infosz; |
7e7ab095 MS |
1943 | lnet_ping_info_t *info; |
1944 | lnet_process_id_t tmpid; | |
1945 | int i; | |
1946 | int nob; | |
1947 | int rc; | |
1948 | int rc2; | |
1949 | sigset_t blocked; | |
d7e09d03 | 1950 | |
6c9e5a55 AS |
1951 | infosz = offsetof(lnet_ping_info_t, pi_ni[n_ids]); |
1952 | ||
d7e09d03 PT |
1953 | if (n_ids <= 0 || |
1954 | id.nid == LNET_NID_ANY || | |
1955 | timeout_ms > 500000 || /* arbitrary limit! */ | |
1956 | n_ids > 20) /* arbitrary limit! */ | |
1957 | return -EINVAL; | |
1958 | ||
1959 | if (id.pid == LNET_PID_ANY) | |
1960 | id.pid = LUSTRE_SRV_LNET_PID; | |
1961 | ||
1962 | LIBCFS_ALLOC(info, infosz); | |
06ace26e | 1963 | if (!info) |
d7e09d03 PT |
1964 | return -ENOMEM; |
1965 | ||
1966 | /* NB 2 events max (including any unlink event) */ | |
1967 | rc = LNetEQAlloc(2, LNET_EQ_HANDLER_NONE, &eqh); | |
5fd88337 | 1968 | if (rc) { |
d7e09d03 PT |
1969 | CERROR("Can't allocate EQ: %d\n", rc); |
1970 | goto out_0; | |
1971 | } | |
1972 | ||
1973 | /* initialize md content */ | |
1974 | md.start = info; | |
1975 | md.length = infosz; | |
1976 | md.threshold = 2; /*GET/REPLY*/ | |
1977 | md.max_size = 0; | |
1978 | md.options = LNET_MD_TRUNCATE; | |
1979 | md.user_ptr = NULL; | |
1980 | md.eq_handle = eqh; | |
1981 | ||
1982 | rc = LNetMDBind(md, LNET_UNLINK, &mdh); | |
5fd88337 | 1983 | if (rc) { |
d7e09d03 PT |
1984 | CERROR("Can't bind MD: %d\n", rc); |
1985 | goto out_1; | |
1986 | } | |
1987 | ||
1988 | rc = LNetGet(LNET_NID_ANY, mdh, id, | |
1989 | LNET_RESERVED_PORTAL, | |
1990 | LNET_PROTO_PING_MATCHBITS, 0); | |
1991 | ||
5fd88337 | 1992 | if (rc) { |
d7e09d03 PT |
1993 | /* Don't CERROR; this could be deliberate! */ |
1994 | ||
1995 | rc2 = LNetMDUnlink(mdh); | |
5fd88337 | 1996 | LASSERT(!rc2); |
d7e09d03 PT |
1997 | |
1998 | /* NB must wait for the UNLINK event below... */ | |
1999 | unlinked = 1; | |
2000 | timeout_ms = a_long_time; | |
2001 | } | |
2002 | ||
2003 | do { | |
2004 | /* MUST block for unlink to complete */ | |
2005 | if (unlinked) | |
2006 | blocked = cfs_block_allsigs(); | |
2007 | ||
2008 | rc2 = LNetEQPoll(&eqh, 1, timeout_ms, &event, &which); | |
2009 | ||
2010 | if (unlinked) | |
2011 | cfs_restore_sigs(blocked); | |
2012 | ||
2013 | CDEBUG(D_NET, "poll %d(%d %d)%s\n", rc2, | |
2014 | (rc2 <= 0) ? -1 : event.type, | |
2015 | (rc2 <= 0) ? -1 : event.status, | |
2016 | (rc2 > 0 && event.unlinked) ? " unlinked" : ""); | |
2017 | ||
3b7566d9 | 2018 | LASSERT(rc2 != -EOVERFLOW); /* can't miss anything */ |
d7e09d03 | 2019 | |
5fd88337 | 2020 | if (rc2 <= 0 || event.status) { |
d7e09d03 | 2021 | /* timeout or error */ |
5fd88337 | 2022 | if (!replied && !rc) |
d7e09d03 | 2023 | rc = (rc2 < 0) ? rc2 : |
5fd88337 | 2024 | !rc2 ? -ETIMEDOUT : |
d7e09d03 PT |
2025 | event.status; |
2026 | ||
2027 | if (!unlinked) { | |
2028 | /* Ensure completion in finite time... */ | |
2029 | LNetMDUnlink(mdh); | |
2030 | /* No assertion (racing with network) */ | |
2031 | unlinked = 1; | |
2032 | timeout_ms = a_long_time; | |
5fd88337 | 2033 | } else if (!rc2) { |
d7e09d03 PT |
2034 | /* timed out waiting for unlink */ |
2035 | CWARN("ping %s: late network completion\n", | |
2036 | libcfs_id2str(id)); | |
2037 | } | |
2038 | } else if (event.type == LNET_EVENT_REPLY) { | |
2039 | replied = 1; | |
2040 | rc = event.mlength; | |
2041 | } | |
2042 | ||
2043 | } while (rc2 <= 0 || !event.unlinked); | |
2044 | ||
2045 | if (!replied) { | |
2046 | if (rc >= 0) | |
2047 | CWARN("%s: Unexpected rc >= 0 but no reply!\n", | |
2048 | libcfs_id2str(id)); | |
2049 | rc = -EIO; | |
2050 | goto out_1; | |
2051 | } | |
2052 | ||
2053 | nob = rc; | |
3b7566d9 | 2054 | LASSERT(nob >= 0 && nob <= infosz); |
d7e09d03 PT |
2055 | |
2056 | rc = -EPROTO; /* if I can't parse... */ | |
2057 | ||
2058 | if (nob < 8) { | |
2059 | /* can't check magic/version */ | |
2060 | CERROR("%s: ping info too short %d\n", | |
2061 | libcfs_id2str(id), nob); | |
2062 | goto out_1; | |
2063 | } | |
2064 | ||
2065 | if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) { | |
2066 | lnet_swap_pinginfo(info); | |
2067 | } else if (info->pi_magic != LNET_PROTO_PING_MAGIC) { | |
2068 | CERROR("%s: Unexpected magic %08x\n", | |
2069 | libcfs_id2str(id), info->pi_magic); | |
2070 | goto out_1; | |
2071 | } | |
2072 | ||
5fd88337 | 2073 | if (!(info->pi_features & LNET_PING_FEAT_NI_STATUS)) { |
d7e09d03 PT |
2074 | CERROR("%s: ping w/o NI status: 0x%x\n", |
2075 | libcfs_id2str(id), info->pi_features); | |
2076 | goto out_1; | |
2077 | } | |
2078 | ||
2079 | if (nob < offsetof(lnet_ping_info_t, pi_ni[0])) { | |
2080 | CERROR("%s: Short reply %d(%d min)\n", libcfs_id2str(id), | |
2081 | nob, (int)offsetof(lnet_ping_info_t, pi_ni[0])); | |
2082 | goto out_1; | |
2083 | } | |
2084 | ||
2085 | if (info->pi_nnis < n_ids) | |
2086 | n_ids = info->pi_nnis; | |
2087 | ||
2088 | if (nob < offsetof(lnet_ping_info_t, pi_ni[n_ids])) { | |
2089 | CERROR("%s: Short reply %d(%d expected)\n", libcfs_id2str(id), | |
2090 | nob, (int)offsetof(lnet_ping_info_t, pi_ni[n_ids])); | |
2091 | goto out_1; | |
2092 | } | |
2093 | ||
2094 | rc = -EFAULT; /* If I SEGV... */ | |
2095 | ||
751a624a | 2096 | memset(&tmpid, 0, sizeof(tmpid)); |
d7e09d03 PT |
2097 | for (i = 0; i < n_ids; i++) { |
2098 | tmpid.pid = info->pi_pid; | |
2099 | tmpid.nid = info->pi_ni[i].ns_nid; | |
2100 | if (copy_to_user(&ids[i], &tmpid, sizeof(tmpid))) | |
2101 | goto out_1; | |
2102 | } | |
2103 | rc = info->pi_nnis; | |
2104 | ||
2105 | out_1: | |
2106 | rc2 = LNetEQFree(eqh); | |
5fd88337 | 2107 | if (rc2) |
d7e09d03 | 2108 | CERROR("rc2 %d\n", rc2); |
5fd88337 | 2109 | LASSERT(!rc2); |
d7e09d03 PT |
2110 | |
2111 | out_0: | |
2112 | LIBCFS_FREE(info, infosz); | |
2113 | return rc; | |
2114 | } |