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