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