Whamcloud - gitweb
LU-5810 tests: add client hostname to lctl mark
[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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, 2015, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #ifndef _GNU_SOURCE
38 #define _GNU_SOURCE /* pull in O_DIRECTORY in bits/fcntl.h */
39 #endif
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <limits.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <sys/mman.h>
48 #include <sys/vfs.h>
49 #include <sys/ioctl.h>
50 #include <sys/xattr.h>
51 #include <signal.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <semaphore.h>
55 #include <time.h>
56 #include <err.h>
57
58 #include <lustre/lustre_idl.h>
59 #include <lustre/lustreapi.h>
60
61 #define T1 "write data before unlink\n"
62 #define T2 "write data after unlink\n"
63 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";
64 char *buf, *buf_align;
65 int bufsize = 0;
66 sem_t sem;
67 #define ALIGN_LEN 65535
68 #define XATTR "user.multiop"
69
70 char usage[] =
71 "Usage: %s filename command-sequence [path...]\n"
72 "    command-sequence items:\n"
73 "        A  fsetxattr(\"user.multiop\")\n"
74 "        a  fgetxattr(\"user.multiop\")\n"
75 "        c  close\n"
76 "        B[num] call setstripe ioctl to create stripes\n"
77 "        C[num] create with optional stripes\n"
78 "        d  mkdir\n"
79 "        D  open(O_DIRECTORY)\n"
80 "        e[R|W|U] apply lease. R: Read; W: Write; U: Unlock\n"
81 "        E[+|-] get lease. +/-: expect lease to (not) exist\n"
82 "        f  statfs\n"
83 "        F  print FID\n"
84 "        H[num] create HSM released file with num stripes\n"
85 "        G gid get grouplock\n"
86 "        g gid put grouplock\n"
87 "        K  link path to filename\n"
88 "        L  link\n"
89 "        l  symlink filename to path\n"
90 "        m  mknod\n"
91 "        M  rw mmap to EOF (must open and stat prior)\n"
92 "        n  rename path to filename\n"
93 "        N  rename filename to path\n"
94 "        o  open(O_RDONLY)\n"
95 "        O  open(O_CREAT|O_RDWR)\n"
96 "        r[num] read [optional length]\n"
97 "        R  reference entire mmap-ed region\n"
98 "        s  stat\n"
99 "        S  fstat\n"
100 "        t  fchmod\n"
101 "        T[num] ftruncate [optional position, default 0]\n"
102 "        u  unlink\n"
103 "        U  munmap\n"
104 "        v  verbose\n"
105 "        V  open a volatile file\n"
106 "        w[num] write optional length\n"
107 "        x  get file data version\n"
108 "        W  write entire mmap-ed region\n"
109 "        y  fsync\n"
110 "        Y  fdatasync\n"
111 "        z[num] seek [optional position, default 0]\n"
112 "        _  wait for signal\n";
113
114 void usr1_handler(int unused)
115 {
116         int saved_errno = errno;
117
118         /*
119          * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
120          * that the following functions can be safely called inside a signal
121          * handler:
122          *            sem_post()
123          */
124         sem_post(&sem);
125
126         errno = saved_errno;
127 }
128
129 static const char *
130 pop_arg(int argc, char *argv[])
131 {
132         static int cur_arg = 3;
133
134         if (cur_arg >= argc)
135                 return NULL;
136
137         return argv[cur_arg++];
138 }
139
140 struct flag_mapping {
141         const char *string;
142         const int  flag;
143 } flag_table[] = {
144         {"O_RDONLY", O_RDONLY},
145         {"O_WRONLY", O_WRONLY},
146         {"O_RDWR", O_RDWR},
147         {"O_CREAT", O_CREAT},
148         {"O_EXCL", O_EXCL},
149         {"O_NOCTTY", O_NOCTTY},
150         {"O_TRUNC", O_TRUNC},
151         {"O_APPEND", O_APPEND},
152         {"O_NONBLOCK", O_NONBLOCK},
153         {"O_NDELAY", O_NDELAY},
154         {"O_SYNC", O_SYNC},
155 #ifdef O_DIRECT
156         {"O_DIRECT", O_DIRECT},
157 #endif
158 #ifdef O_NOATIME
159         {"O_NOATIME", O_NOATIME},
160 #endif
161         {"O_LARGEFILE", O_LARGEFILE},
162         {"O_DIRECTORY", O_DIRECTORY},
163         {"O_NOFOLLOW", O_NOFOLLOW},
164         {"O_LOV_DELAY_CREATE", O_LOV_DELAY_CREATE},
165         {"", -1}
166 };
167
168 int get_flags(char *data, int *rflags)
169 {
170         char *cloned_flags;
171         char *tmp;
172         int flag_set = 0;
173         int flags = 0;
174         int size = 0;
175
176         cloned_flags = strdup(data);
177         if (cloned_flags == NULL) {
178                 fprintf(stderr, "Insufficient memory.\n");
179                 exit(-1);
180         }
181
182         for (tmp = strtok(cloned_flags, ":"); tmp;
183              tmp = strtok(NULL, ":")) {
184                 int i;
185
186                 size = tmp - cloned_flags;
187                 for (i = 0; flag_table[i].flag != -1; i++) {
188                         if (!strcmp(tmp, flag_table[i].string)){
189                                 flags |= flag_table[i].flag;
190                                 size += strlen(flag_table[i].string);
191                                 flag_set = 1;
192                                 break;
193                         }
194                 }
195         }
196         free(cloned_flags);
197
198         if (!flag_set) {
199                 *rflags = O_RDONLY;
200                 return 0;
201         }
202
203         *rflags = flags;
204         return size;
205 }
206
207 #define POP_ARG() (pop_arg(argc, argv))
208
209 int main(int argc, char **argv)
210 {
211         char                    *fname, *commands;
212         const char              *newfile;
213         const char              *oldpath;
214         struct stat              st;
215         struct statfs            stfs;
216         size_t                   mmap_len = 0, i;
217         unsigned char           *mmap_ptr = NULL, junk = 0;
218         int                      rc, len, fd = -1;
219         int                      flags;
220         int                      save_errno;
221         int                      verbose = 0;
222         int                      gid = 0;
223         lustre_fid               fid;
224         struct timespec          ts;
225         struct lov_user_md_v3    lum;
226         __u64                    dv;
227
228         if (argc < 3) {
229                 fprintf(stderr, usage, argv[0]);
230                 exit(1);
231         }
232
233         memset(&st, 0, sizeof(st));
234         sem_init(&sem, 0, 0);
235         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
236         sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
237                   NULL);
238
239         fname = argv[1];
240
241         for (commands = argv[2]; *commands; commands++) {
242                 switch (*commands) {
243                 case '_':
244                         if (verbose) {
245                                 printf("PAUSING\n");
246                                 fflush(stdout);
247                         }
248                         len = atoi(commands+1);
249                         if (len <= 0)
250                                 len = 3600; /* 1 hour */
251                         ts.tv_sec = time(NULL) + len;
252                         ts.tv_nsec = 0;
253                         while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR);
254                         break;
255                 case 'A':
256                         if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
257                                 save_errno = errno;
258                                 perror("fsetxattr");
259                                 exit(save_errno);
260                         }
261                         break;
262                 case 'a':
263                         if (fgetxattr(fd, XATTR, NULL, 0) == -1) {
264                                 save_errno = errno;
265                                 perror("fgetxattr");
266                                 exit(save_errno);
267                         }
268                         break;
269                 case 'c':
270                         if (close(fd) == -1) {
271                                 save_errno = errno;
272                                 perror("close");
273                                 exit(save_errno);
274                         }
275                         fd = -1;
276                         break;
277                 case 'B':
278                         lum = (struct lov_user_md_v3) {
279                                 .lmm_magic = LOV_USER_MAGIC_V3,
280                                 .lmm_stripe_count = atoi(commands + 1),
281                         };
282
283                         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
284                                 save_errno = errno;
285                                 perror("LL_IOC_LOV_SETSTRIPE");
286                                 exit(save_errno);
287                         }
288                         break;
289                 case 'C':
290                         len = atoi(commands+1);
291                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
292                                              0, 0, len, 0);
293                         if (fd == -1) {
294                                 save_errno = errno;
295                                 perror("create stripe file");
296                                 exit(save_errno);
297                         }
298                         break;
299                 case 'd':
300                         if (mkdir(fname, 0755) == -1) {
301                                 save_errno = errno;
302                                 perror("mkdir(0755)");
303                                 exit(save_errno);
304                         }
305                         break;
306                 case 'D':
307                         fd = open(fname, O_DIRECTORY);
308                         if (fd == -1) {
309                                 save_errno = errno;
310                                 perror("open(O_DIRECTORY)");
311                                 exit(save_errno);
312                         }
313                         break;
314                 case 'e':
315                         commands++;
316                         switch (*commands) {
317                         case 'U':
318                                 flags = LL_LEASE_UNLCK;
319                                 break;
320                         case 'R':
321                                 flags = LL_LEASE_RDLCK;
322                                 break;
323                         case 'W':
324                                 flags = LL_LEASE_WRLCK;
325                                 break;
326                         default:
327                                 errx(-1, "unknown mode: %c", *commands);
328                         }
329
330                         rc = ioctl(fd, LL_IOC_SET_LEASE, flags);
331                         if (rc < 0)
332                                 err(errno, "apply lease error");
333
334                         if (flags != LL_LEASE_UNLCK)
335                                 break;
336
337                         /* F_UNLCK, interpret return code */
338                         if (rc > 0) {
339                                 const char *str = "unknown";
340                                 if (rc == LL_LEASE_RDLCK)
341                                         str = "read";
342                                 else if (rc == LL_LEASE_WRLCK)
343                                         str = "write";
344                                 fprintf(stdout, "%s lease(%d) released.\n",
345                                         str, rc);
346                         } else if (rc == 0) {
347                                 fprintf(stdout, "lease already broken.\n");
348                         }
349                         break;
350                 case 'E':
351                         commands++;
352                         if (*commands != '-' && *commands != '+')
353                                 errx(-1, "unknown mode: %c\n", *commands);
354
355                         rc = ioctl(fd, LL_IOC_GET_LEASE);
356                         if (rc > 0) {
357                                 const char *str = "unknown";
358
359                                 if (rc == LL_LEASE_RDLCK)
360                                         str = "read";
361                                 else if (rc == LL_LEASE_WRLCK)
362                                         str = "write";
363                                 fprintf(stdout, "%s lease(%d) has applied.\n",
364                                         str, rc);
365                                 if (*commands == '-')
366                                         errx(-1, "expect lease to not exist");
367                         } else if (rc == 0) {
368                                 fprintf(stdout, "no lease applied.\n");
369                                 if (*commands == '+')
370                                         errx(-1, "expect lease exists");
371                         } else {
372                                 err(errno, "free lease error");
373                         }
374                         break;
375                 case 'f':
376                         if (statfs(fname, &stfs) == -1)
377                                 errx(-1, "statfs()");
378                         break;
379                 case 'F':
380                         if (fd == -1)
381                                 rc = llapi_path2fid(fname, &fid);
382                         else
383                                 rc = llapi_fd2fid(fd, &fid);
384                         if (rc != 0)
385                                 fprintf(stderr,
386                                         "llapi_path/fd2fid() on %d, rc=%d\n",
387                                         fd, rc);
388                         else
389                                 printf(DFID"\n", PFID(&fid));
390                         break;
391                 case 'G':
392                         gid = atoi(commands+1);
393                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
394                                 save_errno = errno;
395                                 perror("ioctl(GROUP_LOCK)");
396                                 exit(save_errno);
397                         }
398                         break;
399                 case 'g':
400                         gid = atoi(commands+1);
401                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
402                                 save_errno = errno;
403                                 perror("ioctl(GROUP_UNLOCK)");
404                                 exit(save_errno);
405                         }
406                         break;
407                 case 'H':
408                         len = atoi(commands+1);
409                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY,
410                                 0644, 0, 0, len,
411                                 LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED);
412                         if (fd == -1) {
413                                 save_errno = errno;
414                                 perror("create stripe file");
415                                 exit(save_errno);
416                         }
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 }