Whamcloud - gitweb
LU-17504 build: fix gcc-13 [-Werror=stringop-overread] error
[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                 int off;
277
278                 /* I should never get this step if it's unknown feature
279                  * because make_session will reject unknown feature */
280                 LASSERT((sn->sn_features & ~LST_FEATS_MASK) == 0);
281
282                 opc   = breq->blk_opc;
283                 flags = breq->blk_flags;
284                 len   = breq->blk_len;
285                 off   = breq->blk_offset;
286         }
287         npg   = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
288
289         rc = sfw_create_test_rpc(tsu, dest, sn->sn_features, npg, len, &rpc);
290         if (rc != 0)
291                 return rc;
292
293         unsafe_memcpy(&rpc->crpc_bulk, bulk,
294                       offsetof(struct srpc_bulk, bk_iovs[npg]),
295                       FLEXIBLE_OBJECT);
296         if (opc == LST_BRW_WRITE)
297                 brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_MAGIC);
298         else
299                 brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_POISON);
300
301         req = &rpc->crpc_reqstmsg.msg_body.brw_reqst;
302         req->brw_flags = flags;
303         req->brw_rw    = opc;
304         req->brw_len   = len;
305
306         *rpcpp = rpc;
307         return 0;
308 }
309
310 static void
311 brw_client_done_rpc(struct sfw_test_unit *tsu, struct srpc_client_rpc *rpc)
312 {
313         __u64 magic = BRW_MAGIC;
314         struct sfw_test_instance *tsi = tsu->tsu_instance;
315         struct sfw_session *sn = tsi->tsi_batch->bat_session;
316         struct srpc_msg *msg = &rpc->crpc_replymsg;
317         struct srpc_brw_reply *reply = &msg->msg_body.brw_reply;
318         struct srpc_brw_reqst *reqst = &rpc->crpc_reqstmsg.msg_body.brw_reqst;
319
320         LASSERT(sn != NULL);
321
322         if (rpc->crpc_status != 0) {
323                 CERROR("BRW RPC to %s failed with %d\n",
324                        libcfs_id2str(rpc->crpc_dest), rpc->crpc_status);
325                 if (!tsi->tsi_stopping) /* rpc could have been aborted */
326                         atomic_inc(&sn->sn_brw_errors);
327                 return;
328         }
329
330         if (msg->msg_magic != SRPC_MSG_MAGIC) {
331                 __swab64s(&magic);
332                 __swab32s(&reply->brw_status);
333         }
334
335         CDEBUG(reply->brw_status ? D_WARNING : D_NET,
336                "BRW RPC to %s finished with brw_status: %d\n",
337                libcfs_id2str(rpc->crpc_dest), reply->brw_status);
338
339         if (reply->brw_status != 0) {
340                 atomic_inc(&sn->sn_brw_errors);
341                 rpc->crpc_status = -(int)reply->brw_status;
342                 return;
343         }
344
345         if (reqst->brw_rw == LST_BRW_WRITE)
346                 return;
347
348         if (brw_check_bulk(&rpc->crpc_bulk, reqst->brw_flags, magic) != 0) {
349                 CERROR("Bulk data from %s is corrupted!\n",
350                        libcfs_id2str(rpc->crpc_dest));
351                 atomic_inc(&sn->sn_brw_errors);
352                 rpc->crpc_status = -EBADMSG;
353         }
354 }
355
356 static void
357 brw_server_rpc_done(struct srpc_server_rpc *rpc)
358 {
359         struct srpc_bulk *blk = rpc->srpc_bulk;
360
361         if (blk == NULL)
362                 return;
363
364         if (rpc->srpc_status != 0)
365                 CERROR("Bulk transfer %s %s has failed: %d\n",
366                        blk->bk_sink ? "from" : "to",
367                        libcfs_id2str(rpc->srpc_peer), rpc->srpc_status);
368         else
369                 CDEBUG(D_NET, "Transferred %d pages bulk data %s %s\n",
370                        blk->bk_niov, blk->bk_sink ? "from" : "to",
371                        libcfs_id2str(rpc->srpc_peer));
372 }
373
374 static int
375 brw_bulk_ready(struct srpc_server_rpc *rpc, int status)
376 {
377         __u64 magic = BRW_MAGIC;
378         struct srpc_brw_reply *reply = &rpc->srpc_replymsg.msg_body.brw_reply;
379         struct srpc_brw_reqst *reqst;
380         struct srpc_msg *reqstmsg;
381
382         LASSERT (rpc->srpc_bulk != NULL);
383         LASSERT (rpc->srpc_reqstbuf != NULL);
384
385         reqstmsg = &rpc->srpc_reqstbuf->buf_msg;
386         reqst = &reqstmsg->msg_body.brw_reqst;
387
388         if (status != 0) {
389                 CERROR ("BRW bulk %s failed for RPC from %s: %d\n",
390                         reqst->brw_rw == LST_BRW_READ ? "READ" : "WRITE",
391                         libcfs_id2str(rpc->srpc_peer), status);
392                 return -EIO;
393         }
394
395         if (reqst->brw_rw == LST_BRW_READ)
396                 return 0;
397
398         if (reqstmsg->msg_magic != SRPC_MSG_MAGIC)
399                 __swab64s(&magic);
400
401         if (brw_check_bulk(rpc->srpc_bulk, reqst->brw_flags, magic) != 0) {
402                 CERROR ("Bulk data from %s is corrupted!\n",
403                         libcfs_id2str(rpc->srpc_peer));
404                 reply->brw_status = EBADMSG;
405         }
406
407         return 0;
408 }
409
410 static int
411 brw_server_handle(struct srpc_server_rpc *rpc)
412 {
413         struct srpc_service *sv = rpc->srpc_scd->scd_svc;
414         struct srpc_msg *replymsg = &rpc->srpc_replymsg;
415         struct srpc_msg *reqstmsg = &rpc->srpc_reqstbuf->buf_msg;
416         struct srpc_brw_reply *reply = &replymsg->msg_body.brw_reply;
417         struct srpc_brw_reqst *reqst = &reqstmsg->msg_body.brw_reqst;
418
419         LASSERT (sv->sv_id == SRPC_SERVICE_BRW);
420
421         if (reqstmsg->msg_magic != SRPC_MSG_MAGIC) {
422                 LASSERT (reqstmsg->msg_magic == __swab32(SRPC_MSG_MAGIC));
423
424                 __swab32s(&reqst->brw_rw);
425                 __swab32s(&reqst->brw_len);
426                 __swab32s(&reqst->brw_flags);
427                 __swab64s(&reqst->brw_rpyid);
428                 __swab64s(&reqst->brw_bulkid);
429         }
430         LASSERT (reqstmsg->msg_type == (__u32)srpc_service2request(sv->sv_id));
431
432         reply->brw_status = 0;
433         rpc->srpc_done = brw_server_rpc_done;
434
435         if ((reqst->brw_rw != LST_BRW_READ && reqst->brw_rw != LST_BRW_WRITE) ||
436             (reqst->brw_flags != LST_BRW_CHECK_NONE &&
437              reqst->brw_flags != LST_BRW_CHECK_FULL &&
438              reqst->brw_flags != LST_BRW_CHECK_SIMPLE)) {
439                 reply->brw_status = EINVAL;
440                 return 0;
441         }
442
443         if ((reqstmsg->msg_ses_feats & ~LST_FEATS_MASK) != 0) {
444                 replymsg->msg_ses_feats = LST_FEATS_MASK;
445                 reply->brw_status = EPROTO;
446                 return 0;
447         }
448
449         if ((reqstmsg->msg_ses_feats & LST_FEAT_BULK_LEN) == 0) {
450                 /* compat with old version */
451                 if ((reqst->brw_len & ~PAGE_MASK) != 0) {
452                         reply->brw_status = EINVAL;
453                         return 0;
454                 }
455         }
456
457         replymsg->msg_ses_feats = reqstmsg->msg_ses_feats;
458
459         if (reqst->brw_len == 0 || reqst->brw_len > LNET_MTU) {
460                 reply->brw_status = EINVAL;
461                 return 0;
462         }
463
464         srpc_init_bulk(rpc->srpc_bulk, 0, reqst->brw_len,
465                        reqst->brw_rw == LST_BRW_WRITE);
466
467         if (reqst->brw_rw == LST_BRW_READ)
468                 brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_MAGIC);
469         else
470                 brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_POISON);
471
472         return 0;
473 }
474
475 static int
476 brw_srpc_init(struct srpc_server_rpc *rpc, int cpt)
477 {
478         /* just alloc a maximal size - actual values will be adjusted later */
479         rpc->srpc_bulk = srpc_alloc_bulk(cpt, LNET_MTU);
480         if (rpc->srpc_bulk == NULL)
481                 return -ENOMEM;
482
483         srpc_init_bulk(rpc->srpc_bulk, 0, 0, 0);
484
485         return 0;
486 }
487
488 static void
489 brw_srpc_fini(struct srpc_server_rpc *rpc)
490 {
491         srpc_free_bulk(rpc->srpc_bulk);
492         rpc->srpc_bulk = NULL;
493 }
494
495 struct sfw_test_client_ops brw_test_client = {
496         .tso_init       = brw_client_init,
497         .tso_fini       = brw_client_fini,
498         .tso_prep_rpc   = brw_client_prep_rpc,
499         .tso_done_rpc   = brw_client_done_rpc,
500 };
501
502 struct srpc_service brw_test_service = {
503         .sv_id         = SRPC_SERVICE_BRW,
504         .sv_name       = "brw_test",
505         .sv_handler    = brw_server_handle,
506         .sv_bulk_ready = brw_bulk_ready,
507
508         .sv_srpc_init  = brw_srpc_init,
509         .sv_srpc_fini  = brw_srpc_fini,
510 };
511
512 void brw_init_test_service(void)
513 {
514         unsigned long cache_size = cfs_totalram_pages() >> 4;
515
516         /* brw prealloc cache should don't eat more than half memory */
517         cache_size /= ((LNET_MTU >> PAGE_SHIFT) + 1) ;
518
519         brw_test_service.sv_wi_total   = brw_srv_workitems;
520
521         if (brw_test_service.sv_wi_total > cache_size)
522                 brw_test_service.sv_wi_total = cache_size;
523 }