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