Whamcloud - gitweb
e46f4803aad23563deea4b6a38057cde46a165db
[fs/lustre-release.git] / lustre / liblustre / tests / sanity.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Lustre Light user test program
5  *
6  *  Copyright (c) 2002, 2003 Cluster File Systems, Inc.
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #define _BSD_SOURCE
25 #define _FILE_OFFSET_BITS 64
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <getopt.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <sys/queue.h>
36 #include <signal.h>
37 #include <errno.h>
38 #include <dirent.h>
39 #include <sys/uio.h>
40 #include <sys/time.h>
41 #include <time.h>
42 #include <sys/ioctl.h>
43
44 #include "test_common.h"
45 #include <ioctl.h>
46 #include <lustre/liblustreapi.h>
47
48 #ifndef PAGE_SIZE
49 #define PAGE_SIZE getpagesize()
50 #endif
51 #define _npages (2048)
52
53 void *buf_alloc;
54 int buf_size;
55 int opt_verbose;
56 struct timeval start;
57
58 extern char *lustre_path;
59
60 #define ENTRY(str)                                                      \
61         do {                                                            \
62                 char buf[100];                                          \
63                 int len;                                                \
64                 sprintf(buf, "===== START %s: %s ", __FUNCTION__, (str)); \
65                 len = strlen(buf);                                      \
66                 if (len < 79) {                                         \
67                         memset(buf+len, '=', 100-len);                  \
68                         buf[79] = '\n';                                 \
69                         buf[80] = 0;                                    \
70                 }                                                       \
71                 printf("%s", buf);                                      \
72                 gettimeofday(&start, NULL);                             \
73         } while (0)
74
75 #define LEAVE()                                                         \
76         do {                                                            \
77                 struct timeval stop;                                    \
78                 char buf[100] = { '\0' };                               \
79                 int len = sizeof(buf) - 1;                              \
80                 long usec;                                              \
81                 gettimeofday(&stop, NULL);                              \
82                 usec = (stop.tv_sec - start.tv_sec) * 1000000 +         \
83                        (stop.tv_usec - start.tv_usec);                  \
84                 len = snprintf(buf, len,                                \
85                                "===== END TEST %s: successfully (%gs)", \
86                                __FUNCTION__, (double)usec / 1000000);   \
87                 if (len < 79) {                                         \
88                         memset(buf+len, '=', sizeof(buf) - len);        \
89                         buf[79] = '\n';                                 \
90                         buf[80] = 0;                                    \
91                 }                                                       \
92                 printf("%s", buf);                                      \
93                 return 0;                                               \
94         } while (0)
95
96 #define MAX_PATH_LENGTH 4096
97
98 int t1(char *name)
99 {
100         char path[MAX_PATH_LENGTH] = "";
101
102         snprintf(path, MAX_PATH_LENGTH, "%s/test_t1", lustre_path);
103
104         if (opt_verbose)
105                 printf("touch+unlink %s\n", path);
106
107         t_touch(path);
108         t_unlink(path);
109         LEAVE();
110 }
111
112 int t2(char *name)
113 {
114         char path[MAX_PATH_LENGTH] = "";
115
116         ENTRY("mkdir/rmdir");
117         snprintf(path, MAX_PATH_LENGTH, "%s/test_t2", lustre_path);
118
119         t_mkdir(path);
120         t_rmdir(path);
121         LEAVE();
122 }
123
124 int t3(char *name)
125 {
126         char path[MAX_PATH_LENGTH] = "";
127
128         ENTRY("regular stat");
129         snprintf(path, MAX_PATH_LENGTH, "%s/test_t3", lustre_path);
130
131         t_touch(path);
132         t_check_stat(path, NULL);
133         t_unlink(path);
134         LEAVE();
135 }
136
137 int t4(char *name)
138 {
139         char path[MAX_PATH_LENGTH] = "";
140
141         ENTRY("dir stat");
142         snprintf(path, MAX_PATH_LENGTH, "%s/test_t4", lustre_path);
143
144         t_mkdir(path);
145         t_check_stat(path, NULL);
146         t_rmdir(path);
147         LEAVE();
148 }
149
150 int t6(char *name)
151 {
152         char path[MAX_PATH_LENGTH] = "";
153         char path2[MAX_PATH_LENGTH] = "";
154
155         ENTRY("symlink");
156         snprintf(path, MAX_PATH_LENGTH, "%s/test_t6", lustre_path);
157         snprintf(path2, MAX_PATH_LENGTH, "%s/test_t6_link", lustre_path);
158
159         t_touch(path);
160         t_symlink(path, path2);
161         t_check_stat(path2, NULL);
162         t_unlink(path2);
163         t_unlink(path);
164         LEAVE();
165 }
166
167 int t6b(char *name)
168 {
169         char path[MAX_PATH_LENGTH] = "";
170         char path2[MAX_PATH_LENGTH] = "";
171         char cwd[MAX_PATH_LENGTH] = "";
172         char *tmp;
173         int fd;
174
175         ENTRY("symlink + chdir and open");
176         snprintf(path, MAX_PATH_LENGTH, "%s/test_t6b", lustre_path);
177         snprintf(path2, MAX_PATH_LENGTH, "%s/test_t6b_link", lustre_path);
178
179         t_mkdir(path);
180         t_symlink(path, path2);
181         t_check_stat(path2, NULL);
182
183         tmp = getcwd(cwd, MAX_PATH_LENGTH);
184         if (tmp == NULL) {
185                 fprintf(stderr, "current path too long to fit in "
186                         "MAX_PATH_LENGTH?\n");
187                 LEAVE();
188         }
189         t_chdir(path2);
190         t_chdir(cwd);
191         t_rmdir(path);
192         t_touch(path);
193
194         fd = t_open(path2);
195         t_close(fd);
196
197         t_unlink(path2);
198         t_unlink(path);
199         LEAVE();
200 }
201
202 int t7(char *name)
203 {
204         char path[MAX_PATH_LENGTH] = "";
205         int rc;
206
207         ENTRY("mknod");
208         snprintf(path, MAX_PATH_LENGTH, "%s/test_t7", lustre_path);
209
210         if (geteuid() != 0) {
211                 rc = mknod(path, S_IFCHR | 0644, (5<<8 | 4));
212                 if (rc != -1 || errno != EPERM) {
213                         printf("mknod shouldn't success: rc %d, errno %d\n",
214                                 rc, errno);
215                 }
216         } else {
217                 t_mknod(path, S_IFCHR | 0644, 5, 4);
218                 t_check_stat(path, NULL);
219                 t_unlink(path);
220         }
221         LEAVE();
222 }
223
224 int t8(char *name)
225 {
226         char path[MAX_PATH_LENGTH] = "";
227
228         ENTRY("chmod");
229         snprintf(path, MAX_PATH_LENGTH, "%s/test_t8", lustre_path);
230
231         /* Check file. */
232         t_touch(path);
233         t_chmod_raw(path, 0700);
234         t_check_stat(path, NULL);
235         t_unlink(path);
236
237         /* Check dir. */
238         t_mkdir(path);
239         t_chmod_raw(path, 0700);
240         t_check_stat(path, NULL);
241         t_rmdir(path);
242
243         LEAVE();
244 }
245
246 int t9(char *name)
247 {
248         char path[MAX_PATH_LENGTH] = "";
249         char path2[MAX_PATH_LENGTH] = "";
250
251         ENTRY("hard link");
252         snprintf(path, MAX_PATH_LENGTH, "%s/test_t9", lustre_path);
253         snprintf(path2, MAX_PATH_LENGTH, "%s/test_t9_link", lustre_path);
254
255         t_touch(path);
256         t_link(path, path2);
257         t_check_stat(path, NULL);
258         t_check_stat(path2, NULL);
259         t_unlink(path);
260         t_unlink(path2);
261         LEAVE();
262 }
263
264 int t10(char *name)
265 {
266         char dir1[MAX_PATH_LENGTH] = "";
267         char dir2[MAX_PATH_LENGTH] = "";
268         char path1[MAX_PATH_LENGTH] = "";
269         char path2[MAX_PATH_LENGTH] = "";
270         char rename1[MAX_PATH_LENGTH] = "";
271         char rename2[MAX_PATH_LENGTH] = "";
272         char rename3[MAX_PATH_LENGTH] = "";
273
274         ENTRY("rename");
275         snprintf(dir1, MAX_PATH_LENGTH, "%s/test_t10_dir1", lustre_path);
276         snprintf(dir2, MAX_PATH_LENGTH, "%s/test_t10_dir2", lustre_path);
277         snprintf(path1, MAX_PATH_LENGTH, "%s/test_t10_reg1", lustre_path);
278         snprintf(path2, MAX_PATH_LENGTH, "%s/test_t10_reg2", lustre_path);
279         snprintf(rename1, MAX_PATH_LENGTH, "%s/test_t10_dir1/rename1", lustre_path);
280         snprintf(rename2, MAX_PATH_LENGTH, "%s/test_t10_dir2/rename2", lustre_path);
281         snprintf(rename3, MAX_PATH_LENGTH, "%s/test_t10_dir2/rename3", lustre_path);
282
283         t_mkdir(dir1);
284         t_mkdir(dir2);
285         t_touch(path1);
286         t_touch(path2);
287         t_rename(path1, rename1);
288         t_rename(path2, rename2);
289         t_rename(rename1, rename2);
290         t_rename(dir1, rename3);
291         t_unlink(rename2);
292         t_rmdir(rename3);
293         t_rmdir(dir2);
294         LEAVE();
295 }
296
297 int t11(char *name)
298 {
299         char *base=lustre_path;
300         char path[MAX_PATH_LENGTH], path2[MAX_PATH_LENGTH];
301         int i, j, level = 5, nreg = 5;
302         ENTRY("deep tree");
303
304         safe_strncpy(path, base, MAX_PATH_LENGTH);
305
306         for (i = 0; i < level; i++) {
307                 for (j = 0; j < nreg; j++) {
308                         sprintf(path2, "%s/file%d", path, j);
309                         t_touch(path2);
310                 }
311
312                 strcat(path, "/dir");
313                 t_mkdir(path);
314         }
315
316         for (i = level; i > 0; i--) {
317                 safe_strncpy(path, base, MAX_PATH_LENGTH);
318                 for (j = 1; j < i; j++)
319                         strcat(path, "/dir");
320
321                 for (j = 0; j < nreg; j++) {
322                         sprintf(path2, "%s/file%d", path, j);
323                         t_unlink(path2);
324                 }
325
326                 strcat(path, "/dir");
327                 t_rmdir(path);
328         }
329
330         LEAVE();
331 }
332
333 int t12(char *name)
334 {
335         char dir[MAX_PATH_LENGTH] = "";
336         char buf[1024*128];
337         int fd;
338         ENTRY("empty directory readdir");
339         snprintf(dir, MAX_PATH_LENGTH, "%s/test_t12_dir", lustre_path);
340
341         t_mkdir(dir);
342         fd = t_opendir(dir);
343         t_ls(fd, buf, sizeof(buf));
344         t_close(fd);
345         t_rmdir(dir);
346         LEAVE();
347 }
348
349 int t13(char *name)
350 {
351         char dir[MAX_PATH_LENGTH] = "";
352         char path[1024];
353         char buf[1024];
354         const int nfiles = 20;
355         char *prefix = "test13_filename_prefix_";
356         int fd, i;
357         ENTRY("multiple entries directory readdir");
358         snprintf(dir, MAX_PATH_LENGTH, "%s/test_t13_dir/", lustre_path);
359
360         t_mkdir(dir);
361         printf("Creating %d files...\n", nfiles);
362         for (i = 0; i < nfiles; i++) {
363                 sprintf(path, "%s%s%05d", dir, prefix, i);
364                 t_touch(path);
365         }
366         fd = t_opendir(dir);
367         t_ls(fd, buf, sizeof(buf));
368         t_close(fd);
369         printf("Cleanup...\n");
370         for (i = 0; i < nfiles; i++) {
371                 sprintf(path, "%s%s%05d", dir, prefix, i);
372                 t_unlink(path);
373         }
374         t_rmdir(dir);
375         LEAVE();
376 }
377
378 int t14(char *name)
379 {
380         char dir[MAX_PATH_LENGTH] = "";
381         char path[1024];
382         char buf[1024];
383         const int nfiles = 256;
384         char *prefix = "test14_filename_long_prefix_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA___";
385         struct dirent64 *ent;
386         int fd, i, rc, pos, index;
387         loff_t base = 0;
388         ENTRY(">1 block(4k) directory readdir");
389         snprintf(dir, MAX_PATH_LENGTH, "%s/test_t14_dir/", lustre_path);
390
391         rc = mkdir(dir, 0755);
392         if (rc < 0 && errno != EEXIST) {
393                 printf("mkdir(%s) error: %s\n", dir, strerror(errno));
394                 exit(1);
395         }
396         printf("Creating %d files...\n", nfiles);
397         for (i = 0; i < nfiles; i++) {
398                 sprintf(path, "%s%s%05d", dir, prefix, i);
399                 t_touch(path);
400         }
401         fd = t_opendir(dir);
402         printf("Listing...\n");
403         index = 0;
404         while ((rc = getdirentries64(fd, buf, 1024, &base)) > 0) {
405                 pos = 0;
406                 while (pos < rc) {
407                         char *item;
408
409                         ent = (struct dirent64 *) ((char*) buf + pos);
410                         item = (char *) ent->d_name;
411                         if (!strcmp(item, ".") || !strcmp(item, ".."))
412                                 goto iter;
413                         if (strstr(item, prefix) != item) {
414                                 printf("found bad name %s\n", item);
415                                 return(-1);
416                         }
417                         printf("[%03d]: %s\n",
418                                 index++, item + strlen(prefix));
419 iter:
420                         pos += ent->d_reclen;
421                 }
422         }
423         if (rc < 0) {
424                 printf("getdents error %d\n", rc);
425                 return(-1);
426         }
427         if (index != nfiles) {
428                 printf("get %d files != %d\n", index, nfiles);
429                 return(-1);
430         }
431         t_close(fd);
432         printf("Cleanup...\n");
433         for (i = 0; i < nfiles; i++) {
434                 sprintf(path, "%s%s%05d", dir, prefix, i);
435                 t_unlink(path);
436         }
437         t_rmdir(dir);
438         LEAVE();
439 }
440
441 int t15(char *name)
442 {
443         char file[MAX_PATH_LENGTH] = "";
444         int fd;
445         ENTRY("open-stat-close");
446         snprintf(file, MAX_PATH_LENGTH, "%s/test_t15_file", lustre_path);
447
448         t_touch(file);
449         fd = t_open(file);
450         t_check_stat(file, NULL);
451         t_close(fd);
452         t_unlink(file);
453         LEAVE();
454 }
455
456 int t16(char *name)
457 {
458         char file[MAX_PATH_LENGTH] = "";
459         ENTRY("small-write-read");
460         snprintf(file, MAX_PATH_LENGTH, "%s/test_t16_file", lustre_path);
461
462         t_echo_create(file, "aaaaaaaaaaaaaaaaaaaaaa");
463         t_grep(file, "aaaaaaaaaaaaaaaaaaaaaa");
464         t_unlink(file);
465         LEAVE();
466 }
467
468 int t17(char *name)
469 {
470         char file[MAX_PATH_LENGTH] = "";
471         int fd;
472         ENTRY("open-unlink without close");
473         snprintf(file, MAX_PATH_LENGTH, "%s/test_t17_file", lustre_path);
474
475         fd = open(file, O_WRONLY | O_CREAT, 0666);
476         if (fd < 0) {
477                 printf("failed to create file: %s\n", strerror(errno));
478                 return(-1);
479         }
480         t_unlink(file);
481         LEAVE();
482 }
483
484 int t18(char *name)
485 {
486         char file[MAX_PATH_LENGTH] = "";
487         char buf[128];
488         int fd, i;
489         struct stat statbuf[3];
490         ENTRY("write should change mtime/ctime");
491         snprintf(file, MAX_PATH_LENGTH, "%s/test_t18_file", lustre_path);
492
493         for (i = 0; i < 3; i++) {
494                 fd = open(file, O_RDWR|O_CREAT|O_APPEND, (mode_t)0666);
495                 if (fd < 0) {
496                         printf("error open file: %s\n", strerror(errno));
497                         return(-1);
498                 }
499                 if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
500                         printf("error write file\n");
501                         return(-1);
502                 }
503                 close(fd);
504                 if(stat(file, &statbuf[i]) != 0) {
505                         printf("Error stat\n");
506                         return(1);
507                 }
508                 printf("ctime %lu, mtime %lu\n",
509                         statbuf[i].st_ctime, statbuf[i].st_mtime);
510                 sleep(2);
511         }
512
513         for (i = 1; i < 3; i++) {
514                 if ((statbuf[i].st_ctime <= statbuf[i-1].st_ctime) ||
515                     (statbuf[i].st_mtime <= statbuf[i-1].st_mtime)) {
516                         printf("time error\n");
517                         return(-1);
518                 }
519         }
520         t_unlink(file);
521         LEAVE();
522 }
523
524 int t18b(char *name)
525 {
526         char file[MAX_PATH_LENGTH] = "";
527         int i;
528         struct stat statbuf[3];
529         ENTRY("utime should change mtime/atime/ctime");
530         snprintf(file, MAX_PATH_LENGTH, "%s/test_t18b_file", lustre_path);
531         t_touch(file);
532
533         for (i = 0; i < 3; i++) {
534                 t_utime(file, NULL);
535                 if(stat(file, &statbuf[i]) != 0) {
536                         printf("Error stat\n");
537                         return(1);
538                 }
539                 printf("atime %lu, mtime %lu, ctime %lu\n",
540                        statbuf[i].st_atime, statbuf[i].st_mtime,
541                        statbuf[i].st_ctime);
542                 sleep(2);
543         }
544
545         for (i = 1; i < 3; i++) {
546                 if ((statbuf[i].st_atime <= statbuf[i-1].st_atime) ||
547                     (statbuf[i].st_mtime <= statbuf[i-1].st_mtime) ||
548                     (statbuf[i].st_ctime <= statbuf[i-1].st_ctime)) {
549                         printf("time error\n");
550                         return(-1);
551                 }
552         }
553         t_unlink(file);
554         LEAVE();
555 }
556
557 static int check_file_size(char *file, off_t size)
558 {
559         struct stat statbuf;
560
561         if (stat(file, &statbuf) != 0) {
562                 printf("Error stat(%s)\n", file);
563                 return(1);
564         }
565         if (statbuf.st_size != size) {
566                 printf("size of %s: %ld != %lld\n", file, statbuf.st_size, size);
567                 return(-1);
568         }
569         return 0;
570 }
571
572 int t19(char *name)
573 {
574         char file[MAX_PATH_LENGTH] = "";
575         int fd;
576         int result;
577         ENTRY("open(O_TRUNC) should truncate file to 0-length");
578         snprintf(file, MAX_PATH_LENGTH, "%s/test_t19_file", lustre_path);
579
580         t_echo_create(file, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
581
582         fd = open(file, O_RDWR|O_CREAT|O_TRUNC, (mode_t)0666);
583         if (fd < 0) {
584                 printf("error open file: %s\n", strerror(errno));
585                 return(-1);
586         }
587         close(fd);
588         result = check_file_size(file, 0);
589         if (result != 0)
590                 return result;
591         t_unlink(file);
592         LEAVE();
593 }
594
595 int t20(char *name)
596 {
597         char file[MAX_PATH_LENGTH] = "";
598         int fd;
599         struct iovec iov[2];
600         char buf[100];
601         ssize_t ret;
602         ENTRY("trap app's general bad pointer for file i/o");
603         snprintf(file, MAX_PATH_LENGTH, "%s/test_t20_file", lustre_path);
604
605         fd = open(file, O_RDWR|O_CREAT, (mode_t)0666);
606         if (fd < 0) {
607                 printf("error open file: %s\n", strerror(errno));
608                 return(-1);
609         }
610
611         ret = write(fd, NULL, 20);
612         if (ret != -1 || errno != EFAULT) {
613                 printf("write 1: ret %ld, errno %d\n", ret, errno);
614                 return(1);
615         }
616         ret = write(fd, (void *)-1, 20);
617         if (ret != -1 || errno != EFAULT) {
618                 printf("write 2: ret %ld, errno %d\n", ret, errno);
619                 return(1);
620         }
621         iov[0].iov_base = NULL;
622         iov[0].iov_len = 10;
623         iov[1].iov_base = (void *)-1;
624         iov[1].iov_len = 10;
625         ret = writev(fd, iov, 2);
626         if (ret != -1 || errno != EFAULT) {
627                 printf("writev 1: ret %ld, errno %d\n", ret, errno);
628                 return(1);
629         }
630         iov[0].iov_base = NULL;
631         iov[0].iov_len = 0;
632         iov[1].iov_base = buf;
633         iov[1].iov_len = sizeof(buf);
634         ret = writev(fd, iov, 2);
635         if (ret != sizeof(buf)) {
636                 printf("write 3 ret %ld, error %d\n", ret, errno);
637                 return(1);
638         }
639         lseek(fd, 0, SEEK_SET);
640
641         ret = read(fd, NULL, 20);
642         if (ret != -1 || errno != EFAULT) {
643                 printf("read 1: ret %ld, errno %d\n", ret, errno);
644                 return(1);
645         }
646         ret = read(fd, (void *)-1, 20);
647         if (ret != -1 || errno != EFAULT) {
648                 printf("read 2: ret %ld, errno %d\n", ret, errno);
649                 return(1);
650         }
651         iov[0].iov_base = NULL;
652         iov[0].iov_len = 10;
653         iov[1].iov_base = (void *)-1;
654         iov[1].iov_len = 10;
655         ret = readv(fd, iov, 2);
656         if (ret != -1 || errno != EFAULT) {
657                 printf("readv 1: ret %ld, errno %d\n", ret, errno);
658                 return(1);
659         }
660         iov[0].iov_base = NULL;
661         iov[0].iov_len = 0;
662         iov[1].iov_base = buf;
663         iov[1].iov_len = sizeof(buf);
664         ret = readv(fd, iov, 2);
665         if (ret != sizeof(buf)) {
666                 printf("read 3 ret %ld, error %d\n", ret, errno);
667                 return(1);
668         }
669
670         close(fd);
671         t_unlink(file);
672         LEAVE();
673 }
674
675 int t21(char *name)
676 {
677         char file[MAX_PATH_LENGTH] = "";
678         int fd, ret;
679         struct flock lock = {
680                 .l_type = F_RDLCK,
681                 .l_whence = SEEK_SET,
682         };
683
684         ENTRY("basic fcntl support");
685         snprintf(file, MAX_PATH_LENGTH, "%s/test_t21_file", lustre_path);
686
687         fd = open(file, O_RDWR|O_CREAT, (mode_t)0666);
688         if (fd < 0) {
689                 printf("error open file: %s\n", file);
690                 return(-1);
691         }
692
693         t_fcntl(fd, F_SETFL, O_APPEND);
694         if (!(ret = t_fcntl(fd, F_GETFL)) & O_APPEND) {
695                 printf("error get flag: ret %x\n", ret);
696                 return(-1);
697         }
698
699         t_fcntl(fd, F_SETLK, &lock);
700         t_fcntl(fd, F_GETLK, &lock);
701         lock.l_type = F_WRLCK;
702         t_fcntl(fd, F_SETLKW, &lock);
703         t_fcntl(fd, F_GETLK, &lock);
704         lock.l_type = F_UNLCK;
705         t_fcntl(fd, F_SETLK, &lock);
706
707         close(fd);
708         t_unlink(file);
709         LEAVE();
710 }
711
712 int t22(char *name)
713 {
714         char file[MAX_PATH_LENGTH] = "";
715         int fd;
716         char *str = "1234567890";
717         char buf[100];
718         ssize_t ret;
719         ENTRY("make sure O_APPEND take effect");
720         snprintf(file, MAX_PATH_LENGTH, "%s/test_t22_file", lustre_path);
721
722         fd = open(file, O_RDWR|O_CREAT|O_APPEND, (mode_t)0666);
723         if (fd < 0) {
724                 printf("error open file: %s\n", strerror(errno));
725                 return(-1);
726         }
727
728         lseek(fd, 100, SEEK_SET);
729         ret = write(fd, str, strlen(str));
730         if (ret != strlen(str)) {
731                 printf("write 1: ret %ld, errno %d\n", ret, errno);
732                 return(1);
733         }
734
735         lseek(fd, 0, SEEK_SET);
736         ret = read(fd, buf, sizeof(buf));
737         if (ret != strlen(str)) {
738                 printf("read 1 got %ld\n", ret);
739                 return(1);
740         }
741
742         if (memcmp(buf, str, strlen(str))) {
743                 printf("read 1 data err\n");
744                 return(1);
745         }
746
747         if (fcntl(fd, F_SETFL, 0)) {
748                 printf("fcntl err: %s\n", strerror(errno));
749                 return(1);
750         }
751
752         lseek(fd, 100, SEEK_SET);
753         ret = write(fd, str, strlen(str));
754         if (ret != strlen(str)) {
755                 printf("write 2: ret %ld, errno %d\n", ret, errno);
756                 return(1);
757         }
758
759         lseek(fd, 100, SEEK_SET);
760         ret = read(fd, buf, sizeof(buf));
761         if (ret != strlen(str)) {
762                 printf("read 2 got %ld\n", ret);
763                 return(1);
764         }
765
766         if (memcmp(buf, str, strlen(str))) {
767                 printf("read 2 data err\n");
768                 return(1);
769         }
770
771         close(fd);
772         t_unlink(file);
773         LEAVE();
774 }
775
776 int t23(char *name)
777 {
778         char path[MAX_PATH_LENGTH];
779         int fd;
780         long long ret;
781         loff_t off;
782
783         ENTRY("handle seek > 2GB");
784         snprintf(path, MAX_PATH_LENGTH, "%s/f%s", lustre_path, name);
785
786         fd = open(path, O_WRONLY | O_CREAT | O_LARGEFILE, 0666);
787         if (fd < 0) {
788                 printf("failed to create file %s: %s\n", path, strerror(errno));
789                 return(-1);
790         }
791
792         off = 2048ULL * 1024 * 1024 - buf_size / 2;
793         ret = lseek(fd, off, SEEK_SET);
794         if (ret != off) {
795                 printf("seek error for initial %llu != %llu\n",
796                        ret, (long long)off);
797                 return -1;
798         }
799
800         ret = write(fd, buf_alloc, buf_size);
801         if (ret != buf_size) {
802                 printf("write error for %d != %llubytes @ %llu\n",
803                        buf_size, ret, (long long)off);
804                 if (ret == -1)
805                         perror("write");
806                 return -1;
807         }
808
809         ret = lseek(fd, off, SEEK_SET);
810         if (ret != off) {
811                 printf("seek < 2GB error for %llu != %llu\n",
812                        ret, (long long)off);
813                 if (ret == -1)
814                         perror("seek < 2GB");
815                 return -1;
816         }
817
818         ret = lseek(fd, off + buf_size - 2, SEEK_SET);
819         if (ret != off + buf_size - 2) {
820                 printf("seek > 2GB error for %llu != %llu\n",
821                        ret, (long long)off);
822                 if (ret == -1)
823                         perror("seek > 2GB");
824                 return -1;
825         }
826
827         ret = lseek(fd, -buf_size + 2, SEEK_CUR);
828         if (ret != off) {
829                 printf("relative seek error for %d %llu != %llu\n",
830                        -buf_size + 2, ret, off);
831                 if (ret == -1)
832                         perror("relative seek");
833                 return -1;
834         }
835
836         ret = lseek(fd, 0, SEEK_END);
837         if (ret != off + buf_size) {
838                 printf("end seek error for %llu != %llu\n",
839                        ret, (long long)off + buf_size);
840                 if (ret == -1)
841                         perror("end seek");
842                 return -1;
843         }
844
845         ret = lseek(fd, 0, SEEK_SET);
846         if (ret != 0) {
847                 printf("seek 0 error for %llu != 0\n", ret);
848                 if (ret == -1)
849                         perror("seek 0");
850                 return -1;
851         }
852
853         off = 2048ULL * 1024 * 1024, SEEK_SET;
854         ret = lseek(fd, off, SEEK_SET);
855         if (ret != off) {
856                 printf("seek 2GB error for %llu != %llu\n", ret, off);
857                 if (ret == -1)
858                         perror("seek 2GB");
859                 return -1;
860         }
861
862         close(fd);
863         t_unlink(path);
864         LEAVE();
865 }
866
867 /* pos:   i/o start from
868  * xfer:  npages per transfer
869  */
870 static int pages_io(int xfer, loff_t pos)
871 {
872         char path[MAX_PATH_LENGTH] = "";
873
874         int check_sum[_npages] = {0,}, *buf;
875         int fd, rc, i, j, data_error = 0;
876         struct timeval tw1, tw2, tr1, tr2;
877         double tw, tr;
878         loff_t ret;
879
880         snprintf(path, MAX_PATH_LENGTH, "%s/test_t50", lustre_path);
881
882         memset(buf_alloc, 0, buf_size);
883
884         /* create sample data */
885         for (i = 0, buf = buf_alloc; i < _npages; i++) {
886                 for (j = 0; j < PAGE_SIZE/sizeof(int); j++, buf++) {
887                         *buf = rand();
888                 }
889         }
890
891         /* compute checksum */
892         for (i = 0, buf = buf_alloc; i < _npages; i++) {
893                 for (j = 0; j < PAGE_SIZE/sizeof(int); j++, buf++) {
894                         check_sum[i] += *buf;
895                 }
896         }
897
898         unlink(path);
899         t_touch(path);
900
901         fd = t_open(path);
902
903         /* write */
904         ret = lseek(fd, pos, SEEK_SET);
905         if (ret != pos) {
906                 perror("write seek");
907                 return 1;
908         }
909         gettimeofday(&tw1, NULL);
910         for (i = 0, buf = buf_alloc; i < _npages;
911              i += xfer, buf += xfer * PAGE_SIZE / sizeof(int)) {
912                 rc = write(fd, buf, PAGE_SIZE * xfer);
913                 if (rc != PAGE_SIZE * xfer) {
914                         printf("write error (i %d, rc %d): %s\n", i, rc,
915                                strerror(errno));
916                         return(1);
917                 }
918         }
919         gettimeofday(&tw2, NULL);
920
921         memset(buf_alloc, 0, buf_size);
922
923         /* read */
924         ret = lseek(fd, pos, SEEK_SET);
925         if (ret != pos) {
926                 perror("read seek");
927                 return 1;
928         }
929         gettimeofday(&tr1, NULL);
930         for (i = 0, buf = buf_alloc; i < _npages;
931              i += xfer, buf += xfer * PAGE_SIZE / sizeof(int)) {
932                 rc = read(fd, buf, PAGE_SIZE * xfer);
933                 if (rc != PAGE_SIZE * xfer) {
934                         printf("read error (i %d, rc %d): %s\n", i, rc,
935                                strerror(errno));
936                         return(1);
937                 }
938         }
939         gettimeofday(&tr2, NULL);
940
941         /* compute checksum */
942         for (i = 0, buf = buf_alloc; i < _npages; i++) {
943                 int sum = 0;
944                 for (j = 0; j < PAGE_SIZE/sizeof(int); j++, buf++) {
945                         sum += *buf;
946                 }
947                 if (sum != check_sum[i]) {
948                         data_error = 1;
949                         printf("chunk %d checksum error expected %#x got %#x\n",
950                                 i, check_sum[i], sum);
951                 }
952         }
953
954         t_close(fd);
955         t_unlink(path);
956         tw = (tw2.tv_sec - tw1.tv_sec) * 1000000 + (tw2.tv_usec - tw1.tv_usec);
957         tr = (tr2.tv_sec - tr1.tv_sec) * 1000000 + (tr2.tv_usec - tr1.tv_usec);
958         printf(" (R:%.3fM/s, W:%.3fM/s)\n",
959                 (_npages * PAGE_SIZE) / (tw / 1000000.0) / (1024 * 1024),
960                 (_npages * PAGE_SIZE) / (tr / 1000000.0) / (1024 * 1024));
961
962         if (data_error)
963                 return 1;
964
965         return 0;
966 }
967
968 int t50(char *name)
969 {
970         int np = 1;
971         loff_t offset = 0;
972
973         ENTRY("4k aligned i/o sanity");
974         while (np <= _npages) {
975                 printf("%3d per xfer(total %d)...\t", np, _npages);
976                 fflush(stdout);
977                 if (pages_io(np, offset) != 0)
978                         return 1;
979                 np += np;
980         }
981         LEAVE();
982 }
983
984 int t50b(char *name)
985 {
986         loff_t off_array[] = {1, 17, 255, 258, 4095, 4097, 8191,
987                               1024*1024*1024*1024ULL};
988         int i;
989         loff_t offset;
990
991         ENTRY("4k un-aligned i/o sanity");
992         for (i = 0; i < sizeof(off_array)/sizeof(loff_t); i++) {
993                 offset = off_array[i];
994                 printf("16 per xfer(total %d), offset %10lld...\t",
995                         _npages, offset);
996                 if (pages_io(16, offset) != 0)
997                         return 1;
998         }
999
1000         LEAVE();
1001 }
1002
1003 enum {
1004         T51_STEP = 42,
1005         T51_NR   = 1000
1006 };
1007
1008 /*
1009  * truncate(2) checks.
1010  */
1011 int t51(char *name)
1012 {
1013         char file[MAX_PATH_LENGTH] = "";
1014         int fd;
1015         off_t size;
1016         int result;
1017
1018         ENTRY("truncate() should truncate file to proper length");
1019         snprintf(file, MAX_PATH_LENGTH, "%s/test_t51_file", lustre_path);
1020
1021         for (size = 0; size < T51_NR * T51_STEP; size += T51_STEP) {
1022                 t_echo_create(file, "");
1023                 if (truncate(file, size) != 0) {
1024                         printf("\nerror truncating file: %s\n",strerror(errno));
1025                         return(-1);
1026                 }
1027                 result = check_file_size(file, size);
1028                 if (result != 0)
1029                         return result;
1030                 t_unlink(file);
1031
1032                 t_echo_create(file, "");
1033                 fd = open(file, O_RDWR|O_CREAT, (mode_t)0666);
1034                 if (fd < 0) {
1035                         printf("\nerror open file: %s\n", strerror(errno));
1036                         return(-1);
1037                 }
1038                 if (ftruncate(fd, size) != 0) {
1039                         printf("\nerror ftruncating file:%s\n",strerror(errno));
1040                         return(-1);
1041                 }
1042                 close(fd);
1043                 result = check_file_size(file, size);
1044                 if (result != 0)
1045                         return result;
1046                 t_unlink(file);
1047                 if (size % (T51_STEP * (T51_NR / 75)) == 0) {
1048                         printf(".");
1049                         fflush(stdout);
1050                 }
1051         }
1052         printf("\n");
1053         LEAVE();
1054 }
1055 /*
1056  * check atime update during read
1057  */
1058 int t52(char *name)
1059 {
1060         char file[MAX_PATH_LENGTH] = "";
1061         char buf[16];
1062         struct stat statbuf;
1063         time_t atime;
1064         time_t diff;
1065         int fd, i;
1066
1067         ENTRY("atime should be updated during read");
1068         snprintf(file, MAX_PATH_LENGTH, "%s/test_t52_file", lustre_path);
1069
1070         t_echo_create(file, "check atime update during read");
1071         fd = open(file, O_RDONLY);
1072         if (fd < 0) {
1073                 printf("\nerror open file: %s\n", strerror(errno));
1074                 return(-1);
1075         }
1076         stat(file, &statbuf);
1077         printf("st_atime=%s", ctime(&statbuf.st_atime));
1078         atime = statbuf.st_atime;
1079         for (i = 0; i < 3; i++) {
1080                 sleep(2);
1081                 read(fd, buf, sizeof(buf));
1082                 stat(file, &statbuf);
1083                 printf("st_atime=%s", ctime(&statbuf.st_atime));
1084                 diff = statbuf.st_atime - atime;
1085                 if (diff <= 0) {
1086                         printf("atime doesn't updated! failed!\n");
1087                         close(fd);
1088                         t_unlink(file);
1089                         return -1;
1090                 }       
1091                 atime = statbuf.st_atime; 
1092         }
1093         close(fd);
1094         t_unlink(file);
1095         LEAVE();
1096 }
1097
1098 #define NEW_TIME        10000
1099 int t53(char *name)
1100 {
1101         char file[MAX_PATH_LENGTH] = "";
1102         struct utimbuf times;   /* struct. buffer for utime() */
1103         struct stat stat_buf;   /* struct buffer to hold file info. */
1104         time_t mtime, atime;
1105  
1106         ENTRY("mtime/atime should be updated by utime() call");
1107         snprintf(file, MAX_PATH_LENGTH, "%s/test_t53_file", lustre_path);
1108
1109         t_echo_create(file, "check mtime/atime update by utime() call");
1110  
1111         /* Initialize the modification and access time in the times arg */
1112         times.actime = NEW_TIME+10;
1113         times.modtime = NEW_TIME;
1114  
1115         /* file modification/access time */
1116         utime(file, &times);
1117  
1118         if (stat(file, &stat_buf) < 0) {
1119                 printf("stat(2) of %s failed, error:%d %s\n",
1120                         file, errno, strerror(errno)); 
1121         }
1122         mtime = stat_buf.st_mtime;
1123         atime = stat_buf.st_atime;
1124  
1125         if ((mtime == NEW_TIME) && (atime == NEW_TIME + 10)) {
1126                 t_unlink(file);
1127                 LEAVE();
1128         }
1129
1130         printf("mod time %ld, expected %ld\n", mtime, (long)NEW_TIME);
1131         printf("acc time %ld, expected %ld\n", atime, (long)NEW_TIME + 10);
1132  
1133         t_unlink(file);
1134         return (-1);
1135 }
1136
1137 int t54(char *name)
1138 {
1139         char file[MAX_PATH_LENGTH] = "";
1140         struct flock lock;
1141         int fd, err;
1142
1143         ENTRY("fcntl should return 0 when succeed in getting flock");
1144         snprintf(file, MAX_PATH_LENGTH, "%s/test_t54_file", lustre_path);
1145
1146         t_echo_create(file, "fcntl should return 0 when succeed");
1147
1148         fd = open(file, O_RDWR);
1149         if (fd < 0) {
1150                 printf("\nerror open file: %s\n", strerror(errno));
1151                 return(-1);
1152         }
1153         lock.l_type   = F_WRLCK;
1154         lock.l_start  = 0;
1155         lock.l_whence = 0;
1156         lock.l_len    = 1;
1157         if ((err = t_fcntl(fd, F_SETLKW, &lock)) != 0) {
1158                 fprintf(stderr, "fcntl returned: %d (%s)\n", 
1159                         err, strerror(err));
1160                 close(fd);
1161                 t_unlink(file);
1162                 return (-1);
1163         }
1164
1165         lock.l_type   = F_UNLCK;
1166         t_fcntl(fd, F_SETLKW, &lock);
1167         close(fd);
1168         t_unlink(file);
1169         LEAVE();
1170 }
1171
1172 /* for O_DIRECTORY */
1173 #define _GNU_SOURCE
1174
1175 #define STRIPE_SIZE       (2048 * 2048)
1176 #define STRIPE_OFFSET           0
1177 #define STRIPE_COUNT            1
1178 int t55(char *name)
1179 {
1180         char path[MAX_PATH_LENGTH] = "";
1181         char file[MAX_PATH_LENGTH] = "";
1182         struct lov_user_md *lum = NULL;
1183         struct lov_user_ost_data *lo = NULL;
1184         int index, fd, buflen, rc;
1185
1186         ENTRY("setstripe/getstripe");
1187         snprintf(path, MAX_PATH_LENGTH, "%s/test_t55", lustre_path);
1188         snprintf(file, MAX_PATH_LENGTH, "%s/test_t55/file_t55", lustre_path);
1189       
1190         buflen = sizeof(struct lov_user_md);
1191         buflen += STRIPE_COUNT * sizeof(struct lov_user_ost_data);
1192         lum = (struct lov_user_md *)malloc(buflen);
1193         if (!lum) {
1194                 printf("out of memory!\n");
1195                 return -1;
1196         }
1197         memset(lum, 0, buflen);
1198
1199         t_mkdir(path);
1200         rc = llapi_file_create(path, STRIPE_SIZE, STRIPE_OFFSET,
1201                                STRIPE_COUNT, LOV_PATTERN_RAID0);
1202         if (rc) {
1203                 printf("llapi_file_create failed: rc = %d (%s) \n",
1204                        rc, strerror(-rc));
1205                 t_rmdir(path);
1206                 free(lum);
1207                 return -1;
1208         }
1209
1210         fd = open(file, O_CREAT | O_RDWR, 0644);
1211         if (fd < 0) {
1212                 printf("open file(%s) failed: rc = %d (%s) \n)",
1213                        file, fd, strerror(errno));
1214                 t_rmdir(path);
1215                 free(lum);
1216                 return -1;
1217         }
1218         
1219         lum->lmm_magic = LOV_USER_MAGIC;
1220         lum->lmm_stripe_count = STRIPE_COUNT;
1221         rc = ioctl(fd, LL_IOC_LOV_GETSTRIPE, lum);
1222         if (rc) {
1223                 printf("dir:ioctl(LL_IOC_LOV_GETSTRIPE) failed: rc = %d(%s)\n",
1224                        rc, strerror(errno));
1225                 close(fd);
1226                 t_unlink(file);
1227                 t_rmdir(path);
1228                 free(lum);
1229                 return -1;
1230         }
1231
1232         close(fd);
1233
1234         if (opt_verbose) {
1235                 printf("lmm_magic:          0x%08X\n",  lum->lmm_magic);
1236                 printf("lmm_object_id:      "LPX64"\n", lum->lmm_object_id);
1237                 printf("lmm_object_gr:      "LPX64"\n", lum->lmm_object_gr);
1238                 printf("lmm_stripe_count:   %u\n", (int)lum->lmm_stripe_count);
1239                 printf("lmm_stripe_size:    %u\n",      lum->lmm_stripe_size);
1240                 printf("lmm_stripe_pattern: %x\n",      lum->lmm_pattern);
1241         
1242                 for (index = 0; index < lum->lmm_stripe_count; index++) {
1243                         lo = lum->lmm_objects + index;
1244                         printf("object %d:\n", index);
1245                         printf("\tobject_gr:    "LPX64"\n", lo->l_object_gr);
1246                         printf("\tobject_id:    "LPX64"\n", lo->l_object_id);
1247                         printf("\tost_gen:      %#x\n", lo->l_ost_gen);
1248                         printf("\tost_idx:      %u\n", lo->l_ost_idx);
1249                 }
1250         }
1251
1252         if (lum->lmm_magic != LOV_USER_MAGIC ||
1253             lum->lmm_pattern != LOV_PATTERN_RAID0 ||
1254             lum->lmm_stripe_size != STRIPE_SIZE ||
1255             lum->lmm_objects[0].l_ost_idx != STRIPE_OFFSET ||
1256             lum->lmm_stripe_count != STRIPE_COUNT) {
1257                 printf("incorrect striping information!\n");
1258                 t_unlink(file);
1259                 t_rmdir(path);
1260                 free(lum);
1261                 return -1;
1262         }
1263         t_unlink(file);
1264
1265         /* setstripe on regular file */
1266         rc = llapi_file_create(file, STRIPE_SIZE, STRIPE_OFFSET,
1267                                STRIPE_COUNT, LOV_PATTERN_RAID0);
1268         if (rc) {
1269                 printf("llapi_file_create failed: rc = %d (%s) \n",
1270                        rc, strerror(-rc));
1271                 t_unlink(file);
1272                 t_rmdir(path);
1273                 free(lum);
1274                 return -1;
1275         }
1276         fd = open(file, O_RDWR, 0644);
1277         if (fd < 0) {
1278                 printf("failed to open(%s): rc = %d (%s)\n", 
1279                        file, fd, strerror(errno));
1280                 t_unlink(file);
1281                 t_rmdir(path);
1282                 free(lum);
1283                 return -1;
1284         }
1285
1286         lum->lmm_magic = LOV_USER_MAGIC;
1287         lum->lmm_stripe_count = STRIPE_COUNT;
1288         rc = ioctl(fd, LL_IOC_LOV_GETSTRIPE, lum);
1289         if (rc) {
1290                 printf("file:ioctl(LL_IOC_LOV_GETSTRIPE) failed: rc = %d(%s)\n",
1291                        rc, strerror(errno));
1292                 close(fd);
1293                 t_unlink(file);
1294                 t_rmdir(path);
1295                 free(lum);
1296                 return -1;
1297         }
1298         close(fd);
1299
1300         if (opt_verbose) {
1301                 printf("lmm_magic:          0x%08X\n",  lum->lmm_magic);
1302                 printf("lmm_object_id:      "LPX64"\n", lum->lmm_object_id);
1303                 printf("lmm_object_gr:      "LPX64"\n", lum->lmm_object_gr);
1304                 printf("lmm_stripe_count:   %u\n", (int)lum->lmm_stripe_count);
1305                 printf("lmm_stripe_size:    %u\n",      lum->lmm_stripe_size);
1306                 printf("lmm_stripe_pattern: %x\n",      lum->lmm_pattern);
1307         
1308                 for (index = 0; index < lum->lmm_stripe_count; index++) {
1309                         lo = lum->lmm_objects + index;
1310                         printf("object %d:\n", index);
1311                         printf("\tobject_gr:    "LPX64"\n", lo->l_object_gr);
1312                         printf("\tobject_id:    "LPX64"\n", lo->l_object_id);
1313                         printf("\tost_gen:      %#x\n", lo->l_ost_gen);
1314                         printf("\tost_idx:      %u\n", lo->l_ost_idx);
1315                 }
1316         }
1317
1318         if (lum->lmm_magic != LOV_USER_MAGIC ||
1319             lum->lmm_pattern != LOV_PATTERN_RAID0 ||
1320             lum->lmm_stripe_size != STRIPE_SIZE ||
1321             lum->lmm_objects[0].l_ost_idx != STRIPE_OFFSET ||
1322             lum->lmm_stripe_count != STRIPE_COUNT) {
1323                 printf("incorrect striping information!\n");
1324                 t_unlink(file);
1325                 t_rmdir(path);
1326                 free(lum);
1327                 return -1;
1328         }
1329
1330         t_unlink(file);
1331         t_rmdir(path);
1332         free(lum);
1333         LEAVE();
1334 }
1335
1336 /*
1337  * getdirentries should return -1 and set errno to EINVAL when the size
1338  * specified as an argument is too small to contain at least one entry
1339  * (see bugzilla ticket 12229)
1340  */
1341 int t56(char *name)
1342 {
1343         int fd;
1344         size_t nbytes;
1345         off_t basep = 0;
1346         ssize_t rc = 0;
1347         struct dirent dir;
1348
1349         ENTRY("getdirentries should fail if nbytes is too small");
1350
1351         /* Set count to be very small.  The result should be EINVAL */
1352         nbytes = 8;
1353
1354         /* open the directory and call getdirentries */
1355         fd = t_opendir(lustre_path);
1356
1357         rc = getdirentries(fd, (char *)&dir, nbytes, &basep);
1358
1359         if (rc != -1) {
1360                 printf("Test failed: getdirentries returned %d\n", rc);
1361                 t_close(fd);
1362                 return -1;
1363         }
1364         if (errno != EINVAL) {
1365                 printf("Test failed: getdirentries returned %d but errno is set"
1366                                 " to %d (should be EINVAL)\n", rc, errno);
1367                 t_close(fd);
1368                 return -1;
1369         }
1370         t_close(fd);
1371
1372         LEAVE();
1373 }
1374
1375
1376 extern void __liblustre_setup_(void);
1377 extern void __liblustre_cleanup_(void);
1378
1379
1380 void usage(char *cmd)
1381 {
1382         printf("\n"
1383                "usage: %s [--only {test}] --target mgsnid:/fsname\n",
1384                cmd);
1385         printf("       %s --dumpfile dumpfile\n", cmd);
1386         exit(-1);
1387 }
1388
1389 struct testlist {
1390         int (*test)(char *name);
1391         char *name;
1392 } testlist[] = {
1393         { t1, "1" },
1394         { t2, "2" },
1395         { t3, "3" },
1396         { t4, "4" },
1397         { t6, "6" },
1398         { t6b, "6b" },
1399         { t7, "7" },
1400         { t8, "8" },
1401         { t9, "9" },
1402         { t10, "10" },
1403         { t11, "11" },
1404         { t12, "12" },
1405         { t13, "13" },
1406         { t14, "14" },
1407         { t15, "15" },
1408         { t16, "16" },
1409         { t17, "17" },
1410         { t18, "18" },
1411         { t18b, "t8b" },
1412         { t19, "19" },
1413         { t20, "20" },
1414         { t21, "21" },
1415         { t22, "22" },
1416         { t23, "23" },
1417         { t50, "50" },
1418         { t50b, "50b" },
1419         { t51, "51" },
1420         { t53, "53" },
1421         { t54, "54" },
1422         { t55, "55" },
1423         { t56, "56" },
1424         { NULL, NULL }
1425 };
1426
1427 int main(int argc, char * const argv[])
1428 {
1429         struct testlist *test;
1430         int opt_index, c, rc = 0, numonly = 0;
1431         char *only[100];
1432         static struct option long_opts[] = {
1433                 {"dumpfile", 1, 0, 'd'},
1434                 {"only", 1, 0, 'o'},
1435                 {"target", 1, 0, 't'},
1436                 {"verbose", 1, 0, 'v'},
1437                 {0, 0, 0, 0}
1438         };
1439
1440         while ((c = getopt_long(argc, argv, "d:o:t:v", long_opts, &opt_index)) != -1) {
1441                 switch (c) {
1442                 case 'd':
1443                         setenv(ENV_LUSTRE_DUMPFILE, optarg, 1);
1444                         break;
1445                 case 'o':
1446                         if (numonly == 0)
1447                                 printf("Only running test(s): ");
1448                         printf("%s ", optarg);
1449                         only[numonly++] = optarg;
1450                         break;
1451                 case 't':
1452                         setenv(ENV_LUSTRE_MNTTGT, optarg, 1);
1453                         break;
1454                 case 'v':
1455                         opt_verbose++;
1456                         break;
1457                 default:
1458                         usage(argv[0]);
1459                         break;
1460                 }
1461         }
1462
1463         if (getenv(ENV_LUSTRE_MNTTGT) == NULL &&
1464             getenv(ENV_LUSTRE_DUMPFILE) == NULL)
1465                 usage(argv[0]);
1466
1467         if (optind != argc)
1468                 usage(argv[0]);
1469
1470         printf("\n");
1471
1472         __liblustre_setup_();
1473
1474         buf_size = _npages * PAGE_SIZE;
1475         if (opt_verbose)
1476                 printf("allocating %d bytes buffer\n", buf_size);
1477         buf_alloc = calloc(1, buf_size);
1478         if (buf_alloc == NULL) {
1479                 fprintf(stderr, "error allocating %d\n", buf_size);
1480                 exit(-ENOMEM);
1481         }
1482
1483         for (test = testlist; test->test != NULL; test++) {
1484                 int run = 1, i;
1485
1486                 if (numonly > 0) {
1487                         int len;
1488
1489                         run = 0;
1490                         len = strlen(test->name);
1491                         for (i = 0; i < numonly; i++) {
1492                                 int olen = strlen(only[i]);
1493
1494                                 if (len < olen)
1495                                         continue;
1496
1497                                 if (strncmp(only[i], test->name, olen) == 0) {
1498                                         switch(test->name[olen]) {
1499                                         case '0': case '1': case '2': case '3':
1500                                         case '4': case '5': case '6': case '7':
1501                                         case '8': case '9':
1502                                                 break;
1503                                         default:
1504                                                 run = 1;
1505                                                 break;
1506                                         }
1507                                 }
1508                         }
1509                 }
1510                 if (run && (rc = (test->test)(test->name)) != 0)
1511                         break;
1512         }
1513
1514         free(buf_alloc);
1515
1516         printf("liblustre is about to shutdown\n");
1517         __liblustre_cleanup_();
1518
1519         printf("complete successfully\n");
1520         return rc;
1521 }