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