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