Whamcloud - gitweb
6b3fa8004ed7062ee9b6a01a4ace56b38044fde8
[fs/lustre-release.git] / lnet / selftest / brw_test.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
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/brw_test.c
37  *
38  * Author: Isaac Huang <isaac@clusterfs.com>
39  */
40
41 #include "selftest.h"
42
43
44 extern int brw_inject_errors;
45
46 static void
47 brw_client_fini (sfw_test_instance_t *tsi)
48 {
49         srpc_bulk_t     *bulk;
50         sfw_test_unit_t *tsu;
51
52         LASSERT (tsi->tsi_is_client);
53
54         cfs_list_for_each_entry_typed (tsu, &tsi->tsi_units,
55                                        sfw_test_unit_t, tsu_list) {
56                 bulk = tsu->tsu_private;
57                 if (bulk == NULL) continue;
58
59                 srpc_free_bulk(bulk);
60                 tsu->tsu_private = NULL;
61         }
62 }
63
64 int
65 brw_client_init (sfw_test_instance_t *tsi)
66 {
67         test_bulk_req_t  *breq = &tsi->tsi_u.bulk;
68         int               flags = breq->blk_flags;
69         int               npg = breq->blk_npg;
70         srpc_bulk_t      *bulk;
71         sfw_test_unit_t  *tsu;
72
73         LASSERT (tsi->tsi_is_client);
74
75         if (npg > LNET_MAX_IOV || npg <= 0)
76                 return -EINVAL;
77
78         if (breq->blk_opc != LST_BRW_READ && breq->blk_opc != LST_BRW_WRITE)
79                 return -EINVAL;
80
81         if (flags != LST_BRW_CHECK_NONE &&
82             flags != LST_BRW_CHECK_FULL && flags != LST_BRW_CHECK_SIMPLE)
83                 return -EINVAL;
84
85         cfs_list_for_each_entry_typed (tsu, &tsi->tsi_units,
86                                        sfw_test_unit_t, tsu_list) {
87                 bulk = srpc_alloc_bulk(npg, breq->blk_opc == LST_BRW_READ);
88                 if (bulk == NULL) {
89                         brw_client_fini(tsi);
90                         return -ENOMEM;
91                 }
92
93                 tsu->tsu_private = bulk;
94         }
95
96         return 0;
97 }
98
99 #define BRW_POISON      0xbeefbeefbeefbeefULL
100 #define BRW_MAGIC       0xeeb0eeb1eeb2eeb3ULL
101 #define BRW_MSIZE       sizeof(__u64)
102
103 int
104 brw_inject_one_error (void)
105 {
106         struct timeval tv;
107
108         if (brw_inject_errors <= 0) return 0;
109
110 #ifndef __KERNEL__
111         gettimeofday(&tv, NULL);
112 #else
113         cfs_gettimeofday(&tv);
114 #endif
115
116         if ((tv.tv_usec & 1) == 0) return 0;
117
118         return brw_inject_errors--;
119 }
120
121 void
122 brw_fill_page (cfs_page_t *pg, int pattern, __u64 magic)
123 {
124         char *addr = cfs_page_address(pg);
125         int   i;
126
127         LASSERT (addr != NULL);
128
129         if (pattern == LST_BRW_CHECK_NONE) return;
130
131         if (magic == BRW_MAGIC)
132                 magic += brw_inject_one_error();
133
134         if (pattern == LST_BRW_CHECK_SIMPLE) {
135                 memcpy(addr, &magic, BRW_MSIZE);
136                 addr += CFS_PAGE_SIZE - BRW_MSIZE;
137                 memcpy(addr, &magic, BRW_MSIZE);
138                 return;
139         }
140
141         if (pattern == LST_BRW_CHECK_FULL) {
142                 for (i = 0; i < CFS_PAGE_SIZE / BRW_MSIZE; i++)
143                         memcpy(addr + i * BRW_MSIZE, &magic, BRW_MSIZE);
144                 return;
145         }
146
147         LBUG ();
148         return;
149 }
150
151 int
152 brw_check_page (cfs_page_t *pg, int pattern, __u64 magic)
153 {
154         char  *addr = cfs_page_address(pg);
155         __u64  data = 0; /* make compiler happy */
156         int    i;
157
158         LASSERT (addr != NULL);
159
160         if (pattern == LST_BRW_CHECK_NONE)
161                 return 0;
162
163         if (pattern == LST_BRW_CHECK_SIMPLE) {
164                 data = *((__u64 *) addr);
165                 if (data != magic) goto bad_data;
166
167                 addr += CFS_PAGE_SIZE - BRW_MSIZE;
168                 data = *((__u64 *) addr);
169                 if (data != magic) goto bad_data;
170
171                 return 0;
172         }
173
174         if (pattern == LST_BRW_CHECK_FULL) {
175                 for (i = 0; i < CFS_PAGE_SIZE / BRW_MSIZE; i++) {
176                         data = *(((__u64 *) addr) + i);
177                         if (data != magic) goto bad_data;
178                 }
179
180                 return 0;
181         }
182
183         LBUG ();
184
185 bad_data:
186         CERROR ("Bad data in page %p: "LPX64", "LPX64" expected\n",
187                 pg, data, magic);
188         return 1;
189 }
190
191 void
192 brw_fill_bulk (srpc_bulk_t *bk, int pattern, __u64 magic)
193 {
194         int         i;
195         cfs_page_t *pg;
196
197         for (i = 0; i < bk->bk_niov; i++) {
198 #ifdef __KERNEL__
199                 pg = bk->bk_iovs[i].kiov_page;
200 #else
201                 LASSERT (bk->bk_pages != NULL);
202                 pg = bk->bk_pages[i];
203 #endif
204                 brw_fill_page(pg, pattern, magic);
205         }
206 }
207
208 int
209 brw_check_bulk (srpc_bulk_t *bk, int pattern, __u64 magic)
210 {
211         int         i;
212         cfs_page_t *pg;
213
214         for (i = 0; i < bk->bk_niov; i++) {
215 #ifdef __KERNEL__
216                 pg = bk->bk_iovs[i].kiov_page;
217 #else
218                 LASSERT (bk->bk_pages != NULL);
219                 pg = bk->bk_pages[i];
220 #endif
221                 if (brw_check_page(pg, pattern, magic) != 0) {
222                         CERROR ("Bulk page %p (%d/%d) is corrupted!\n",
223                                 pg, i, bk->bk_niov);
224                         return 1;
225                 }
226         }
227
228         return 0;
229 }
230
231 static int
232 brw_client_prep_rpc (sfw_test_unit_t *tsu,
233                      lnet_process_id_t dest, srpc_client_rpc_t **rpcpp)
234 {
235         srpc_bulk_t         *bulk = tsu->tsu_private;
236         sfw_test_instance_t *tsi = tsu->tsu_instance;
237         test_bulk_req_t     *breq = &tsi->tsi_u.bulk;
238         int                  npg = breq->blk_npg;
239         int                  flags = breq->blk_flags;
240         srpc_client_rpc_t   *rpc;
241         srpc_brw_reqst_t    *req;
242         int                  rc;
243
244         LASSERT (bulk != NULL);
245         LASSERT (bulk->bk_niov == npg);
246
247         rc = sfw_create_test_rpc(tsu, dest, npg, npg * CFS_PAGE_SIZE, &rpc);
248         if (rc != 0) return rc;
249
250         memcpy(&rpc->crpc_bulk, bulk, offsetof(srpc_bulk_t, bk_iovs[npg]));
251         if (breq->blk_opc == LST_BRW_WRITE)
252                 brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_MAGIC);
253         else
254                 brw_fill_bulk(&rpc->crpc_bulk, flags, BRW_POISON);
255
256         req = &rpc->crpc_reqstmsg.msg_body.brw_reqst;
257         req->brw_flags = flags;
258         req->brw_rw    = breq->blk_opc;
259         req->brw_len   = npg * CFS_PAGE_SIZE;
260
261         *rpcpp = rpc;
262         return 0;
263 }
264
265 static void
266 brw_client_done_rpc (sfw_test_unit_t *tsu, srpc_client_rpc_t *rpc)
267 {
268         __u64                magic = BRW_MAGIC;
269         sfw_test_instance_t *tsi = tsu->tsu_instance;
270         sfw_session_t       *sn = tsi->tsi_batch->bat_session;
271         srpc_msg_t          *msg = &rpc->crpc_replymsg;
272         srpc_brw_reply_t    *reply = &msg->msg_body.brw_reply;
273         srpc_brw_reqst_t    *reqst = &rpc->crpc_reqstmsg.msg_body.brw_reqst;
274
275         LASSERT (sn != NULL);
276
277         if (rpc->crpc_status != 0) {
278                 CERROR ("BRW RPC to %s failed with %d\n",
279                         libcfs_id2str(rpc->crpc_dest), rpc->crpc_status);
280                 if (!tsi->tsi_stopping) /* rpc could have been aborted */
281                         cfs_atomic_inc(&sn->sn_brw_errors);
282                 goto out;
283         }
284
285         if (msg->msg_magic != SRPC_MSG_MAGIC) {
286                 __swab64s(&magic);
287                 __swab32s(&reply->brw_status);
288         }
289
290         CDEBUG (reply->brw_status ? D_WARNING : D_NET,
291                 "BRW RPC to %s finished with brw_status: %d\n",
292                 libcfs_id2str(rpc->crpc_dest), reply->brw_status);
293
294         if (reply->brw_status != 0) {
295                 cfs_atomic_inc(&sn->sn_brw_errors);
296                 rpc->crpc_status = -(int)reply->brw_status;
297                 goto out;
298         }
299
300         if (reqst->brw_rw == LST_BRW_WRITE) goto out;
301
302         if (brw_check_bulk(&rpc->crpc_bulk, reqst->brw_flags, magic) != 0) {
303                 CERROR ("Bulk data from %s is corrupted!\n",
304                         libcfs_id2str(rpc->crpc_dest));
305                 cfs_atomic_inc(&sn->sn_brw_errors);
306                 rpc->crpc_status = -EBADMSG;
307         }
308
309 out:
310 #ifndef __KERNEL__
311         rpc->crpc_bulk.bk_pages = NULL;
312 #endif
313         return;
314 }
315
316 void
317 brw_server_rpc_done (srpc_server_rpc_t *rpc)
318 {
319         srpc_bulk_t *blk = rpc->srpc_bulk;
320
321         if (blk == NULL) return;
322
323         if (rpc->srpc_status != 0)
324                 CERROR ("Bulk transfer %s %s has failed: %d\n",
325                         blk->bk_sink ? "from" : "to",
326                         libcfs_id2str(rpc->srpc_peer), rpc->srpc_status);
327         else
328                 CDEBUG (D_NET, "Transfered %d pages bulk data %s %s\n",
329                         blk->bk_niov, blk->bk_sink ? "from" : "to",
330                         libcfs_id2str(rpc->srpc_peer));
331
332         sfw_free_pages(rpc);
333 }
334
335 int
336 brw_bulk_ready (srpc_server_rpc_t *rpc, int status)
337 {
338         __u64             magic = BRW_MAGIC;
339         srpc_brw_reply_t *reply = &rpc->srpc_replymsg.msg_body.brw_reply;
340         srpc_brw_reqst_t *reqst;
341         srpc_msg_t       *reqstmsg;
342
343         LASSERT (rpc->srpc_bulk != NULL);
344         LASSERT (rpc->srpc_reqstbuf != NULL);
345
346         reqstmsg = &rpc->srpc_reqstbuf->buf_msg;
347         reqst = &reqstmsg->msg_body.brw_reqst;
348
349         if (status != 0) {
350                 CERROR ("BRW bulk %s failed for RPC from %s: %d\n",
351                         reqst->brw_rw == LST_BRW_READ ? "READ" : "WRITE",
352                         libcfs_id2str(rpc->srpc_peer), status);
353                 return -EIO;
354         }
355
356         if (reqst->brw_rw == LST_BRW_READ)
357                 return 0;
358
359         if (reqstmsg->msg_magic != SRPC_MSG_MAGIC)
360                 __swab64s(&magic);
361
362         if (brw_check_bulk(rpc->srpc_bulk, reqst->brw_flags, magic) != 0) {
363                 CERROR ("Bulk data from %s is corrupted!\n",
364                         libcfs_id2str(rpc->srpc_peer));
365                 reply->brw_status = EBADMSG;
366         }
367
368         return 0;
369 }
370
371 int
372 brw_server_handle (srpc_server_rpc_t *rpc)
373 {
374         srpc_service_t   *sv = rpc->srpc_service;
375         srpc_msg_t       *replymsg = &rpc->srpc_replymsg;
376         srpc_msg_t       *reqstmsg = &rpc->srpc_reqstbuf->buf_msg;
377         srpc_brw_reply_t *reply = &replymsg->msg_body.brw_reply;
378         srpc_brw_reqst_t *reqst = &reqstmsg->msg_body.brw_reqst;
379         int               rc;
380
381         LASSERT (sv->sv_id == SRPC_SERVICE_BRW);
382
383         if (reqstmsg->msg_magic != SRPC_MSG_MAGIC) {
384                 LASSERT (reqstmsg->msg_magic == __swab32(SRPC_MSG_MAGIC));
385
386                 __swab32s(&reqstmsg->msg_type);
387                 __swab32s(&reqst->brw_rw);
388                 __swab32s(&reqst->brw_len);
389                 __swab32s(&reqst->brw_flags);
390                 __swab64s(&reqst->brw_rpyid);
391                 __swab64s(&reqst->brw_bulkid);
392         }
393         LASSERT (reqstmsg->msg_type == (__u32)srpc_service2request(sv->sv_id));
394
395         rpc->srpc_done = brw_server_rpc_done;
396
397         if ((reqst->brw_rw != LST_BRW_READ && reqst->brw_rw != LST_BRW_WRITE) ||
398             reqst->brw_len == 0 || (reqst->brw_len & ~CFS_PAGE_MASK) != 0 ||
399             reqst->brw_len / CFS_PAGE_SIZE > LNET_MAX_IOV ||
400             (reqst->brw_flags != LST_BRW_CHECK_NONE &&
401              reqst->brw_flags != LST_BRW_CHECK_FULL &&
402              reqst->brw_flags != LST_BRW_CHECK_SIMPLE)) {
403                 reply->brw_status = EINVAL;
404                 return 0;
405         }
406
407         reply->brw_status = 0;
408         rc = sfw_alloc_pages(rpc, reqst->brw_len / CFS_PAGE_SIZE,
409                              reqst->brw_rw == LST_BRW_WRITE);
410         if (rc != 0) return rc;
411
412         if (reqst->brw_rw == LST_BRW_READ)
413                 brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_MAGIC);
414         else
415                 brw_fill_bulk(rpc->srpc_bulk, reqst->brw_flags, BRW_POISON);
416
417         return 0;
418 }
419
420 sfw_test_client_ops_t brw_test_client;
421 void brw_init_test_client(void)
422 {
423         brw_test_client.tso_init       = brw_client_init;
424         brw_test_client.tso_fini       = brw_client_fini;
425         brw_test_client.tso_prep_rpc   = brw_client_prep_rpc;
426         brw_test_client.tso_done_rpc   = brw_client_done_rpc;
427 };
428
429 srpc_service_t brw_test_service;
430 void brw_init_test_service(void)
431 {
432         brw_test_service.sv_id         = SRPC_SERVICE_BRW;
433         brw_test_service.sv_name       = "brw_test";
434         brw_test_service.sv_handler    = brw_server_handle;
435         brw_test_service.sv_bulk_ready = brw_bulk_ready;
436 }