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