Whamcloud - gitweb
LU-7243 misc: update Intel copyright messages 2015
[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 <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 <sys/xattr.h>
50 #include <signal.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <semaphore.h>
54 #include <time.h>
55 #include <err.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                                 void *tmp;
519                                 tmp = realloc(buf, len + ALIGN_LEN);
520                                 if (tmp == NULL) {
521                                         free(buf);
522                                         save_errno = errno;
523                                         perror("allocating buf for read\n");
524                                         exit(save_errno);
525                                 }
526                                 buf = tmp;
527                                 bufsize = len;
528                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
529                                                      ~ALIGN_LEN);
530                         }
531                         while (len > 0) {
532                                 rc = read(fd, buf_align, len);
533                                 if (rc == -1) {
534                                         save_errno = errno;
535                                         perror("read");
536                                         exit(save_errno);
537                                 }
538                                 if (rc < len) {
539                                         fprintf(stderr, "short read: %u/%u\n",
540                                                 rc, len);
541                                         if (rc == 0)
542                                                 exit(ENODATA);
543                                 }
544                                 len -= rc;
545                                 if (verbose >= 2)
546                                         printf("%.*s\n", rc, buf_align);
547                         }
548                         break;
549                 case 'R':
550                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
551                                 junk += mmap_ptr[i];
552                         break;
553                 case 's':
554                         if (stat(fname, &st) == -1) {
555                                 save_errno = errno;
556                                 perror("stat");
557                                 exit(save_errno);
558                         }
559                         break;
560                 case 'S':
561                         if (fstat(fd, &st) == -1) {
562                                 save_errno = errno;
563                                 perror("fstat");
564                                 exit(save_errno);
565                         }
566                         break;
567                 case 't':
568                         if (fchmod(fd, 0) == -1) {
569                                 save_errno = errno;
570                                 perror("fchmod");
571                                 exit(save_errno);
572                         }
573                         break;
574                 case 'T':
575                         len = atoi(commands+1);
576                         if (ftruncate(fd, len) == -1) {
577                                 save_errno = errno;
578                                 printf("ftruncate (%d,%d)\n", fd, len);
579                                 perror("ftruncate");
580                                 exit(save_errno);
581                         }
582                         break;
583                 case 'u':
584                         if (unlink(fname) == -1) {
585                                 save_errno = errno;
586                                 perror("unlink");
587                                 exit(save_errno);
588                         }
589                         break;
590                 case 'U':
591                         if (munmap(mmap_ptr, mmap_len)) {
592                                 save_errno = errno;
593                                 perror("munmap");
594                                 exit(save_errno);
595                         }
596                         break;
597                 case 'v':
598                         verbose++;
599                         break;
600                 case 'V':
601                         len = get_flags(commands + 1, &flags);
602                         commands += len;
603                         fd = llapi_create_volatile(fname, flags);
604                         if (fd < 0) {
605                                 perror("llapi_create_volatile");
606                                 exit(fd);
607                         }
608                         break;
609                 case 'w':
610                         len = atoi(commands+1);
611                         if (len <= 0)
612                                 len = 1;
613                         if (bufsize < len) {
614                                 void *tmp;
615                                 tmp = realloc(buf, len + ALIGN_LEN);
616                                 if (tmp == NULL) {
617                                         free(buf);
618                                         save_errno = errno;
619                                         perror("allocating buf for write\n");
620                                         exit(save_errno);
621                                 }
622                                 buf = tmp;
623                                 bufsize = len;
624                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
625                                                      ~ALIGN_LEN);
626                                 strncpy(buf_align, msg, bufsize);
627                         }
628                         while (len > 0) {
629                                 rc = write(fd, buf_align, len);
630                                 if (rc == -1) {
631                                         save_errno = errno;
632                                         perror("write");
633                                         exit(save_errno);
634                                 }
635                                 if (rc < len)
636                                         fprintf(stderr, "short write: %u/%u\n",
637                                                 rc, len);
638                                 len -= rc;
639                         }
640                         break;
641                 case 'W':
642                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
643                                 mmap_ptr[i] += junk++;
644                         break;
645                 case 'x':
646                         rc = llapi_get_data_version(fd, &dv, 0);
647                         if (rc) {
648                                 fprintf(stderr, "cannot get file data version"
649                                         " %d\n", rc);
650                                 exit(-rc);
651                         }
652                         printf("dataversion is "LPU64"\n", dv);
653                         break;
654                 case 'y':
655                         if (fsync(fd) == -1) {
656                                 save_errno = errno;
657                                 perror("fsync");
658                                 exit(save_errno);
659                         }
660                         break;
661                 case 'Y':
662                         if (fdatasync(fd) == -1) {
663                                 save_errno = errno;
664                                 perror("fdatasync");
665                                 exit(save_errno);
666                         }
667                         break;
668                 case 'z':
669                         len = atoi(commands+1);
670                         if (lseek(fd, len, SEEK_SET) == -1) {
671                                 save_errno = errno;
672                                 perror("lseek");
673                                 exit(save_errno);
674                         }
675                         break;
676                 case '-':
677                 case '0':
678                 case '1':
679                 case '2':
680                 case '3':
681                 case '4':
682                 case '5':
683                 case '6':
684                 case '7':
685                 case '8':
686                 case '9':
687                         break;
688                 default:
689                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
690                         fprintf(stderr, usage, argv[0]);
691                         exit(1);
692                 }
693         }
694
695         if (buf)
696                 free(buf);
697
698         return 0;
699 }