Whamcloud - gitweb
LU-8995 tests: set debug size correctly
[fs/lustre-release.git] / lustre / tests / multiop.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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2015, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32
33 #ifndef _GNU_SOURCE
34 #define _GNU_SOURCE /* pull in O_DIRECTORY in bits/fcntl.h */
35 #endif
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <limits.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 #include <sys/vfs.h>
45 #include <sys/ioctl.h>
46 #include <sys/xattr.h>
47 #include <sys/file.h>
48 #include <signal.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <semaphore.h>
52 #include <time.h>
53 #include <err.h>
54
55 #include <lustre/lustreapi.h>
56
57 #define T1 "write data before unlink\n"
58 #define T2 "write data after unlink\n"
59 char msg[] = "yabba dabba doo, I'm coming for you, I live in a shoe, I don't know what to do.\n'Bigger, bigger,and bigger yet!' cried the Creator.  'You are not yet substantial enough for my boundless intents!'  And ever greater and greater the object became, until all was lost 'neath its momentus bulk.\n";
60 char *buf, *buf_align;
61 int bufsize = 0;
62 sem_t sem;
63 #define ALIGN_LEN 65535
64 #define XATTR "user.multiop"
65
66 char usage[] =
67 "Usage: %s filename command-sequence [path...]\n"
68 "    command-sequence items:\n"
69 "        A  fsetxattr(\"user.multiop\")\n"
70 "        a  fgetxattr(\"user.multiop\")\n"
71 "        c  close\n"
72 "        B[num] call setstripe ioctl to create stripes\n"
73 "        C[num] create with optional stripes\n"
74 "        d  mkdir\n"
75 "        D  open(O_DIRECTORY)\n"
76 "        e[R|W|U] apply lease. R: Read; W: Write; U: Unlock\n"
77 "        E[+|-] get lease. +/-: expect lease to (not) exist\n"
78 "        f  statfs\n"
79 "        F  print FID\n"
80 "        H[num] create HSM released file with num stripes\n"
81 "        G gid get grouplock\n"
82 "        g gid put grouplock\n"
83 "        K  link path to filename\n"
84 "        L  link\n"
85 "        l  symlink filename to path\n"
86 "        m  mknod\n"
87 "        M  rw mmap to EOF (must open and stat prior)\n"
88 "        n  rename path to filename\n"
89 "        N  rename filename to path\n"
90 "        o  open(O_RDONLY)\n"
91 "        O  open(O_CREAT|O_RDWR)\n"
92 "        r[num] read [optional length]\n"
93 "        R  reference entire mmap-ed region\n"
94 "        s  stat\n"
95 "        S  fstat\n"
96 "        t  fchmod\n"
97 "        T[num] ftruncate [optional position, default 0]\n"
98 "        u  unlink\n"
99 "        U  munmap\n"
100 "        v  verbose\n"
101 "        V  open a volatile file\n"
102 "        w[num] write optional length\n"
103 "        x  get file data version\n"
104 "        W  write entire mmap-ed region\n"
105 "        y  fsync\n"
106 "        Y  fdatasync\n"
107 "        z[num] seek [optional position, default 0]\n"
108 "        _  wait for signal\n";
109
110 void usr1_handler(int unused)
111 {
112         int saved_errno = errno;
113
114         /*
115          * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
116          * that the following functions can be safely called inside a signal
117          * handler:
118          *            sem_post()
119          */
120         sem_post(&sem);
121
122         errno = saved_errno;
123 }
124
125 static const char *
126 pop_arg(int argc, char *argv[])
127 {
128         static int cur_arg = 3;
129
130         if (cur_arg >= argc)
131                 return NULL;
132
133         return argv[cur_arg++];
134 }
135
136 struct flag_mapping {
137         const char *string;
138         const int  flag;
139 } flag_table[] = {
140         {"O_RDONLY", O_RDONLY},
141         {"O_WRONLY", O_WRONLY},
142         {"O_RDWR", O_RDWR},
143         {"O_CREAT", O_CREAT},
144         {"O_EXCL", O_EXCL},
145         {"O_NOCTTY", O_NOCTTY},
146         {"O_TRUNC", O_TRUNC},
147         {"O_APPEND", O_APPEND},
148         {"O_NONBLOCK", O_NONBLOCK},
149         {"O_NDELAY", O_NDELAY},
150         {"O_SYNC", O_SYNC},
151 #ifdef O_DIRECT
152         {"O_DIRECT", O_DIRECT},
153 #endif
154 #ifdef O_NOATIME
155         {"O_NOATIME", O_NOATIME},
156 #endif
157         {"O_LARGEFILE", O_LARGEFILE},
158         {"O_DIRECTORY", O_DIRECTORY},
159         {"O_NOFOLLOW", O_NOFOLLOW},
160         {"O_LOV_DELAY_CREATE", O_LOV_DELAY_CREATE},
161         {"", -1}
162 };
163
164 int get_flags(char *data, int *rflags)
165 {
166         char *cloned_flags;
167         char *tmp;
168         int flag_set = 0;
169         int flags = 0;
170         int size = 0;
171
172         cloned_flags = strdup(data);
173         if (cloned_flags == NULL) {
174                 fprintf(stderr, "Insufficient memory.\n");
175                 exit(-1);
176         }
177
178         for (tmp = strtok(cloned_flags, ":"); tmp;
179              tmp = strtok(NULL, ":")) {
180                 int i;
181
182                 size = tmp - cloned_flags;
183                 for (i = 0; flag_table[i].flag != -1; i++) {
184                         if (!strcmp(tmp, flag_table[i].string)){
185                                 flags |= flag_table[i].flag;
186                                 size += strlen(flag_table[i].string);
187                                 flag_set = 1;
188                                 break;
189                         }
190                 }
191         }
192         free(cloned_flags);
193
194         if (!flag_set) {
195                 *rflags = O_RDONLY;
196                 return 0;
197         }
198
199         *rflags = flags;
200         return size;
201 }
202
203 #define POP_ARG() (pop_arg(argc, argv))
204
205 int main(int argc, char **argv)
206 {
207         char                    *fname, *commands;
208         const char              *newfile;
209         const char              *oldpath;
210         struct stat              st;
211         struct statfs            stfs;
212         size_t                   mmap_len = 0, i;
213         unsigned char           *mmap_ptr = NULL, junk = 0;
214         int                      rc, len, fd = -1;
215         int                      flags;
216         int                      save_errno;
217         int                      verbose = 0;
218         int                      gid = 0;
219         lustre_fid               fid;
220         struct timespec          ts;
221         struct lov_user_md_v3    lum;
222         __u64                    dv;
223
224         if (argc < 3) {
225                 fprintf(stderr, usage, argv[0]);
226                 exit(1);
227         }
228
229         memset(&st, 0, sizeof(st));
230         sem_init(&sem, 0, 0);
231         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
232         sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
233                   NULL);
234
235         fname = argv[1];
236
237         for (commands = argv[2]; *commands; commands++) {
238                 switch (*commands) {
239                 case '_':
240                         if (verbose) {
241                                 printf("PAUSING\n");
242                                 fflush(stdout);
243                         }
244                         len = atoi(commands+1);
245                         if (len <= 0)
246                                 len = 3600; /* 1 hour */
247                         ts.tv_sec = time(NULL) + len;
248                         ts.tv_nsec = 0;
249                         while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR);
250                         break;
251                 case 'A':
252                         if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
253                                 save_errno = errno;
254                                 perror("fsetxattr");
255                                 exit(save_errno);
256                         }
257                         break;
258                 case 'a':
259                         if (fgetxattr(fd, XATTR, NULL, 0) == -1) {
260                                 save_errno = errno;
261                                 perror("fgetxattr");
262                                 exit(save_errno);
263                         }
264                         break;
265                 case 'c':
266                         if (close(fd) == -1) {
267                                 save_errno = errno;
268                                 perror("close");
269                                 exit(save_errno);
270                         }
271                         fd = -1;
272                         break;
273                 case 'B':
274                         lum = (struct lov_user_md_v3) {
275                                 .lmm_magic = LOV_USER_MAGIC_V3,
276                                 .lmm_stripe_count = atoi(commands + 1),
277                         };
278
279                         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
280                                 save_errno = errno;
281                                 perror("LL_IOC_LOV_SETSTRIPE");
282                                 exit(save_errno);
283                         }
284                         break;
285                 case 'C':
286                         len = atoi(commands+1);
287                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
288                                              0, 0, len, 0);
289                         if (fd == -1) {
290                                 save_errno = errno;
291                                 perror("create stripe file");
292                                 exit(save_errno);
293                         }
294                         break;
295                 case 'd':
296                         if (mkdir(fname, 0755) == -1) {
297                                 save_errno = errno;
298                                 perror("mkdir(0755)");
299                                 exit(save_errno);
300                         }
301                         break;
302                 case 'D':
303                         fd = open(fname, O_DIRECTORY);
304                         if (fd == -1) {
305                                 save_errno = errno;
306                                 perror("open(O_DIRECTORY)");
307                                 exit(save_errno);
308                         }
309                         break;
310                 case 'e':
311                         commands++;
312                         switch (*commands) {
313                         case 'U':
314                                 flags = LL_LEASE_UNLCK;
315                                 break;
316                         case 'R':
317                                 flags = LL_LEASE_RDLCK;
318                                 break;
319                         case 'W':
320                                 flags = LL_LEASE_WRLCK;
321                                 break;
322                         default:
323                                 errx(-1, "unknown mode: %c", *commands);
324                         }
325
326                         rc = ioctl(fd, LL_IOC_SET_LEASE, flags);
327                         if (rc < 0)
328                                 err(errno, "apply lease error");
329
330                         if (flags != LL_LEASE_UNLCK)
331                                 break;
332
333                         /* F_UNLCK, interpret return code */
334                         if (rc > 0) {
335                                 const char *str = "unknown";
336                                 if (rc == LL_LEASE_RDLCK)
337                                         str = "read";
338                                 else if (rc == LL_LEASE_WRLCK)
339                                         str = "write";
340                                 fprintf(stdout, "%s lease(%d) released.\n",
341                                         str, rc);
342                         } else if (rc == 0) {
343                                 fprintf(stdout, "lease already broken.\n");
344                         }
345                         break;
346                 case 'E':
347                         commands++;
348                         if (*commands != '-' && *commands != '+')
349                                 errx(-1, "unknown mode: %c\n", *commands);
350
351                         rc = ioctl(fd, LL_IOC_GET_LEASE);
352                         if (rc > 0) {
353                                 const char *str = "unknown";
354
355                                 if (rc == LL_LEASE_RDLCK)
356                                         str = "read";
357                                 else if (rc == LL_LEASE_WRLCK)
358                                         str = "write";
359                                 fprintf(stdout, "%s lease(%d) has applied.\n",
360                                         str, rc);
361                                 if (*commands == '-')
362                                         errx(-1, "expect lease to not exist");
363                         } else if (rc == 0) {
364                                 fprintf(stdout, "no lease applied.\n");
365                                 if (*commands == '+')
366                                         errx(-1, "expect lease exists");
367                         } else {
368                                 err(errno, "free lease error");
369                         }
370                         break;
371                 case 'f':
372                         if (statfs(fname, &stfs) == -1)
373                                 errx(-1, "statfs()");
374                         break;
375                 case 'F':
376                         if (fd == -1)
377                                 rc = llapi_path2fid(fname, &fid);
378                         else
379                                 rc = llapi_fd2fid(fd, &fid);
380                         if (rc != 0)
381                                 fprintf(stderr,
382                                         "llapi_path/fd2fid() on %d, rc=%d\n",
383                                         fd, rc);
384                         else
385                                 printf(DFID"\n", PFID(&fid));
386                         break;
387                 case 'G':
388                         gid = atoi(commands+1);
389                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
390                                 save_errno = errno;
391                                 perror("ioctl(GROUP_LOCK)");
392                                 exit(save_errno);
393                         }
394                         break;
395                 case 'g':
396                         gid = atoi(commands+1);
397                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
398                                 save_errno = errno;
399                                 perror("ioctl(GROUP_UNLOCK)");
400                                 exit(save_errno);
401                         }
402                         break;
403                 case 'H':
404                         len = atoi(commands+1);
405                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY,
406                                 0644, 0, 0, len,
407                                 LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED);
408                         if (fd == -1) {
409                                 save_errno = errno;
410                                 perror("create stripe file");
411                                 exit(save_errno);
412                         }
413                         break;
414                 case 'j':
415                         if (flock(fd, LOCK_EX) == -1)
416                                 errx(-1, "flock()");
417                         break;
418                 case 'K':
419                         oldpath = POP_ARG();
420                         if (oldpath == NULL)
421                                 oldpath = fname;
422
423                         if (link(oldpath, fname)) {
424                                 save_errno = errno;
425                                 perror("link()");
426                                 exit(save_errno);
427                         }
428                         break;
429                 case 'l':
430                         newfile = POP_ARG();
431                         if (!newfile)
432                                 newfile = fname;
433                         if (symlink(fname, newfile)) {
434                                 save_errno = errno;
435                                 perror("symlink()");
436                                 exit(save_errno);
437                         }
438                         break;
439                 case 'L':
440                         newfile = POP_ARG();
441                         if (newfile == NULL)
442                                 newfile = fname;
443
444                         if (link(fname, newfile)) {
445                                 save_errno = errno;
446                                 perror("link()");
447                                 exit(save_errno);
448                         }
449                         break;
450                 case 'm':
451                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
452                                 save_errno = errno;
453                                 perror("mknod(S_IFREG|0644, 0)");
454                                 exit(save_errno);
455                         }
456                         break;
457                 case 'M':
458                         if (st.st_size == 0) {
459                                 fprintf(stderr, "mmap without preceeding stat, or on"
460                                         " zero length file.\n");
461                                 exit(-1);
462                         }
463                         mmap_len = st.st_size;
464                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
465                                         MAP_SHARED, fd, 0);
466                         if (mmap_ptr == MAP_FAILED) {
467                                 save_errno = errno;
468                                 perror("mmap");
469                                 exit(save_errno);
470                         }
471                         break;
472                 case 'n':
473                         oldpath = POP_ARG();
474                         if (oldpath == NULL)
475                                 oldpath = fname;
476
477                         if (rename(oldpath, fname) < 0) {
478                                 save_errno = errno;
479                                 perror("rename()");
480                                 exit(save_errno);
481                         }
482                         break;
483                 case 'N':
484                         newfile = POP_ARG();
485                         if (!newfile)
486                                 newfile = fname;
487                         if (rename (fname, newfile)) {
488                                 save_errno = errno;
489                                 perror("rename()");
490                                 exit(save_errno);
491                         }
492                         break;
493                 case 'O':
494                         fd = open(fname, O_CREAT|O_RDWR, 0644);
495                         if (fd == -1) {
496                                 save_errno = errno;
497                                 perror("open(O_RDWR|O_CREAT)");
498                                 exit(save_errno);
499                         }
500                         break;
501                 case 'o':
502                         len = get_flags(commands+1, &flags);
503                         commands += len;
504                         if (flags & O_CREAT)
505                                 fd = open(fname, flags, 0666);
506                         else
507                                 fd = open(fname, flags);
508                         if (fd == -1) {
509                                 save_errno = errno;
510                                 perror("open");
511                                 exit(save_errno);
512                         }
513                         break;
514                 case 'r':
515                         len = atoi(commands+1);
516                         if (len <= 0)
517                                 len = 1;
518                         if (bufsize < len) {
519                                 void *tmp;
520                                 tmp = realloc(buf, len + ALIGN_LEN);
521                                 if (tmp == NULL) {
522                                         free(buf);
523                                         save_errno = errno;
524                                         perror("allocating buf for read\n");
525                                         exit(save_errno);
526                                 }
527                                 buf = tmp;
528                                 bufsize = len;
529                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
530                                                      ~ALIGN_LEN);
531                         }
532                         while (len > 0) {
533                                 rc = read(fd, buf_align, len);
534                                 if (rc == -1) {
535                                         save_errno = errno;
536                                         perror("read");
537                                         exit(save_errno);
538                                 }
539                                 if (rc < len) {
540                                         fprintf(stderr, "short read: %u/%u\n",
541                                                 rc, len);
542                                         if (rc == 0)
543                                                 exit(ENODATA);
544                                 }
545                                 len -= rc;
546                                 if (verbose >= 2)
547                                         printf("%.*s\n", rc, buf_align);
548                         }
549                         break;
550                 case 'R':
551                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
552                                 junk += mmap_ptr[i];
553                         break;
554                 case 's':
555                         if (stat(fname, &st) == -1) {
556                                 save_errno = errno;
557                                 perror("stat");
558                                 exit(save_errno);
559                         }
560                         break;
561                 case 'S':
562                         if (fstat(fd, &st) == -1) {
563                                 save_errno = errno;
564                                 perror("fstat");
565                                 exit(save_errno);
566                         }
567                         break;
568                 case 't':
569                         if (fchmod(fd, 0) == -1) {
570                                 save_errno = errno;
571                                 perror("fchmod");
572                                 exit(save_errno);
573                         }
574                         break;
575                 case 'T':
576                         len = atoi(commands+1);
577                         if (ftruncate(fd, len) == -1) {
578                                 save_errno = errno;
579                                 printf("ftruncate (%d,%d)\n", fd, len);
580                                 perror("ftruncate");
581                                 exit(save_errno);
582                         }
583                         break;
584                 case 'u':
585                         if (unlink(fname) == -1) {
586                                 save_errno = errno;
587                                 perror("unlink");
588                                 exit(save_errno);
589                         }
590                         break;
591                 case 'U':
592                         if (munmap(mmap_ptr, mmap_len)) {
593                                 save_errno = errno;
594                                 perror("munmap");
595                                 exit(save_errno);
596                         }
597                         break;
598                 case 'v':
599                         verbose++;
600                         break;
601                 case 'V':
602                         len = get_flags(commands + 1, &flags);
603                         commands += len;
604                         fd = llapi_create_volatile(fname, flags);
605                         if (fd < 0) {
606                                 perror("llapi_create_volatile");
607                                 exit(fd);
608                         }
609                         break;
610                 case 'w':
611                         len = atoi(commands+1);
612                         if (len <= 0)
613                                 len = 1;
614                         if (bufsize < len) {
615                                 void *tmp;
616                                 tmp = realloc(buf, len + ALIGN_LEN);
617                                 if (tmp == NULL) {
618                                         free(buf);
619                                         save_errno = errno;
620                                         perror("allocating buf for write\n");
621                                         exit(save_errno);
622                                 }
623                                 buf = tmp;
624                                 bufsize = len;
625                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
626                                                      ~ALIGN_LEN);
627                                 strncpy(buf_align, msg, bufsize);
628                         }
629                         while (len > 0) {
630                                 rc = write(fd, buf_align, len);
631                                 if (rc == -1) {
632                                         save_errno = errno;
633                                         perror("write");
634                                         exit(save_errno);
635                                 }
636                                 if (rc < len)
637                                         fprintf(stderr, "short write: %u/%u\n",
638                                                 rc, len);
639                                 len -= rc;
640                         }
641                         break;
642                 case 'W':
643                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
644                                 mmap_ptr[i] += junk++;
645                         break;
646                 case 'x':
647                         rc = llapi_get_data_version(fd, &dv, 0);
648                         if (rc) {
649                                 fprintf(stderr, "cannot get file data version"
650                                         " %d\n", rc);
651                                 exit(-rc);
652                         }
653                         printf("dataversion is %ju\n", (uintmax_t)dv);
654                         break;
655                 case 'y':
656                         if (fsync(fd) == -1) {
657                                 save_errno = errno;
658                                 perror("fsync");
659                                 exit(save_errno);
660                         }
661                         break;
662                 case 'Y':
663                         if (fdatasync(fd) == -1) {
664                                 save_errno = errno;
665                                 perror("fdatasync");
666                                 exit(save_errno);
667                         }
668                         break;
669                 case 'z':
670                         len = atoi(commands+1);
671                         if (lseek(fd, len, SEEK_SET) == -1) {
672                                 save_errno = errno;
673                                 perror("lseek");
674                                 exit(save_errno);
675                         }
676                         break;
677                 case '-':
678                 case '0':
679                 case '1':
680                 case '2':
681                 case '3':
682                 case '4':
683                 case '5':
684                 case '6':
685                 case '7':
686                 case '8':
687                 case '9':
688                         break;
689                 default:
690                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
691                         fprintf(stderr, usage, argv[0]);
692                         exit(1);
693                 }
694         }
695
696         if (buf)
697                 free(buf);
698
699         return 0;
700 }