Whamcloud - gitweb
LU-2955 tests: make replay-ost-single/8b SLOW for ZFS
[fs/lustre-release.git] / lustre / tests / iam_ut.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  * lustre/tests/iam_ut.c
35  *
36  * iam_ut.c
37  * iam unit-tests
38  *
39  * Author: Nikita Danilov <nikita@clusterfs.com>
40  */
41
42 #include <unistd.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <fcntl.h>
46 #include <string.h>
47 #include <errno.h>
48 #include <assert.h>
49
50 #include <sys/types.h>
51
52 #ifdef HAVE_ENDIAN_H
53 #include <endian.h>
54 #endif
55
56 #include <libcfs/libcfs.h>
57
58 enum {
59         /*
60          * Maximal format name length.
61          */
62         DX_FMT_NAME_LEN    = 16
63 };
64
65 struct iam_uapi_info {
66         __u16 iui_keysize;
67         __u16 iui_recsize;
68         __u16 iui_ptrsize;
69         __u16 iui_height;
70         char  iui_fmt_name[DX_FMT_NAME_LEN];
71 };
72
73 struct iam_uapi_op {
74         void *iul_key;
75         void *iul_rec;
76 };
77
78 struct iam_uapi_it {
79         struct iam_uapi_op iui_op;
80         __u16              iui_state;
81 };
82
83 enum iam_ioctl_cmd {
84         IAM_IOC_INIT     = _IOW('i', 1, struct iam_uapi_info),
85         IAM_IOC_GETINFO  = _IOR('i', 2, struct iam_uapi_info),
86         IAM_IOC_INSERT   = _IOR('i', 3, struct iam_uapi_op),
87         IAM_IOC_LOOKUP   = _IOWR('i', 4, struct iam_uapi_op),
88         IAM_IOC_DELETE   = _IOR('i', 5, struct iam_uapi_op),
89         IAM_IOC_IT_START = _IOR('i', 6, struct iam_uapi_it),
90         IAM_IOC_IT_NEXT  = _IOW('i', 7, struct iam_uapi_it),
91         IAM_IOC_IT_STOP  = _IOR('i', 8, struct iam_uapi_it),
92
93         IAM_IOC_POLYMORPH = _IOR('i', 9, unsigned long)
94 };
95
96 static void usage(void)
97 {
98         printf("usage: iam_ut [-v] [-h] file\n");
99 }
100
101 static int doop(int fd, const void *key, const void *rec,
102                 int cmd, const char *name)
103 {
104         int result;
105
106         struct iam_uapi_op op = {
107                 .iul_key = key,
108                 .iul_rec = rec
109         };
110         result = ioctl(fd, cmd, &op);
111         if (result != 0)
112                 fprintf(stderr, "ioctl(%s): %i/%i (%m)\n", name, result, errno);
113         return result;
114 }
115
116 static int doit(int fd, const void *key, const void *rec,
117                 int cmd, const char *name)
118 {
119         int result;
120
121         struct iam_uapi_it it = {
122                 .iui_op = {
123                         .iul_key = key,
124                         .iul_rec = rec
125                 },
126                 .iui_state = 0
127         };
128
129         assert((void *)&it == (void *)&it.iui_op);
130
131         result = ioctl(fd, cmd, &it);
132         if (result != 0)
133                 fprintf(stderr, "ioctl(%s): %i/%i (%m)\n", name, result, errno);
134         else
135                 result = it.iui_state;
136         return result;
137 }
138
139 static int insert(int fd, const void *key, const void *rec)
140 {
141         return doop(fd, key, rec, IAM_IOC_INSERT, "IAM_IOC_INSERT");
142 }
143
144 static int lookup(int fd, const void *key, void *rec)
145 {
146         return doop(fd, key, rec, IAM_IOC_LOOKUP, "IAM_IOC_LOOKUP");
147 }
148
149 static int delete(int fd, const void *key, void *rec)
150 {
151         return doop(fd, key, rec, IAM_IOC_DELETE, "IAM_IOC_DELETE");
152 }
153
154 static int rec_is_nul_term(int recsize)
155 {
156         return recsize == 255;
157 }
158
159 static void print_rec(const unsigned char *rec, int nr)
160 {
161         int i;
162
163         for (i = 0; i < nr; ++i) {
164                 printf("%c", rec[i]);
165                 if (rec_is_nul_term(nr) && rec[i] == 0)
166                         break;
167         }
168         printf("|    |");
169         for (i = 0; i < nr; ++i) {
170                 printf("%x", rec[i]);
171                 if (rec_is_nul_term(nr) && rec[i] == 0)
172                         break;
173         }
174         printf("\n");
175 }
176
177 enum op {
178         OP_TEST,
179         OP_INSERT,
180         OP_LOOKUP,
181         OP_DELETE,
182         OP_IT_START,
183         OP_IT_NEXT,
184         OP_IT_STOP
185 };
186
187 unsigned char hex2dec(unsigned char hex)
188 {
189         if ('0' <= hex && hex <= '9') {
190                 return hex - '0';
191         } else if ('a' <= hex && hex <= 'f') {
192                 return hex - 'a' + 10;
193         } else if ('A' <= hex && hex <= 'F') {
194                 return hex - 'A' + 10;
195         } else {
196                 fprintf(stderr, "Wrong hex digit '%c'\n", hex);
197                 exit(1);
198         }
199 }
200
201 unsigned char *packdigit(unsigned char *number)
202 {
203         unsigned char *area;
204         unsigned char *scan;
205
206         area = calloc(strlen(number) / 2 + 2, sizeof area[0]);
207         if (area != NULL) {
208                 for (scan = area; *number; number += 2, scan++)
209                         *scan = (hex2dec(number[0]) << 4) | hex2dec(number[1]);
210         }
211         return area;
212 }
213
214 int main(int argc, char **argv)
215 {
216         int i;
217         int rc;
218         int opt;
219         int keysize;
220         int recsize;
221         int N = 0x10000;
222         int verbose = 0;
223         int doinit = 1;
224         int keynul = 1;
225         int recnul = 1;
226
227         void *(*copier)(void *, void *, size_t);
228
229         enum op op;
230
231         char *key;
232         char *rec;
233
234         char *key_opt;
235         char *rec_opt;
236
237         struct iam_uapi_info ua;
238
239         setbuf(stdout, NULL);
240         setbuf(stderr, NULL);
241
242         key_opt = NULL;
243         rec_opt = NULL;
244
245         op = OP_TEST;
246
247         do {
248                 opt = getopt(argc, argv, "vilk:K:N:r:R:dsSnP:");
249                 switch (opt) {
250                 case 'v':
251                         verbose++;
252                 case -1:
253                         break;
254                 case 'K':
255                         key_opt = packdigit(optarg);
256                         keynul = 0;
257                         break;
258                 case 'k':
259                         key_opt = optarg;
260                         break;
261                 case 'N':
262                         N = atoi(optarg);
263                         break;
264                 case 'R':
265                         rec_opt = packdigit(optarg);
266                         recnul = 0;
267                         break;
268                 case 'r':
269                         rec_opt = optarg;
270                         break;
271                 case 'i':
272                         op = OP_INSERT;
273                         break;
274                 case 'l':
275                         op = OP_LOOKUP;
276                         break;
277                 case 'd':
278                         op = OP_DELETE;
279                         break;
280                 case 's':
281                         op = OP_IT_START;
282                         break;
283                 case 'S':
284                         op = OP_IT_STOP;
285                         doinit = 0;
286                         break;
287                 case 'n':
288                         op = OP_IT_NEXT;
289                         doinit = 0;
290                         break;
291                 case 'P': {
292                         unsigned long mode;
293
294                         mode = strtoul(optarg, NULL, 0);
295                         rc = ioctl(0, IAM_IOC_POLYMORPH, mode);
296                         if (rc == -1)
297                                 perror("IAM_IOC_POLYMORPH");
298                         return 0;
299                 }
300                 case '?':
301                 default:
302                         fprintf(stderr, "Unable to parse options.");
303                 case 'h':
304                         usage();
305                         return 0;
306                 }
307         } while (opt != -1);
308
309         if (doinit) {
310                 rc = ioctl(0, IAM_IOC_INIT, &ua);
311                 if (rc != 0) {
312                         fprintf(stderr, "ioctl(IAM_IOC_INIT): %i (%m)\n", rc);
313                         return 1;
314                 }
315         }
316         rc = ioctl(0, IAM_IOC_GETINFO, &ua);
317         if (rc != 0) {
318                 fprintf(stderr, "ioctl(IAM_IOC_GETATTR): %i (%m)\n", rc);
319                 return 1;
320         }
321
322         keysize = ua.iui_keysize;
323         recsize = ua.iui_recsize;
324         if (verbose > 0)
325                 printf("keysize: %i, recsize: %i, ptrsize: %i, "
326                        "height: %i, name: %s\n",
327                        keysize, recsize, ua.iui_ptrsize,
328                        ua.iui_height, ua.iui_fmt_name);
329
330         key = calloc(keysize + 1, sizeof key[0]);
331         rec = calloc(recsize + 1, sizeof rec[0]);
332
333         if (key == NULL || rec == NULL) {
334                 fprintf(stderr, "cannot allocate memory\n");
335                 rc = 1;
336                 goto out;
337         }
338
339         copier = keynul ? &strncpy : &memcpy;
340         copier(key, key_opt ? : "RIVERRUN", keysize + 1);
341         if (keynul == 0) {
342                 free(key_opt);
343                 key_opt = NULL;
344         }
345         copier = recnul ? &strncpy : &memcpy;
346         copier(rec, rec_opt ? : "PALEFIRE", recsize + 1);
347         if (recnul == 0) {
348                 free(rec_opt);
349                 rec_opt = NULL;
350         }
351
352         if (op == OP_INSERT) {
353                 rc = doop(0, key, rec, IAM_IOC_INSERT, "IAM_IOC_INSERT");
354                 goto out;
355         } else if (op == OP_DELETE) {
356                 rc = doop(0, key, rec, IAM_IOC_DELETE, "IAM_IOC_DELETE");
357                 goto out;
358         } else if (op == OP_LOOKUP) {
359                 rc = doop(0, key, rec, IAM_IOC_LOOKUP, "IAM_IOC_LOOKUP");
360                 if (rc == 0)
361                         print_rec(rec, recsize);
362                 goto out;
363         } else if (op == OP_IT_START) {
364                 rc = doop(0, key, rec, IAM_IOC_IT_START, "IAM_IOC_IT_START");
365                 if (rc == 0) {
366                         print_rec(key, keysize);
367                         print_rec(rec, recsize);
368                 }
369                 goto out;
370         } else if (op == OP_IT_STOP) {
371                 rc = doop(0, key, rec, IAM_IOC_IT_STOP, "IAM_IOC_IT_STOP");
372                 goto out;
373         } else if (op == OP_IT_NEXT) {
374                 rc = doop(0, key, rec, IAM_IOC_IT_NEXT, "IAM_IOC_IT_NEXT");
375                 if (rc == 0) {
376                         print_rec(key, keysize);
377                         print_rec(rec, recsize);
378                 }
379                 goto out;
380         }
381
382         rc = insert(0, key, rec);
383         if (rc != 0) {
384                 rc = 1;
385                 goto out;
386         }
387
388         rc = insert(0, "DAEDALUS", "FINNEGAN");
389         if (rc != 0) {
390                 rc = 1;
391                 goto out;
392         }
393
394         rc = insert(0, "DAEDALUS", "FINNEGAN");
395         if (errno != EEXIST) {
396                 if (rc == 0)
397                         fprintf(stderr, "Duplicate key not detected!\n");
398                 if (rc != 0) {
399                         rc = 1;
400                         goto out;
401                 }
402         }
403
404         rc = lookup(0, "RIVERRUN", rec);
405         if (rc != 0) {
406                 rc = 1;
407                 goto out;
408         }
409
410         print_rec(rec, recsize);
411
412         for (i = 0; i < N; ++i) {
413                 memset(key, 0, keysize + 1);
414                 memset(rec, 0, recsize + 1);
415                 snprintf(key, keysize + 1, "y-%x-x", i);
416                 snprintf(rec, recsize + 1, "p-%x-q", 1000 - i);
417                 rc = insert(0, key, rec);
418                 if (rc != 0) {
419                         rc = 1;
420                         goto out;
421                 }
422                 if (verbose > 1)
423                         printf("key %#x inserted\n", i);
424         }
425
426         rc = 0;
427
428 out:
429         if (key) {
430                 free(key);
431         }
432         if (rec) {
433                 free(rec);
434         }
435         return rc;
436 }