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