Whamcloud - gitweb
LU-56 lnet: SMP improvements for LNet selftest
[fs/lustre-release.git] / lnet / selftest / brw_test.c
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 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  *
34  * lnet/selftest/brw_test.c
35  *
36  * Author: Isaac Huang <isaac@clusterfs.com>
37  */
38
39 #include "selftest.h"
40
41 static int brw_srv_workitems = SFW_TEST_WI_MAX;
42 CFS_MODULE_PARM(brw_srv_workitems, "i", int, 0644, "# BRW server workitems");
43
44 static int brw_inject_errors;
45 CFS_MODULE_PARM(brw_inject_errors, "i", int, 0644,
46                 "# data errors to inject randomly, zero by default");
47
48 static void
49 brw_client_fini (sfw_test_instance_t *tsi)
50 {
51         srpc_bulk_t     *bulk;
52         sfw_test_unit_t *tsu;
53
54         LASSERT (tsi->tsi_is_client);
55
56         cfs_list_for_each_entry_typed (tsu, &tsi->tsi_units,
57                                        sfw_test_unit_t, tsu_list) {
58                 bulk = tsu->tsu_private;
59                 if (bulk == NULL) continue;
60
61                 srpc_free_bulk(bulk);
62                 tsu->tsu_private = NULL;
63         }
64 }
65
66 int
67 brw_client_init (sfw_test_instance_t *tsi)
68 {
69         test_bulk_req_t  *breq = &tsi->tsi_u.bulk;
70         int               flags = breq->blk_flags;
71         int               npg = breq->blk_npg;
72         srpc_bulk_t      *bulk;
73         sfw_test_unit_t  *tsu;
74
75         LASSERT (tsi->tsi_is_client);
76
77         if (npg > LNET_MAX_IOV || npg <= 0)
78                 return -EINVAL;
79
80         if (breq->blk_opc != LST_BRW_READ && breq->blk_opc != LST_BRW_WRITE)
81                 return -EINVAL;
82
83         if (flags != LST_BRW_CHECK_NONE &&
84             flags != LST_BRW_CHECK_FULL && flags != LST_BRW_CHECK_SIMPLE)
85                 return -EINVAL;
86
87         cfs_list_for_each_entry_typed(tsu, &tsi->tsi_units,
88                                       sfw_test_unit_t, tsu_list) {
89                 bulk = srpc_alloc_bulk(lnet_cpt_of_nid(tsu->tsu_dest.nid),
90                                        npg, breq->blk_opc == LST_BRW_READ);
91                 if (bulk == NULL) {
92                         brw_client_fini(tsi);
93                         return -ENOMEM;
94                 }
95
96                 tsu->tsu_private = bulk;
97         }
98
99         return 0;
100 }
101
102 #define BRW_POISON      0xbeefbeefbeefbeefULL
103 #define BRW_MAGIC       0xeeb0eeb1eeb2eeb3ULL
104 #define BRW_MSIZE       sizeof(__u64)
105
106 int
107 brw_inject_one_error (void)
108 {
109         struct timeval tv;
110
111         if (brw_inject_errors <= 0) return 0;
112
113 #ifndef __KERNEL__
114         gettimeofday(&tv, NULL);
115 #else
116         cfs_gettimeofday(&tv);
117 #endif
118
119         if ((tv.tv_usec & 1) == 0) return 0;
120
121         return brw_inject_errors--;
122 }
123
124 void
125 brw_fill_page (cfs_page_t *pg, int pattern, __u64 magic)
126 {
127         char *addr = cfs_page_address(pg);
128         int   i;
129
130         LASSERT (addr != NULL);
131
132         if (pattern == LST_BRW_CHECK_NONE) return;
133
134         if (magic == BRW_MAGIC)
135                 magic += brw_inject_one_error();
136
137         if (pattern == LST_BRW_CHECK_SIMPLE) {
138                 memcpy(addr, &magic, BRW_MSIZE);
139                 addr += CFS_PAGE_SIZE - BRW_MSIZE;
140                 memcpy(addr, &magic, BRW_MSIZE);
141                 return;
142         }
143
144         if (pattern == LST_BRW_CHECK_FULL) {
145                 for (i = 0; i < CFS_PAGE_SIZE / BRW_MSIZE; i++)
146                         memcpy(addr + i * BRW_MSIZE, &magic, BRW_MSIZE);
147                 return;
148         }
149
150         LBUG ();
151         return;
152 }
153
154 int
155 brw_check_page (cfs_page_t *pg, int pattern, __u64 magic)
156 {
157         char  *addr = cfs_page_address(pg);
158         __u64  data = 0; /* make compiler happy */
159         int    i;
160
161         LASSERT (addr != NULL);
162
163         if (pattern == LST_BRW_CHECK_NONE)
164                 return 0;
165
166         if (pattern == LST_BRW_CHECK_SIMPLE) {
167                 data = *((__u64 *) addr);
168                 if (data != magic) goto bad_data;
169
170                 addr += CFS_PAGE_SIZE - BRW_MSIZE;
171                 data = *((__u64 *) addr);
172                 if (data != magic) goto bad_data;
173
174                 return 0;
175         }
176
177         if (pattern == LST_BRW_CHECK_FULL) {
178                 for (i = 0; i < CFS_PAGE_SIZE / BRW_MSIZE; i++) {
179                         data = *(((__u64 *) addr) + i);
180                         if (data != magic) goto bad_data;
181                 }
182
183                 return 0;
184         }
185
186         LBUG ();
187
188 bad_data:
189         CERROR ("Bad data in page %p: "LPX64", "LPX64" expected\n",
190                 pg, data, magic);
191         return 1;
192 }
193
194 void
195 brw_fill_bulk (srpc_bulk_t *bk, int pattern, __u64 magic)
196 {
197         int         i;
198         cfs_page_t *pg;
199
200         for (i = 0; i < bk->bk_niov; i++) {
201 #ifdef __KERNEL__
202                 pg = bk->bk_iovs[i].kiov_page;
203 #else
204                 LASSERT (bk->bk_pages != NULL);
205                 pg = bk->bk_pages[i];
206 #endif
207                 brw_fill_page(pg, pattern, magic);
208         }
209 }
210
211 int
212 brw_check_bulk (srpc_bulk_t *bk, int pattern, __u64 magic)
213 {
214         int         i;
215         cfs_page_t *pg;
216
217         for (i = 0; i < bk->bk_niov; i++) {
218 #ifdef __KERNEL__
219                 pg = bk->bk_iovs[i].kiov_page;
220 #else
221                 LASSERT (bk->bk_pages != NULL);
222                 pg = bk->bk_pages[i];
223 #endif
224                 if (brw_check_page(pg, pattern, magic) != 0) {
225                         CERROR ("Bulk page %p (%d/%d) is corrupted!\n",
226                                 pg, i, bk->bk_niov);
227                         return 1;
228                 }
229         }
230
231         return 0;
232 }
233
234 static int
235 brw_client_prep_rpc (sfw_test_unit_t *tsu,
236                      lnet_process_id_t dest, srpc_client_rpc_t **rpcpp)
237 {
238         srpc_bulk_t         *bulk = tsu->tsu_private;
239         sfw_test_instance_t *tsi = tsu->tsu_instance;
240         test_bulk_req_t     *breq = &tsi->tsi_u.bulk;
241         int                  npg = breq->blk_npg;
242         int                  flags = breq->blk_flags;
243         srpc_client_rpc_t   *rpc;
244         srpc_brw_reqst_t    *req;
245         int                  rc;
246
247         LASSERT (bulk != NULL);
248         LASSERT (bulk->bk_niov == npg);
249
250         rc = sfw_create_test_rpc(tsu, dest, npg, npg * CFS_PAGE_SIZE, &rpc);
251         if (rc != 0) return rc;
252
253         memcpy(&rpc->crpc_bulk, bulk, offsetof(srpc_bulk_t, bk_iovs[npg]));
254         if (breq->blk_opc == LST_BRW_WRITE)
255                 brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_MAGIC);
256         else
257                 brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_POISON);
258
259         req = &rpc->crpc_reqstmsg.msg_body.brw_reqst;
260         req->brw_flags = flags;
261         req->brw_rw    = breq->blk_opc;
262         req->brw_len   = npg * CFS_PAGE_SIZE;
263
264         *rpcpp = rpc;
265         return 0;
266 }
267
268 static void
269 brw_client_done_rpc (sfw_test_unit_t *tsu, srpc_client_rpc_t *rpc)
270 {
271         __u64                magic = BRW_MAGIC;
272         sfw_test_instance_t *tsi = tsu->tsu_instance;
273         sfw_session_t       *sn = tsi->tsi_batch->bat_session;
274         srpc_msg_t          *msg = &rpc->crpc_replymsg;
275         srpc_brw_reply_t    *reply = &msg->msg_body.brw_reply;
276         srpc_brw_reqst_t    *reqst = &rpc->crpc_reqstmsg.msg_body.brw_reqst;
277
278         LASSERT (sn != NULL);
279
280         if (rpc->crpc_status != 0) {
281                 CERROR ("BRW RPC to %s failed with %d\n",
282                         libcfs_id2str(rpc->crpc_dest), rpc->crpc_status);
283                 if (!tsi->tsi_stopping) /* rpc could have been aborted */
284                         cfs_atomic_inc(&sn->sn_brw_errors);
285                 goto out;
286         }
287
288         if (msg->msg_magic != SRPC_MSG_MAGIC) {
289                 __swab64s(&magic);
290                 __swab32s(&reply->brw_status);
291         }
292
293         CDEBUG (reply->brw_status ? D_WARNING : D_NET,
294                 "BRW RPC to %s finished with brw_status: %d\n",
295                 libcfs_id2str(rpc->crpc_dest), reply->brw_status);
296
297         if (reply->brw_status != 0) {
298                 cfs_atomic_inc(&sn->sn_brw_errors);
299                 rpc->crpc_status = -(int)reply->brw_status;
300                 goto out;
301         }
302
303         if (reqst->brw_rw == LST_BRW_WRITE) goto out;
304
305         if (brw_check_bulk(&rpc->crpc_bulk, reqst->brw_flags, magic) != 0) {
306                 CERROR ("Bulk data from %s is corrupted!\n",
307                         libcfs_id2str(rpc->crpc_dest));
308                 cfs_atomic_inc(&sn->sn_brw_errors);
309                 rpc->crpc_status = -EBADMSG;
310         }
311
312 out:
313 #ifndef __KERNEL__
314         rpc->crpc_bulk.bk_pages = NULL;
315 #endif
316         return;
317 }
318
319 void
320 brw_server_rpc_done (srpc_server_rpc_t *rpc)
321 {
322         srpc_bulk_t *blk = rpc->srpc_bulk;
323
324         if (blk == NULL) return;
325
326         if (rpc->srpc_status != 0)
327                 CERROR ("Bulk transfer %s %s has failed: %d\n",
328                         blk->bk_sink ? "from" : "to",
329                         libcfs_id2str(rpc->srpc_peer), rpc->srpc_status);
330         else
331                 CDEBUG (D_NET, "Transfered %d pages bulk data %s %s\n",
332                         blk->bk_niov, blk->bk_sink ? "from" : "to",
333                         libcfs_id2str(rpc->srpc_peer));
334
335         sfw_free_pages(rpc);
336 }
337
338 int
339 brw_bulk_ready (srpc_server_rpc_t *rpc, int status)
340 {
341         __u64             magic = BRW_MAGIC;
342         srpc_brw_reply_t *reply = &rpc->srpc_replymsg.msg_body.brw_reply;
343         srpc_brw_reqst_t *reqst;
344         srpc_msg_t       *reqstmsg;
345
346         LASSERT (rpc->srpc_bulk != NULL);
347         LASSERT (rpc->srpc_reqstbuf != NULL);
348
349         reqstmsg = &rpc->srpc_reqstbuf->buf_msg;
350         reqst = &reqstmsg->msg_body.brw_reqst;
351
352         if (status != 0) {
353                 CERROR ("BRW bulk %s failed for RPC from %s: %d\n",
354                         reqst->brw_rw == LST_BRW_READ ? "READ" : "WRITE",
355                         libcfs_id2str(rpc->srpc_peer), status);
356                 return -EIO;
357         }
358
359         if (reqst->brw_rw == LST_BRW_READ)
360                 return 0;
361
362         if (reqstmsg->msg_magic != SRPC_MSG_MAGIC)
363                 __swab64s(&magic);
364
365         if (brw_check_bulk(rpc->srpc_bulk, reqst->brw_flags, magic) != 0) {
366                 CERROR ("Bulk data from %s is corrupted!\n",
367                         libcfs_id2str(rpc->srpc_peer));
368                 reply->brw_status = EBADMSG;
369         }
370
371         return 0;
372 }
373
374 int
375 brw_server_handle(struct srpc_server_rpc *rpc)
376 {
377         struct srpc_service     *sv = rpc->srpc_scd->scd_svc;
378         srpc_msg_t       *replymsg = &rpc->srpc_replymsg;
379         srpc_msg_t       *reqstmsg = &rpc->srpc_reqstbuf->buf_msg;
380         srpc_brw_reply_t *reply = &replymsg->msg_body.brw_reply;
381         srpc_brw_reqst_t *reqst = &reqstmsg->msg_body.brw_reqst;
382         int               rc;
383
384         LASSERT (sv->sv_id == SRPC_SERVICE_BRW);
385
386         if (reqstmsg->msg_magic != SRPC_MSG_MAGIC) {
387                 LASSERT (reqstmsg->msg_magic == __swab32(SRPC_MSG_MAGIC));
388
389                 __swab32s(&reqstmsg->msg_type);
390                 __swab32s(&reqst->brw_rw);
391                 __swab32s(&reqst->brw_len);
392                 __swab32s(&reqst->brw_flags);
393                 __swab64s(&reqst->brw_rpyid);
394                 __swab64s(&reqst->brw_bulkid);
395         }
396         LASSERT (reqstmsg->msg_type == (__u32)srpc_service2request(sv->sv_id));
397
398         rpc->srpc_done = brw_server_rpc_done;
399
400         if ((reqst->brw_rw != LST_BRW_READ && reqst->brw_rw != LST_BRW_WRITE) ||
401             reqst->brw_len == 0 || (reqst->brw_len & ~CFS_PAGE_MASK) != 0 ||
402             reqst->brw_len / CFS_PAGE_SIZE > LNET_MAX_IOV ||
403             (reqst->brw_flags != LST_BRW_CHECK_NONE &&
404              reqst->brw_flags != LST_BRW_CHECK_FULL &&
405              reqst->brw_flags != LST_BRW_CHECK_SIMPLE)) {
406                 reply->brw_status = EINVAL;
407                 return 0;
408         }
409
410         reply->brw_status = 0;
411         /* allocate from "local" node */
412         rc = sfw_alloc_pages(rpc, rpc->srpc_scd->scd_cpt,
413                              reqst->brw_len / CFS_PAGE_SIZE,
414                              reqst->brw_rw == LST_BRW_WRITE);
415         if (rc != 0)
416                 return rc;
417
418         if (reqst->brw_rw == LST_BRW_READ)
419                 brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_MAGIC);
420         else
421                 brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_POISON);
422
423         return 0;
424 }
425
426 sfw_test_client_ops_t brw_test_client;
427 void brw_init_test_client(void)
428 {
429         brw_test_client.tso_init       = brw_client_init;
430         brw_test_client.tso_fini       = brw_client_fini;
431         brw_test_client.tso_prep_rpc   = brw_client_prep_rpc;
432         brw_test_client.tso_done_rpc   = brw_client_done_rpc;
433 };
434
435 srpc_service_t brw_test_service;
436 void brw_init_test_service(void)
437 {
438 #ifndef __KERNEL__
439         char *s;
440
441         s = getenv("BRW_INJECT_ERRORS");
442         brw_inject_errors = s != NULL ? atoi(s) : brw_inject_errors;
443 #endif
444
445         brw_test_service.sv_id         = SRPC_SERVICE_BRW;
446         brw_test_service.sv_name       = "brw_test";
447         brw_test_service.sv_handler    = brw_server_handle;
448         brw_test_service.sv_bulk_ready = brw_bulk_ready;
449         brw_test_service.sv_wi_total   = brw_srv_workitems;
450 }