Whamcloud - gitweb
LU-11069 llite: correct file position after appending writes
[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 "        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         lustre_fid               fid;
222         struct timespec          ts;
223         struct lov_user_md_v3    lum;
224         __u64                    dv;
225         long long rc = 0;
226         long long last_rc;
227
228         if (argc < 3) {
229                 fprintf(stderr, usage, argv[0]);
230                 exit(1);
231         }
232
233         memset(&st, 0, sizeof(st));
234         sem_init(&sem, 0, 0);
235         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
236         sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
237                   NULL);
238
239         fname = argv[1];
240
241         for (commands = argv[2]; *commands; commands++) {
242                 /* XXX Most commands return 0 or we exit so we only
243                  * update rc where really needed. */
244                 last_rc = rc;
245                 rc = 0;
246
247                 switch (*commands) {
248                 case '_':
249                         if (verbose) {
250                                 printf("PAUSING\n");
251                                 fflush(stdout);
252                         }
253                         len = atoi(commands+1);
254                         if (len <= 0)
255                                 len = 3600; /* 1 hour */
256                         ts.tv_sec = time(NULL) + len;
257                         ts.tv_nsec = 0;
258                         while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR);
259                         break;
260                 case 'A':
261                         if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
262                                 save_errno = errno;
263                                 perror("fsetxattr");
264                                 exit(save_errno);
265                         }
266                         break;
267                 case 'a':
268                         rc = fgetxattr(fd, XATTR, NULL, 0);
269                         if (rc < 0) {
270                                 save_errno = errno;
271                                 perror("fgetxattr");
272                                 exit(save_errno);
273                         }
274                         break;
275                 case 'c':
276                         if (close(fd) == -1) {
277                                 save_errno = errno;
278                                 perror("close");
279                                 exit(save_errno);
280                         }
281                         fd = -1;
282                         break;
283                 case 'B':
284                         lum = (struct lov_user_md_v3) {
285                                 .lmm_magic = LOV_USER_MAGIC_V3,
286                                 .lmm_stripe_count = atoi(commands + 1),
287                         };
288
289                         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
290                                 save_errno = errno;
291                                 perror("LL_IOC_LOV_SETSTRIPE");
292                                 exit(save_errno);
293                         }
294                         break;
295                 case 'C':
296                         len = atoi(commands+1);
297                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
298                                              0, 0, len, 0);
299                         if (fd == -1) {
300                                 save_errno = errno;
301                                 perror("create stripe file");
302                                 exit(save_errno);
303                         }
304                         rc = fd;
305                         break;
306                 case 'd':
307                         if (mkdir(fname, 0755) == -1) {
308                                 save_errno = errno;
309                                 perror("mkdir(0755)");
310                                 exit(save_errno);
311                         }
312                         break;
313                 case 'D':
314                         fd = open(fname, O_DIRECTORY);
315                         if (fd == -1) {
316                                 save_errno = errno;
317                                 perror("open(O_DIRECTORY)");
318                                 exit(save_errno);
319                         }
320                         rc = fd;
321                         break;
322                 case 'e':
323                         commands++;
324                         switch (*commands) {
325                         case 'U':
326                                 flags = LL_LEASE_UNLCK;
327                                 break;
328                         case 'R':
329                                 flags = LL_LEASE_RDLCK;
330                                 break;
331                         case 'W':
332                                 flags = LL_LEASE_WRLCK;
333                                 break;
334                         default:
335                                 errx(-1, "unknown mode: %c", *commands);
336                         }
337
338                         rc = ioctl(fd, LL_IOC_SET_LEASE, flags);
339                         if (rc < 0)
340                                 err(errno, "apply lease error");
341
342                         if (flags != LL_LEASE_UNLCK)
343                                 break;
344
345                         /* F_UNLCK, interpret return code */
346                         if (rc > 0) {
347                                 const char *str = "unknown";
348                                 if (rc == LL_LEASE_RDLCK)
349                                         str = "read";
350                                 else if (rc == LL_LEASE_WRLCK)
351                                         str = "write";
352                                 fprintf(stdout, "%s lease(%lld) released.\n",
353                                         str, rc);
354                         } else if (rc == 0) {
355                                 fprintf(stdout, "lease already broken.\n");
356                         }
357                         break;
358                 case 'E':
359                         commands++;
360                         if (*commands != '-' && *commands != '+')
361                                 errx(-1, "unknown mode: %c\n", *commands);
362
363                         rc = ioctl(fd, LL_IOC_GET_LEASE);
364                         if (rc > 0) {
365                                 const char *str = "unknown";
366
367                                 if (rc == LL_LEASE_RDLCK)
368                                         str = "read";
369                                 else if (rc == LL_LEASE_WRLCK)
370                                         str = "write";
371                                 fprintf(stdout, "%s lease(%lld) has applied.\n",
372                                         str, rc);
373                                 if (*commands == '-')
374                                         errx(-1, "expect lease to not exist");
375                         } else if (rc == 0) {
376                                 fprintf(stdout, "no lease applied.\n");
377                                 if (*commands == '+')
378                                         errx(-1, "expect lease exists");
379                         } else {
380                                 err(errno, "free lease error");
381                         }
382                         break;
383                 case 'f':
384                         if (statfs(fname, &stfs) == -1)
385                                 errx(-1, "statfs()");
386                         break;
387                 case 'F':
388                         if (fd == -1)
389                                 rc = llapi_path2fid(fname, &fid);
390                         else
391                                 rc = llapi_fd2fid(fd, &fid);
392                         if (rc != 0)
393                                 fprintf(stderr,
394                                         "llapi_path/fd2fid() on %d, rc=%lld\n",
395                                         fd, rc);
396                         else
397                                 printf(DFID"\n", PFID(&fid));
398                         break;
399                 case 'G':
400                         gid = atoi(commands+1);
401                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
402                                 save_errno = errno;
403                                 perror("ioctl(GROUP_LOCK)");
404                                 exit(save_errno);
405                         }
406                         break;
407                 case 'g':
408                         gid = atoi(commands+1);
409                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
410                                 save_errno = errno;
411                                 perror("ioctl(GROUP_UNLOCK)");
412                                 exit(save_errno);
413                         }
414                         break;
415                 case 'H':
416                         len = atoi(commands+1);
417                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY,
418                                 0644, 0, 0, len,
419                                 LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED);
420                         if (fd == -1) {
421                                 save_errno = errno;
422                                 perror("create stripe file");
423                                 exit(save_errno);
424                         }
425                         rc = fd;
426                         break;
427                 case 'j':
428                         if (flock(fd, LOCK_EX) == -1)
429                                 errx(-1, "flock()");
430                         break;
431                 case 'K':
432                         oldpath = POP_ARG();
433                         if (oldpath == NULL)
434                                 oldpath = fname;
435
436                         if (link(oldpath, fname)) {
437                                 save_errno = errno;
438                                 perror("link()");
439                                 exit(save_errno);
440                         }
441                         break;
442                 case 'l':
443                         newfile = POP_ARG();
444                         if (!newfile)
445                                 newfile = fname;
446                         if (symlink(fname, newfile)) {
447                                 save_errno = errno;
448                                 perror("symlink()");
449                                 exit(save_errno);
450                         }
451                         break;
452                 case 'L':
453                         newfile = POP_ARG();
454                         if (newfile == NULL)
455                                 newfile = fname;
456
457                         if (link(fname, newfile)) {
458                                 save_errno = errno;
459                                 perror("link()");
460                                 exit(save_errno);
461                         }
462                         break;
463                 case 'm':
464                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
465                                 save_errno = errno;
466                                 perror("mknod(S_IFREG|0644, 0)");
467                                 exit(save_errno);
468                         }
469                         break;
470                 case 'M':
471                         if (st.st_size == 0) {
472                                 fprintf(stderr, "mmap without preceeding stat, or on"
473                                         " zero length file.\n");
474                                 exit(-1);
475                         }
476                         mmap_len = st.st_size;
477                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
478                                         MAP_SHARED, fd, 0);
479                         if (mmap_ptr == MAP_FAILED) {
480                                 save_errno = errno;
481                                 perror("mmap");
482                                 exit(save_errno);
483                         }
484                         break;
485                 case 'n':
486                         oldpath = POP_ARG();
487                         if (oldpath == NULL)
488                                 oldpath = fname;
489
490                         if (rename(oldpath, fname) < 0) {
491                                 save_errno = errno;
492                                 perror("rename()");
493                                 exit(save_errno);
494                         }
495                         break;
496                 case 'N':
497                         newfile = POP_ARG();
498                         if (!newfile)
499                                 newfile = fname;
500                         if (rename (fname, newfile)) {
501                                 save_errno = errno;
502                                 perror("rename()");
503                                 exit(save_errno);
504                         }
505                         break;
506                 case 'O':
507                         fd = open(fname, O_CREAT|O_RDWR, 0644);
508                         if (fd == -1) {
509                                 save_errno = errno;
510                                 perror("open(O_RDWR|O_CREAT)");
511                                 exit(save_errno);
512                         }
513                         rc = fd;
514                         break;
515                 case 'o':
516                         len = get_flags(commands+1, &flags);
517                         commands += len;
518                         if (flags & O_CREAT)
519                                 fd = open(fname, flags, 0666);
520                         else
521                                 fd = open(fname, flags);
522                         if (fd == -1) {
523                                 save_errno = errno;
524                                 perror("open");
525                                 exit(save_errno);
526                         }
527                         rc = fd;
528                         break;
529                 case 'p':
530                         printf("%lld\n", last_rc);
531                         break;
532                 case 'r':
533                         len = atoi(commands+1);
534                         if (len <= 0)
535                                 len = 1;
536                         if (bufsize < len) {
537                                 void *tmp;
538                                 tmp = realloc(buf, len + ALIGN_LEN);
539                                 if (tmp == NULL) {
540                                         free(buf);
541                                         save_errno = errno;
542                                         perror("allocating buf for read\n");
543                                         exit(save_errno);
544                                 }
545                                 buf = tmp;
546                                 bufsize = len;
547                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
548                                                      ~ALIGN_LEN);
549                         }
550                         while (len > 0) {
551                                 rc = read(fd, buf_align, len);
552                                 if (rc == -1) {
553                                         save_errno = errno;
554                                         perror("read");
555                                         exit(save_errno);
556                                 }
557                                 if (rc < len) {
558                                         fprintf(stderr, "short read: %lld/%u\n",
559                                                 rc, len);
560                                         if (rc == 0)
561                                                 exit(ENODATA);
562                                 }
563                                 len -= rc;
564                                 if (verbose >= 2)
565                                         printf("%.*s\n", (int)rc, buf_align);
566                         }
567                         break;
568                 case 'R':
569                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
570                                 junk += mmap_ptr[i];
571                         break;
572                 case 's':
573                         if (stat(fname, &st) == -1) {
574                                 save_errno = errno;
575                                 perror("stat");
576                                 exit(save_errno);
577                         }
578                         break;
579                 case 'S':
580                         if (fstat(fd, &st) == -1) {
581                                 save_errno = errno;
582                                 perror("fstat");
583                                 exit(save_errno);
584                         }
585                         break;
586                 case 't':
587                         if (fchmod(fd, 0) == -1) {
588                                 save_errno = errno;
589                                 perror("fchmod");
590                                 exit(save_errno);
591                         }
592                         break;
593                 case 'T':
594                         len = atoi(commands+1);
595                         if (ftruncate(fd, len) == -1) {
596                                 save_errno = errno;
597                                 printf("ftruncate (%d,%d)\n", fd, len);
598                                 perror("ftruncate");
599                                 exit(save_errno);
600                         }
601                         break;
602                 case 'u':
603                         if (unlink(fname) == -1) {
604                                 save_errno = errno;
605                                 perror("unlink");
606                                 exit(save_errno);
607                         }
608                         break;
609                 case 'U':
610                         if (munmap(mmap_ptr, mmap_len)) {
611                                 save_errno = errno;
612                                 perror("munmap");
613                                 exit(save_errno);
614                         }
615                         break;
616                 case 'v':
617                         verbose++;
618                         break;
619                 case 'V':
620                         len = get_flags(commands + 1, &flags);
621                         commands += len;
622                         fd = llapi_create_volatile(fname, flags);
623                         if (fd < 0) {
624                                 perror("llapi_create_volatile");
625                                 exit(fd);
626                         }
627                         rc = fd;
628                         break;
629                 case 'w':
630                         len = atoi(commands+1);
631                         if (len <= 0)
632                                 len = 1;
633                         if (bufsize < len) {
634                                 void *tmp;
635                                 tmp = realloc(buf, len + ALIGN_LEN);
636                                 if (tmp == NULL) {
637                                         free(buf);
638                                         save_errno = errno;
639                                         perror("allocating buf for write\n");
640                                         exit(save_errno);
641                                 }
642                                 buf = tmp;
643                                 bufsize = len;
644                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
645                                                      ~ALIGN_LEN);
646                                 strncpy(buf_align, msg, bufsize);
647                         }
648                         while (len > 0) {
649                                 rc = write(fd, buf_align, len);
650                                 if (rc == -1) {
651                                         save_errno = errno;
652                                         perror("write");
653                                         exit(save_errno);
654                                 }
655                                 if (rc < len)
656                                         fprintf(stderr, "short write: %lld/%u\n",
657                                                 rc, len);
658                                 len -= rc;
659                         }
660                         break;
661                 case 'W':
662                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
663                                 mmap_ptr[i] += junk++;
664                         break;
665                 case 'x':
666                         rc = llapi_get_data_version(fd, &dv, 0);
667                         if (rc) {
668                                 fprintf(stderr, "cannot get file data version"
669                                         " %lld\n", rc);
670                                 exit(-rc);
671                         }
672                         printf("dataversion is %ju\n", (uintmax_t)dv);
673                         break;
674                 case 'y':
675                         if (fsync(fd) == -1) {
676                                 save_errno = errno;
677                                 perror("fsync");
678                                 exit(save_errno);
679                         }
680                         break;
681                 case 'Y':
682                         if (fdatasync(fd) == -1) {
683                                 save_errno = errno;
684                                 perror("fdatasync");
685                                 exit(save_errno);
686                         }
687                         break;
688                 case 'z': {
689                         off_t off;
690
691                         len = atoi(commands + 1);
692                         off = lseek(fd, len, SEEK_SET);
693                         if (off == (off_t)-1) {
694                                 save_errno = errno;
695                                 perror("lseek");
696                                 exit(save_errno);
697                         }
698
699                         rc = off;
700                         break;
701                 }
702                 case 'Z': {
703                         off_t off;
704
705                         len = atoi(commands + 1);
706                         off = lseek(fd, len, SEEK_CUR);
707                         if (off == (off_t)-1) {
708                                 save_errno = errno;
709                                 perror("lseek");
710                                 exit(save_errno);
711                         }
712
713                         rc = off;
714                         break;
715                 }
716                 case '-':
717                 case '0':
718                 case '1':
719                 case '2':
720                 case '3':
721                 case '4':
722                 case '5':
723                 case '6':
724                 case '7':
725                 case '8':
726                 case '9':
727                         break;
728                 default:
729                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
730                         fprintf(stderr, usage, argv[0]);
731                         exit(1);
732                 }
733         }
734
735         if (buf)
736                 free(buf);
737
738         return 0;
739 }