Whamcloud - gitweb
LU-17676 build: configure should prefer to ask if
[fs/lustre-release.git] / lnet / selftest / brw_test.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5  * Use is subject to license terms.
6  *
7  * Copyright (c) 2012, 2017, Intel Corporation.
8  */
9
10 /*
11  * This file is part of Lustre, http://www.lustre.org/
12  *
13  * Author: Isaac Huang <isaac@clusterfs.com>
14  */
15
16 #include "selftest.h"
17
18 static int brw_srv_workitems = SFW_TEST_WI_MAX;
19 module_param(brw_srv_workitems, int, 0644);
20 MODULE_PARM_DESC(brw_srv_workitems, "# BRW server workitems");
21
22 static int brw_inject_errors;
23 module_param(brw_inject_errors, int, 0644);
24 MODULE_PARM_DESC(brw_inject_errors, "# data errors to inject randomly, zero by default");
25
26 #define BRW_POISON      0xbeefbeefbeefbeefULL
27 #define BRW_MAGIC       0xeeb0eeb1eeb2eeb3ULL
28 #define BRW_MSIZE       sizeof(__u64)
29
30 static void
31 brw_client_fini(struct sfw_test_instance *tsi)
32 {
33         struct srpc_bulk *bulk;
34         struct sfw_test_unit *tsu;
35
36         LASSERT(tsi->tsi_is_client);
37
38         list_for_each_entry(tsu, &tsi->tsi_units, tsu_list) {
39                 bulk = tsu->tsu_private;
40                 if (bulk == NULL)
41                         continue;
42
43                 srpc_free_bulk(bulk);
44                 tsu->tsu_private = NULL;
45         }
46 }
47
48 static int
49 brw_client_init(struct sfw_test_instance *tsi)
50 {
51         struct sfw_session *sn = tsi->tsi_batch->bat_session;
52         int               flags;
53         int               off;
54         unsigned int      len;
55         int               opc;
56         struct srpc_bulk *bulk;
57         struct sfw_test_unit *tsu;
58
59         LASSERT(sn != NULL);
60         LASSERT(tsi->tsi_is_client);
61
62         if ((sn->sn_features & LST_FEAT_BULK_LEN) == 0) {
63                 struct test_bulk_req *breq = &tsi->tsi_u.bulk_v0;
64
65                 opc   = breq->blk_opc;
66                 flags = breq->blk_flags;
67                 /* NB: this is not going to work for variable page size,
68                  * but we have to keep it for compatibility */
69                 len   = breq->blk_npg * PAGE_SIZE;
70                 off   = 0;
71
72         } else {
73                 struct test_bulk_req_v1 *breq = &tsi->tsi_u.bulk_v1;
74
75                 /* I should never get this step if it's unknown feature
76                  * because make_session will reject unknown feature */
77                 LASSERT((sn->sn_features & ~LST_FEATS_MASK) == 0);
78
79                 opc   = breq->blk_opc;
80                 flags = breq->blk_flags;
81                 len   = breq->blk_len;
82                 off   = breq->blk_offset & ~PAGE_MASK;
83         }
84
85         if (off % BRW_MSIZE != 0)
86                 return -EINVAL;
87
88         if (len > LNET_MTU)
89                 return -EINVAL;
90
91         if (opc != LST_BRW_READ && opc != LST_BRW_WRITE)
92                 return -EINVAL;
93
94         if (flags != LST_BRW_CHECK_NONE &&
95             flags != LST_BRW_CHECK_FULL && flags != LST_BRW_CHECK_SIMPLE)
96                 return -EINVAL;
97
98         list_for_each_entry(tsu, &tsi->tsi_units, tsu_list) {
99                 bulk = srpc_alloc_bulk(lnet_cpt_of_nid(tsu->tsu_dest.nid, NULL),
100                                        len);
101                 if (bulk == NULL) {
102                         brw_client_fini(tsi);
103                         return -ENOMEM;
104                 }
105                 srpc_init_bulk(bulk, off, len, opc == LST_BRW_READ);
106
107                 tsu->tsu_private = bulk;
108         }
109
110         return 0;
111 }
112
113 #define BRW_POISON      0xbeefbeefbeefbeefULL
114 #define BRW_MAGIC       0xeeb0eeb1eeb2eeb3ULL
115 #define BRW_MSIZE       sizeof(__u64)
116
117 static int brw_inject_one_error(void)
118 {
119         struct timespec64 ts;
120
121         if (brw_inject_errors <= 0) return 0;
122
123         ktime_get_ts64(&ts);
124
125         if (((ts.tv_nsec / NSEC_PER_USEC) & 1) == 0)
126                 return 0;
127
128         return brw_inject_errors--;
129 }
130
131 static void
132 brw_fill_page(struct page *pg, int off, int len, int pattern, __u64 magic)
133 {
134         char *addr = page_address(pg) + off;
135         int   i;
136
137         LASSERT(addr != NULL);
138         LASSERT(off % BRW_MSIZE == 0 && len % BRW_MSIZE == 0);
139
140         if (pattern == LST_BRW_CHECK_NONE)
141                 return;
142
143         if (magic == BRW_MAGIC)
144                 magic += brw_inject_one_error();
145
146         if (pattern == LST_BRW_CHECK_SIMPLE) {
147                 memcpy(addr, &magic, BRW_MSIZE);
148                 if (len > BRW_MSIZE) {
149                         addr += len - BRW_MSIZE;
150                         memcpy(addr, &magic, BRW_MSIZE);
151                 }
152                 return;
153         }
154
155         if (pattern == LST_BRW_CHECK_FULL) {
156                 for (i = 0; i < len; i += BRW_MSIZE)
157                         memcpy(addr + i, &magic, BRW_MSIZE);
158                 return;
159         }
160         LBUG();
161 }
162
163 static int
164 brw_check_page(struct page *pg, int off, int len, int pattern, __u64 magic)
165 {
166         char  *addr = page_address(pg) + off;
167         __u64  data = 0; /* make compiler happy */
168         int    i;
169
170         LASSERT(addr != NULL);
171         LASSERT(off % BRW_MSIZE == 0 && len % BRW_MSIZE == 0);
172
173         if (pattern == LST_BRW_CHECK_NONE)
174                 return 0;
175
176         if (pattern == LST_BRW_CHECK_SIMPLE) {
177                 data = *((__u64 *) addr);
178                 if (data != magic)
179                         goto bad_data;
180
181                 if (len > BRW_MSIZE) {
182                         addr += len - BRW_MSIZE;
183                         data = *((__u64 *) addr);
184                         if (data != magic)
185                                 goto bad_data;
186                 }
187                 return 0;
188         }
189
190         if (pattern == LST_BRW_CHECK_FULL) {
191                 for (i = 0; i < len; i += BRW_MSIZE) {
192                         data = *(__u64 *)(addr + i);
193                         if (data != magic)
194                                 goto bad_data;
195                 }
196                 return 0;
197         }
198
199         LBUG();
200
201 bad_data:
202         CERROR ("Bad data in page %p: %#llx, %#llx expected\n",
203                 pg, data, magic);
204         return 1;
205 }
206
207 static void
208 brw_fill_bulk(struct srpc_bulk *bk, int pattern, __u64 magic)
209 {
210         int          i;
211         struct page *pg;
212
213         for (i = 0; i < bk->bk_niov; i++) {
214                 int     off;
215                 int     len;
216
217                 pg = bk->bk_iovs[i].bv_page;
218                 off = bk->bk_iovs[i].bv_offset;
219                 len = bk->bk_iovs[i].bv_len;
220                 brw_fill_page(pg, off, len, pattern, magic);
221         }
222 }
223
224 static int
225 brw_check_bulk(struct srpc_bulk *bk, int pattern, __u64 magic)
226 {
227         int          i;
228         struct page *pg;
229
230         for (i = 0; i < bk->bk_niov; i++) {
231                 int     off;
232                 int     len;
233
234                 pg = bk->bk_iovs[i].bv_page;
235                 off = bk->bk_iovs[i].bv_offset;
236                 len = bk->bk_iovs[i].bv_len;
237                 if (brw_check_page(pg, off, len, pattern, magic) != 0) {
238                         CERROR("Bulk page %p (%d/%d) is corrupted!\n",
239                                pg, i, bk->bk_niov);
240                         return 1;
241                 }
242         }
243
244         return 0;
245 }
246
247 static int
248 brw_client_prep_rpc(struct sfw_test_unit *tsu, struct lnet_process_id dest,
249                     struct srpc_client_rpc **rpcpp)
250 {
251         struct srpc_bulk *bulk = tsu->tsu_private;
252         struct sfw_test_instance *tsi = tsu->tsu_instance;
253         struct sfw_session *sn = tsi->tsi_batch->bat_session;
254         struct srpc_client_rpc *rpc;
255         struct srpc_brw_reqst *req;
256         int flags;
257         int npg;
258         int len;
259         int off;
260         int opc;
261         int rc;
262
263         LASSERT(sn != NULL);
264         LASSERT(bulk != NULL);
265
266         if ((sn->sn_features & LST_FEAT_BULK_LEN) == 0) {
267                 struct test_bulk_req *breq = &tsi->tsi_u.bulk_v0;
268
269                 opc   = breq->blk_opc;
270                 flags = breq->blk_flags;
271                 len   = breq->blk_npg * PAGE_SIZE;
272                 off   = 0;
273
274         } else {
275                 struct test_bulk_req_v1 *breq = &tsi->tsi_u.bulk_v1;
276
277                 /* I should never get this step if it's unknown feature
278                  * because make_session will reject unknown feature */
279                 LASSERT((sn->sn_features & ~LST_FEATS_MASK) == 0);
280
281                 opc   = breq->blk_opc;
282                 flags = breq->blk_flags;
283                 len   = breq->blk_len;
284                 off   = breq->blk_offset;
285         }
286         npg   = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
287
288         rc = sfw_create_test_rpc(tsu, dest, sn->sn_features, npg, len, &rpc);
289         if (rc != 0)
290                 return rc;
291
292         unsafe_memcpy(&rpc->crpc_bulk, bulk,
293                       offsetof(struct srpc_bulk, bk_iovs[npg]),
294                       FLEXIBLE_OBJECT);
295         if (opc == LST_BRW_WRITE)
296                 brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_MAGIC);
297         else
298                 brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_POISON);
299
300         req = &rpc->crpc_reqstmsg.msg_body.brw_reqst;
301         req->brw_flags = flags;
302         req->brw_rw    = opc;
303         req->brw_len   = len;
304
305         *rpcpp = rpc;
306         return 0;
307 }
308
309 static void
310 brw_client_done_rpc(struct sfw_test_unit *tsu, struct srpc_client_rpc *rpc)
311 {
312         __u64 magic = BRW_MAGIC;
313         struct sfw_test_instance *tsi = tsu->tsu_instance;
314         struct sfw_session *sn = tsi->tsi_batch->bat_session;
315         struct srpc_msg *msg = &rpc->crpc_replymsg;
316         struct srpc_brw_reply *reply = &msg->msg_body.brw_reply;
317         struct srpc_brw_reqst *reqst = &rpc->crpc_reqstmsg.msg_body.brw_reqst;
318
319         LASSERT(sn != NULL);
320
321         if (rpc->crpc_status != 0) {
322                 CERROR("BRW RPC to %s failed with %d\n",
323                        libcfs_id2str(rpc->crpc_dest), rpc->crpc_status);
324                 if (!tsi->tsi_stopping) /* rpc could have been aborted */
325                         atomic_inc(&sn->sn_brw_errors);
326                 return;
327         }
328
329         if (msg->msg_magic != SRPC_MSG_MAGIC) {
330                 __swab64s(&magic);
331                 __swab32s(&reply->brw_status);
332         }
333
334         CDEBUG(reply->brw_status ? D_WARNING : D_NET,
335                "BRW RPC to %s finished with brw_status: %d\n",
336                libcfs_id2str(rpc->crpc_dest), reply->brw_status);
337
338         if (reply->brw_status != 0) {
339                 atomic_inc(&sn->sn_brw_errors);
340                 rpc->crpc_status = -(int)reply->brw_status;
341                 return;
342         }
343
344         if (reqst->brw_rw == LST_BRW_WRITE)
345                 return;
346
347         if (brw_check_bulk(&rpc->crpc_bulk, reqst->brw_flags, magic) != 0) {
348                 CERROR("Bulk data from %s is corrupted!\n",
349                        libcfs_id2str(rpc->crpc_dest));
350                 atomic_inc(&sn->sn_brw_errors);
351                 rpc->crpc_status = -EBADMSG;
352         }
353 }
354
355 static void
356 brw_server_rpc_done(struct srpc_server_rpc *rpc)
357 {
358         struct srpc_bulk *blk = rpc->srpc_bulk;
359
360         if (blk == NULL)
361                 return;
362
363         if (rpc->srpc_status != 0)
364                 CERROR("Bulk transfer %s %s has failed: %d\n",
365                        blk->bk_sink ? "from" : "to",
366                        libcfs_id2str(rpc->srpc_peer), rpc->srpc_status);
367         else
368                 CDEBUG(D_NET, "Transferred %d pages bulk data %s %s\n",
369                        blk->bk_niov, blk->bk_sink ? "from" : "to",
370                        libcfs_id2str(rpc->srpc_peer));
371 }
372
373 static int
374 brw_bulk_ready(struct srpc_server_rpc *rpc, int status)
375 {
376         __u64 magic = BRW_MAGIC;
377         struct srpc_brw_reply *reply = &rpc->srpc_replymsg.msg_body.brw_reply;
378         struct srpc_brw_reqst *reqst;
379         struct srpc_msg *reqstmsg;
380
381         LASSERT (rpc->srpc_bulk != NULL);
382         LASSERT (rpc->srpc_reqstbuf != NULL);
383
384         reqstmsg = &rpc->srpc_reqstbuf->buf_msg;
385         reqst = &reqstmsg->msg_body.brw_reqst;
386
387         if (status != 0) {
388                 CERROR ("BRW bulk %s failed for RPC from %s: %d\n",
389                         reqst->brw_rw == LST_BRW_READ ? "READ" : "WRITE",
390                         libcfs_id2str(rpc->srpc_peer), status);
391                 return -EIO;
392         }
393
394         if (reqst->brw_rw == LST_BRW_READ)
395                 return 0;
396
397         if (reqstmsg->msg_magic != SRPC_MSG_MAGIC)
398                 __swab64s(&magic);
399
400         if (brw_check_bulk(rpc->srpc_bulk, reqst->brw_flags, magic) != 0) {
401                 CERROR ("Bulk data from %s is corrupted!\n",
402                         libcfs_id2str(rpc->srpc_peer));
403                 reply->brw_status = EBADMSG;
404         }
405
406         return 0;
407 }
408
409 static int
410 brw_server_handle(struct srpc_server_rpc *rpc)
411 {
412         struct srpc_service *sv = rpc->srpc_scd->scd_svc;
413         struct srpc_msg *replymsg = &rpc->srpc_replymsg;
414         struct srpc_msg *reqstmsg = &rpc->srpc_reqstbuf->buf_msg;
415         struct srpc_brw_reply *reply = &replymsg->msg_body.brw_reply;
416         struct srpc_brw_reqst *reqst = &reqstmsg->msg_body.brw_reqst;
417
418         LASSERT (sv->sv_id == SRPC_SERVICE_BRW);
419
420         if (reqstmsg->msg_magic != SRPC_MSG_MAGIC) {
421                 LASSERT (reqstmsg->msg_magic == __swab32(SRPC_MSG_MAGIC));
422
423                 __swab32s(&reqst->brw_rw);
424                 __swab32s(&reqst->brw_len);
425                 __swab32s(&reqst->brw_flags);
426                 __swab64s(&reqst->brw_rpyid);
427                 __swab64s(&reqst->brw_bulkid);
428         }
429         LASSERT (reqstmsg->msg_type == (__u32)srpc_service2request(sv->sv_id));
430
431         reply->brw_status = 0;
432         rpc->srpc_done = brw_server_rpc_done;
433
434         if ((reqst->brw_rw != LST_BRW_READ && reqst->brw_rw != LST_BRW_WRITE) ||
435             (reqst->brw_flags != LST_BRW_CHECK_NONE &&
436              reqst->brw_flags != LST_BRW_CHECK_FULL &&
437              reqst->brw_flags != LST_BRW_CHECK_SIMPLE)) {
438                 reply->brw_status = EINVAL;
439                 return 0;
440         }
441
442         if ((reqstmsg->msg_ses_feats & ~LST_FEATS_MASK) != 0) {
443                 replymsg->msg_ses_feats = LST_FEATS_MASK;
444                 reply->brw_status = EPROTO;
445                 return 0;
446         }
447
448         if ((reqstmsg->msg_ses_feats & LST_FEAT_BULK_LEN) == 0) {
449                 /* compat with old version */
450                 if ((reqst->brw_len & ~PAGE_MASK) != 0) {
451                         reply->brw_status = EINVAL;
452                         return 0;
453                 }
454         }
455
456         replymsg->msg_ses_feats = reqstmsg->msg_ses_feats;
457
458         if (reqst->brw_len == 0 || reqst->brw_len > LNET_MTU) {
459                 reply->brw_status = EINVAL;
460                 return 0;
461         }
462
463         srpc_init_bulk(rpc->srpc_bulk, 0, reqst->brw_len,
464                        reqst->brw_rw == LST_BRW_WRITE);
465
466         if (reqst->brw_rw == LST_BRW_READ)
467                 brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_MAGIC);
468         else
469                 brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_POISON);
470
471         return 0;
472 }
473
474 static int
475 brw_srpc_init(struct srpc_server_rpc *rpc, int cpt)
476 {
477         /* just alloc a maximal size - actual values will be adjusted later */
478         rpc->srpc_bulk = srpc_alloc_bulk(cpt, LNET_MTU);
479         if (rpc->srpc_bulk == NULL)
480                 return -ENOMEM;
481
482         srpc_init_bulk(rpc->srpc_bulk, 0, 0, 0);
483
484         return 0;
485 }
486
487 static void
488 brw_srpc_fini(struct srpc_server_rpc *rpc)
489 {
490         srpc_free_bulk(rpc->srpc_bulk);
491         rpc->srpc_bulk = NULL;
492 }
493
494 struct sfw_test_client_ops brw_test_client = {
495         .tso_init       = brw_client_init,
496         .tso_fini       = brw_client_fini,
497         .tso_prep_rpc   = brw_client_prep_rpc,
498         .tso_done_rpc   = brw_client_done_rpc,
499 };
500
501 struct srpc_service brw_test_service = {
502         .sv_id         = SRPC_SERVICE_BRW,
503         .sv_name       = "brw_test",
504         .sv_handler    = brw_server_handle,
505         .sv_bulk_ready = brw_bulk_ready,
506
507         .sv_srpc_init  = brw_srpc_init,
508         .sv_srpc_fini  = brw_srpc_fini,
509 };
510
511 void brw_init_test_service(void)
512 {
513         unsigned long cache_size = cfs_totalram_pages() >> 4;
514
515         /* brw prealloc cache should don't eat more than half memory */
516         cache_size /= ((LNET_MTU >> PAGE_SHIFT) + 1) ;
517
518         brw_test_service.sv_wi_total   = brw_srv_workitems;
519
520         if (brw_test_service.sv_wi_total > cache_size)
521                 brw_test_service.sv_wi_total = cache_size;
522 }