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