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