Whamcloud - gitweb
4b53784e3e29dce712c9301095b81b4e4deaa1e4
[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 [sun.com URL with a
20  * copy of GPLv2].
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  2008 Sun Microsystems, Inc. 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         list_for_each_entry (tsu, &tsi->tsi_units, tsu_list) {
55                 bulk = tsu->tsu_private;
56                 if (bulk == NULL) continue;
57
58                 srpc_free_bulk(bulk);
59                 tsu->tsu_private = NULL;
60         }
61 }
62
63 int
64 brw_client_init (sfw_test_instance_t *tsi)
65 {
66         test_bulk_req_t  *breq = &tsi->tsi_u.bulk;
67         int               flags = breq->blk_flags;
68         int               npg = breq->blk_npg;
69         srpc_bulk_t      *bulk;
70         sfw_test_unit_t  *tsu;
71
72         LASSERT (tsi->tsi_is_client);
73
74         if (npg > LNET_MAX_IOV || npg <= 0)
75                 return -EINVAL;
76
77         if (breq->blk_opc != LST_BRW_READ && breq->blk_opc != LST_BRW_WRITE)
78                 return -EINVAL;
79
80         if (flags != LST_BRW_CHECK_NONE &&
81             flags != LST_BRW_CHECK_FULL && flags != LST_BRW_CHECK_SIMPLE)
82                 return -EINVAL;
83
84         list_for_each_entry (tsu, &tsi->tsi_units, 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         do_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;
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                         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                 atomic_inc(&sn->sn_brw_errors);
294                 rpc->crpc_status = -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                 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 == 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 {
420         .tso_init      = brw_client_init,
421         .tso_fini      = brw_client_fini,
422         .tso_prep_rpc  = brw_client_prep_rpc,
423         .tso_done_rpc  = brw_client_done_rpc,
424 };
425
426 srpc_service_t brw_test_service =
427 {
428         .sv_name       = "brw test",
429         .sv_handler    = brw_server_handle,
430         .sv_bulk_ready = brw_bulk_ready,
431         .sv_id         = SRPC_SERVICE_BRW,
432 };