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