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/framework.c | |
37 | * | |
38 | * Author: Isaac Huang <isaac@clusterfs.com> | |
39 | * Author: Liang Zhen <liangzhen@clusterfs.com> | |
40 | */ | |
41 | ||
42 | #define DEBUG_SUBSYSTEM S_LNET | |
43 | ||
44 | #include "selftest.h" | |
45 | ||
46 | lst_sid_t LST_INVALID_SID = {LNET_NID_ANY, -1}; | |
47 | ||
48 | static int session_timeout = 100; | |
8cc7b4b9 PT |
49 | module_param(session_timeout, int, 0444); |
50 | MODULE_PARM_DESC(session_timeout, "test session timeout in seconds (100 by default, 0 == never)"); | |
d7e09d03 PT |
51 | |
52 | static int rpc_timeout = 64; | |
8cc7b4b9 PT |
53 | module_param(rpc_timeout, int, 0644); |
54 | MODULE_PARM_DESC(rpc_timeout, "rpc timeout in seconds (64 by default, 0 == never)"); | |
d7e09d03 | 55 | |
74d68011 MS |
56 | #define sfw_unpack_id(id) \ |
57 | do { \ | |
d7e09d03 PT |
58 | __swab64s(&(id).nid); \ |
59 | __swab32s(&(id).pid); \ | |
60 | } while (0) | |
61 | ||
74d68011 MS |
62 | #define sfw_unpack_sid(sid) \ |
63 | do { \ | |
d7e09d03 PT |
64 | __swab64s(&(sid).ses_nid); \ |
65 | __swab64s(&(sid).ses_stamp); \ | |
66 | } while (0) | |
67 | ||
74d68011 MS |
68 | #define sfw_unpack_fw_counters(fc) \ |
69 | do { \ | |
d7e09d03 PT |
70 | __swab32s(&(fc).running_ms); \ |
71 | __swab32s(&(fc).active_batches); \ | |
72 | __swab32s(&(fc).zombie_sessions); \ | |
73 | __swab32s(&(fc).brw_errors); \ | |
74 | __swab32s(&(fc).ping_errors); \ | |
75 | } while (0) | |
76 | ||
77 | #define sfw_unpack_rpc_counters(rc) \ | |
74d68011 | 78 | do { \ |
d7e09d03 PT |
79 | __swab32s(&(rc).errors); \ |
80 | __swab32s(&(rc).rpcs_sent); \ | |
81 | __swab32s(&(rc).rpcs_rcvd); \ | |
82 | __swab32s(&(rc).rpcs_dropped); \ | |
83 | __swab32s(&(rc).rpcs_expired); \ | |
84 | __swab64s(&(rc).bulk_get); \ | |
85 | __swab64s(&(rc).bulk_put); \ | |
86 | } while (0) | |
87 | ||
88 | #define sfw_unpack_lnet_counters(lc) \ | |
74d68011 | 89 | do { \ |
d7e09d03 PT |
90 | __swab32s(&(lc).errors); \ |
91 | __swab32s(&(lc).msgs_max); \ | |
92 | __swab32s(&(lc).msgs_alloc); \ | |
93 | __swab32s(&(lc).send_count); \ | |
94 | __swab32s(&(lc).recv_count); \ | |
95 | __swab32s(&(lc).drop_count); \ | |
96 | __swab32s(&(lc).route_count); \ | |
97 | __swab64s(&(lc).send_length); \ | |
98 | __swab64s(&(lc).recv_length); \ | |
99 | __swab64s(&(lc).drop_length); \ | |
100 | __swab64s(&(lc).route_length); \ | |
101 | } while (0) | |
102 | ||
103 | #define sfw_test_active(t) (atomic_read(&(t)->tsi_nactive) != 0) | |
104 | #define sfw_batch_active(b) (atomic_read(&(b)->bat_nactive) != 0) | |
105 | ||
62366bf1 | 106 | static struct smoketest_framework { |
74d68011 MS |
107 | struct list_head fw_zombie_rpcs; /* RPCs to be recycled */ |
108 | struct list_head fw_zombie_sessions; /* stopping sessions */ | |
109 | struct list_head fw_tests; /* registered test cases */ | |
110 | atomic_t fw_nzombies; /* # zombie sessions */ | |
111 | spinlock_t fw_lock; /* serialise */ | |
112 | sfw_session_t *fw_session; /* _the_ session */ | |
113 | int fw_shuttingdown; /* shutdown in progress */ | |
114 | srpc_server_rpc_t *fw_active_srpc; /* running RPC */ | |
d7e09d03 PT |
115 | } sfw_data; |
116 | ||
117 | /* forward ref's */ | |
63418983 MY |
118 | int sfw_stop_batch(sfw_batch_t *tsb, int force); |
119 | void sfw_destroy_session(sfw_session_t *sn); | |
d7e09d03 PT |
120 | |
121 | static inline sfw_test_case_t * | |
122 | sfw_find_test_case(int id) | |
123 | { | |
124 | sfw_test_case_t *tsc; | |
125 | ||
63418983 MY |
126 | LASSERT(id <= SRPC_SERVICE_MAX_ID); |
127 | LASSERT(id > SRPC_FRAMEWORK_SERVICE_MAX_ID); | |
d7e09d03 | 128 | |
63418983 | 129 | list_for_each_entry(tsc, &sfw_data.fw_tests, tsc_list) { |
d7e09d03 PT |
130 | if (tsc->tsc_srv_service->sv_id == id) |
131 | return tsc; | |
132 | } | |
133 | ||
134 | return NULL; | |
135 | } | |
136 | ||
137 | static int | |
63418983 | 138 | sfw_register_test(srpc_service_t *service, sfw_test_client_ops_t *cliops) |
d7e09d03 PT |
139 | { |
140 | sfw_test_case_t *tsc; | |
141 | ||
142 | if (sfw_find_test_case(service->sv_id) != NULL) { | |
63418983 | 143 | CERROR("Failed to register test %s (%d)\n", |
d7e09d03 PT |
144 | service->sv_name, service->sv_id); |
145 | return -EEXIST; | |
146 | } | |
147 | ||
148 | LIBCFS_ALLOC(tsc, sizeof(sfw_test_case_t)); | |
149 | if (tsc == NULL) | |
150 | return -ENOMEM; | |
151 | ||
d7e09d03 PT |
152 | tsc->tsc_cli_ops = cliops; |
153 | tsc->tsc_srv_service = service; | |
154 | ||
155 | list_add_tail(&tsc->tsc_list, &sfw_data.fw_tests); | |
156 | return 0; | |
157 | } | |
158 | ||
8d94b6d2 | 159 | static void |
63418983 | 160 | sfw_add_session_timer(void) |
d7e09d03 PT |
161 | { |
162 | sfw_session_t *sn = sfw_data.fw_session; | |
74d68011 | 163 | stt_timer_t *timer = &sn->sn_timer; |
d7e09d03 | 164 | |
63418983 | 165 | LASSERT(!sfw_data.fw_shuttingdown); |
d7e09d03 PT |
166 | |
167 | if (sn == NULL || sn->sn_timeout == 0) | |
168 | return; | |
169 | ||
63418983 | 170 | LASSERT(!sn->sn_timer_active); |
d7e09d03 PT |
171 | |
172 | sn->sn_timer_active = 1; | |
d9f79e6b | 173 | timer->stt_expires = ktime_get_real_seconds() + sn->sn_timeout; |
d7e09d03 PT |
174 | stt_add_timer(timer); |
175 | return; | |
176 | } | |
177 | ||
8d94b6d2 | 178 | static int |
63418983 | 179 | sfw_del_session_timer(void) |
d7e09d03 PT |
180 | { |
181 | sfw_session_t *sn = sfw_data.fw_session; | |
182 | ||
183 | if (sn == NULL || !sn->sn_timer_active) | |
184 | return 0; | |
185 | ||
63418983 | 186 | LASSERT(sn->sn_timeout != 0); |
d7e09d03 PT |
187 | |
188 | if (stt_del_timer(&sn->sn_timer)) { /* timer defused */ | |
189 | sn->sn_timer_active = 0; | |
190 | return 0; | |
191 | } | |
192 | ||
193 | return EBUSY; /* racing with sfw_session_expired() */ | |
194 | } | |
195 | ||
d7e09d03 | 196 | static void |
63418983 | 197 | sfw_deactivate_session(void) |
8a136d11 | 198 | __must_hold(&sfw_data.fw_lock) |
d7e09d03 PT |
199 | { |
200 | sfw_session_t *sn = sfw_data.fw_session; | |
74d68011 MS |
201 | int nactive = 0; |
202 | sfw_batch_t *tsb; | |
d7e09d03 PT |
203 | sfw_test_case_t *tsc; |
204 | ||
550d35d8 DM |
205 | if (sn == NULL) |
206 | return; | |
d7e09d03 | 207 | |
63418983 | 208 | LASSERT(!sn->sn_timer_active); |
d7e09d03 PT |
209 | |
210 | sfw_data.fw_session = NULL; | |
211 | atomic_inc(&sfw_data.fw_nzombies); | |
212 | list_add(&sn->sn_list, &sfw_data.fw_zombie_sessions); | |
213 | ||
214 | spin_unlock(&sfw_data.fw_lock); | |
215 | ||
216 | list_for_each_entry(tsc, &sfw_data.fw_tests, tsc_list) { | |
217 | srpc_abort_service(tsc->tsc_srv_service); | |
218 | } | |
219 | ||
220 | spin_lock(&sfw_data.fw_lock); | |
221 | ||
63418983 | 222 | list_for_each_entry(tsb, &sn->sn_batches, bat_list) { |
d7e09d03 PT |
223 | if (sfw_batch_active(tsb)) { |
224 | nactive++; | |
225 | sfw_stop_batch(tsb, 1); | |
226 | } | |
227 | } | |
228 | ||
229 | if (nactive != 0) | |
230 | return; /* wait for active batches to stop */ | |
231 | ||
232 | list_del_init(&sn->sn_list); | |
233 | spin_unlock(&sfw_data.fw_lock); | |
234 | ||
235 | sfw_destroy_session(sn); | |
236 | ||
237 | spin_lock(&sfw_data.fw_lock); | |
238 | } | |
239 | ||
240 | ||
8d94b6d2 | 241 | static void |
63418983 | 242 | sfw_session_expired(void *data) |
d7e09d03 PT |
243 | { |
244 | sfw_session_t *sn = data; | |
245 | ||
246 | spin_lock(&sfw_data.fw_lock); | |
247 | ||
63418983 MY |
248 | LASSERT(sn->sn_timer_active); |
249 | LASSERT(sn == sfw_data.fw_session); | |
d7e09d03 | 250 | |
63418983 | 251 | CWARN("Session expired! sid: %s-%llu, name: %s\n", |
d7e09d03 PT |
252 | libcfs_nid2str(sn->sn_id.ses_nid), |
253 | sn->sn_id.ses_stamp, &sn->sn_name[0]); | |
254 | ||
255 | sn->sn_timer_active = 0; | |
256 | sfw_deactivate_session(); | |
257 | ||
258 | spin_unlock(&sfw_data.fw_lock); | |
259 | } | |
260 | ||
261 | static inline void | |
262 | sfw_init_session(sfw_session_t *sn, lst_sid_t sid, | |
263 | unsigned features, const char *name) | |
264 | { | |
265 | stt_timer_t *timer = &sn->sn_timer; | |
266 | ||
267 | memset(sn, 0, sizeof(sfw_session_t)); | |
268 | INIT_LIST_HEAD(&sn->sn_list); | |
269 | INIT_LIST_HEAD(&sn->sn_batches); | |
270 | atomic_set(&sn->sn_refcount, 1); /* +1 for caller */ | |
271 | atomic_set(&sn->sn_brw_errors, 0); | |
272 | atomic_set(&sn->sn_ping_errors, 0); | |
273 | strlcpy(&sn->sn_name[0], name, sizeof(sn->sn_name)); | |
274 | ||
275 | sn->sn_timer_active = 0; | |
74d68011 | 276 | sn->sn_id = sid; |
d7e09d03 PT |
277 | sn->sn_features = features; |
278 | sn->sn_timeout = session_timeout; | |
279 | sn->sn_started = cfs_time_current(); | |
280 | ||
281 | timer->stt_data = sn; | |
282 | timer->stt_func = sfw_session_expired; | |
283 | INIT_LIST_HEAD(&timer->stt_list); | |
284 | } | |
285 | ||
286 | /* completion handler for incoming framework RPCs */ | |
8d94b6d2 | 287 | static void |
d7e09d03 PT |
288 | sfw_server_rpc_done(struct srpc_server_rpc *rpc) |
289 | { | |
74d68011 MS |
290 | struct srpc_service *sv = rpc->srpc_scd->scd_svc; |
291 | int status = rpc->srpc_status; | |
d7e09d03 | 292 | |
63418983 | 293 | CDEBUG(D_NET, |
2d00bd17 | 294 | "Incoming framework RPC done: service %s, peer %s, status %s:%d\n", |
d7e09d03 PT |
295 | sv->sv_name, libcfs_id2str(rpc->srpc_peer), |
296 | swi_state2str(rpc->srpc_wi.swi_state), | |
297 | status); | |
298 | ||
299 | if (rpc->srpc_bulk != NULL) | |
300 | sfw_free_pages(rpc); | |
301 | return; | |
302 | } | |
303 | ||
8d94b6d2 | 304 | static void |
63418983 | 305 | sfw_client_rpc_fini(srpc_client_rpc_t *rpc) |
d7e09d03 | 306 | { |
63418983 MY |
307 | LASSERT(rpc->crpc_bulk.bk_niov == 0); |
308 | LASSERT(list_empty(&rpc->crpc_list)); | |
309 | LASSERT(atomic_read(&rpc->crpc_refcount) == 0); | |
d7e09d03 | 310 | |
63418983 | 311 | CDEBUG(D_NET, |
2d00bd17 | 312 | "Outgoing framework RPC done: service %d, peer %s, status %s:%d:%d\n", |
d7e09d03 PT |
313 | rpc->crpc_service, libcfs_id2str(rpc->crpc_dest), |
314 | swi_state2str(rpc->crpc_wi.swi_state), | |
315 | rpc->crpc_aborted, rpc->crpc_status); | |
316 | ||
317 | spin_lock(&sfw_data.fw_lock); | |
318 | ||
319 | /* my callers must finish all RPCs before shutting me down */ | |
320 | LASSERT(!sfw_data.fw_shuttingdown); | |
321 | list_add(&rpc->crpc_list, &sfw_data.fw_zombie_rpcs); | |
322 | ||
323 | spin_unlock(&sfw_data.fw_lock); | |
324 | } | |
325 | ||
8d94b6d2 | 326 | static sfw_batch_t * |
63418983 | 327 | sfw_find_batch(lst_bid_t bid) |
d7e09d03 PT |
328 | { |
329 | sfw_session_t *sn = sfw_data.fw_session; | |
74d68011 | 330 | sfw_batch_t *bat; |
d7e09d03 | 331 | |
63418983 | 332 | LASSERT(sn != NULL); |
d7e09d03 | 333 | |
63418983 | 334 | list_for_each_entry(bat, &sn->sn_batches, bat_list) { |
d7e09d03 PT |
335 | if (bat->bat_id.bat_id == bid.bat_id) |
336 | return bat; | |
337 | } | |
338 | ||
339 | return NULL; | |
340 | } | |
341 | ||
8d94b6d2 | 342 | static sfw_batch_t * |
63418983 | 343 | sfw_bid2batch(lst_bid_t bid) |
d7e09d03 PT |
344 | { |
345 | sfw_session_t *sn = sfw_data.fw_session; | |
74d68011 | 346 | sfw_batch_t *bat; |
d7e09d03 | 347 | |
63418983 | 348 | LASSERT(sn != NULL); |
d7e09d03 PT |
349 | |
350 | bat = sfw_find_batch(bid); | |
351 | if (bat != NULL) | |
352 | return bat; | |
353 | ||
354 | LIBCFS_ALLOC(bat, sizeof(sfw_batch_t)); | |
355 | if (bat == NULL) | |
356 | return NULL; | |
357 | ||
358 | bat->bat_error = 0; | |
359 | bat->bat_session = sn; | |
360 | bat->bat_id = bid; | |
361 | atomic_set(&bat->bat_nactive, 0); | |
362 | INIT_LIST_HEAD(&bat->bat_tests); | |
363 | ||
364 | list_add_tail(&bat->bat_list, &sn->sn_batches); | |
365 | return bat; | |
366 | } | |
367 | ||
8d94b6d2 | 368 | static int |
63418983 | 369 | sfw_get_stats(srpc_stat_reqst_t *request, srpc_stat_reply_t *reply) |
d7e09d03 | 370 | { |
74d68011 | 371 | sfw_session_t *sn = sfw_data.fw_session; |
d7e09d03 | 372 | sfw_counters_t *cnt = &reply->str_fw; |
74d68011 | 373 | sfw_batch_t *bat; |
d7e09d03 PT |
374 | |
375 | reply->str_sid = (sn == NULL) ? LST_INVALID_SID : sn->sn_id; | |
376 | ||
377 | if (request->str_sid.ses_nid == LNET_NID_ANY) { | |
378 | reply->str_status = EINVAL; | |
379 | return 0; | |
380 | } | |
381 | ||
382 | if (sn == NULL || !sfw_sid_equal(request->str_sid, sn->sn_id)) { | |
383 | reply->str_status = ESRCH; | |
384 | return 0; | |
385 | } | |
386 | ||
387 | lnet_counters_get(&reply->str_lnet); | |
388 | srpc_get_counters(&reply->str_rpc); | |
389 | ||
390 | /* send over the msecs since the session was started | |
391 | - with 32 bits to send, this is ~49 days */ | |
70513c5d | 392 | cnt->running_ms = jiffies_to_msecs(jiffies - sn->sn_started); |
d7e09d03 PT |
393 | cnt->brw_errors = atomic_read(&sn->sn_brw_errors); |
394 | cnt->ping_errors = atomic_read(&sn->sn_ping_errors); | |
395 | cnt->zombie_sessions = atomic_read(&sfw_data.fw_nzombies); | |
396 | ||
397 | cnt->active_batches = 0; | |
63418983 | 398 | list_for_each_entry(bat, &sn->sn_batches, bat_list) { |
d7e09d03 PT |
399 | if (atomic_read(&bat->bat_nactive) > 0) |
400 | cnt->active_batches++; | |
401 | } | |
402 | ||
403 | reply->str_status = 0; | |
404 | return 0; | |
405 | } | |
406 | ||
407 | int | |
408 | sfw_make_session(srpc_mksn_reqst_t *request, srpc_mksn_reply_t *reply) | |
409 | { | |
410 | sfw_session_t *sn = sfw_data.fw_session; | |
74d68011 | 411 | srpc_msg_t *msg = container_of(request, srpc_msg_t, |
d7e09d03 | 412 | msg_body.mksn_reqst); |
74d68011 | 413 | int cplen = 0; |
d7e09d03 PT |
414 | |
415 | if (request->mksn_sid.ses_nid == LNET_NID_ANY) { | |
416 | reply->mksn_sid = (sn == NULL) ? LST_INVALID_SID : sn->sn_id; | |
417 | reply->mksn_status = EINVAL; | |
418 | return 0; | |
419 | } | |
420 | ||
421 | if (sn != NULL) { | |
422 | reply->mksn_status = 0; | |
423 | reply->mksn_sid = sn->sn_id; | |
424 | reply->mksn_timeout = sn->sn_timeout; | |
425 | ||
426 | if (sfw_sid_equal(request->mksn_sid, sn->sn_id)) { | |
427 | atomic_inc(&sn->sn_refcount); | |
428 | return 0; | |
429 | } | |
430 | ||
431 | if (!request->mksn_force) { | |
432 | reply->mksn_status = EBUSY; | |
433 | cplen = strlcpy(&reply->mksn_name[0], &sn->sn_name[0], | |
434 | sizeof(reply->mksn_name)); | |
435 | if (cplen >= sizeof(reply->mksn_name)) | |
436 | return -E2BIG; | |
437 | return 0; | |
438 | } | |
439 | } | |
440 | ||
441 | /* reject the request if it requires unknown features | |
442 | * NB: old version will always accept all features because it's not | |
443 | * aware of srpc_msg_t::msg_ses_feats, it's a defect but it's also | |
444 | * harmless because it will return zero feature to console, and it's | |
445 | * console's responsibility to make sure all nodes in a session have | |
446 | * same feature mask. */ | |
447 | if ((msg->msg_ses_feats & ~LST_FEATS_MASK) != 0) { | |
448 | reply->mksn_status = EPROTO; | |
449 | return 0; | |
450 | } | |
451 | ||
452 | /* brand new or create by force */ | |
453 | LIBCFS_ALLOC(sn, sizeof(sfw_session_t)); | |
454 | if (sn == NULL) { | |
63418983 | 455 | CERROR("Dropping RPC (mksn) under memory pressure.\n"); |
d7e09d03 PT |
456 | return -ENOMEM; |
457 | } | |
458 | ||
459 | sfw_init_session(sn, request->mksn_sid, | |
460 | msg->msg_ses_feats, &request->mksn_name[0]); | |
461 | ||
462 | spin_lock(&sfw_data.fw_lock); | |
463 | ||
464 | sfw_deactivate_session(); | |
465 | LASSERT(sfw_data.fw_session == NULL); | |
466 | sfw_data.fw_session = sn; | |
467 | ||
468 | spin_unlock(&sfw_data.fw_lock); | |
469 | ||
470 | reply->mksn_status = 0; | |
471 | reply->mksn_sid = sn->sn_id; | |
472 | reply->mksn_timeout = sn->sn_timeout; | |
473 | return 0; | |
474 | } | |
475 | ||
8d94b6d2 | 476 | static int |
63418983 | 477 | sfw_remove_session(srpc_rmsn_reqst_t *request, srpc_rmsn_reply_t *reply) |
d7e09d03 PT |
478 | { |
479 | sfw_session_t *sn = sfw_data.fw_session; | |
480 | ||
481 | reply->rmsn_sid = (sn == NULL) ? LST_INVALID_SID : sn->sn_id; | |
482 | ||
483 | if (request->rmsn_sid.ses_nid == LNET_NID_ANY) { | |
484 | reply->rmsn_status = EINVAL; | |
485 | return 0; | |
486 | } | |
487 | ||
488 | if (sn == NULL || !sfw_sid_equal(request->rmsn_sid, sn->sn_id)) { | |
489 | reply->rmsn_status = (sn == NULL) ? ESRCH : EBUSY; | |
490 | return 0; | |
491 | } | |
492 | ||
493 | if (!atomic_dec_and_test(&sn->sn_refcount)) { | |
494 | reply->rmsn_status = 0; | |
495 | return 0; | |
496 | } | |
497 | ||
498 | spin_lock(&sfw_data.fw_lock); | |
499 | sfw_deactivate_session(); | |
500 | spin_unlock(&sfw_data.fw_lock); | |
501 | ||
502 | reply->rmsn_status = 0; | |
503 | reply->rmsn_sid = LST_INVALID_SID; | |
504 | LASSERT(sfw_data.fw_session == NULL); | |
505 | return 0; | |
506 | } | |
507 | ||
8d94b6d2 | 508 | static int |
63418983 | 509 | sfw_debug_session(srpc_debug_reqst_t *request, srpc_debug_reply_t *reply) |
d7e09d03 PT |
510 | { |
511 | sfw_session_t *sn = sfw_data.fw_session; | |
512 | ||
513 | if (sn == NULL) { | |
514 | reply->dbg_status = ESRCH; | |
515 | reply->dbg_sid = LST_INVALID_SID; | |
516 | return 0; | |
517 | } | |
518 | ||
519 | reply->dbg_status = 0; | |
520 | reply->dbg_sid = sn->sn_id; | |
521 | reply->dbg_timeout = sn->sn_timeout; | |
522 | if (strlcpy(reply->dbg_name, &sn->sn_name[0], sizeof(reply->dbg_name)) | |
523 | >= sizeof(reply->dbg_name)) | |
524 | return -E2BIG; | |
525 | ||
526 | return 0; | |
527 | } | |
528 | ||
8d94b6d2 | 529 | static void |
63418983 | 530 | sfw_test_rpc_fini(srpc_client_rpc_t *rpc) |
d7e09d03 | 531 | { |
74d68011 | 532 | sfw_test_unit_t *tsu = rpc->crpc_priv; |
d7e09d03 PT |
533 | sfw_test_instance_t *tsi = tsu->tsu_instance; |
534 | ||
535 | /* Called with hold of tsi->tsi_lock */ | |
63418983 | 536 | LASSERT(list_empty(&rpc->crpc_list)); |
d7e09d03 PT |
537 | list_add(&rpc->crpc_list, &tsi->tsi_free_rpcs); |
538 | } | |
539 | ||
540 | static inline int | |
541 | sfw_test_buffers(sfw_test_instance_t *tsi) | |
542 | { | |
74d68011 MS |
543 | struct sfw_test_case *tsc = sfw_find_test_case(tsi->tsi_service); |
544 | struct srpc_service *svc = tsc->tsc_srv_service; | |
545 | int nbuf; | |
d7e09d03 PT |
546 | |
547 | nbuf = min(svc->sv_wi_total, tsi->tsi_loop) / svc->sv_ncpts; | |
548 | return max(SFW_TEST_WI_MIN, nbuf + SFW_TEST_WI_EXTRA); | |
549 | } | |
550 | ||
8d94b6d2 | 551 | static int |
d7e09d03 PT |
552 | sfw_load_test(struct sfw_test_instance *tsi) |
553 | { | |
74d68011 MS |
554 | struct sfw_test_case *tsc; |
555 | struct srpc_service *svc; | |
556 | int nbuf; | |
557 | int rc; | |
d7e09d03 PT |
558 | |
559 | LASSERT(tsi != NULL); | |
560 | tsc = sfw_find_test_case(tsi->tsi_service); | |
561 | nbuf = sfw_test_buffers(tsi); | |
562 | LASSERT(tsc != NULL); | |
563 | svc = tsc->tsc_srv_service; | |
564 | ||
565 | if (tsi->tsi_is_client) { | |
566 | tsi->tsi_ops = tsc->tsc_cli_ops; | |
567 | return 0; | |
568 | } | |
569 | ||
570 | rc = srpc_service_add_buffers(svc, nbuf); | |
571 | if (rc != 0) { | |
2d00bd17 JP |
572 | CWARN("Failed to reserve enough buffers: service %s, %d needed: %d\n", |
573 | svc->sv_name, nbuf, rc); | |
d7e09d03 PT |
574 | /* NB: this error handler is not strictly correct, because |
575 | * it may release more buffers than already allocated, | |
576 | * but it doesn't matter because request portal should | |
577 | * be lazy portal and will grow buffers if necessary. */ | |
578 | srpc_service_remove_buffers(svc, nbuf); | |
579 | return -ENOMEM; | |
580 | } | |
581 | ||
582 | CDEBUG(D_NET, "Reserved %d buffers for test %s\n", | |
583 | nbuf * (srpc_serv_is_framework(svc) ? | |
584 | 1 : cfs_cpt_number(cfs_cpt_table)), svc->sv_name); | |
585 | return 0; | |
586 | } | |
587 | ||
8d94b6d2 | 588 | static void |
d7e09d03 PT |
589 | sfw_unload_test(struct sfw_test_instance *tsi) |
590 | { | |
591 | struct sfw_test_case *tsc = sfw_find_test_case(tsi->tsi_service); | |
592 | ||
593 | LASSERT(tsc != NULL); | |
594 | ||
595 | if (tsi->tsi_is_client) | |
596 | return; | |
597 | ||
598 | /* shrink buffers, because request portal is lazy portal | |
599 | * which can grow buffers at runtime so we may leave | |
600 | * some buffers behind, but never mind... */ | |
601 | srpc_service_remove_buffers(tsc->tsc_srv_service, | |
602 | sfw_test_buffers(tsi)); | |
603 | return; | |
604 | } | |
605 | ||
8d94b6d2 | 606 | static void |
63418983 | 607 | sfw_destroy_test_instance(sfw_test_instance_t *tsi) |
d7e09d03 PT |
608 | { |
609 | srpc_client_rpc_t *rpc; | |
74d68011 | 610 | sfw_test_unit_t *tsu; |
d7e09d03 | 611 | |
550d35d8 DM |
612 | if (!tsi->tsi_is_client) |
613 | goto clean; | |
d7e09d03 PT |
614 | |
615 | tsi->tsi_ops->tso_fini(tsi); | |
616 | ||
63418983 MY |
617 | LASSERT(!tsi->tsi_stopping); |
618 | LASSERT(list_empty(&tsi->tsi_active_rpcs)); | |
619 | LASSERT(!sfw_test_active(tsi)); | |
d7e09d03 PT |
620 | |
621 | while (!list_empty(&tsi->tsi_units)) { | |
622 | tsu = list_entry(tsi->tsi_units.next, | |
623 | sfw_test_unit_t, tsu_list); | |
624 | list_del(&tsu->tsu_list); | |
625 | LIBCFS_FREE(tsu, sizeof(*tsu)); | |
626 | } | |
627 | ||
628 | while (!list_empty(&tsi->tsi_free_rpcs)) { | |
629 | rpc = list_entry(tsi->tsi_free_rpcs.next, | |
630 | srpc_client_rpc_t, crpc_list); | |
631 | list_del(&rpc->crpc_list); | |
632 | LIBCFS_FREE(rpc, srpc_client_rpc_size(rpc)); | |
633 | } | |
634 | ||
635 | clean: | |
636 | sfw_unload_test(tsi); | |
637 | LIBCFS_FREE(tsi, sizeof(*tsi)); | |
638 | return; | |
639 | } | |
640 | ||
8d94b6d2 | 641 | static void |
63418983 | 642 | sfw_destroy_batch(sfw_batch_t *tsb) |
d7e09d03 PT |
643 | { |
644 | sfw_test_instance_t *tsi; | |
645 | ||
63418983 MY |
646 | LASSERT(!sfw_batch_active(tsb)); |
647 | LASSERT(list_empty(&tsb->bat_list)); | |
d7e09d03 PT |
648 | |
649 | while (!list_empty(&tsb->bat_tests)) { | |
650 | tsi = list_entry(tsb->bat_tests.next, | |
651 | sfw_test_instance_t, tsi_list); | |
652 | list_del_init(&tsi->tsi_list); | |
653 | sfw_destroy_test_instance(tsi); | |
654 | } | |
655 | ||
656 | LIBCFS_FREE(tsb, sizeof(sfw_batch_t)); | |
657 | return; | |
658 | } | |
659 | ||
660 | void | |
63418983 | 661 | sfw_destroy_session(sfw_session_t *sn) |
d7e09d03 PT |
662 | { |
663 | sfw_batch_t *batch; | |
664 | ||
63418983 MY |
665 | LASSERT(list_empty(&sn->sn_list)); |
666 | LASSERT(sn != sfw_data.fw_session); | |
d7e09d03 PT |
667 | |
668 | while (!list_empty(&sn->sn_batches)) { | |
669 | batch = list_entry(sn->sn_batches.next, | |
670 | sfw_batch_t, bat_list); | |
671 | list_del_init(&batch->bat_list); | |
672 | sfw_destroy_batch(batch); | |
673 | } | |
674 | ||
675 | LIBCFS_FREE(sn, sizeof(*sn)); | |
676 | atomic_dec(&sfw_data.fw_nzombies); | |
677 | return; | |
678 | } | |
679 | ||
8d94b6d2 | 680 | static void |
d7e09d03 PT |
681 | sfw_unpack_addtest_req(srpc_msg_t *msg) |
682 | { | |
683 | srpc_test_reqst_t *req = &msg->msg_body.tes_reqst; | |
684 | ||
63418983 MY |
685 | LASSERT(msg->msg_type == SRPC_MSG_TEST_REQST); |
686 | LASSERT(req->tsr_is_client); | |
d7e09d03 PT |
687 | |
688 | if (msg->msg_magic == SRPC_MSG_MAGIC) | |
689 | return; /* no flipping needed */ | |
690 | ||
63418983 | 691 | LASSERT(msg->msg_magic == __swab32(SRPC_MSG_MAGIC)); |
d7e09d03 PT |
692 | |
693 | if (req->tsr_service == SRPC_SERVICE_BRW) { | |
694 | if ((msg->msg_ses_feats & LST_FEAT_BULK_LEN) == 0) { | |
695 | test_bulk_req_t *bulk = &req->tsr_u.bulk_v0; | |
696 | ||
697 | __swab32s(&bulk->blk_opc); | |
698 | __swab32s(&bulk->blk_npg); | |
699 | __swab32s(&bulk->blk_flags); | |
700 | ||
701 | } else { | |
702 | test_bulk_req_v1_t *bulk = &req->tsr_u.bulk_v1; | |
703 | ||
704 | __swab16s(&bulk->blk_opc); | |
705 | __swab16s(&bulk->blk_flags); | |
706 | __swab32s(&bulk->blk_offset); | |
707 | __swab32s(&bulk->blk_len); | |
708 | } | |
709 | ||
710 | return; | |
711 | } | |
712 | ||
713 | if (req->tsr_service == SRPC_SERVICE_PING) { | |
714 | test_ping_req_t *ping = &req->tsr_u.ping; | |
715 | ||
716 | __swab32s(&ping->png_size); | |
717 | __swab32s(&ping->png_flags); | |
718 | return; | |
719 | } | |
720 | ||
63418983 | 721 | LBUG(); |
d7e09d03 PT |
722 | return; |
723 | } | |
724 | ||
8d94b6d2 | 725 | static int |
63418983 | 726 | sfw_add_test_instance(sfw_batch_t *tsb, srpc_server_rpc_t *rpc) |
d7e09d03 | 727 | { |
74d68011 MS |
728 | srpc_msg_t *msg = &rpc->srpc_reqstbuf->buf_msg; |
729 | srpc_test_reqst_t *req = &msg->msg_body.tes_reqst; | |
730 | srpc_bulk_t *bk = rpc->srpc_bulk; | |
731 | int ndest = req->tsr_ndest; | |
732 | sfw_test_unit_t *tsu; | |
d7e09d03 | 733 | sfw_test_instance_t *tsi; |
74d68011 MS |
734 | int i; |
735 | int rc; | |
d7e09d03 PT |
736 | |
737 | LIBCFS_ALLOC(tsi, sizeof(*tsi)); | |
738 | if (tsi == NULL) { | |
63418983 | 739 | CERROR("Can't allocate test instance for batch: %llu\n", |
d7e09d03 PT |
740 | tsb->bat_id.bat_id); |
741 | return -ENOMEM; | |
742 | } | |
743 | ||
d7e09d03 PT |
744 | spin_lock_init(&tsi->tsi_lock); |
745 | atomic_set(&tsi->tsi_nactive, 0); | |
746 | INIT_LIST_HEAD(&tsi->tsi_units); | |
747 | INIT_LIST_HEAD(&tsi->tsi_free_rpcs); | |
748 | INIT_LIST_HEAD(&tsi->tsi_active_rpcs); | |
749 | ||
750 | tsi->tsi_stopping = 0; | |
74d68011 MS |
751 | tsi->tsi_batch = tsb; |
752 | tsi->tsi_loop = req->tsr_loop; | |
753 | tsi->tsi_concur = req->tsr_concur; | |
d7e09d03 PT |
754 | tsi->tsi_service = req->tsr_service; |
755 | tsi->tsi_is_client = !!(req->tsr_is_client); | |
756 | tsi->tsi_stoptsu_onerr = !!(req->tsr_stop_onerr); | |
757 | ||
758 | rc = sfw_load_test(tsi); | |
759 | if (rc != 0) { | |
760 | LIBCFS_FREE(tsi, sizeof(*tsi)); | |
761 | return rc; | |
762 | } | |
763 | ||
63418983 | 764 | LASSERT(!sfw_batch_active(tsb)); |
d7e09d03 PT |
765 | |
766 | if (!tsi->tsi_is_client) { | |
767 | /* it's test server, just add it to tsb */ | |
768 | list_add_tail(&tsi->tsi_list, &tsb->bat_tests); | |
769 | return 0; | |
770 | } | |
771 | ||
63418983 MY |
772 | LASSERT(bk != NULL); |
773 | LASSERT(bk->bk_niov * SFW_ID_PER_PAGE >= (unsigned int)ndest); | |
d7e09d03 PT |
774 | LASSERT((unsigned int)bk->bk_len >= |
775 | sizeof(lnet_process_id_packed_t) * ndest); | |
776 | ||
777 | sfw_unpack_addtest_req(msg); | |
778 | memcpy(&tsi->tsi_u, &req->tsr_u, sizeof(tsi->tsi_u)); | |
779 | ||
780 | for (i = 0; i < ndest; i++) { | |
781 | lnet_process_id_packed_t *dests; | |
74d68011 MS |
782 | lnet_process_id_packed_t id; |
783 | int j; | |
d7e09d03 PT |
784 | |
785 | dests = page_address(bk->bk_iovs[i / SFW_ID_PER_PAGE].kiov_page); | |
63418983 | 786 | LASSERT(dests != NULL); /* my pages are within KVM always */ |
d7e09d03 PT |
787 | id = dests[i % SFW_ID_PER_PAGE]; |
788 | if (msg->msg_magic != SRPC_MSG_MAGIC) | |
789 | sfw_unpack_id(id); | |
790 | ||
791 | for (j = 0; j < tsi->tsi_concur; j++) { | |
792 | LIBCFS_ALLOC(tsu, sizeof(sfw_test_unit_t)); | |
793 | if (tsu == NULL) { | |
794 | rc = -ENOMEM; | |
63418983 | 795 | CERROR("Can't allocate tsu for %d\n", |
d7e09d03 PT |
796 | tsi->tsi_service); |
797 | goto error; | |
798 | } | |
799 | ||
800 | tsu->tsu_dest.nid = id.nid; | |
801 | tsu->tsu_dest.pid = id.pid; | |
802 | tsu->tsu_instance = tsi; | |
803 | tsu->tsu_private = NULL; | |
804 | list_add_tail(&tsu->tsu_list, &tsi->tsi_units); | |
805 | } | |
806 | } | |
807 | ||
808 | rc = tsi->tsi_ops->tso_init(tsi); | |
809 | if (rc == 0) { | |
810 | list_add_tail(&tsi->tsi_list, &tsb->bat_tests); | |
811 | return 0; | |
812 | } | |
813 | ||
814 | error: | |
63418983 | 815 | LASSERT(rc != 0); |
d7e09d03 PT |
816 | sfw_destroy_test_instance(tsi); |
817 | return rc; | |
818 | } | |
819 | ||
820 | static void | |
63418983 | 821 | sfw_test_unit_done(sfw_test_unit_t *tsu) |
d7e09d03 PT |
822 | { |
823 | sfw_test_instance_t *tsi = tsu->tsu_instance; | |
74d68011 MS |
824 | sfw_batch_t *tsb = tsi->tsi_batch; |
825 | sfw_session_t *sn = tsb->bat_session; | |
d7e09d03 | 826 | |
63418983 | 827 | LASSERT(sfw_test_active(tsi)); |
d7e09d03 PT |
828 | |
829 | if (!atomic_dec_and_test(&tsi->tsi_nactive)) | |
830 | return; | |
831 | ||
832 | /* the test instance is done */ | |
833 | spin_lock(&tsi->tsi_lock); | |
834 | ||
835 | tsi->tsi_stopping = 0; | |
836 | ||
837 | spin_unlock(&tsi->tsi_lock); | |
838 | ||
839 | spin_lock(&sfw_data.fw_lock); | |
840 | ||
841 | if (!atomic_dec_and_test(&tsb->bat_nactive) ||/* tsb still active */ | |
842 | sn == sfw_data.fw_session) { /* sn also active */ | |
843 | spin_unlock(&sfw_data.fw_lock); | |
844 | return; | |
845 | } | |
846 | ||
63418983 | 847 | LASSERT(!list_empty(&sn->sn_list)); /* I'm a zombie! */ |
d7e09d03 | 848 | |
63418983 | 849 | list_for_each_entry(tsb, &sn->sn_batches, bat_list) { |
d7e09d03 PT |
850 | if (sfw_batch_active(tsb)) { |
851 | spin_unlock(&sfw_data.fw_lock); | |
852 | return; | |
853 | } | |
854 | } | |
855 | ||
856 | list_del_init(&sn->sn_list); | |
857 | spin_unlock(&sfw_data.fw_lock); | |
858 | ||
859 | sfw_destroy_session(sn); | |
860 | return; | |
861 | } | |
862 | ||
8d94b6d2 | 863 | static void |
63418983 | 864 | sfw_test_rpc_done(srpc_client_rpc_t *rpc) |
d7e09d03 | 865 | { |
74d68011 | 866 | sfw_test_unit_t *tsu = rpc->crpc_priv; |
d7e09d03 | 867 | sfw_test_instance_t *tsi = tsu->tsu_instance; |
74d68011 | 868 | int done = 0; |
d7e09d03 PT |
869 | |
870 | tsi->tsi_ops->tso_done_rpc(tsu, rpc); | |
871 | ||
872 | spin_lock(&tsi->tsi_lock); | |
873 | ||
63418983 MY |
874 | LASSERT(sfw_test_active(tsi)); |
875 | LASSERT(!list_empty(&rpc->crpc_list)); | |
d7e09d03 PT |
876 | |
877 | list_del_init(&rpc->crpc_list); | |
878 | ||
879 | /* batch is stopping or loop is done or get error */ | |
880 | if (tsi->tsi_stopping || | |
881 | tsu->tsu_loop == 0 || | |
882 | (rpc->crpc_status != 0 && tsi->tsi_stoptsu_onerr)) | |
883 | done = 1; | |
884 | ||
885 | /* dec ref for poster */ | |
886 | srpc_client_rpc_decref(rpc); | |
887 | ||
888 | spin_unlock(&tsi->tsi_lock); | |
889 | ||
890 | if (!done) { | |
891 | swi_schedule_workitem(&tsu->tsu_worker); | |
892 | return; | |
893 | } | |
894 | ||
895 | sfw_test_unit_done(tsu); | |
896 | return; | |
897 | } | |
898 | ||
899 | int | |
900 | sfw_create_test_rpc(sfw_test_unit_t *tsu, lnet_process_id_t peer, | |
901 | unsigned features, int nblk, int blklen, | |
902 | srpc_client_rpc_t **rpcpp) | |
903 | { | |
74d68011 | 904 | srpc_client_rpc_t *rpc = NULL; |
d7e09d03 PT |
905 | sfw_test_instance_t *tsi = tsu->tsu_instance; |
906 | ||
907 | spin_lock(&tsi->tsi_lock); | |
908 | ||
63418983 | 909 | LASSERT(sfw_test_active(tsi)); |
d7e09d03 PT |
910 | |
911 | if (!list_empty(&tsi->tsi_free_rpcs)) { | |
912 | /* pick request from buffer */ | |
913 | rpc = list_entry(tsi->tsi_free_rpcs.next, | |
914 | srpc_client_rpc_t, crpc_list); | |
63418983 | 915 | LASSERT(nblk == rpc->crpc_bulk.bk_niov); |
d7e09d03 PT |
916 | list_del_init(&rpc->crpc_list); |
917 | } | |
918 | ||
919 | spin_unlock(&tsi->tsi_lock); | |
920 | ||
921 | if (rpc == NULL) { | |
922 | rpc = srpc_create_client_rpc(peer, tsi->tsi_service, nblk, | |
923 | blklen, sfw_test_rpc_done, | |
924 | sfw_test_rpc_fini, tsu); | |
925 | } else { | |
926 | srpc_init_client_rpc(rpc, peer, tsi->tsi_service, nblk, | |
927 | blklen, sfw_test_rpc_done, | |
928 | sfw_test_rpc_fini, tsu); | |
929 | } | |
930 | ||
931 | if (rpc == NULL) { | |
932 | CERROR("Can't create rpc for test %d\n", tsi->tsi_service); | |
933 | return -ENOMEM; | |
934 | } | |
935 | ||
936 | rpc->crpc_reqstmsg.msg_ses_feats = features; | |
937 | *rpcpp = rpc; | |
938 | ||
939 | return 0; | |
940 | } | |
941 | ||
8d94b6d2 | 942 | static int |
63418983 | 943 | sfw_run_test(swi_workitem_t *wi) |
d7e09d03 | 944 | { |
74d68011 | 945 | sfw_test_unit_t *tsu = wi->swi_workitem.wi_data; |
d7e09d03 | 946 | sfw_test_instance_t *tsi = tsu->tsu_instance; |
74d68011 | 947 | srpc_client_rpc_t *rpc = NULL; |
d7e09d03 | 948 | |
63418983 | 949 | LASSERT(wi == &tsu->tsu_worker); |
d7e09d03 PT |
950 | |
951 | if (tsi->tsi_ops->tso_prep_rpc(tsu, tsu->tsu_dest, &rpc) != 0) { | |
63418983 | 952 | LASSERT(rpc == NULL); |
d7e09d03 PT |
953 | goto test_done; |
954 | } | |
955 | ||
63418983 | 956 | LASSERT(rpc != NULL); |
d7e09d03 PT |
957 | |
958 | spin_lock(&tsi->tsi_lock); | |
959 | ||
960 | if (tsi->tsi_stopping) { | |
961 | list_add(&rpc->crpc_list, &tsi->tsi_free_rpcs); | |
962 | spin_unlock(&tsi->tsi_lock); | |
963 | goto test_done; | |
964 | } | |
965 | ||
966 | if (tsu->tsu_loop > 0) | |
967 | tsu->tsu_loop--; | |
968 | ||
969 | list_add_tail(&rpc->crpc_list, &tsi->tsi_active_rpcs); | |
970 | spin_unlock(&tsi->tsi_lock); | |
971 | ||
972 | rpc->crpc_timeout = rpc_timeout; | |
973 | ||
974 | spin_lock(&rpc->crpc_lock); | |
975 | srpc_post_rpc(rpc); | |
976 | spin_unlock(&rpc->crpc_lock); | |
977 | return 0; | |
978 | ||
979 | test_done: | |
980 | /* | |
981 | * No one can schedule me now since: | |
982 | * - previous RPC, if any, has done and | |
983 | * - no new RPC is initiated. | |
984 | * - my batch is still active; no one can run it again now. | |
985 | * Cancel pending schedules and prevent future schedule attempts: | |
986 | */ | |
987 | swi_exit_workitem(wi); | |
988 | sfw_test_unit_done(tsu); | |
989 | return 1; | |
990 | } | |
991 | ||
8d94b6d2 | 992 | static int |
63418983 | 993 | sfw_run_batch(sfw_batch_t *tsb) |
d7e09d03 | 994 | { |
74d68011 MS |
995 | swi_workitem_t *wi; |
996 | sfw_test_unit_t *tsu; | |
d7e09d03 PT |
997 | sfw_test_instance_t *tsi; |
998 | ||
999 | if (sfw_batch_active(tsb)) { | |
b0f5aad5 | 1000 | CDEBUG(D_NET, "Batch already active: %llu (%d)\n", |
d7e09d03 PT |
1001 | tsb->bat_id.bat_id, atomic_read(&tsb->bat_nactive)); |
1002 | return 0; | |
1003 | } | |
1004 | ||
63418983 | 1005 | list_for_each_entry(tsi, &tsb->bat_tests, tsi_list) { |
d7e09d03 PT |
1006 | if (!tsi->tsi_is_client) /* skip server instances */ |
1007 | continue; | |
1008 | ||
63418983 MY |
1009 | LASSERT(!tsi->tsi_stopping); |
1010 | LASSERT(!sfw_test_active(tsi)); | |
d7e09d03 PT |
1011 | |
1012 | atomic_inc(&tsb->bat_nactive); | |
1013 | ||
63418983 | 1014 | list_for_each_entry(tsu, &tsi->tsi_units, tsu_list) { |
d7e09d03 PT |
1015 | atomic_inc(&tsi->tsi_nactive); |
1016 | tsu->tsu_loop = tsi->tsi_loop; | |
1017 | wi = &tsu->tsu_worker; | |
1018 | swi_init_workitem(wi, tsu, sfw_run_test, | |
1019 | lst_sched_test[\ | |
1020 | lnet_cpt_of_nid(tsu->tsu_dest.nid)]); | |
1021 | swi_schedule_workitem(wi); | |
1022 | } | |
1023 | } | |
1024 | ||
1025 | return 0; | |
1026 | } | |
1027 | ||
1028 | int | |
63418983 | 1029 | sfw_stop_batch(sfw_batch_t *tsb, int force) |
d7e09d03 PT |
1030 | { |
1031 | sfw_test_instance_t *tsi; | |
74d68011 | 1032 | srpc_client_rpc_t *rpc; |
d7e09d03 PT |
1033 | |
1034 | if (!sfw_batch_active(tsb)) { | |
b0f5aad5 | 1035 | CDEBUG(D_NET, "Batch %llu inactive\n", tsb->bat_id.bat_id); |
d7e09d03 PT |
1036 | return 0; |
1037 | } | |
1038 | ||
63418983 | 1039 | list_for_each_entry(tsi, &tsb->bat_tests, tsi_list) { |
d7e09d03 PT |
1040 | spin_lock(&tsi->tsi_lock); |
1041 | ||
1042 | if (!tsi->tsi_is_client || | |
1043 | !sfw_test_active(tsi) || tsi->tsi_stopping) { | |
1044 | spin_unlock(&tsi->tsi_lock); | |
1045 | continue; | |
1046 | } | |
1047 | ||
1048 | tsi->tsi_stopping = 1; | |
1049 | ||
1050 | if (!force) { | |
1051 | spin_unlock(&tsi->tsi_lock); | |
1052 | continue; | |
1053 | } | |
1054 | ||
1055 | /* abort launched rpcs in the test */ | |
1056 | list_for_each_entry(rpc, &tsi->tsi_active_rpcs, crpc_list) { | |
1057 | spin_lock(&rpc->crpc_lock); | |
1058 | ||
1059 | srpc_abort_rpc(rpc, -EINTR); | |
1060 | ||
1061 | spin_unlock(&rpc->crpc_lock); | |
1062 | } | |
1063 | ||
1064 | spin_unlock(&tsi->tsi_lock); | |
1065 | } | |
1066 | ||
1067 | return 0; | |
1068 | } | |
1069 | ||
8d94b6d2 | 1070 | static int |
63418983 | 1071 | sfw_query_batch(sfw_batch_t *tsb, int testidx, srpc_batch_reply_t *reply) |
d7e09d03 PT |
1072 | { |
1073 | sfw_test_instance_t *tsi; | |
1074 | ||
1075 | if (testidx < 0) | |
1076 | return -EINVAL; | |
1077 | ||
1078 | if (testidx == 0) { | |
1079 | reply->bar_active = atomic_read(&tsb->bat_nactive); | |
1080 | return 0; | |
1081 | } | |
1082 | ||
63418983 | 1083 | list_for_each_entry(tsi, &tsb->bat_tests, tsi_list) { |
d7e09d03 PT |
1084 | if (testidx-- > 1) |
1085 | continue; | |
1086 | ||
1087 | reply->bar_active = atomic_read(&tsi->tsi_nactive); | |
1088 | return 0; | |
1089 | } | |
1090 | ||
1091 | return -ENOENT; | |
1092 | } | |
1093 | ||
1094 | void | |
63418983 | 1095 | sfw_free_pages(srpc_server_rpc_t *rpc) |
d7e09d03 PT |
1096 | { |
1097 | srpc_free_bulk(rpc->srpc_bulk); | |
1098 | rpc->srpc_bulk = NULL; | |
1099 | } | |
1100 | ||
1101 | int | |
1102 | sfw_alloc_pages(struct srpc_server_rpc *rpc, int cpt, int npages, int len, | |
1103 | int sink) | |
1104 | { | |
1105 | LASSERT(rpc->srpc_bulk == NULL); | |
1106 | LASSERT(npages > 0 && npages <= LNET_MAX_IOV); | |
1107 | ||
1108 | rpc->srpc_bulk = srpc_alloc_bulk(cpt, npages, len, sink); | |
1109 | if (rpc->srpc_bulk == NULL) | |
1110 | return -ENOMEM; | |
1111 | ||
1112 | return 0; | |
1113 | } | |
1114 | ||
8d94b6d2 | 1115 | static int |
63418983 | 1116 | sfw_add_test(srpc_server_rpc_t *rpc) |
d7e09d03 | 1117 | { |
74d68011 | 1118 | sfw_session_t *sn = sfw_data.fw_session; |
d7e09d03 PT |
1119 | srpc_test_reply_t *reply = &rpc->srpc_replymsg.msg_body.tes_reply; |
1120 | srpc_test_reqst_t *request; | |
74d68011 MS |
1121 | int rc; |
1122 | sfw_batch_t *bat; | |
d7e09d03 PT |
1123 | |
1124 | request = &rpc->srpc_reqstbuf->buf_msg.msg_body.tes_reqst; | |
1125 | reply->tsr_sid = (sn == NULL) ? LST_INVALID_SID : sn->sn_id; | |
1126 | ||
1127 | if (request->tsr_loop == 0 || | |
1128 | request->tsr_concur == 0 || | |
1129 | request->tsr_sid.ses_nid == LNET_NID_ANY || | |
1130 | request->tsr_ndest > SFW_MAX_NDESTS || | |
1131 | (request->tsr_is_client && request->tsr_ndest == 0) || | |
1132 | request->tsr_concur > SFW_MAX_CONCUR || | |
1133 | request->tsr_service > SRPC_SERVICE_MAX_ID || | |
1134 | request->tsr_service <= SRPC_FRAMEWORK_SERVICE_MAX_ID) { | |
1135 | reply->tsr_status = EINVAL; | |
1136 | return 0; | |
1137 | } | |
1138 | ||
1139 | if (sn == NULL || !sfw_sid_equal(request->tsr_sid, sn->sn_id) || | |
1140 | sfw_find_test_case(request->tsr_service) == NULL) { | |
1141 | reply->tsr_status = ENOENT; | |
1142 | return 0; | |
1143 | } | |
1144 | ||
1145 | bat = sfw_bid2batch(request->tsr_bid); | |
1146 | if (bat == NULL) { | |
63418983 | 1147 | CERROR("Dropping RPC (%s) from %s under memory pressure.\n", |
d7e09d03 PT |
1148 | rpc->srpc_scd->scd_svc->sv_name, |
1149 | libcfs_id2str(rpc->srpc_peer)); | |
1150 | return -ENOMEM; | |
1151 | } | |
1152 | ||
1153 | if (sfw_batch_active(bat)) { | |
1154 | reply->tsr_status = EBUSY; | |
1155 | return 0; | |
1156 | } | |
1157 | ||
1158 | if (request->tsr_is_client && rpc->srpc_bulk == NULL) { | |
1159 | /* rpc will be resumed later in sfw_bulk_ready */ | |
74d68011 MS |
1160 | int npg = sfw_id_pages(request->tsr_ndest); |
1161 | int len; | |
d7e09d03 PT |
1162 | |
1163 | if ((sn->sn_features & LST_FEAT_BULK_LEN) == 0) { | |
1164 | len = npg * PAGE_CACHE_SIZE; | |
1165 | ||
1166 | } else { | |
1167 | len = sizeof(lnet_process_id_packed_t) * | |
1168 | request->tsr_ndest; | |
1169 | } | |
1170 | ||
1171 | return sfw_alloc_pages(rpc, CFS_CPT_ANY, npg, len, 1); | |
1172 | } | |
1173 | ||
1174 | rc = sfw_add_test_instance(bat, rpc); | |
63418983 | 1175 | CDEBUG(rc == 0 ? D_NET : D_WARNING, |
d7e09d03 PT |
1176 | "%s test: sv %d %s, loop %d, concur %d, ndest %d\n", |
1177 | rc == 0 ? "Added" : "Failed to add", request->tsr_service, | |
1178 | request->tsr_is_client ? "client" : "server", | |
1179 | request->tsr_loop, request->tsr_concur, request->tsr_ndest); | |
1180 | ||
1181 | reply->tsr_status = (rc < 0) ? -rc : rc; | |
1182 | return 0; | |
1183 | } | |
1184 | ||
8d94b6d2 | 1185 | static int |
63418983 | 1186 | sfw_control_batch(srpc_batch_reqst_t *request, srpc_batch_reply_t *reply) |
d7e09d03 PT |
1187 | { |
1188 | sfw_session_t *sn = sfw_data.fw_session; | |
74d68011 MS |
1189 | int rc = 0; |
1190 | sfw_batch_t *bat; | |
d7e09d03 PT |
1191 | |
1192 | reply->bar_sid = (sn == NULL) ? LST_INVALID_SID : sn->sn_id; | |
1193 | ||
1194 | if (sn == NULL || !sfw_sid_equal(request->bar_sid, sn->sn_id)) { | |
1195 | reply->bar_status = ESRCH; | |
1196 | return 0; | |
1197 | } | |
1198 | ||
1199 | bat = sfw_find_batch(request->bar_bid); | |
1200 | if (bat == NULL) { | |
1201 | reply->bar_status = ENOENT; | |
1202 | return 0; | |
1203 | } | |
1204 | ||
1205 | switch (request->bar_opc) { | |
1206 | case SRPC_BATCH_OPC_RUN: | |
1207 | rc = sfw_run_batch(bat); | |
1208 | break; | |
1209 | ||
1210 | case SRPC_BATCH_OPC_STOP: | |
1211 | rc = sfw_stop_batch(bat, request->bar_arg); | |
1212 | break; | |
1213 | ||
1214 | case SRPC_BATCH_OPC_QUERY: | |
1215 | rc = sfw_query_batch(bat, request->bar_testidx, reply); | |
1216 | break; | |
1217 | ||
1218 | default: | |
1219 | return -EINVAL; /* drop it */ | |
1220 | } | |
1221 | ||
1222 | reply->bar_status = (rc < 0) ? -rc : rc; | |
1223 | return 0; | |
1224 | } | |
1225 | ||
8d94b6d2 | 1226 | static int |
d7e09d03 PT |
1227 | sfw_handle_server_rpc(struct srpc_server_rpc *rpc) |
1228 | { | |
74d68011 MS |
1229 | struct srpc_service *sv = rpc->srpc_scd->scd_svc; |
1230 | srpc_msg_t *reply = &rpc->srpc_replymsg; | |
1231 | srpc_msg_t *request = &rpc->srpc_reqstbuf->buf_msg; | |
1232 | unsigned features = LST_FEATS_MASK; | |
1233 | int rc = 0; | |
d7e09d03 PT |
1234 | |
1235 | LASSERT(sfw_data.fw_active_srpc == NULL); | |
1236 | LASSERT(sv->sv_id <= SRPC_FRAMEWORK_SERVICE_MAX_ID); | |
1237 | ||
1238 | spin_lock(&sfw_data.fw_lock); | |
1239 | ||
1240 | if (sfw_data.fw_shuttingdown) { | |
1241 | spin_unlock(&sfw_data.fw_lock); | |
1242 | return -ESHUTDOWN; | |
1243 | } | |
1244 | ||
1245 | /* Remove timer to avoid racing with it or expiring active session */ | |
1246 | if (sfw_del_session_timer() != 0) { | |
1247 | CERROR("Dropping RPC (%s) from %s: racing with expiry timer.", | |
1248 | sv->sv_name, libcfs_id2str(rpc->srpc_peer)); | |
1249 | spin_unlock(&sfw_data.fw_lock); | |
1250 | return -EAGAIN; | |
1251 | } | |
1252 | ||
1253 | sfw_data.fw_active_srpc = rpc; | |
1254 | spin_unlock(&sfw_data.fw_lock); | |
1255 | ||
1256 | sfw_unpack_message(request); | |
1257 | LASSERT(request->msg_type == srpc_service2request(sv->sv_id)); | |
1258 | ||
1259 | /* rpc module should have checked this */ | |
1260 | LASSERT(request->msg_version == SRPC_MSG_VERSION); | |
1261 | ||
1262 | if (sv->sv_id != SRPC_SERVICE_MAKE_SESSION && | |
1263 | sv->sv_id != SRPC_SERVICE_DEBUG) { | |
1264 | sfw_session_t *sn = sfw_data.fw_session; | |
1265 | ||
1266 | if (sn != NULL && | |
1267 | sn->sn_features != request->msg_ses_feats) { | |
2d00bd17 | 1268 | CNETERR("Features of framework RPC don't match features of current session: %x/%x\n", |
d7e09d03 PT |
1269 | request->msg_ses_feats, sn->sn_features); |
1270 | reply->msg_body.reply.status = EPROTO; | |
1271 | reply->msg_body.reply.sid = sn->sn_id; | |
1272 | goto out; | |
1273 | } | |
1274 | ||
1275 | } else if ((request->msg_ses_feats & ~LST_FEATS_MASK) != 0) { | |
1276 | /* NB: at this point, old version will ignore features and | |
1277 | * create new session anyway, so console should be able | |
1278 | * to handle this */ | |
1279 | reply->msg_body.reply.status = EPROTO; | |
1280 | goto out; | |
1281 | } | |
1282 | ||
a58a38ac | 1283 | switch (sv->sv_id) { |
d7e09d03 | 1284 | default: |
63418983 | 1285 | LBUG(); |
d7e09d03 PT |
1286 | case SRPC_SERVICE_TEST: |
1287 | rc = sfw_add_test(rpc); | |
1288 | break; | |
1289 | ||
1290 | case SRPC_SERVICE_BATCH: | |
1291 | rc = sfw_control_batch(&request->msg_body.bat_reqst, | |
1292 | &reply->msg_body.bat_reply); | |
1293 | break; | |
1294 | ||
1295 | case SRPC_SERVICE_QUERY_STAT: | |
1296 | rc = sfw_get_stats(&request->msg_body.stat_reqst, | |
1297 | &reply->msg_body.stat_reply); | |
1298 | break; | |
1299 | ||
1300 | case SRPC_SERVICE_DEBUG: | |
1301 | rc = sfw_debug_session(&request->msg_body.dbg_reqst, | |
1302 | &reply->msg_body.dbg_reply); | |
1303 | break; | |
1304 | ||
1305 | case SRPC_SERVICE_MAKE_SESSION: | |
1306 | rc = sfw_make_session(&request->msg_body.mksn_reqst, | |
1307 | &reply->msg_body.mksn_reply); | |
1308 | break; | |
1309 | ||
1310 | case SRPC_SERVICE_REMOVE_SESSION: | |
1311 | rc = sfw_remove_session(&request->msg_body.rmsn_reqst, | |
1312 | &reply->msg_body.rmsn_reply); | |
1313 | break; | |
1314 | } | |
1315 | ||
1316 | if (sfw_data.fw_session != NULL) | |
1317 | features = sfw_data.fw_session->sn_features; | |
1318 | out: | |
1319 | reply->msg_ses_feats = features; | |
1320 | rpc->srpc_done = sfw_server_rpc_done; | |
1321 | spin_lock(&sfw_data.fw_lock); | |
1322 | ||
1323 | if (!sfw_data.fw_shuttingdown) | |
1324 | sfw_add_session_timer(); | |
1325 | ||
1326 | sfw_data.fw_active_srpc = NULL; | |
1327 | spin_unlock(&sfw_data.fw_lock); | |
1328 | return rc; | |
1329 | } | |
1330 | ||
8d94b6d2 | 1331 | static int |
d7e09d03 PT |
1332 | sfw_bulk_ready(struct srpc_server_rpc *rpc, int status) |
1333 | { | |
74d68011 MS |
1334 | struct srpc_service *sv = rpc->srpc_scd->scd_svc; |
1335 | int rc; | |
d7e09d03 PT |
1336 | |
1337 | LASSERT(rpc->srpc_bulk != NULL); | |
1338 | LASSERT(sv->sv_id == SRPC_SERVICE_TEST); | |
1339 | LASSERT(sfw_data.fw_active_srpc == NULL); | |
1340 | LASSERT(rpc->srpc_reqstbuf->buf_msg.msg_body.tes_reqst.tsr_is_client); | |
1341 | ||
1342 | spin_lock(&sfw_data.fw_lock); | |
1343 | ||
1344 | if (status != 0) { | |
2d00bd17 | 1345 | CERROR("Bulk transfer failed for RPC: service %s, peer %s, status %d\n", |
d7e09d03 PT |
1346 | sv->sv_name, libcfs_id2str(rpc->srpc_peer), status); |
1347 | spin_unlock(&sfw_data.fw_lock); | |
1348 | return -EIO; | |
1349 | } | |
1350 | ||
1351 | if (sfw_data.fw_shuttingdown) { | |
1352 | spin_unlock(&sfw_data.fw_lock); | |
1353 | return -ESHUTDOWN; | |
1354 | } | |
1355 | ||
1356 | if (sfw_del_session_timer() != 0) { | |
1357 | CERROR("Dropping RPC (%s) from %s: racing with expiry timer", | |
1358 | sv->sv_name, libcfs_id2str(rpc->srpc_peer)); | |
1359 | spin_unlock(&sfw_data.fw_lock); | |
1360 | return -EAGAIN; | |
1361 | } | |
1362 | ||
1363 | sfw_data.fw_active_srpc = rpc; | |
1364 | spin_unlock(&sfw_data.fw_lock); | |
1365 | ||
1366 | rc = sfw_add_test(rpc); | |
1367 | ||
1368 | spin_lock(&sfw_data.fw_lock); | |
1369 | ||
1370 | if (!sfw_data.fw_shuttingdown) | |
1371 | sfw_add_session_timer(); | |
1372 | ||
1373 | sfw_data.fw_active_srpc = NULL; | |
1374 | spin_unlock(&sfw_data.fw_lock); | |
1375 | return rc; | |
1376 | } | |
1377 | ||
1378 | srpc_client_rpc_t * | |
1379 | sfw_create_rpc(lnet_process_id_t peer, int service, | |
1380 | unsigned features, int nbulkiov, int bulklen, | |
1381 | void (*done)(srpc_client_rpc_t *), void *priv) | |
1382 | { | |
1383 | srpc_client_rpc_t *rpc = NULL; | |
1384 | ||
1385 | spin_lock(&sfw_data.fw_lock); | |
1386 | ||
63418983 MY |
1387 | LASSERT(!sfw_data.fw_shuttingdown); |
1388 | LASSERT(service <= SRPC_FRAMEWORK_SERVICE_MAX_ID); | |
d7e09d03 PT |
1389 | |
1390 | if (nbulkiov == 0 && !list_empty(&sfw_data.fw_zombie_rpcs)) { | |
1391 | rpc = list_entry(sfw_data.fw_zombie_rpcs.next, | |
1392 | srpc_client_rpc_t, crpc_list); | |
1393 | list_del(&rpc->crpc_list); | |
1394 | ||
1395 | srpc_init_client_rpc(rpc, peer, service, 0, 0, | |
1396 | done, sfw_client_rpc_fini, priv); | |
1397 | } | |
1398 | ||
1399 | spin_unlock(&sfw_data.fw_lock); | |
1400 | ||
1401 | if (rpc == NULL) { | |
1402 | rpc = srpc_create_client_rpc(peer, service, | |
1403 | nbulkiov, bulklen, done, | |
1404 | nbulkiov != 0 ? NULL : | |
1405 | sfw_client_rpc_fini, | |
1406 | priv); | |
1407 | } | |
1408 | ||
1409 | if (rpc != NULL) /* "session" is concept in framework */ | |
1410 | rpc->crpc_reqstmsg.msg_ses_feats = features; | |
1411 | ||
1412 | return rpc; | |
1413 | } | |
1414 | ||
1415 | void | |
63418983 | 1416 | sfw_unpack_message(srpc_msg_t *msg) |
d7e09d03 PT |
1417 | { |
1418 | if (msg->msg_magic == SRPC_MSG_MAGIC) | |
1419 | return; /* no flipping needed */ | |
1420 | ||
1421 | /* srpc module should guarantee I wouldn't get crap */ | |
63418983 | 1422 | LASSERT(msg->msg_magic == __swab32(SRPC_MSG_MAGIC)); |
d7e09d03 PT |
1423 | |
1424 | if (msg->msg_type == SRPC_MSG_STAT_REQST) { | |
1425 | srpc_stat_reqst_t *req = &msg->msg_body.stat_reqst; | |
1426 | ||
1427 | __swab32s(&req->str_type); | |
1428 | __swab64s(&req->str_rpyid); | |
1429 | sfw_unpack_sid(req->str_sid); | |
1430 | return; | |
1431 | } | |
1432 | ||
1433 | if (msg->msg_type == SRPC_MSG_STAT_REPLY) { | |
1434 | srpc_stat_reply_t *rep = &msg->msg_body.stat_reply; | |
1435 | ||
1436 | __swab32s(&rep->str_status); | |
1437 | sfw_unpack_sid(rep->str_sid); | |
1438 | sfw_unpack_fw_counters(rep->str_fw); | |
1439 | sfw_unpack_rpc_counters(rep->str_rpc); | |
1440 | sfw_unpack_lnet_counters(rep->str_lnet); | |
1441 | return; | |
1442 | } | |
1443 | ||
1444 | if (msg->msg_type == SRPC_MSG_MKSN_REQST) { | |
1445 | srpc_mksn_reqst_t *req = &msg->msg_body.mksn_reqst; | |
1446 | ||
1447 | __swab64s(&req->mksn_rpyid); | |
1448 | __swab32s(&req->mksn_force); | |
1449 | sfw_unpack_sid(req->mksn_sid); | |
1450 | return; | |
1451 | } | |
1452 | ||
1453 | if (msg->msg_type == SRPC_MSG_MKSN_REPLY) { | |
1454 | srpc_mksn_reply_t *rep = &msg->msg_body.mksn_reply; | |
1455 | ||
1456 | __swab32s(&rep->mksn_status); | |
1457 | __swab32s(&rep->mksn_timeout); | |
1458 | sfw_unpack_sid(rep->mksn_sid); | |
1459 | return; | |
1460 | } | |
1461 | ||
1462 | if (msg->msg_type == SRPC_MSG_RMSN_REQST) { | |
1463 | srpc_rmsn_reqst_t *req = &msg->msg_body.rmsn_reqst; | |
1464 | ||
1465 | __swab64s(&req->rmsn_rpyid); | |
1466 | sfw_unpack_sid(req->rmsn_sid); | |
1467 | return; | |
1468 | } | |
1469 | ||
1470 | if (msg->msg_type == SRPC_MSG_RMSN_REPLY) { | |
1471 | srpc_rmsn_reply_t *rep = &msg->msg_body.rmsn_reply; | |
1472 | ||
1473 | __swab32s(&rep->rmsn_status); | |
1474 | sfw_unpack_sid(rep->rmsn_sid); | |
1475 | return; | |
1476 | } | |
1477 | ||
1478 | if (msg->msg_type == SRPC_MSG_DEBUG_REQST) { | |
1479 | srpc_debug_reqst_t *req = &msg->msg_body.dbg_reqst; | |
1480 | ||
1481 | __swab64s(&req->dbg_rpyid); | |
1482 | __swab32s(&req->dbg_flags); | |
1483 | sfw_unpack_sid(req->dbg_sid); | |
1484 | return; | |
1485 | } | |
1486 | ||
1487 | if (msg->msg_type == SRPC_MSG_DEBUG_REPLY) { | |
1488 | srpc_debug_reply_t *rep = &msg->msg_body.dbg_reply; | |
1489 | ||
1490 | __swab32s(&rep->dbg_nbatch); | |
1491 | __swab32s(&rep->dbg_timeout); | |
1492 | sfw_unpack_sid(rep->dbg_sid); | |
1493 | return; | |
1494 | } | |
1495 | ||
1496 | if (msg->msg_type == SRPC_MSG_BATCH_REQST) { | |
1497 | srpc_batch_reqst_t *req = &msg->msg_body.bat_reqst; | |
1498 | ||
1499 | __swab32s(&req->bar_opc); | |
1500 | __swab64s(&req->bar_rpyid); | |
1501 | __swab32s(&req->bar_testidx); | |
1502 | __swab32s(&req->bar_arg); | |
1503 | sfw_unpack_sid(req->bar_sid); | |
1504 | __swab64s(&req->bar_bid.bat_id); | |
1505 | return; | |
1506 | } | |
1507 | ||
1508 | if (msg->msg_type == SRPC_MSG_BATCH_REPLY) { | |
1509 | srpc_batch_reply_t *rep = &msg->msg_body.bat_reply; | |
1510 | ||
1511 | __swab32s(&rep->bar_status); | |
1512 | sfw_unpack_sid(rep->bar_sid); | |
1513 | return; | |
1514 | } | |
1515 | ||
1516 | if (msg->msg_type == SRPC_MSG_TEST_REQST) { | |
1517 | srpc_test_reqst_t *req = &msg->msg_body.tes_reqst; | |
1518 | ||
1519 | __swab64s(&req->tsr_rpyid); | |
1520 | __swab64s(&req->tsr_bulkid); | |
1521 | __swab32s(&req->tsr_loop); | |
1522 | __swab32s(&req->tsr_ndest); | |
1523 | __swab32s(&req->tsr_concur); | |
1524 | __swab32s(&req->tsr_service); | |
1525 | sfw_unpack_sid(req->tsr_sid); | |
1526 | __swab64s(&req->tsr_bid.bat_id); | |
1527 | return; | |
1528 | } | |
1529 | ||
1530 | if (msg->msg_type == SRPC_MSG_TEST_REPLY) { | |
1531 | srpc_test_reply_t *rep = &msg->msg_body.tes_reply; | |
1532 | ||
1533 | __swab32s(&rep->tsr_status); | |
1534 | sfw_unpack_sid(rep->tsr_sid); | |
1535 | return; | |
1536 | } | |
1537 | ||
1538 | if (msg->msg_type == SRPC_MSG_JOIN_REQST) { | |
1539 | srpc_join_reqst_t *req = &msg->msg_body.join_reqst; | |
1540 | ||
1541 | __swab64s(&req->join_rpyid); | |
1542 | sfw_unpack_sid(req->join_sid); | |
1543 | return; | |
1544 | } | |
1545 | ||
1546 | if (msg->msg_type == SRPC_MSG_JOIN_REPLY) { | |
1547 | srpc_join_reply_t *rep = &msg->msg_body.join_reply; | |
1548 | ||
1549 | __swab32s(&rep->join_status); | |
1550 | __swab32s(&rep->join_timeout); | |
1551 | sfw_unpack_sid(rep->join_sid); | |
1552 | return; | |
1553 | } | |
1554 | ||
63418983 | 1555 | LBUG(); |
d7e09d03 PT |
1556 | return; |
1557 | } | |
1558 | ||
1559 | void | |
63418983 | 1560 | sfw_abort_rpc(srpc_client_rpc_t *rpc) |
d7e09d03 PT |
1561 | { |
1562 | LASSERT(atomic_read(&rpc->crpc_refcount) > 0); | |
1563 | LASSERT(rpc->crpc_service <= SRPC_FRAMEWORK_SERVICE_MAX_ID); | |
1564 | ||
1565 | spin_lock(&rpc->crpc_lock); | |
1566 | srpc_abort_rpc(rpc, -EINTR); | |
1567 | spin_unlock(&rpc->crpc_lock); | |
1568 | return; | |
1569 | } | |
1570 | ||
1571 | void | |
63418983 | 1572 | sfw_post_rpc(srpc_client_rpc_t *rpc) |
d7e09d03 PT |
1573 | { |
1574 | spin_lock(&rpc->crpc_lock); | |
1575 | ||
63418983 MY |
1576 | LASSERT(!rpc->crpc_closed); |
1577 | LASSERT(!rpc->crpc_aborted); | |
1578 | LASSERT(list_empty(&rpc->crpc_list)); | |
1579 | LASSERT(!sfw_data.fw_shuttingdown); | |
d7e09d03 PT |
1580 | |
1581 | rpc->crpc_timeout = rpc_timeout; | |
1582 | srpc_post_rpc(rpc); | |
1583 | ||
1584 | spin_unlock(&rpc->crpc_lock); | |
1585 | return; | |
1586 | } | |
1587 | ||
9d0b2b7a | 1588 | static srpc_service_t sfw_services[] = { |
d7e09d03 PT |
1589 | { |
1590 | /* sv_id */ SRPC_SERVICE_DEBUG, | |
1591 | /* sv_name */ "debug", | |
1592 | 0 | |
1593 | }, | |
1594 | { | |
1595 | /* sv_id */ SRPC_SERVICE_QUERY_STAT, | |
1596 | /* sv_name */ "query stats", | |
1597 | 0 | |
1598 | }, | |
1599 | { | |
1600 | /* sv_id */ SRPC_SERVICE_MAKE_SESSION, | |
1601 | /* sv_name */ "make session", | |
1602 | 0 | |
1603 | }, | |
1604 | { | |
1605 | /* sv_id */ SRPC_SERVICE_REMOVE_SESSION, | |
1606 | /* sv_name */ "remove session", | |
1607 | 0 | |
1608 | }, | |
1609 | { | |
1610 | /* sv_id */ SRPC_SERVICE_BATCH, | |
1611 | /* sv_name */ "batch service", | |
1612 | 0 | |
1613 | }, | |
1614 | { | |
1615 | /* sv_id */ SRPC_SERVICE_TEST, | |
1616 | /* sv_name */ "test service", | |
1617 | 0 | |
1618 | }, | |
1619 | { | |
1620 | /* sv_id */ 0, | |
1621 | /* sv_name */ NULL, | |
1622 | 0 | |
1623 | } | |
1624 | }; | |
1625 | ||
1626 | extern sfw_test_client_ops_t ping_test_client; | |
1627 | extern srpc_service_t ping_test_service; | |
1628 | extern void ping_init_test_client(void); | |
1629 | extern void ping_init_test_service(void); | |
1630 | ||
1631 | extern sfw_test_client_ops_t brw_test_client; | |
1632 | extern srpc_service_t brw_test_service; | |
1633 | extern void brw_init_test_client(void); | |
1634 | extern void brw_init_test_service(void); | |
1635 | ||
1636 | ||
1637 | int | |
63418983 | 1638 | sfw_startup(void) |
d7e09d03 | 1639 | { |
74d68011 MS |
1640 | int i; |
1641 | int rc; | |
1642 | int error; | |
1643 | srpc_service_t *sv; | |
d7e09d03 PT |
1644 | sfw_test_case_t *tsc; |
1645 | ||
1646 | ||
1647 | if (session_timeout < 0) { | |
63418983 | 1648 | CERROR("Session timeout must be non-negative: %d\n", |
d7e09d03 PT |
1649 | session_timeout); |
1650 | return -EINVAL; | |
1651 | } | |
1652 | ||
1653 | if (rpc_timeout < 0) { | |
63418983 | 1654 | CERROR("RPC timeout must be non-negative: %d\n", |
d7e09d03 PT |
1655 | rpc_timeout); |
1656 | return -EINVAL; | |
1657 | } | |
1658 | ||
1659 | if (session_timeout == 0) | |
2d00bd17 | 1660 | CWARN("Zero session_timeout specified - test sessions never expire.\n"); |
d7e09d03 PT |
1661 | |
1662 | if (rpc_timeout == 0) | |
2d00bd17 | 1663 | CWARN("Zero rpc_timeout specified - test RPC never expire.\n"); |
d7e09d03 PT |
1664 | |
1665 | memset(&sfw_data, 0, sizeof(struct smoketest_framework)); | |
1666 | ||
1667 | sfw_data.fw_session = NULL; | |
1668 | sfw_data.fw_active_srpc = NULL; | |
1669 | spin_lock_init(&sfw_data.fw_lock); | |
1670 | atomic_set(&sfw_data.fw_nzombies, 0); | |
1671 | INIT_LIST_HEAD(&sfw_data.fw_tests); | |
1672 | INIT_LIST_HEAD(&sfw_data.fw_zombie_rpcs); | |
1673 | INIT_LIST_HEAD(&sfw_data.fw_zombie_sessions); | |
1674 | ||
1675 | brw_init_test_client(); | |
1676 | brw_init_test_service(); | |
1677 | rc = sfw_register_test(&brw_test_service, &brw_test_client); | |
63418983 | 1678 | LASSERT(rc == 0); |
d7e09d03 PT |
1679 | |
1680 | ping_init_test_client(); | |
1681 | ping_init_test_service(); | |
1682 | rc = sfw_register_test(&ping_test_service, &ping_test_client); | |
63418983 | 1683 | LASSERT(rc == 0); |
d7e09d03 PT |
1684 | |
1685 | error = 0; | |
63418983 | 1686 | list_for_each_entry(tsc, &sfw_data.fw_tests, tsc_list) { |
d7e09d03 PT |
1687 | sv = tsc->tsc_srv_service; |
1688 | ||
1689 | rc = srpc_add_service(sv); | |
63418983 | 1690 | LASSERT(rc != -EBUSY); |
d7e09d03 | 1691 | if (rc != 0) { |
63418983 | 1692 | CWARN("Failed to add %s service: %d\n", |
d7e09d03 PT |
1693 | sv->sv_name, rc); |
1694 | error = rc; | |
1695 | } | |
1696 | } | |
1697 | ||
1698 | for (i = 0; ; i++) { | |
1699 | sv = &sfw_services[i]; | |
550d35d8 DM |
1700 | if (sv->sv_name == NULL) |
1701 | break; | |
d7e09d03 PT |
1702 | |
1703 | sv->sv_bulk_ready = NULL; | |
1704 | sv->sv_handler = sfw_handle_server_rpc; | |
1705 | sv->sv_wi_total = SFW_FRWK_WI_MAX; | |
1706 | if (sv->sv_id == SRPC_SERVICE_TEST) | |
1707 | sv->sv_bulk_ready = sfw_bulk_ready; | |
1708 | ||
1709 | rc = srpc_add_service(sv); | |
63418983 | 1710 | LASSERT(rc != -EBUSY); |
d7e09d03 | 1711 | if (rc != 0) { |
63418983 | 1712 | CWARN("Failed to add %s service: %d\n", |
d7e09d03 PT |
1713 | sv->sv_name, rc); |
1714 | error = rc; | |
1715 | } | |
1716 | ||
1717 | /* about to sfw_shutdown, no need to add buffer */ | |
550d35d8 DM |
1718 | if (error) |
1719 | continue; | |
d7e09d03 PT |
1720 | |
1721 | rc = srpc_service_add_buffers(sv, sv->sv_wi_total); | |
1722 | if (rc != 0) { | |
2d00bd17 | 1723 | CWARN("Failed to reserve enough buffers: service %s, %d needed: %d\n", |
d7e09d03 PT |
1724 | sv->sv_name, sv->sv_wi_total, rc); |
1725 | error = -ENOMEM; | |
1726 | } | |
1727 | } | |
1728 | ||
1729 | if (error != 0) | |
1730 | sfw_shutdown(); | |
1731 | return error; | |
1732 | } | |
1733 | ||
1734 | void | |
63418983 | 1735 | sfw_shutdown(void) |
d7e09d03 | 1736 | { |
74d68011 | 1737 | srpc_service_t *sv; |
d7e09d03 | 1738 | sfw_test_case_t *tsc; |
74d68011 | 1739 | int i; |
d7e09d03 PT |
1740 | |
1741 | spin_lock(&sfw_data.fw_lock); | |
1742 | ||
1743 | sfw_data.fw_shuttingdown = 1; | |
1744 | lst_wait_until(sfw_data.fw_active_srpc == NULL, sfw_data.fw_lock, | |
1745 | "waiting for active RPC to finish.\n"); | |
1746 | ||
1747 | if (sfw_del_session_timer() != 0) | |
1748 | lst_wait_until(sfw_data.fw_session == NULL, sfw_data.fw_lock, | |
1749 | "waiting for session timer to explode.\n"); | |
1750 | ||
1751 | sfw_deactivate_session(); | |
1752 | lst_wait_until(atomic_read(&sfw_data.fw_nzombies) == 0, | |
1753 | sfw_data.fw_lock, | |
1754 | "waiting for %d zombie sessions to die.\n", | |
1755 | atomic_read(&sfw_data.fw_nzombies)); | |
1756 | ||
1757 | spin_unlock(&sfw_data.fw_lock); | |
1758 | ||
1759 | for (i = 0; ; i++) { | |
1760 | sv = &sfw_services[i]; | |
1761 | if (sv->sv_name == NULL) | |
1762 | break; | |
1763 | ||
1764 | srpc_shutdown_service(sv); | |
1765 | srpc_remove_service(sv); | |
1766 | } | |
1767 | ||
63418983 | 1768 | list_for_each_entry(tsc, &sfw_data.fw_tests, tsc_list) { |
d7e09d03 PT |
1769 | sv = tsc->tsc_srv_service; |
1770 | srpc_shutdown_service(sv); | |
1771 | srpc_remove_service(sv); | |
1772 | } | |
1773 | ||
1774 | while (!list_empty(&sfw_data.fw_zombie_rpcs)) { | |
1775 | srpc_client_rpc_t *rpc; | |
1776 | ||
1777 | rpc = list_entry(sfw_data.fw_zombie_rpcs.next, | |
1778 | srpc_client_rpc_t, crpc_list); | |
1779 | list_del(&rpc->crpc_list); | |
1780 | ||
1781 | LIBCFS_FREE(rpc, srpc_client_rpc_size(rpc)); | |
1782 | } | |
1783 | ||
1784 | for (i = 0; ; i++) { | |
1785 | sv = &sfw_services[i]; | |
1786 | if (sv->sv_name == NULL) | |
1787 | break; | |
1788 | ||
1789 | srpc_wait_service_shutdown(sv); | |
1790 | } | |
1791 | ||
1792 | while (!list_empty(&sfw_data.fw_tests)) { | |
1793 | tsc = list_entry(sfw_data.fw_tests.next, | |
1794 | sfw_test_case_t, tsc_list); | |
1795 | ||
1796 | srpc_wait_service_shutdown(tsc->tsc_srv_service); | |
1797 | ||
1798 | list_del(&tsc->tsc_list); | |
1799 | LIBCFS_FREE(tsc, sizeof(*tsc)); | |
1800 | } | |
1801 | ||
1802 | return; | |
1803 | } |