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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
30 | * Copyright (c) 2012, Intel Corporation. | |
31 | */ | |
32 | /* | |
33 | * This file is part of Lustre, http://www.lustre.org/ | |
34 | * Lustre is a trademark of Sun Microsystems, Inc. | |
35 | * | |
36 | * lnet/selftest/rpc.c | |
37 | * | |
38 | * Author: Isaac Huang <isaac@clusterfs.com> | |
39 | * | |
40 | * 2012-05-13: Liang Zhen <liang@whamcloud.com> | |
41 | * - percpt data for service to improve smp performance | |
42 | * - code cleanup | |
43 | */ | |
44 | ||
45 | #define DEBUG_SUBSYSTEM S_LNET | |
46 | ||
47 | #include "selftest.h" | |
48 | ||
49 | typedef enum { | |
50 | SRPC_STATE_NONE, | |
51 | SRPC_STATE_NI_INIT, | |
52 | SRPC_STATE_EQ_INIT, | |
53 | SRPC_STATE_RUNNING, | |
54 | SRPC_STATE_STOPPING, | |
55 | } srpc_state_t; | |
56 | ||
57 | struct smoketest_rpc { | |
58 | spinlock_t rpc_glock; /* global lock */ | |
59 | srpc_service_t *rpc_services[SRPC_SERVICE_MAX_ID + 1]; | |
60 | lnet_handle_eq_t rpc_lnet_eq; /* _the_ LNet event queue */ | |
61 | srpc_state_t rpc_state; | |
62 | srpc_counters_t rpc_counters; | |
63 | __u64 rpc_matchbits; /* matchbits counter */ | |
64 | } srpc_data; | |
65 | ||
66 | static inline int | |
67 | srpc_serv_portal(int svc_id) | |
68 | { | |
69 | return svc_id < SRPC_FRAMEWORK_SERVICE_MAX_ID ? | |
70 | SRPC_FRAMEWORK_REQUEST_PORTAL : SRPC_REQUEST_PORTAL; | |
71 | } | |
72 | ||
73 | /* forward ref's */ | |
74 | int srpc_handle_rpc (swi_workitem_t *wi); | |
75 | ||
76 | void srpc_get_counters (srpc_counters_t *cnt) | |
77 | { | |
78 | spin_lock(&srpc_data.rpc_glock); | |
79 | *cnt = srpc_data.rpc_counters; | |
80 | spin_unlock(&srpc_data.rpc_glock); | |
81 | } | |
82 | ||
83 | void srpc_set_counters (const srpc_counters_t *cnt) | |
84 | { | |
85 | spin_lock(&srpc_data.rpc_glock); | |
86 | srpc_data.rpc_counters = *cnt; | |
87 | spin_unlock(&srpc_data.rpc_glock); | |
88 | } | |
89 | ||
90 | int | |
91 | srpc_add_bulk_page(srpc_bulk_t *bk, struct page *pg, int i, int nob) | |
92 | { | |
93 | nob = min(nob, (int)PAGE_CACHE_SIZE); | |
94 | ||
95 | LASSERT(nob > 0); | |
96 | LASSERT(i >= 0 && i < bk->bk_niov); | |
97 | ||
98 | bk->bk_iovs[i].kiov_offset = 0; | |
99 | bk->bk_iovs[i].kiov_page = pg; | |
100 | bk->bk_iovs[i].kiov_len = nob; | |
101 | return nob; | |
102 | } | |
103 | ||
104 | void | |
105 | srpc_free_bulk (srpc_bulk_t *bk) | |
106 | { | |
107 | int i; | |
108 | struct page *pg; | |
109 | ||
110 | LASSERT (bk != NULL); | |
111 | ||
112 | for (i = 0; i < bk->bk_niov; i++) { | |
113 | pg = bk->bk_iovs[i].kiov_page; | |
114 | if (pg == NULL) break; | |
115 | ||
116 | __free_page(pg); | |
117 | } | |
118 | ||
119 | LIBCFS_FREE(bk, offsetof(srpc_bulk_t, bk_iovs[bk->bk_niov])); | |
120 | return; | |
121 | } | |
122 | ||
123 | srpc_bulk_t * | |
124 | srpc_alloc_bulk(int cpt, unsigned bulk_npg, unsigned bulk_len, int sink) | |
125 | { | |
126 | srpc_bulk_t *bk; | |
127 | struct page **pages; | |
128 | int i; | |
129 | ||
130 | LASSERT(bulk_npg > 0 && bulk_npg <= LNET_MAX_IOV); | |
131 | ||
132 | LIBCFS_CPT_ALLOC(bk, lnet_cpt_table(), cpt, | |
133 | offsetof(srpc_bulk_t, bk_iovs[bulk_npg])); | |
134 | if (bk == NULL) { | |
135 | CERROR("Can't allocate descriptor for %d pages\n", bulk_npg); | |
136 | return NULL; | |
137 | } | |
138 | ||
139 | memset(bk, 0, offsetof(srpc_bulk_t, bk_iovs[bulk_npg])); | |
140 | bk->bk_sink = sink; | |
141 | bk->bk_len = bulk_len; | |
142 | bk->bk_niov = bulk_npg; | |
143 | UNUSED(pages); | |
144 | ||
145 | for (i = 0; i < bulk_npg; i++) { | |
146 | struct page *pg; | |
147 | int nob; | |
148 | ||
49c02a75 PT |
149 | pg = alloc_pages_node(cfs_cpt_spread_node(lnet_cpt_table(), cpt), |
150 | GFP_IOFS, 0); | |
d7e09d03 PT |
151 | if (pg == NULL) { |
152 | CERROR("Can't allocate page %d of %d\n", i, bulk_npg); | |
153 | srpc_free_bulk(bk); | |
154 | return NULL; | |
155 | } | |
156 | ||
157 | nob = srpc_add_bulk_page(bk, pg, i, bulk_len); | |
158 | bulk_len -= nob; | |
159 | } | |
160 | ||
161 | return bk; | |
162 | } | |
163 | ||
164 | static inline __u64 | |
165 | srpc_next_id (void) | |
166 | { | |
167 | __u64 id; | |
168 | ||
169 | spin_lock(&srpc_data.rpc_glock); | |
170 | id = srpc_data.rpc_matchbits++; | |
171 | spin_unlock(&srpc_data.rpc_glock); | |
172 | return id; | |
173 | } | |
174 | ||
175 | void | |
176 | srpc_init_server_rpc(struct srpc_server_rpc *rpc, | |
177 | struct srpc_service_cd *scd, | |
178 | struct srpc_buffer *buffer) | |
179 | { | |
180 | memset(rpc, 0, sizeof(*rpc)); | |
181 | swi_init_workitem(&rpc->srpc_wi, rpc, srpc_handle_rpc, | |
182 | srpc_serv_is_framework(scd->scd_svc) ? | |
183 | lst_sched_serial : lst_sched_test[scd->scd_cpt]); | |
184 | ||
185 | rpc->srpc_ev.ev_fired = 1; /* no event expected now */ | |
186 | ||
187 | rpc->srpc_scd = scd; | |
188 | rpc->srpc_reqstbuf = buffer; | |
189 | rpc->srpc_peer = buffer->buf_peer; | |
190 | rpc->srpc_self = buffer->buf_self; | |
191 | LNetInvalidateHandle(&rpc->srpc_replymdh); | |
192 | } | |
193 | ||
194 | static void | |
195 | srpc_service_fini(struct srpc_service *svc) | |
196 | { | |
197 | struct srpc_service_cd *scd; | |
198 | struct srpc_server_rpc *rpc; | |
199 | struct srpc_buffer *buf; | |
200 | struct list_head *q; | |
201 | int i; | |
202 | ||
203 | if (svc->sv_cpt_data == NULL) | |
204 | return; | |
205 | ||
206 | cfs_percpt_for_each(scd, i, svc->sv_cpt_data) { | |
207 | while (1) { | |
208 | if (!list_empty(&scd->scd_buf_posted)) | |
209 | q = &scd->scd_buf_posted; | |
210 | else if (!list_empty(&scd->scd_buf_blocked)) | |
211 | q = &scd->scd_buf_blocked; | |
212 | else | |
213 | break; | |
214 | ||
215 | while (!list_empty(q)) { | |
216 | buf = list_entry(q->next, | |
217 | struct srpc_buffer, | |
218 | buf_list); | |
219 | list_del(&buf->buf_list); | |
220 | LIBCFS_FREE(buf, sizeof(*buf)); | |
221 | } | |
222 | } | |
223 | ||
224 | LASSERT(list_empty(&scd->scd_rpc_active)); | |
225 | ||
226 | while (!list_empty(&scd->scd_rpc_free)) { | |
227 | rpc = list_entry(scd->scd_rpc_free.next, | |
228 | struct srpc_server_rpc, | |
229 | srpc_list); | |
230 | list_del(&rpc->srpc_list); | |
231 | LIBCFS_FREE(rpc, sizeof(*rpc)); | |
232 | } | |
233 | } | |
234 | ||
235 | cfs_percpt_free(svc->sv_cpt_data); | |
236 | svc->sv_cpt_data = NULL; | |
237 | } | |
238 | ||
239 | static int | |
240 | srpc_service_nrpcs(struct srpc_service *svc) | |
241 | { | |
242 | int nrpcs = svc->sv_wi_total / svc->sv_ncpts; | |
243 | ||
244 | return srpc_serv_is_framework(svc) ? | |
245 | max(nrpcs, SFW_FRWK_WI_MIN) : max(nrpcs, SFW_TEST_WI_MIN); | |
246 | } | |
247 | ||
248 | int srpc_add_buffer(struct swi_workitem *wi); | |
249 | ||
250 | static int | |
251 | srpc_service_init(struct srpc_service *svc) | |
252 | { | |
253 | struct srpc_service_cd *scd; | |
254 | struct srpc_server_rpc *rpc; | |
255 | int nrpcs; | |
256 | int i; | |
257 | int j; | |
258 | ||
259 | svc->sv_shuttingdown = 0; | |
260 | ||
261 | svc->sv_cpt_data = cfs_percpt_alloc(lnet_cpt_table(), | |
262 | sizeof(struct srpc_service_cd)); | |
263 | if (svc->sv_cpt_data == NULL) | |
264 | return -ENOMEM; | |
265 | ||
266 | svc->sv_ncpts = srpc_serv_is_framework(svc) ? | |
267 | 1 : cfs_cpt_number(lnet_cpt_table()); | |
268 | nrpcs = srpc_service_nrpcs(svc); | |
269 | ||
270 | cfs_percpt_for_each(scd, i, svc->sv_cpt_data) { | |
271 | scd->scd_cpt = i; | |
272 | scd->scd_svc = svc; | |
273 | spin_lock_init(&scd->scd_lock); | |
274 | INIT_LIST_HEAD(&scd->scd_rpc_free); | |
275 | INIT_LIST_HEAD(&scd->scd_rpc_active); | |
276 | INIT_LIST_HEAD(&scd->scd_buf_posted); | |
277 | INIT_LIST_HEAD(&scd->scd_buf_blocked); | |
278 | ||
279 | scd->scd_ev.ev_data = scd; | |
280 | scd->scd_ev.ev_type = SRPC_REQUEST_RCVD; | |
281 | ||
282 | /* NB: don't use lst_sched_serial for adding buffer, | |
283 | * see details in srpc_service_add_buffers() */ | |
284 | swi_init_workitem(&scd->scd_buf_wi, scd, | |
285 | srpc_add_buffer, lst_sched_test[i]); | |
286 | ||
287 | if (i != 0 && srpc_serv_is_framework(svc)) { | |
288 | /* NB: framework service only needs srpc_service_cd for | |
289 | * one partition, but we allocate for all to make | |
290 | * it easier to implement, it will waste a little | |
291 | * memory but nobody should care about this */ | |
292 | continue; | |
293 | } | |
294 | ||
295 | for (j = 0; j < nrpcs; j++) { | |
296 | LIBCFS_CPT_ALLOC(rpc, lnet_cpt_table(), | |
297 | i, sizeof(*rpc)); | |
298 | if (rpc == NULL) { | |
299 | srpc_service_fini(svc); | |
300 | return -ENOMEM; | |
301 | } | |
302 | list_add(&rpc->srpc_list, &scd->scd_rpc_free); | |
303 | } | |
304 | } | |
305 | ||
306 | return 0; | |
307 | } | |
308 | ||
309 | int | |
310 | srpc_add_service(struct srpc_service *sv) | |
311 | { | |
312 | int id = sv->sv_id; | |
313 | ||
314 | LASSERT(0 <= id && id <= SRPC_SERVICE_MAX_ID); | |
315 | ||
316 | if (srpc_service_init(sv) != 0) | |
317 | return -ENOMEM; | |
318 | ||
319 | spin_lock(&srpc_data.rpc_glock); | |
320 | ||
321 | LASSERT(srpc_data.rpc_state == SRPC_STATE_RUNNING); | |
322 | ||
323 | if (srpc_data.rpc_services[id] != NULL) { | |
324 | spin_unlock(&srpc_data.rpc_glock); | |
325 | goto failed; | |
326 | } | |
327 | ||
328 | srpc_data.rpc_services[id] = sv; | |
329 | spin_unlock(&srpc_data.rpc_glock); | |
330 | ||
331 | CDEBUG(D_NET, "Adding service: id %d, name %s\n", id, sv->sv_name); | |
332 | return 0; | |
333 | ||
334 | failed: | |
335 | srpc_service_fini(sv); | |
336 | return -EBUSY; | |
337 | } | |
338 | ||
339 | int | |
340 | srpc_remove_service (srpc_service_t *sv) | |
341 | { | |
342 | int id = sv->sv_id; | |
343 | ||
344 | spin_lock(&srpc_data.rpc_glock); | |
345 | ||
346 | if (srpc_data.rpc_services[id] != sv) { | |
347 | spin_unlock(&srpc_data.rpc_glock); | |
348 | return -ENOENT; | |
349 | } | |
350 | ||
351 | srpc_data.rpc_services[id] = NULL; | |
352 | spin_unlock(&srpc_data.rpc_glock); | |
353 | return 0; | |
354 | } | |
355 | ||
356 | int | |
357 | srpc_post_passive_rdma(int portal, int local, __u64 matchbits, void *buf, | |
358 | int len, int options, lnet_process_id_t peer, | |
359 | lnet_handle_md_t *mdh, srpc_event_t *ev) | |
360 | { | |
361 | int rc; | |
362 | lnet_md_t md; | |
363 | lnet_handle_me_t meh; | |
364 | ||
365 | rc = LNetMEAttach(portal, peer, matchbits, 0, LNET_UNLINK, | |
366 | local ? LNET_INS_LOCAL : LNET_INS_AFTER, &meh); | |
367 | if (rc != 0) { | |
368 | CERROR ("LNetMEAttach failed: %d\n", rc); | |
369 | LASSERT (rc == -ENOMEM); | |
370 | return -ENOMEM; | |
371 | } | |
372 | ||
373 | md.threshold = 1; | |
374 | md.user_ptr = ev; | |
375 | md.start = buf; | |
376 | md.length = len; | |
377 | md.options = options; | |
378 | md.eq_handle = srpc_data.rpc_lnet_eq; | |
379 | ||
380 | rc = LNetMDAttach(meh, md, LNET_UNLINK, mdh); | |
381 | if (rc != 0) { | |
382 | CERROR ("LNetMDAttach failed: %d\n", rc); | |
383 | LASSERT (rc == -ENOMEM); | |
384 | ||
385 | rc = LNetMEUnlink(meh); | |
386 | LASSERT (rc == 0); | |
387 | return -ENOMEM; | |
388 | } | |
389 | ||
390 | CDEBUG (D_NET, | |
391 | "Posted passive RDMA: peer %s, portal %d, matchbits "LPX64"\n", | |
392 | libcfs_id2str(peer), portal, matchbits); | |
393 | return 0; | |
394 | } | |
395 | ||
396 | int | |
397 | srpc_post_active_rdma(int portal, __u64 matchbits, void *buf, int len, | |
398 | int options, lnet_process_id_t peer, lnet_nid_t self, | |
399 | lnet_handle_md_t *mdh, srpc_event_t *ev) | |
400 | { | |
401 | int rc; | |
402 | lnet_md_t md; | |
403 | ||
404 | md.user_ptr = ev; | |
405 | md.start = buf; | |
406 | md.length = len; | |
407 | md.eq_handle = srpc_data.rpc_lnet_eq; | |
408 | md.threshold = ((options & LNET_MD_OP_GET) != 0) ? 2 : 1; | |
409 | md.options = options & ~(LNET_MD_OP_PUT | LNET_MD_OP_GET); | |
410 | ||
411 | rc = LNetMDBind(md, LNET_UNLINK, mdh); | |
412 | if (rc != 0) { | |
413 | CERROR ("LNetMDBind failed: %d\n", rc); | |
414 | LASSERT (rc == -ENOMEM); | |
415 | return -ENOMEM; | |
416 | } | |
417 | ||
418 | /* this is kind of an abuse of the LNET_MD_OP_{PUT,GET} options. | |
419 | * they're only meaningful for MDs attached to an ME (i.e. passive | |
420 | * buffers... */ | |
421 | if ((options & LNET_MD_OP_PUT) != 0) { | |
422 | rc = LNetPut(self, *mdh, LNET_NOACK_REQ, peer, | |
423 | portal, matchbits, 0, 0); | |
424 | } else { | |
425 | LASSERT ((options & LNET_MD_OP_GET) != 0); | |
426 | ||
427 | rc = LNetGet(self, *mdh, peer, portal, matchbits, 0); | |
428 | } | |
429 | ||
430 | if (rc != 0) { | |
431 | CERROR ("LNet%s(%s, %d, "LPD64") failed: %d\n", | |
432 | ((options & LNET_MD_OP_PUT) != 0) ? "Put" : "Get", | |
433 | libcfs_id2str(peer), portal, matchbits, rc); | |
434 | ||
435 | /* The forthcoming unlink event will complete this operation | |
436 | * with failure, so fall through and return success here. | |
437 | */ | |
438 | rc = LNetMDUnlink(*mdh); | |
439 | LASSERT (rc == 0); | |
440 | } else { | |
441 | CDEBUG (D_NET, | |
442 | "Posted active RDMA: peer %s, portal %u, matchbits "LPX64"\n", | |
443 | libcfs_id2str(peer), portal, matchbits); | |
444 | } | |
445 | return 0; | |
446 | } | |
447 | ||
448 | int | |
449 | srpc_post_active_rqtbuf(lnet_process_id_t peer, int service, void *buf, | |
450 | int len, lnet_handle_md_t *mdh, srpc_event_t *ev) | |
451 | { | |
452 | return srpc_post_active_rdma(srpc_serv_portal(service), service, | |
453 | buf, len, LNET_MD_OP_PUT, peer, | |
454 | LNET_NID_ANY, mdh, ev); | |
455 | } | |
456 | ||
457 | int | |
458 | srpc_post_passive_rqtbuf(int service, int local, void *buf, int len, | |
459 | lnet_handle_md_t *mdh, srpc_event_t *ev) | |
460 | { | |
461 | lnet_process_id_t any = {0}; | |
462 | ||
463 | any.nid = LNET_NID_ANY; | |
464 | any.pid = LNET_PID_ANY; | |
465 | ||
466 | return srpc_post_passive_rdma(srpc_serv_portal(service), | |
467 | local, service, buf, len, | |
468 | LNET_MD_OP_PUT, any, mdh, ev); | |
469 | } | |
470 | ||
471 | int | |
472 | srpc_service_post_buffer(struct srpc_service_cd *scd, struct srpc_buffer *buf) | |
473 | { | |
474 | struct srpc_service *sv = scd->scd_svc; | |
475 | struct srpc_msg *msg = &buf->buf_msg; | |
476 | int rc; | |
477 | ||
478 | LNetInvalidateHandle(&buf->buf_mdh); | |
479 | list_add(&buf->buf_list, &scd->scd_buf_posted); | |
480 | scd->scd_buf_nposted++; | |
481 | spin_unlock(&scd->scd_lock); | |
482 | ||
483 | rc = srpc_post_passive_rqtbuf(sv->sv_id, | |
484 | !srpc_serv_is_framework(sv), | |
485 | msg, sizeof(*msg), &buf->buf_mdh, | |
486 | &scd->scd_ev); | |
487 | ||
488 | /* At this point, a RPC (new or delayed) may have arrived in | |
489 | * msg and its event handler has been called. So we must add | |
490 | * buf to scd_buf_posted _before_ dropping scd_lock */ | |
491 | ||
492 | spin_lock(&scd->scd_lock); | |
493 | ||
494 | if (rc == 0) { | |
495 | if (!sv->sv_shuttingdown) | |
496 | return 0; | |
497 | ||
498 | spin_unlock(&scd->scd_lock); | |
499 | /* srpc_shutdown_service might have tried to unlink me | |
500 | * when my buf_mdh was still invalid */ | |
501 | LNetMDUnlink(buf->buf_mdh); | |
502 | spin_lock(&scd->scd_lock); | |
503 | return 0; | |
504 | } | |
505 | ||
506 | scd->scd_buf_nposted--; | |
507 | if (sv->sv_shuttingdown) | |
508 | return rc; /* don't allow to change scd_buf_posted */ | |
509 | ||
510 | list_del(&buf->buf_list); | |
511 | spin_unlock(&scd->scd_lock); | |
512 | ||
513 | LIBCFS_FREE(buf, sizeof(*buf)); | |
514 | ||
515 | spin_lock(&scd->scd_lock); | |
516 | return rc; | |
517 | } | |
518 | ||
519 | int | |
520 | srpc_add_buffer(struct swi_workitem *wi) | |
521 | { | |
522 | struct srpc_service_cd *scd = wi->swi_workitem.wi_data; | |
523 | struct srpc_buffer *buf; | |
524 | int rc = 0; | |
525 | ||
526 | /* it's called by workitem scheduler threads, these threads | |
527 | * should have been set CPT affinity, so buffers will be posted | |
528 | * on CPT local list of Portal */ | |
529 | spin_lock(&scd->scd_lock); | |
530 | ||
531 | while (scd->scd_buf_adjust > 0 && | |
532 | !scd->scd_svc->sv_shuttingdown) { | |
533 | scd->scd_buf_adjust--; /* consume it */ | |
534 | scd->scd_buf_posting++; | |
535 | ||
536 | spin_unlock(&scd->scd_lock); | |
537 | ||
538 | LIBCFS_ALLOC(buf, sizeof(*buf)); | |
539 | if (buf == NULL) { | |
540 | CERROR("Failed to add new buf to service: %s\n", | |
541 | scd->scd_svc->sv_name); | |
542 | spin_lock(&scd->scd_lock); | |
543 | rc = -ENOMEM; | |
544 | break; | |
545 | } | |
546 | ||
547 | spin_lock(&scd->scd_lock); | |
548 | if (scd->scd_svc->sv_shuttingdown) { | |
549 | spin_unlock(&scd->scd_lock); | |
550 | LIBCFS_FREE(buf, sizeof(*buf)); | |
551 | ||
552 | spin_lock(&scd->scd_lock); | |
553 | rc = -ESHUTDOWN; | |
554 | break; | |
555 | } | |
556 | ||
557 | rc = srpc_service_post_buffer(scd, buf); | |
558 | if (rc != 0) | |
559 | break; /* buf has been freed inside */ | |
560 | ||
561 | LASSERT(scd->scd_buf_posting > 0); | |
562 | scd->scd_buf_posting--; | |
563 | scd->scd_buf_total++; | |
564 | scd->scd_buf_low = MAX(2, scd->scd_buf_total / 4); | |
565 | } | |
566 | ||
567 | if (rc != 0) { | |
568 | scd->scd_buf_err_stamp = cfs_time_current_sec(); | |
569 | scd->scd_buf_err = rc; | |
570 | ||
571 | LASSERT(scd->scd_buf_posting > 0); | |
572 | scd->scd_buf_posting--; | |
573 | } | |
574 | ||
575 | spin_unlock(&scd->scd_lock); | |
576 | return 0; | |
577 | } | |
578 | ||
579 | int | |
580 | srpc_service_add_buffers(struct srpc_service *sv, int nbuffer) | |
581 | { | |
582 | struct srpc_service_cd *scd; | |
583 | int rc = 0; | |
584 | int i; | |
585 | ||
586 | LASSERTF(nbuffer > 0, "nbuffer must be positive: %d\n", nbuffer); | |
587 | ||
588 | cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { | |
589 | spin_lock(&scd->scd_lock); | |
590 | ||
591 | scd->scd_buf_err = 0; | |
592 | scd->scd_buf_err_stamp = 0; | |
593 | scd->scd_buf_posting = 0; | |
594 | scd->scd_buf_adjust = nbuffer; | |
595 | /* start to post buffers */ | |
596 | swi_schedule_workitem(&scd->scd_buf_wi); | |
597 | spin_unlock(&scd->scd_lock); | |
598 | ||
599 | /* framework service only post buffer for one partition */ | |
600 | if (srpc_serv_is_framework(sv)) | |
601 | break; | |
602 | } | |
603 | ||
604 | cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { | |
605 | spin_lock(&scd->scd_lock); | |
606 | /* | |
607 | * NB: srpc_service_add_buffers() can be called inside | |
608 | * thread context of lst_sched_serial, and we don't normally | |
609 | * allow to sleep inside thread context of WI scheduler | |
610 | * because it will block current scheduler thread from doing | |
611 | * anything else, even worse, it could deadlock if it's | |
612 | * waiting on result from another WI of the same scheduler. | |
613 | * However, it's safe at here because scd_buf_wi is scheduled | |
614 | * by thread in a different WI scheduler (lst_sched_test), | |
615 | * so we don't have any risk of deadlock, though this could | |
616 | * block all WIs pending on lst_sched_serial for a moment | |
617 | * which is not good but not fatal. | |
618 | */ | |
619 | lst_wait_until(scd->scd_buf_err != 0 || | |
620 | (scd->scd_buf_adjust == 0 && | |
621 | scd->scd_buf_posting == 0), | |
622 | scd->scd_lock, "waiting for adding buffer\n"); | |
623 | ||
624 | if (scd->scd_buf_err != 0 && rc == 0) | |
625 | rc = scd->scd_buf_err; | |
626 | ||
627 | spin_unlock(&scd->scd_lock); | |
628 | } | |
629 | ||
630 | return rc; | |
631 | } | |
632 | ||
633 | void | |
634 | srpc_service_remove_buffers(struct srpc_service *sv, int nbuffer) | |
635 | { | |
636 | struct srpc_service_cd *scd; | |
637 | int num; | |
638 | int i; | |
639 | ||
640 | LASSERT(!sv->sv_shuttingdown); | |
641 | ||
642 | cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { | |
643 | spin_lock(&scd->scd_lock); | |
644 | ||
645 | num = scd->scd_buf_total + scd->scd_buf_posting; | |
646 | scd->scd_buf_adjust -= min(nbuffer, num); | |
647 | ||
648 | spin_unlock(&scd->scd_lock); | |
649 | } | |
650 | } | |
651 | ||
652 | /* returns 1 if sv has finished, otherwise 0 */ | |
653 | int | |
654 | srpc_finish_service(struct srpc_service *sv) | |
655 | { | |
656 | struct srpc_service_cd *scd; | |
657 | struct srpc_server_rpc *rpc; | |
658 | int i; | |
659 | ||
660 | LASSERT(sv->sv_shuttingdown); /* srpc_shutdown_service called */ | |
661 | ||
662 | cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { | |
663 | spin_lock(&scd->scd_lock); | |
f8c47be4 SB |
664 | if (!swi_deschedule_workitem(&scd->scd_buf_wi)) { |
665 | spin_unlock(&scd->scd_lock); | |
d7e09d03 | 666 | return 0; |
f8c47be4 | 667 | } |
d7e09d03 PT |
668 | |
669 | if (scd->scd_buf_nposted > 0) { | |
670 | CDEBUG(D_NET, "waiting for %d posted buffers to unlink", | |
671 | scd->scd_buf_nposted); | |
672 | spin_unlock(&scd->scd_lock); | |
673 | return 0; | |
674 | } | |
675 | ||
676 | if (list_empty(&scd->scd_rpc_active)) { | |
677 | spin_unlock(&scd->scd_lock); | |
678 | continue; | |
679 | } | |
680 | ||
681 | rpc = list_entry(scd->scd_rpc_active.next, | |
682 | struct srpc_server_rpc, srpc_list); | |
683 | CNETERR("Active RPC %p on shutdown: sv %s, peer %s, " | |
684 | "wi %s scheduled %d running %d, " | |
685 | "ev fired %d type %d status %d lnet %d\n", | |
686 | rpc, sv->sv_name, libcfs_id2str(rpc->srpc_peer), | |
687 | swi_state2str(rpc->srpc_wi.swi_state), | |
688 | rpc->srpc_wi.swi_workitem.wi_scheduled, | |
689 | rpc->srpc_wi.swi_workitem.wi_running, | |
690 | rpc->srpc_ev.ev_fired, rpc->srpc_ev.ev_type, | |
691 | rpc->srpc_ev.ev_status, rpc->srpc_ev.ev_lnet); | |
692 | spin_unlock(&scd->scd_lock); | |
693 | return 0; | |
694 | } | |
695 | ||
696 | /* no lock needed from now on */ | |
697 | srpc_service_fini(sv); | |
698 | return 1; | |
699 | } | |
700 | ||
701 | /* called with sv->sv_lock held */ | |
702 | void | |
703 | srpc_service_recycle_buffer(struct srpc_service_cd *scd, srpc_buffer_t *buf) | |
704 | { | |
705 | if (!scd->scd_svc->sv_shuttingdown && scd->scd_buf_adjust >= 0) { | |
706 | if (srpc_service_post_buffer(scd, buf) != 0) { | |
707 | CWARN("Failed to post %s buffer\n", | |
708 | scd->scd_svc->sv_name); | |
709 | } | |
710 | return; | |
711 | } | |
712 | ||
713 | /* service is shutting down, or we want to recycle some buffers */ | |
714 | scd->scd_buf_total--; | |
715 | ||
716 | if (scd->scd_buf_adjust < 0) { | |
717 | scd->scd_buf_adjust++; | |
718 | if (scd->scd_buf_adjust < 0 && | |
719 | scd->scd_buf_total == 0 && scd->scd_buf_posting == 0) { | |
720 | CDEBUG(D_INFO, | |
721 | "Try to recyle %d buffers but nothing left\n", | |
722 | scd->scd_buf_adjust); | |
723 | scd->scd_buf_adjust = 0; | |
724 | } | |
725 | } | |
726 | ||
727 | spin_unlock(&scd->scd_lock); | |
728 | LIBCFS_FREE(buf, sizeof(*buf)); | |
729 | spin_lock(&scd->scd_lock); | |
730 | } | |
731 | ||
732 | void | |
733 | srpc_abort_service(struct srpc_service *sv) | |
734 | { | |
735 | struct srpc_service_cd *scd; | |
736 | struct srpc_server_rpc *rpc; | |
737 | int i; | |
738 | ||
739 | CDEBUG(D_NET, "Aborting service: id %d, name %s\n", | |
740 | sv->sv_id, sv->sv_name); | |
741 | ||
742 | cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { | |
743 | spin_lock(&scd->scd_lock); | |
744 | ||
745 | /* schedule in-flight RPCs to notice the abort, NB: | |
746 | * racing with incoming RPCs; complete fix should make test | |
747 | * RPCs carry session ID in its headers */ | |
748 | list_for_each_entry(rpc, &scd->scd_rpc_active, srpc_list) { | |
749 | rpc->srpc_aborted = 1; | |
750 | swi_schedule_workitem(&rpc->srpc_wi); | |
751 | } | |
752 | ||
753 | spin_unlock(&scd->scd_lock); | |
754 | } | |
755 | } | |
756 | ||
757 | void | |
758 | srpc_shutdown_service(srpc_service_t *sv) | |
759 | { | |
760 | struct srpc_service_cd *scd; | |
761 | struct srpc_server_rpc *rpc; | |
762 | srpc_buffer_t *buf; | |
763 | int i; | |
764 | ||
765 | CDEBUG(D_NET, "Shutting down service: id %d, name %s\n", | |
766 | sv->sv_id, sv->sv_name); | |
767 | ||
768 | cfs_percpt_for_each(scd, i, sv->sv_cpt_data) | |
769 | spin_lock(&scd->scd_lock); | |
770 | ||
771 | sv->sv_shuttingdown = 1; /* i.e. no new active RPC */ | |
772 | ||
773 | cfs_percpt_for_each(scd, i, sv->sv_cpt_data) | |
774 | spin_unlock(&scd->scd_lock); | |
775 | ||
776 | cfs_percpt_for_each(scd, i, sv->sv_cpt_data) { | |
777 | spin_lock(&scd->scd_lock); | |
778 | ||
779 | /* schedule in-flight RPCs to notice the shutdown */ | |
780 | list_for_each_entry(rpc, &scd->scd_rpc_active, srpc_list) | |
781 | swi_schedule_workitem(&rpc->srpc_wi); | |
782 | ||
783 | spin_unlock(&scd->scd_lock); | |
784 | ||
785 | /* OK to traverse scd_buf_posted without lock, since no one | |
786 | * touches scd_buf_posted now */ | |
787 | list_for_each_entry(buf, &scd->scd_buf_posted, buf_list) | |
788 | LNetMDUnlink(buf->buf_mdh); | |
789 | } | |
790 | } | |
791 | ||
792 | int | |
793 | srpc_send_request (srpc_client_rpc_t *rpc) | |
794 | { | |
795 | srpc_event_t *ev = &rpc->crpc_reqstev; | |
796 | int rc; | |
797 | ||
798 | ev->ev_fired = 0; | |
799 | ev->ev_data = rpc; | |
800 | ev->ev_type = SRPC_REQUEST_SENT; | |
801 | ||
802 | rc = srpc_post_active_rqtbuf(rpc->crpc_dest, rpc->crpc_service, | |
803 | &rpc->crpc_reqstmsg, sizeof(srpc_msg_t), | |
804 | &rpc->crpc_reqstmdh, ev); | |
805 | if (rc != 0) { | |
806 | LASSERT (rc == -ENOMEM); | |
807 | ev->ev_fired = 1; /* no more event expected */ | |
808 | } | |
809 | return rc; | |
810 | } | |
811 | ||
812 | int | |
813 | srpc_prepare_reply (srpc_client_rpc_t *rpc) | |
814 | { | |
815 | srpc_event_t *ev = &rpc->crpc_replyev; | |
816 | __u64 *id = &rpc->crpc_reqstmsg.msg_body.reqst.rpyid; | |
817 | int rc; | |
818 | ||
819 | ev->ev_fired = 0; | |
820 | ev->ev_data = rpc; | |
821 | ev->ev_type = SRPC_REPLY_RCVD; | |
822 | ||
823 | *id = srpc_next_id(); | |
824 | ||
825 | rc = srpc_post_passive_rdma(SRPC_RDMA_PORTAL, 0, *id, | |
826 | &rpc->crpc_replymsg, sizeof(srpc_msg_t), | |
827 | LNET_MD_OP_PUT, rpc->crpc_dest, | |
828 | &rpc->crpc_replymdh, ev); | |
829 | if (rc != 0) { | |
830 | LASSERT (rc == -ENOMEM); | |
831 | ev->ev_fired = 1; /* no more event expected */ | |
832 | } | |
833 | return rc; | |
834 | } | |
835 | ||
836 | int | |
837 | srpc_prepare_bulk (srpc_client_rpc_t *rpc) | |
838 | { | |
839 | srpc_bulk_t *bk = &rpc->crpc_bulk; | |
840 | srpc_event_t *ev = &rpc->crpc_bulkev; | |
841 | __u64 *id = &rpc->crpc_reqstmsg.msg_body.reqst.bulkid; | |
842 | int rc; | |
843 | int opt; | |
844 | ||
845 | LASSERT (bk->bk_niov <= LNET_MAX_IOV); | |
846 | ||
847 | if (bk->bk_niov == 0) return 0; /* nothing to do */ | |
848 | ||
849 | opt = bk->bk_sink ? LNET_MD_OP_PUT : LNET_MD_OP_GET; | |
850 | opt |= LNET_MD_KIOV; | |
851 | ||
852 | ev->ev_fired = 0; | |
853 | ev->ev_data = rpc; | |
854 | ev->ev_type = SRPC_BULK_REQ_RCVD; | |
855 | ||
856 | *id = srpc_next_id(); | |
857 | ||
858 | rc = srpc_post_passive_rdma(SRPC_RDMA_PORTAL, 0, *id, | |
859 | &bk->bk_iovs[0], bk->bk_niov, opt, | |
860 | rpc->crpc_dest, &bk->bk_mdh, ev); | |
861 | if (rc != 0) { | |
862 | LASSERT (rc == -ENOMEM); | |
863 | ev->ev_fired = 1; /* no more event expected */ | |
864 | } | |
865 | return rc; | |
866 | } | |
867 | ||
868 | int | |
869 | srpc_do_bulk (srpc_server_rpc_t *rpc) | |
870 | { | |
871 | srpc_event_t *ev = &rpc->srpc_ev; | |
872 | srpc_bulk_t *bk = rpc->srpc_bulk; | |
873 | __u64 id = rpc->srpc_reqstbuf->buf_msg.msg_body.reqst.bulkid; | |
874 | int rc; | |
875 | int opt; | |
876 | ||
877 | LASSERT (bk != NULL); | |
878 | ||
879 | opt = bk->bk_sink ? LNET_MD_OP_GET : LNET_MD_OP_PUT; | |
880 | opt |= LNET_MD_KIOV; | |
881 | ||
882 | ev->ev_fired = 0; | |
883 | ev->ev_data = rpc; | |
884 | ev->ev_type = bk->bk_sink ? SRPC_BULK_GET_RPLD : SRPC_BULK_PUT_SENT; | |
885 | ||
886 | rc = srpc_post_active_rdma(SRPC_RDMA_PORTAL, id, | |
887 | &bk->bk_iovs[0], bk->bk_niov, opt, | |
888 | rpc->srpc_peer, rpc->srpc_self, | |
889 | &bk->bk_mdh, ev); | |
890 | if (rc != 0) | |
891 | ev->ev_fired = 1; /* no more event expected */ | |
892 | return rc; | |
893 | } | |
894 | ||
895 | /* only called from srpc_handle_rpc */ | |
896 | void | |
897 | srpc_server_rpc_done(srpc_server_rpc_t *rpc, int status) | |
898 | { | |
899 | struct srpc_service_cd *scd = rpc->srpc_scd; | |
900 | struct srpc_service *sv = scd->scd_svc; | |
901 | srpc_buffer_t *buffer; | |
902 | ||
903 | LASSERT (status != 0 || rpc->srpc_wi.swi_state == SWI_STATE_DONE); | |
904 | ||
905 | rpc->srpc_status = status; | |
906 | ||
907 | CDEBUG_LIMIT (status == 0 ? D_NET : D_NETERROR, | |
908 | "Server RPC %p done: service %s, peer %s, status %s:%d\n", | |
909 | rpc, sv->sv_name, libcfs_id2str(rpc->srpc_peer), | |
910 | swi_state2str(rpc->srpc_wi.swi_state), status); | |
911 | ||
912 | if (status != 0) { | |
913 | spin_lock(&srpc_data.rpc_glock); | |
914 | srpc_data.rpc_counters.rpcs_dropped++; | |
915 | spin_unlock(&srpc_data.rpc_glock); | |
916 | } | |
917 | ||
918 | if (rpc->srpc_done != NULL) | |
919 | (*rpc->srpc_done) (rpc); | |
920 | LASSERT(rpc->srpc_bulk == NULL); | |
921 | ||
922 | spin_lock(&scd->scd_lock); | |
923 | ||
924 | if (rpc->srpc_reqstbuf != NULL) { | |
925 | /* NB might drop sv_lock in srpc_service_recycle_buffer, but | |
926 | * sv won't go away for scd_rpc_active must not be empty */ | |
927 | srpc_service_recycle_buffer(scd, rpc->srpc_reqstbuf); | |
928 | rpc->srpc_reqstbuf = NULL; | |
929 | } | |
930 | ||
931 | list_del(&rpc->srpc_list); /* from scd->scd_rpc_active */ | |
932 | ||
933 | /* | |
934 | * No one can schedule me now since: | |
935 | * - I'm not on scd_rpc_active. | |
936 | * - all LNet events have been fired. | |
937 | * Cancel pending schedules and prevent future schedule attempts: | |
938 | */ | |
939 | LASSERT(rpc->srpc_ev.ev_fired); | |
940 | swi_exit_workitem(&rpc->srpc_wi); | |
941 | ||
942 | if (!sv->sv_shuttingdown && !list_empty(&scd->scd_buf_blocked)) { | |
943 | buffer = list_entry(scd->scd_buf_blocked.next, | |
944 | srpc_buffer_t, buf_list); | |
945 | list_del(&buffer->buf_list); | |
946 | ||
947 | srpc_init_server_rpc(rpc, scd, buffer); | |
948 | list_add_tail(&rpc->srpc_list, &scd->scd_rpc_active); | |
949 | swi_schedule_workitem(&rpc->srpc_wi); | |
950 | } else { | |
951 | list_add(&rpc->srpc_list, &scd->scd_rpc_free); | |
952 | } | |
953 | ||
954 | spin_unlock(&scd->scd_lock); | |
955 | return; | |
956 | } | |
957 | ||
958 | /* handles an incoming RPC */ | |
959 | int | |
960 | srpc_handle_rpc(swi_workitem_t *wi) | |
961 | { | |
962 | struct srpc_server_rpc *rpc = wi->swi_workitem.wi_data; | |
963 | struct srpc_service_cd *scd = rpc->srpc_scd; | |
964 | struct srpc_service *sv = scd->scd_svc; | |
965 | srpc_event_t *ev = &rpc->srpc_ev; | |
966 | int rc = 0; | |
967 | ||
968 | LASSERT(wi == &rpc->srpc_wi); | |
969 | ||
970 | spin_lock(&scd->scd_lock); | |
971 | ||
972 | if (sv->sv_shuttingdown || rpc->srpc_aborted) { | |
973 | spin_unlock(&scd->scd_lock); | |
974 | ||
975 | if (rpc->srpc_bulk != NULL) | |
976 | LNetMDUnlink(rpc->srpc_bulk->bk_mdh); | |
977 | LNetMDUnlink(rpc->srpc_replymdh); | |
978 | ||
979 | if (ev->ev_fired) { /* no more event, OK to finish */ | |
980 | srpc_server_rpc_done(rpc, -ESHUTDOWN); | |
981 | return 1; | |
982 | } | |
983 | return 0; | |
984 | } | |
985 | ||
986 | spin_unlock(&scd->scd_lock); | |
987 | ||
988 | switch (wi->swi_state) { | |
989 | default: | |
990 | LBUG (); | |
991 | case SWI_STATE_NEWBORN: { | |
992 | srpc_msg_t *msg; | |
993 | srpc_generic_reply_t *reply; | |
994 | ||
995 | msg = &rpc->srpc_reqstbuf->buf_msg; | |
996 | reply = &rpc->srpc_replymsg.msg_body.reply; | |
997 | ||
998 | if (msg->msg_magic == 0) { | |
999 | /* moaned already in srpc_lnet_ev_handler */ | |
1000 | srpc_server_rpc_done(rpc, EBADMSG); | |
1001 | return 1; | |
1002 | } | |
1003 | ||
1004 | srpc_unpack_msg_hdr(msg); | |
1005 | if (msg->msg_version != SRPC_MSG_VERSION) { | |
1006 | CWARN("Version mismatch: %u, %u expected, from %s\n", | |
1007 | msg->msg_version, SRPC_MSG_VERSION, | |
1008 | libcfs_id2str(rpc->srpc_peer)); | |
1009 | reply->status = EPROTO; | |
1010 | /* drop through and send reply */ | |
1011 | } else { | |
1012 | reply->status = 0; | |
1013 | rc = (*sv->sv_handler)(rpc); | |
1014 | LASSERT(reply->status == 0 || !rpc->srpc_bulk); | |
1015 | if (rc != 0) { | |
1016 | srpc_server_rpc_done(rpc, rc); | |
1017 | return 1; | |
1018 | } | |
1019 | } | |
1020 | ||
1021 | wi->swi_state = SWI_STATE_BULK_STARTED; | |
1022 | ||
1023 | if (rpc->srpc_bulk != NULL) { | |
1024 | rc = srpc_do_bulk(rpc); | |
1025 | if (rc == 0) | |
1026 | return 0; /* wait for bulk */ | |
1027 | ||
1028 | LASSERT (ev->ev_fired); | |
1029 | ev->ev_status = rc; | |
1030 | } | |
1031 | } | |
1032 | case SWI_STATE_BULK_STARTED: | |
1033 | LASSERT (rpc->srpc_bulk == NULL || ev->ev_fired); | |
1034 | ||
1035 | if (rpc->srpc_bulk != NULL) { | |
1036 | rc = ev->ev_status; | |
1037 | ||
1038 | if (sv->sv_bulk_ready != NULL) | |
1039 | rc = (*sv->sv_bulk_ready) (rpc, rc); | |
1040 | ||
1041 | if (rc != 0) { | |
1042 | srpc_server_rpc_done(rpc, rc); | |
1043 | return 1; | |
1044 | } | |
1045 | } | |
1046 | ||
1047 | wi->swi_state = SWI_STATE_REPLY_SUBMITTED; | |
1048 | rc = srpc_send_reply(rpc); | |
1049 | if (rc == 0) | |
1050 | return 0; /* wait for reply */ | |
1051 | srpc_server_rpc_done(rpc, rc); | |
1052 | return 1; | |
1053 | ||
1054 | case SWI_STATE_REPLY_SUBMITTED: | |
1055 | if (!ev->ev_fired) { | |
1056 | CERROR("RPC %p: bulk %p, service %d\n", | |
1057 | rpc, rpc->srpc_bulk, sv->sv_id); | |
1058 | CERROR("Event: status %d, type %d, lnet %d\n", | |
1059 | ev->ev_status, ev->ev_type, ev->ev_lnet); | |
1060 | LASSERT (ev->ev_fired); | |
1061 | } | |
1062 | ||
1063 | wi->swi_state = SWI_STATE_DONE; | |
1064 | srpc_server_rpc_done(rpc, ev->ev_status); | |
1065 | return 1; | |
1066 | } | |
1067 | ||
1068 | return 0; | |
1069 | } | |
1070 | ||
1071 | void | |
1072 | srpc_client_rpc_expired (void *data) | |
1073 | { | |
1074 | srpc_client_rpc_t *rpc = data; | |
1075 | ||
1076 | CWARN ("Client RPC expired: service %d, peer %s, timeout %d.\n", | |
1077 | rpc->crpc_service, libcfs_id2str(rpc->crpc_dest), | |
1078 | rpc->crpc_timeout); | |
1079 | ||
1080 | spin_lock(&rpc->crpc_lock); | |
1081 | ||
1082 | rpc->crpc_timeout = 0; | |
1083 | srpc_abort_rpc(rpc, -ETIMEDOUT); | |
1084 | ||
1085 | spin_unlock(&rpc->crpc_lock); | |
1086 | ||
1087 | spin_lock(&srpc_data.rpc_glock); | |
1088 | srpc_data.rpc_counters.rpcs_expired++; | |
1089 | spin_unlock(&srpc_data.rpc_glock); | |
1090 | } | |
1091 | ||
1092 | inline void | |
1093 | srpc_add_client_rpc_timer (srpc_client_rpc_t *rpc) | |
1094 | { | |
1095 | stt_timer_t *timer = &rpc->crpc_timer; | |
1096 | ||
1097 | if (rpc->crpc_timeout == 0) return; | |
1098 | ||
1099 | INIT_LIST_HEAD(&timer->stt_list); | |
1100 | timer->stt_data = rpc; | |
1101 | timer->stt_func = srpc_client_rpc_expired; | |
1102 | timer->stt_expires = cfs_time_add(rpc->crpc_timeout, | |
1103 | cfs_time_current_sec()); | |
1104 | stt_add_timer(timer); | |
1105 | return; | |
1106 | } | |
1107 | ||
1108 | /* | |
1109 | * Called with rpc->crpc_lock held. | |
1110 | * | |
1111 | * Upon exit the RPC expiry timer is not queued and the handler is not | |
1112 | * running on any CPU. */ | |
1113 | void | |
1114 | srpc_del_client_rpc_timer (srpc_client_rpc_t *rpc) | |
1115 | { | |
1116 | /* timer not planted or already exploded */ | |
1117 | if (rpc->crpc_timeout == 0) | |
1118 | return; | |
1119 | ||
1120 | /* timer sucessfully defused */ | |
1121 | if (stt_del_timer(&rpc->crpc_timer)) | |
1122 | return; | |
1123 | ||
1124 | /* timer detonated, wait for it to explode */ | |
1125 | while (rpc->crpc_timeout != 0) { | |
1126 | spin_unlock(&rpc->crpc_lock); | |
1127 | ||
1128 | schedule(); | |
1129 | ||
1130 | spin_lock(&rpc->crpc_lock); | |
1131 | } | |
1132 | } | |
1133 | ||
1134 | void | |
1135 | srpc_client_rpc_done (srpc_client_rpc_t *rpc, int status) | |
1136 | { | |
1137 | swi_workitem_t *wi = &rpc->crpc_wi; | |
1138 | ||
1139 | LASSERT(status != 0 || wi->swi_state == SWI_STATE_DONE); | |
1140 | ||
1141 | spin_lock(&rpc->crpc_lock); | |
1142 | ||
1143 | rpc->crpc_closed = 1; | |
1144 | if (rpc->crpc_status == 0) | |
1145 | rpc->crpc_status = status; | |
1146 | ||
1147 | srpc_del_client_rpc_timer(rpc); | |
1148 | ||
1149 | CDEBUG_LIMIT ((status == 0) ? D_NET : D_NETERROR, | |
1150 | "Client RPC done: service %d, peer %s, status %s:%d:%d\n", | |
1151 | rpc->crpc_service, libcfs_id2str(rpc->crpc_dest), | |
1152 | swi_state2str(wi->swi_state), rpc->crpc_aborted, status); | |
1153 | ||
1154 | /* | |
1155 | * No one can schedule me now since: | |
1156 | * - RPC timer has been defused. | |
1157 | * - all LNet events have been fired. | |
1158 | * - crpc_closed has been set, preventing srpc_abort_rpc from | |
1159 | * scheduling me. | |
1160 | * Cancel pending schedules and prevent future schedule attempts: | |
1161 | */ | |
1162 | LASSERT (!srpc_event_pending(rpc)); | |
1163 | swi_exit_workitem(wi); | |
1164 | ||
1165 | spin_unlock(&rpc->crpc_lock); | |
1166 | ||
1167 | (*rpc->crpc_done)(rpc); | |
1168 | return; | |
1169 | } | |
1170 | ||
1171 | /* sends an outgoing RPC */ | |
1172 | int | |
1173 | srpc_send_rpc (swi_workitem_t *wi) | |
1174 | { | |
1175 | int rc = 0; | |
1176 | srpc_client_rpc_t *rpc; | |
1177 | srpc_msg_t *reply; | |
1178 | int do_bulk; | |
1179 | ||
1180 | LASSERT(wi != NULL); | |
1181 | ||
1182 | rpc = wi->swi_workitem.wi_data; | |
1183 | ||
1184 | LASSERT (rpc != NULL); | |
1185 | LASSERT (wi == &rpc->crpc_wi); | |
1186 | ||
1187 | reply = &rpc->crpc_replymsg; | |
1188 | do_bulk = rpc->crpc_bulk.bk_niov > 0; | |
1189 | ||
1190 | spin_lock(&rpc->crpc_lock); | |
1191 | ||
1192 | if (rpc->crpc_aborted) { | |
1193 | spin_unlock(&rpc->crpc_lock); | |
1194 | goto abort; | |
1195 | } | |
1196 | ||
1197 | spin_unlock(&rpc->crpc_lock); | |
1198 | ||
1199 | switch (wi->swi_state) { | |
1200 | default: | |
1201 | LBUG (); | |
1202 | case SWI_STATE_NEWBORN: | |
1203 | LASSERT (!srpc_event_pending(rpc)); | |
1204 | ||
1205 | rc = srpc_prepare_reply(rpc); | |
1206 | if (rc != 0) { | |
1207 | srpc_client_rpc_done(rpc, rc); | |
1208 | return 1; | |
1209 | } | |
1210 | ||
1211 | rc = srpc_prepare_bulk(rpc); | |
1212 | if (rc != 0) break; | |
1213 | ||
1214 | wi->swi_state = SWI_STATE_REQUEST_SUBMITTED; | |
1215 | rc = srpc_send_request(rpc); | |
1216 | break; | |
1217 | ||
1218 | case SWI_STATE_REQUEST_SUBMITTED: | |
1219 | /* CAVEAT EMPTOR: rqtev, rpyev, and bulkev may come in any | |
1220 | * order; however, they're processed in a strict order: | |
1221 | * rqt, rpy, and bulk. */ | |
1222 | if (!rpc->crpc_reqstev.ev_fired) break; | |
1223 | ||
1224 | rc = rpc->crpc_reqstev.ev_status; | |
1225 | if (rc != 0) break; | |
1226 | ||
1227 | wi->swi_state = SWI_STATE_REQUEST_SENT; | |
1228 | /* perhaps more events, fall thru */ | |
1229 | case SWI_STATE_REQUEST_SENT: { | |
1230 | srpc_msg_type_t type = srpc_service2reply(rpc->crpc_service); | |
1231 | ||
1232 | if (!rpc->crpc_replyev.ev_fired) break; | |
1233 | ||
1234 | rc = rpc->crpc_replyev.ev_status; | |
1235 | if (rc != 0) break; | |
1236 | ||
1237 | srpc_unpack_msg_hdr(reply); | |
1238 | if (reply->msg_type != type || | |
1239 | (reply->msg_magic != SRPC_MSG_MAGIC && | |
1240 | reply->msg_magic != __swab32(SRPC_MSG_MAGIC))) { | |
1241 | CWARN ("Bad message from %s: type %u (%d expected)," | |
1242 | " magic %u (%d expected).\n", | |
1243 | libcfs_id2str(rpc->crpc_dest), | |
1244 | reply->msg_type, type, | |
1245 | reply->msg_magic, SRPC_MSG_MAGIC); | |
1246 | rc = -EBADMSG; | |
1247 | break; | |
1248 | } | |
1249 | ||
1250 | if (do_bulk && reply->msg_body.reply.status != 0) { | |
1251 | CWARN ("Remote error %d at %s, unlink bulk buffer in " | |
1252 | "case peer didn't initiate bulk transfer\n", | |
1253 | reply->msg_body.reply.status, | |
1254 | libcfs_id2str(rpc->crpc_dest)); | |
1255 | LNetMDUnlink(rpc->crpc_bulk.bk_mdh); | |
1256 | } | |
1257 | ||
1258 | wi->swi_state = SWI_STATE_REPLY_RECEIVED; | |
1259 | } | |
1260 | case SWI_STATE_REPLY_RECEIVED: | |
1261 | if (do_bulk && !rpc->crpc_bulkev.ev_fired) break; | |
1262 | ||
1263 | rc = do_bulk ? rpc->crpc_bulkev.ev_status : 0; | |
1264 | ||
1265 | /* Bulk buffer was unlinked due to remote error. Clear error | |
1266 | * since reply buffer still contains valid data. | |
1267 | * NB rpc->crpc_done shouldn't look into bulk data in case of | |
1268 | * remote error. */ | |
1269 | if (do_bulk && rpc->crpc_bulkev.ev_lnet == LNET_EVENT_UNLINK && | |
1270 | rpc->crpc_status == 0 && reply->msg_body.reply.status != 0) | |
1271 | rc = 0; | |
1272 | ||
1273 | wi->swi_state = SWI_STATE_DONE; | |
1274 | srpc_client_rpc_done(rpc, rc); | |
1275 | return 1; | |
1276 | } | |
1277 | ||
1278 | if (rc != 0) { | |
1279 | spin_lock(&rpc->crpc_lock); | |
1280 | srpc_abort_rpc(rpc, rc); | |
1281 | spin_unlock(&rpc->crpc_lock); | |
1282 | } | |
1283 | ||
1284 | abort: | |
1285 | if (rpc->crpc_aborted) { | |
1286 | LNetMDUnlink(rpc->crpc_reqstmdh); | |
1287 | LNetMDUnlink(rpc->crpc_replymdh); | |
1288 | LNetMDUnlink(rpc->crpc_bulk.bk_mdh); | |
1289 | ||
1290 | if (!srpc_event_pending(rpc)) { | |
1291 | srpc_client_rpc_done(rpc, -EINTR); | |
1292 | return 1; | |
1293 | } | |
1294 | } | |
1295 | return 0; | |
1296 | } | |
1297 | ||
1298 | srpc_client_rpc_t * | |
1299 | srpc_create_client_rpc (lnet_process_id_t peer, int service, | |
1300 | int nbulkiov, int bulklen, | |
1301 | void (*rpc_done)(srpc_client_rpc_t *), | |
1302 | void (*rpc_fini)(srpc_client_rpc_t *), void *priv) | |
1303 | { | |
1304 | srpc_client_rpc_t *rpc; | |
1305 | ||
1306 | LIBCFS_ALLOC(rpc, offsetof(srpc_client_rpc_t, | |
1307 | crpc_bulk.bk_iovs[nbulkiov])); | |
1308 | if (rpc == NULL) | |
1309 | return NULL; | |
1310 | ||
1311 | srpc_init_client_rpc(rpc, peer, service, nbulkiov, | |
1312 | bulklen, rpc_done, rpc_fini, priv); | |
1313 | return rpc; | |
1314 | } | |
1315 | ||
1316 | /* called with rpc->crpc_lock held */ | |
1317 | void | |
1318 | srpc_abort_rpc (srpc_client_rpc_t *rpc, int why) | |
1319 | { | |
1320 | LASSERT (why != 0); | |
1321 | ||
1322 | if (rpc->crpc_aborted || /* already aborted */ | |
1323 | rpc->crpc_closed) /* callback imminent */ | |
1324 | return; | |
1325 | ||
1326 | CDEBUG (D_NET, | |
1327 | "Aborting RPC: service %d, peer %s, state %s, why %d\n", | |
1328 | rpc->crpc_service, libcfs_id2str(rpc->crpc_dest), | |
1329 | swi_state2str(rpc->crpc_wi.swi_state), why); | |
1330 | ||
1331 | rpc->crpc_aborted = 1; | |
1332 | rpc->crpc_status = why; | |
1333 | swi_schedule_workitem(&rpc->crpc_wi); | |
1334 | return; | |
1335 | } | |
1336 | ||
1337 | /* called with rpc->crpc_lock held */ | |
1338 | void | |
1339 | srpc_post_rpc (srpc_client_rpc_t *rpc) | |
1340 | { | |
1341 | LASSERT (!rpc->crpc_aborted); | |
1342 | LASSERT (srpc_data.rpc_state == SRPC_STATE_RUNNING); | |
1343 | ||
1344 | CDEBUG (D_NET, "Posting RPC: peer %s, service %d, timeout %d\n", | |
1345 | libcfs_id2str(rpc->crpc_dest), rpc->crpc_service, | |
1346 | rpc->crpc_timeout); | |
1347 | ||
1348 | srpc_add_client_rpc_timer(rpc); | |
1349 | swi_schedule_workitem(&rpc->crpc_wi); | |
1350 | return; | |
1351 | } | |
1352 | ||
1353 | ||
1354 | int | |
1355 | srpc_send_reply(struct srpc_server_rpc *rpc) | |
1356 | { | |
1357 | srpc_event_t *ev = &rpc->srpc_ev; | |
1358 | struct srpc_msg *msg = &rpc->srpc_replymsg; | |
1359 | struct srpc_buffer *buffer = rpc->srpc_reqstbuf; | |
1360 | struct srpc_service_cd *scd = rpc->srpc_scd; | |
1361 | struct srpc_service *sv = scd->scd_svc; | |
1362 | __u64 rpyid; | |
1363 | int rc; | |
1364 | ||
1365 | LASSERT(buffer != NULL); | |
1366 | rpyid = buffer->buf_msg.msg_body.reqst.rpyid; | |
1367 | ||
1368 | spin_lock(&scd->scd_lock); | |
1369 | ||
1370 | if (!sv->sv_shuttingdown && !srpc_serv_is_framework(sv)) { | |
1371 | /* Repost buffer before replying since test client | |
1372 | * might send me another RPC once it gets the reply */ | |
1373 | if (srpc_service_post_buffer(scd, buffer) != 0) | |
1374 | CWARN("Failed to repost %s buffer\n", sv->sv_name); | |
1375 | rpc->srpc_reqstbuf = NULL; | |
1376 | } | |
1377 | ||
1378 | spin_unlock(&scd->scd_lock); | |
1379 | ||
1380 | ev->ev_fired = 0; | |
1381 | ev->ev_data = rpc; | |
1382 | ev->ev_type = SRPC_REPLY_SENT; | |
1383 | ||
1384 | msg->msg_magic = SRPC_MSG_MAGIC; | |
1385 | msg->msg_version = SRPC_MSG_VERSION; | |
1386 | msg->msg_type = srpc_service2reply(sv->sv_id); | |
1387 | ||
1388 | rc = srpc_post_active_rdma(SRPC_RDMA_PORTAL, rpyid, msg, | |
1389 | sizeof(*msg), LNET_MD_OP_PUT, | |
1390 | rpc->srpc_peer, rpc->srpc_self, | |
1391 | &rpc->srpc_replymdh, ev); | |
1392 | if (rc != 0) | |
1393 | ev->ev_fired = 1; /* no more event expected */ | |
1394 | return rc; | |
1395 | } | |
1396 | ||
1397 | /* when in kernel always called with LNET_LOCK() held, and in thread context */ | |
1398 | void | |
1399 | srpc_lnet_ev_handler(lnet_event_t *ev) | |
1400 | { | |
1401 | struct srpc_service_cd *scd; | |
1402 | srpc_event_t *rpcev = ev->md.user_ptr; | |
1403 | srpc_client_rpc_t *crpc; | |
1404 | srpc_server_rpc_t *srpc; | |
1405 | srpc_buffer_t *buffer; | |
1406 | srpc_service_t *sv; | |
1407 | srpc_msg_t *msg; | |
1408 | srpc_msg_type_t type; | |
1409 | ||
1410 | LASSERT (!in_interrupt()); | |
1411 | ||
1412 | if (ev->status != 0) { | |
1413 | spin_lock(&srpc_data.rpc_glock); | |
1414 | srpc_data.rpc_counters.errors++; | |
1415 | spin_unlock(&srpc_data.rpc_glock); | |
1416 | } | |
1417 | ||
1418 | rpcev->ev_lnet = ev->type; | |
1419 | ||
1420 | switch (rpcev->ev_type) { | |
1421 | default: | |
1422 | CERROR("Unknown event: status %d, type %d, lnet %d\n", | |
1423 | rpcev->ev_status, rpcev->ev_type, rpcev->ev_lnet); | |
1424 | LBUG (); | |
1425 | case SRPC_REQUEST_SENT: | |
1426 | if (ev->status == 0 && ev->type != LNET_EVENT_UNLINK) { | |
1427 | spin_lock(&srpc_data.rpc_glock); | |
1428 | srpc_data.rpc_counters.rpcs_sent++; | |
1429 | spin_unlock(&srpc_data.rpc_glock); | |
1430 | } | |
1431 | case SRPC_REPLY_RCVD: | |
1432 | case SRPC_BULK_REQ_RCVD: | |
1433 | crpc = rpcev->ev_data; | |
1434 | ||
1435 | if (rpcev != &crpc->crpc_reqstev && | |
1436 | rpcev != &crpc->crpc_replyev && | |
1437 | rpcev != &crpc->crpc_bulkev) { | |
1438 | CERROR("rpcev %p, crpc %p, reqstev %p, replyev %p, bulkev %p\n", | |
1439 | rpcev, crpc, &crpc->crpc_reqstev, | |
1440 | &crpc->crpc_replyev, &crpc->crpc_bulkev); | |
1441 | CERROR("Bad event: status %d, type %d, lnet %d\n", | |
1442 | rpcev->ev_status, rpcev->ev_type, rpcev->ev_lnet); | |
1443 | LBUG (); | |
1444 | } | |
1445 | ||
1446 | spin_lock(&crpc->crpc_lock); | |
1447 | ||
1448 | LASSERT(rpcev->ev_fired == 0); | |
1449 | rpcev->ev_fired = 1; | |
1450 | rpcev->ev_status = (ev->type == LNET_EVENT_UNLINK) ? | |
1451 | -EINTR : ev->status; | |
1452 | swi_schedule_workitem(&crpc->crpc_wi); | |
1453 | ||
1454 | spin_unlock(&crpc->crpc_lock); | |
1455 | break; | |
1456 | ||
1457 | case SRPC_REQUEST_RCVD: | |
1458 | scd = rpcev->ev_data; | |
1459 | sv = scd->scd_svc; | |
1460 | ||
1461 | LASSERT(rpcev == &scd->scd_ev); | |
1462 | ||
1463 | spin_lock(&scd->scd_lock); | |
1464 | ||
1465 | LASSERT (ev->unlinked); | |
1466 | LASSERT (ev->type == LNET_EVENT_PUT || | |
1467 | ev->type == LNET_EVENT_UNLINK); | |
1468 | LASSERT (ev->type != LNET_EVENT_UNLINK || | |
1469 | sv->sv_shuttingdown); | |
1470 | ||
1471 | buffer = container_of(ev->md.start, srpc_buffer_t, buf_msg); | |
1472 | buffer->buf_peer = ev->initiator; | |
1473 | buffer->buf_self = ev->target.nid; | |
1474 | ||
1475 | LASSERT(scd->scd_buf_nposted > 0); | |
1476 | scd->scd_buf_nposted--; | |
1477 | ||
1478 | if (sv->sv_shuttingdown) { | |
1479 | /* Leave buffer on scd->scd_buf_nposted since | |
1480 | * srpc_finish_service needs to traverse it. */ | |
1481 | spin_unlock(&scd->scd_lock); | |
1482 | break; | |
1483 | } | |
1484 | ||
1485 | if (scd->scd_buf_err_stamp != 0 && | |
1486 | scd->scd_buf_err_stamp < cfs_time_current_sec()) { | |
1487 | /* re-enable adding buffer */ | |
1488 | scd->scd_buf_err_stamp = 0; | |
1489 | scd->scd_buf_err = 0; | |
1490 | } | |
1491 | ||
1492 | if (scd->scd_buf_err == 0 && /* adding buffer is enabled */ | |
1493 | scd->scd_buf_adjust == 0 && | |
1494 | scd->scd_buf_nposted < scd->scd_buf_low) { | |
1495 | scd->scd_buf_adjust = MAX(scd->scd_buf_total / 2, | |
1496 | SFW_TEST_WI_MIN); | |
1497 | swi_schedule_workitem(&scd->scd_buf_wi); | |
1498 | } | |
1499 | ||
1500 | list_del(&buffer->buf_list); /* from scd->scd_buf_posted */ | |
1501 | msg = &buffer->buf_msg; | |
1502 | type = srpc_service2request(sv->sv_id); | |
1503 | ||
1504 | if (ev->status != 0 || ev->mlength != sizeof(*msg) || | |
1505 | (msg->msg_type != type && | |
1506 | msg->msg_type != __swab32(type)) || | |
1507 | (msg->msg_magic != SRPC_MSG_MAGIC && | |
1508 | msg->msg_magic != __swab32(SRPC_MSG_MAGIC))) { | |
1509 | CERROR ("Dropping RPC (%s) from %s: " | |
1510 | "status %d mlength %d type %u magic %u.\n", | |
1511 | sv->sv_name, libcfs_id2str(ev->initiator), | |
1512 | ev->status, ev->mlength, | |
1513 | msg->msg_type, msg->msg_magic); | |
1514 | ||
1515 | /* NB can't call srpc_service_recycle_buffer here since | |
1516 | * it may call LNetM[DE]Attach. The invalid magic tells | |
1517 | * srpc_handle_rpc to drop this RPC */ | |
1518 | msg->msg_magic = 0; | |
1519 | } | |
1520 | ||
1521 | if (!list_empty(&scd->scd_rpc_free)) { | |
1522 | srpc = list_entry(scd->scd_rpc_free.next, | |
1523 | struct srpc_server_rpc, | |
1524 | srpc_list); | |
1525 | list_del(&srpc->srpc_list); | |
1526 | ||
1527 | srpc_init_server_rpc(srpc, scd, buffer); | |
1528 | list_add_tail(&srpc->srpc_list, | |
1529 | &scd->scd_rpc_active); | |
1530 | swi_schedule_workitem(&srpc->srpc_wi); | |
1531 | } else { | |
1532 | list_add_tail(&buffer->buf_list, | |
1533 | &scd->scd_buf_blocked); | |
1534 | } | |
1535 | ||
1536 | spin_unlock(&scd->scd_lock); | |
1537 | ||
1538 | spin_lock(&srpc_data.rpc_glock); | |
1539 | srpc_data.rpc_counters.rpcs_rcvd++; | |
1540 | spin_unlock(&srpc_data.rpc_glock); | |
1541 | break; | |
1542 | ||
1543 | case SRPC_BULK_GET_RPLD: | |
1544 | LASSERT (ev->type == LNET_EVENT_SEND || | |
1545 | ev->type == LNET_EVENT_REPLY || | |
1546 | ev->type == LNET_EVENT_UNLINK); | |
1547 | ||
1548 | if (!ev->unlinked) | |
1549 | break; /* wait for final event */ | |
1550 | ||
1551 | case SRPC_BULK_PUT_SENT: | |
1552 | if (ev->status == 0 && ev->type != LNET_EVENT_UNLINK) { | |
1553 | spin_lock(&srpc_data.rpc_glock); | |
1554 | ||
1555 | if (rpcev->ev_type == SRPC_BULK_GET_RPLD) | |
1556 | srpc_data.rpc_counters.bulk_get += ev->mlength; | |
1557 | else | |
1558 | srpc_data.rpc_counters.bulk_put += ev->mlength; | |
1559 | ||
1560 | spin_unlock(&srpc_data.rpc_glock); | |
1561 | } | |
1562 | case SRPC_REPLY_SENT: | |
1563 | srpc = rpcev->ev_data; | |
1564 | scd = srpc->srpc_scd; | |
1565 | ||
1566 | LASSERT(rpcev == &srpc->srpc_ev); | |
1567 | ||
1568 | spin_lock(&scd->scd_lock); | |
1569 | ||
1570 | rpcev->ev_fired = 1; | |
1571 | rpcev->ev_status = (ev->type == LNET_EVENT_UNLINK) ? | |
1572 | -EINTR : ev->status; | |
1573 | swi_schedule_workitem(&srpc->srpc_wi); | |
1574 | ||
1575 | spin_unlock(&scd->scd_lock); | |
1576 | break; | |
1577 | } | |
1578 | } | |
1579 | ||
1580 | ||
1581 | int | |
1582 | srpc_startup (void) | |
1583 | { | |
1584 | int rc; | |
1585 | ||
1586 | memset(&srpc_data, 0, sizeof(struct smoketest_rpc)); | |
1587 | spin_lock_init(&srpc_data.rpc_glock); | |
1588 | ||
1589 | /* 1 second pause to avoid timestamp reuse */ | |
1590 | cfs_pause(cfs_time_seconds(1)); | |
1591 | srpc_data.rpc_matchbits = ((__u64) cfs_time_current_sec()) << 48; | |
1592 | ||
1593 | srpc_data.rpc_state = SRPC_STATE_NONE; | |
1594 | ||
1595 | rc = LNetNIInit(LUSTRE_SRV_LNET_PID); | |
1596 | if (rc < 0) { | |
1597 | CERROR ("LNetNIInit() has failed: %d\n", rc); | |
1598 | return rc; | |
1599 | } | |
1600 | ||
1601 | srpc_data.rpc_state = SRPC_STATE_NI_INIT; | |
1602 | ||
1603 | LNetInvalidateHandle(&srpc_data.rpc_lnet_eq); | |
1604 | rc = LNetEQAlloc(0, srpc_lnet_ev_handler, &srpc_data.rpc_lnet_eq); | |
1605 | if (rc != 0) { | |
1606 | CERROR("LNetEQAlloc() has failed: %d\n", rc); | |
1607 | goto bail; | |
1608 | } | |
1609 | ||
1610 | rc = LNetSetLazyPortal(SRPC_FRAMEWORK_REQUEST_PORTAL); | |
1611 | LASSERT(rc == 0); | |
1612 | rc = LNetSetLazyPortal(SRPC_REQUEST_PORTAL); | |
1613 | LASSERT(rc == 0); | |
1614 | ||
1615 | srpc_data.rpc_state = SRPC_STATE_EQ_INIT; | |
1616 | ||
1617 | rc = stt_startup(); | |
1618 | ||
1619 | bail: | |
1620 | if (rc != 0) | |
1621 | srpc_shutdown(); | |
1622 | else | |
1623 | srpc_data.rpc_state = SRPC_STATE_RUNNING; | |
1624 | ||
1625 | return rc; | |
1626 | } | |
1627 | ||
1628 | void | |
1629 | srpc_shutdown (void) | |
1630 | { | |
1631 | int i; | |
1632 | int rc; | |
1633 | int state; | |
1634 | ||
1635 | state = srpc_data.rpc_state; | |
1636 | srpc_data.rpc_state = SRPC_STATE_STOPPING; | |
1637 | ||
1638 | switch (state) { | |
1639 | default: | |
1640 | LBUG (); | |
1641 | case SRPC_STATE_RUNNING: | |
1642 | spin_lock(&srpc_data.rpc_glock); | |
1643 | ||
1644 | for (i = 0; i <= SRPC_SERVICE_MAX_ID; i++) { | |
1645 | srpc_service_t *sv = srpc_data.rpc_services[i]; | |
1646 | ||
1647 | LASSERTF (sv == NULL, | |
1648 | "service not empty: id %d, name %s\n", | |
1649 | i, sv->sv_name); | |
1650 | } | |
1651 | ||
1652 | spin_unlock(&srpc_data.rpc_glock); | |
1653 | ||
1654 | stt_shutdown(); | |
1655 | ||
1656 | case SRPC_STATE_EQ_INIT: | |
1657 | rc = LNetClearLazyPortal(SRPC_FRAMEWORK_REQUEST_PORTAL); | |
1658 | rc = LNetClearLazyPortal(SRPC_REQUEST_PORTAL); | |
1659 | LASSERT (rc == 0); | |
1660 | rc = LNetEQFree(srpc_data.rpc_lnet_eq); | |
1661 | LASSERT (rc == 0); /* the EQ should have no user by now */ | |
1662 | ||
1663 | case SRPC_STATE_NI_INIT: | |
1664 | LNetNIFini(); | |
1665 | } | |
1666 | ||
1667 | return; | |
1668 | } |