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