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