Whamcloud - gitweb
LU-10657 utils: fd leak in mirror_split()
[fs/lustre-release.git] / lustre / tests / multiop.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32
33 #ifndef _GNU_SOURCE
34 #define _GNU_SOURCE /* pull in O_DIRECTORY in bits/fcntl.h */
35 #endif
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <limits.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 #include <sys/vfs.h>
45 #include <sys/ioctl.h>
46 #include <sys/xattr.h>
47 #include <sys/file.h>
48 #include <signal.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <semaphore.h>
52 #include <time.h>
53 #include <err.h>
54
55 #include <lustre/lustreapi.h>
56
57 #define T1 "write data before unlink\n"
58 #define T2 "write data after unlink\n"
59 char msg[] = "yabba dabba doo, I'm coming for you, I live in a shoe, I don't know what to do.\n'Bigger, bigger,and bigger yet!' cried the Creator.  'You are not yet substantial enough for my boundless intents!'  And ever greater and greater the object became, until all was lost 'neath its momentus bulk.\n";
60 char *buf, *buf_align;
61 int bufsize = 0;
62 sem_t sem;
63 #define ALIGN_LEN 65535
64 #define XATTR "user.multiop"
65
66 char usage[] =
67 "Usage: %s filename command-sequence [path...]\n"
68 "    command-sequence items:\n"
69 "        A  fsetxattr(\"user.multiop\")\n"
70 "        a  fgetxattr(\"user.multiop\")\n"
71 "        c  close\n"
72 "        B[num] call setstripe ioctl to create stripes\n"
73 "        C[num] create with optional stripes\n"
74 "        d  mkdir\n"
75 "        D  open(O_DIRECTORY)\n"
76 "        e[R|W|U] apply lease. R: Read; W: Write; U: Unlock\n"
77 "        E[+|-] get lease. +/-: expect lease to (not) exist\n"
78 "        f  statfs\n"
79 "        F  print FID\n"
80 "        H[num] create HSM released file with num stripes\n"
81 "        G gid get grouplock\n"
82 "        g gid put grouplock\n"
83 "        K  link path to filename\n"
84 "        L  link\n"
85 "        l  symlink filename to path\n"
86 "        m  mknod\n"
87 "        M  rw mmap to EOF (must open and stat prior)\n"
88 "        n  rename path to filename\n"
89 "        N  rename filename to path\n"
90 "        o  open(O_RDONLY)\n"
91 "        O  open(O_CREAT|O_RDWR)\n"
92 "        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         struct lu_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                                 rc = llapi_lease_release(fd);
314                                 break;
315                         case 'R':
316                                 rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
317                                 break;
318                         case 'W':
319                                 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
320                                 break;
321                         default:
322                                 errx(-1, "unknown mode: %c", *commands);
323                         }
324                         if (rc < 0)
325                                 err(errno, "apply/unlock lease error");
326
327                         if (flags != LL_LEASE_UNLCK)
328                                 break;
329
330                         /* F_UNLCK, interpret return code */
331                         if (rc > 0) {
332                                 const char *str = "unknown";
333                                 if (rc == LL_LEASE_RDLCK)
334                                         str = "read";
335                                 else if (rc == LL_LEASE_WRLCK)
336                                         str = "write";
337                                 fprintf(stdout, "%s lease(%d) released.\n",
338                                         str, rc);
339                         } else if (rc == 0) {
340                                 fprintf(stdout, "lease already broken.\n");
341                         }
342                         break;
343                 case 'E':
344                         commands++;
345                         if (*commands != '-' && *commands != '+')
346                                 errx(-1, "unknown mode: %c\n", *commands);
347
348                         rc = llapi_lease_check(fd);
349                         if (rc > 0) {
350                                 const char *str = "unknown";
351
352                                 if (rc == LL_LEASE_RDLCK)
353                                         str = "read";
354                                 else if (rc == LL_LEASE_WRLCK)
355                                         str = "write";
356                                 fprintf(stdout, "%s lease(%d) has applied.\n",
357                                         str, rc);
358                                 if (*commands == '-')
359                                         errx(-1, "expect lease to not exist");
360                         } else if (rc == 0) {
361                                 fprintf(stdout, "no lease applied.\n");
362                                 if (*commands == '+')
363                                         errx(-1, "expect lease exists");
364                         } else {
365                                 err(errno, "free lease error");
366                         }
367                         break;
368                 case 'f':
369                         if (statfs(fname, &stfs) == -1)
370                                 errx(-1, "statfs()");
371                         break;
372                 case 'F':
373                         if (fd == -1)
374                                 rc = llapi_path2fid(fname, &fid);
375                         else
376                                 rc = llapi_fd2fid(fd, &fid);
377                         if (rc != 0)
378                                 fprintf(stderr,
379                                         "llapi_path/fd2fid() on %d, rc=%d\n",
380                                         fd, rc);
381                         else
382                                 printf(DFID"\n", PFID(&fid));
383                         break;
384                 case 'G':
385                         gid = atoi(commands+1);
386                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
387                                 save_errno = errno;
388                                 perror("ioctl(GROUP_LOCK)");
389                                 exit(save_errno);
390                         }
391                         break;
392                 case 'g':
393                         gid = atoi(commands+1);
394                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
395                                 save_errno = errno;
396                                 perror("ioctl(GROUP_UNLOCK)");
397                                 exit(save_errno);
398                         }
399                         break;
400                 case 'H':
401                         len = atoi(commands+1);
402                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY,
403                                 0644, 0, 0, len,
404                                 LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED);
405                         if (fd == -1) {
406                                 save_errno = errno;
407                                 perror("create stripe file");
408                                 exit(save_errno);
409                         }
410                         break;
411                 case 'j':
412                         if (flock(fd, LOCK_EX) == -1)
413                                 errx(-1, "flock()");
414                         break;
415                 case 'K':
416                         oldpath = POP_ARG();
417                         if (oldpath == NULL)
418                                 oldpath = fname;
419
420                         if (link(oldpath, fname)) {
421                                 save_errno = errno;
422                                 perror("link()");
423                                 exit(save_errno);
424                         }
425                         break;
426                 case 'l':
427                         newfile = POP_ARG();
428                         if (!newfile)
429                                 newfile = fname;
430                         if (symlink(fname, newfile)) {
431                                 save_errno = errno;
432                                 perror("symlink()");
433                                 exit(save_errno);
434                         }
435                         break;
436                 case 'L':
437                         newfile = POP_ARG();
438                         if (newfile == NULL)
439                                 newfile = fname;
440
441                         if (link(fname, newfile)) {
442                                 save_errno = errno;
443                                 perror("link()");
444                                 exit(save_errno);
445                         }
446                         break;
447                 case 'm':
448                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
449                                 save_errno = errno;
450                                 perror("mknod(S_IFREG|0644, 0)");
451                                 exit(save_errno);
452                         }
453                         break;
454                 case 'M':
455                         if (st.st_size == 0) {
456                                 fprintf(stderr, "mmap without preceeding stat, or on"
457                                         " zero length file.\n");
458                                 exit(-1);
459                         }
460                         mmap_len = st.st_size;
461                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
462                                         MAP_SHARED, fd, 0);
463                         if (mmap_ptr == MAP_FAILED) {
464                                 save_errno = errno;
465                                 perror("mmap");
466                                 exit(save_errno);
467                         }
468                         break;
469                 case 'n':
470                         oldpath = POP_ARG();
471                         if (oldpath == NULL)
472                                 oldpath = fname;
473
474                         if (rename(oldpath, fname) < 0) {
475                                 save_errno = errno;
476                                 perror("rename()");
477                                 exit(save_errno);
478                         }
479                         break;
480                 case 'N':
481                         newfile = POP_ARG();
482                         if (!newfile)
483                                 newfile = fname;
484                         if (rename (fname, newfile)) {
485                                 save_errno = errno;
486                                 perror("rename()");
487                                 exit(save_errno);
488                         }
489                         break;
490                 case 'O':
491                         fd = open(fname, O_CREAT|O_RDWR, 0644);
492                         if (fd == -1) {
493                                 save_errno = errno;
494                                 perror("open(O_RDWR|O_CREAT)");
495                                 exit(save_errno);
496                         }
497                         break;
498                 case 'o':
499                         len = get_flags(commands+1, &flags);
500                         commands += len;
501                         if (flags & O_CREAT)
502                                 fd = open(fname, flags, 0666);
503                         else
504                                 fd = open(fname, flags);
505                         if (fd == -1) {
506                                 save_errno = errno;
507                                 perror("open");
508                                 exit(save_errno);
509                         }
510                         break;
511                 case 'r':
512                         len = atoi(commands+1);
513                         if (len <= 0)
514                                 len = 1;
515                         if (bufsize < len) {
516                                 void *tmp;
517                                 tmp = realloc(buf, len + ALIGN_LEN);
518                                 if (tmp == NULL) {
519                                         free(buf);
520                                         save_errno = errno;
521                                         perror("allocating buf for read\n");
522                                         exit(save_errno);
523                                 }
524                                 buf = tmp;
525                                 bufsize = len;
526                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
527                                                      ~ALIGN_LEN);
528                         }
529                         while (len > 0) {
530                                 rc = read(fd, buf_align, len);
531                                 if (rc == -1) {
532                                         save_errno = errno;
533                                         perror("read");
534                                         exit(save_errno);
535                                 }
536                                 if (rc < len) {
537                                         fprintf(stderr, "short read: %u/%u\n",
538                                                 rc, len);
539                                         if (rc == 0)
540                                                 exit(ENODATA);
541                                 }
542                                 len -= rc;
543                                 if (verbose >= 2)
544                                         printf("%.*s\n", rc, buf_align);
545                         }
546                         break;
547                 case 'R':
548                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
549                                 junk += mmap_ptr[i];
550                         break;
551                 case 's':
552                         if (stat(fname, &st) == -1) {
553                                 save_errno = errno;
554                                 perror("stat");
555                                 exit(save_errno);
556                         }
557                         break;
558                 case 'S':
559                         if (fstat(fd, &st) == -1) {
560                                 save_errno = errno;
561                                 perror("fstat");
562                                 exit(save_errno);
563                         }
564                         break;
565                 case 't':
566                         if (fchmod(fd, 0) == -1) {
567                                 save_errno = errno;
568                                 perror("fchmod");
569                                 exit(save_errno);
570                         }
571                         break;
572                 case 'T':
573                         len = atoi(commands+1);
574                         if (ftruncate(fd, len) == -1) {
575                                 save_errno = errno;
576                                 printf("ftruncate (%d,%d)\n", fd, len);
577                                 perror("ftruncate");
578                                 exit(save_errno);
579                         }
580                         break;
581                 case 'u':
582                         if (unlink(fname) == -1) {
583                                 save_errno = errno;
584                                 perror("unlink");
585                                 exit(save_errno);
586                         }
587                         break;
588                 case 'U':
589                         if (munmap(mmap_ptr, mmap_len)) {
590                                 save_errno = errno;
591                                 perror("munmap");
592                                 exit(save_errno);
593                         }
594                         break;
595                 case 'v':
596                         verbose++;
597                         break;
598                 case 'V':
599                         len = get_flags(commands + 1, &flags);
600                         commands += len;
601                         fd = llapi_create_volatile(fname, flags);
602                         if (fd < 0) {
603                                 perror("llapi_create_volatile");
604                                 exit(fd);
605                         }
606                         break;
607                 case 'w':
608                         len = atoi(commands+1);
609                         if (len <= 0)
610                                 len = 1;
611                         if (bufsize < len) {
612                                 void *tmp;
613                                 tmp = realloc(buf, len + ALIGN_LEN);
614                                 if (tmp == NULL) {
615                                         free(buf);
616                                         save_errno = errno;
617                                         perror("allocating buf for write\n");
618                                         exit(save_errno);
619                                 }
620                                 buf = tmp;
621                                 bufsize = len;
622                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
623                                                      ~ALIGN_LEN);
624                                 strncpy(buf_align, msg, bufsize);
625                         }
626                         while (len > 0) {
627                                 rc = write(fd, buf_align, len);
628                                 if (rc == -1) {
629                                         save_errno = errno;
630                                         perror("write");
631                                         exit(save_errno);
632                                 }
633                                 if (rc < len)
634                                         fprintf(stderr, "short write: %u/%u\n",
635                                                 rc, len);
636                                 len -= rc;
637                         }
638                         break;
639                 case 'W':
640                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
641                                 mmap_ptr[i] += junk++;
642                         break;
643                 case 'x': {
644                         __u64 dv;
645
646                         rc = llapi_get_data_version(fd, &dv, 0);
647                         if (rc) {
648                                 fprintf(stderr, "cannot get file data version"
649                                         " %d\n", rc);
650                                 exit(-rc);
651                         }
652                         printf("dataversion is %ju\n", (uintmax_t)dv);
653                         break;
654                 }
655                 case 'X': {
656                         __u32 layout_version;
657
658                         rc = llapi_get_ost_layout_version(fd, &layout_version);
659                         if (rc) {
660                                 fprintf(stderr, "cannot get ost layout version"
661                                         " %d\n", rc);
662                                 exit(-rc);
663                         }
664                         printf("ostlayoutversion: %u\n", layout_version);
665                         break;
666                 }
667                 case 'y':
668                         if (fsync(fd) == -1) {
669                                 save_errno = errno;
670                                 perror("fsync");
671                                 exit(save_errno);
672                         }
673                         break;
674                 case 'Y':
675                         if (fdatasync(fd) == -1) {
676                                 save_errno = errno;
677                                 perror("fdatasync");
678                                 exit(save_errno);
679                         }
680                         break;
681                 case 'z':
682                         len = atoi(commands+1);
683                         if (lseek(fd, len, SEEK_SET) == -1) {
684                                 save_errno = errno;
685                                 perror("lseek");
686                                 exit(save_errno);
687                         }
688                         break;
689                 case '-':
690                 case '0':
691                 case '1':
692                 case '2':
693                 case '3':
694                 case '4':
695                 case '5':
696                 case '6':
697                 case '7':
698                 case '8':
699                 case '9':
700                         break;
701                 default:
702                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
703                         fprintf(stderr, usage, argv[0]);
704                         exit(1);
705                 }
706         }
707
708         if (buf)
709                 free(buf);
710
711         return 0;
712 }