Whamcloud - gitweb
LU-5013 llite: add LL_LEASE_{RD,WR,UN}LCK
[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 #ifdef O_NOATIME
154         {"O_NOATIME", O_NOATIME},
155 #endif
156         {"O_LARGEFILE", O_LARGEFILE},
157         {"O_DIRECTORY", O_DIRECTORY},
158         {"O_NOFOLLOW", O_NOFOLLOW},
159         {"O_LOV_DELAY_CREATE", O_LOV_DELAY_CREATE},
160         {"", -1}
161 };
162
163 int get_flags(char *data, int *rflags)
164 {
165         char *cloned_flags;
166         char *tmp;
167         int flag_set = 0;
168         int flags = 0;
169         int size = 0;
170
171         cloned_flags = strdup(data);
172         if (cloned_flags == NULL) {
173                 fprintf(stderr, "Insufficient memory.\n");
174                 exit(-1);
175         }
176
177         for (tmp = strtok(cloned_flags, ":"); tmp;
178              tmp = strtok(NULL, ":")) {
179                 int i;
180
181                 size = tmp - cloned_flags;
182                 for (i = 0; flag_table[i].flag != -1; i++) {
183                         if (!strcmp(tmp, flag_table[i].string)){
184                                 flags |= flag_table[i].flag;
185                                 size += strlen(flag_table[i].string);
186                                 flag_set = 1;
187                                 break;
188                         }
189                 }
190         }
191         free(cloned_flags);
192
193         if (!flag_set) {
194                 *rflags = O_RDONLY;
195                 return 0;
196         }
197
198         *rflags = flags;
199         return size;
200 }
201
202 #define POP_ARG() (pop_arg(argc, argv))
203
204 int main(int argc, char **argv)
205 {
206         char                    *fname, *commands;
207         const char              *newfile;
208         const char              *oldpath;
209         struct stat              st;
210         struct statfs            stfs;
211         size_t                   mmap_len = 0, i;
212         unsigned char           *mmap_ptr = NULL, junk = 0;
213         int                      rc, len, fd = -1;
214         int                      flags;
215         int                      save_errno;
216         int                      verbose = 0;
217         int                      gid = 0;
218         lustre_fid               fid;
219         struct timespec          ts;
220         struct lov_user_md_v3    lum;
221         __u64                    dv;
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 'c':
251                         if (close(fd) == -1) {
252                                 save_errno = errno;
253                                 perror("close");
254                                 exit(save_errno);
255                         }
256                         fd = -1;
257                         break;
258                 case 'B':
259                         lum = (struct lov_user_md_v3) {
260                                 .lmm_magic = LOV_USER_MAGIC_V3,
261                                 .lmm_stripe_count = atoi(commands + 1),
262                         };
263
264                         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
265                                 save_errno = errno;
266                                 perror("LL_IOC_LOV_SETSTRIPE");
267                                 exit(save_errno);
268                         }
269                         break;
270                 case 'C':
271                         len = atoi(commands+1);
272                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
273                                              0, 0, len, 0);
274                         if (fd == -1) {
275                                 save_errno = errno;
276                                 perror("create stripe file");
277                                 exit(save_errno);
278                         }
279                         break;
280                 case 'd':
281                         if (mkdir(fname, 0755) == -1) {
282                                 save_errno = errno;
283                                 perror("mkdir(0755)");
284                                 exit(save_errno);
285                         }
286                         break;
287                 case 'D':
288                         fd = open(fname, O_DIRECTORY);
289                         if (fd == -1) {
290                                 save_errno = errno;
291                                 perror("open(O_DIRECTORY)");
292                                 exit(save_errno);
293                         }
294                         break;
295                 case 'e':
296                         commands++;
297                         switch (*commands) {
298                         case 'U':
299                                 flags = LL_LEASE_UNLCK;
300                                 break;
301                         case 'R':
302                                 flags = LL_LEASE_RDLCK;
303                                 break;
304                         case 'W':
305                                 flags = LL_LEASE_WRLCK;
306                                 break;
307                         default:
308                                 errx(-1, "unknown mode: %c", *commands);
309                         }
310
311                         rc = ioctl(fd, LL_IOC_SET_LEASE, flags);
312                         if (rc < 0)
313                                 err(errno, "apply lease error");
314
315                         if (flags != LL_LEASE_UNLCK)
316                                 break;
317
318                         /* F_UNLCK, interpret return code */
319                         if (rc > 0) {
320                                 const char *str = "unknown";
321                                 if (rc == LL_LEASE_RDLCK)
322                                         str = "read";
323                                 else if (rc == LL_LEASE_WRLCK)
324                                         str = "write";
325                                 fprintf(stdout, "%s lease(%d) released.\n",
326                                         str, rc);
327                         } else if (rc == 0) {
328                                 fprintf(stdout, "lease already broken.\n");
329                         }
330                         break;
331                 case 'E':
332                         commands++;
333                         if (*commands != '-' && *commands != '+')
334                                 errx(-1, "unknown mode: %c\n", *commands);
335
336                         rc = ioctl(fd, LL_IOC_GET_LEASE);
337                         if (rc > 0) {
338                                 const char *str = "unknown";
339
340                                 if (rc == LL_LEASE_RDLCK)
341                                         str = "read";
342                                 else if (rc == LL_LEASE_WRLCK)
343                                         str = "write";
344                                 fprintf(stdout, "%s lease(%d) has applied.\n",
345                                         str, rc);
346                                 if (*commands == '-')
347                                         errx(-1, "expect lease to not exist");
348                         } else if (rc == 0) {
349                                 fprintf(stdout, "no lease applied.\n");
350                                 if (*commands == '+')
351                                         errx(-1, "expect lease exists");
352                         } else {
353                                 err(errno, "free lease error");
354                         }
355                         break;
356                 case 'f':
357                         if (statfs(fname, &stfs) == -1)
358                                 errx(-1, "statfs()");
359                         break;
360                 case 'F':
361                         if (fd == -1)
362                                 rc = llapi_path2fid(fname, &fid);
363                         else
364                                 rc = llapi_fd2fid(fd, &fid);
365                         if (rc != 0)
366                                 fprintf(stderr,
367                                         "llapi_path/fd2fid() on %d, rc=%d\n",
368                                         fd, rc);
369                         else
370                                 printf(DFID"\n", PFID(&fid));
371                         break;
372                 case 'G':
373                         gid = atoi(commands+1);
374                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
375                                 save_errno = errno;
376                                 perror("ioctl(GROUP_LOCK)");
377                                 exit(save_errno);
378                         }
379                         break;
380                 case 'g':
381                         gid = atoi(commands+1);
382                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
383                                 save_errno = errno;
384                                 perror("ioctl(GROUP_UNLOCK)");
385                                 exit(save_errno);
386                         }
387                         break;
388                 case 'H':
389                         len = atoi(commands+1);
390                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY,
391                                 0644, 0, 0, len,
392                                 LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED);
393                         if (fd == -1) {
394                                 save_errno = errno;
395                                 perror("create stripe file");
396                                 exit(save_errno);
397                         }
398                         break;
399                 case 'K':
400                         oldpath = POP_ARG();
401                         if (oldpath == NULL)
402                                 oldpath = fname;
403
404                         if (link(oldpath, fname)) {
405                                 save_errno = errno;
406                                 perror("link()");
407                                 exit(save_errno);
408                         }
409                         break;
410                 case 'l':
411                         newfile = POP_ARG();
412                         if (!newfile)
413                                 newfile = fname;
414                         if (symlink(fname, newfile)) {
415                                 save_errno = errno;
416                                 perror("symlink()");
417                                 exit(save_errno);
418                         }
419                         break;
420                 case 'L':
421                         newfile = POP_ARG();
422                         if (newfile == NULL)
423                                 newfile = fname;
424
425                         if (link(fname, newfile)) {
426                                 save_errno = errno;
427                                 perror("link()");
428                                 exit(save_errno);
429                         }
430                         break;
431                 case 'm':
432                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
433                                 save_errno = errno;
434                                 perror("mknod(S_IFREG|0644, 0)");
435                                 exit(save_errno);
436                         }
437                         break;
438                 case 'M':
439                         if (st.st_size == 0) {
440                                 fprintf(stderr, "mmap without preceeding stat, or on"
441                                         " zero length file.\n");
442                                 exit(-1);
443                         }
444                         mmap_len = st.st_size;
445                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
446                                         MAP_SHARED, fd, 0);
447                         if (mmap_ptr == MAP_FAILED) {
448                                 save_errno = errno;
449                                 perror("mmap");
450                                 exit(save_errno);
451                         }
452                         break;
453                 case 'n':
454                         oldpath = POP_ARG();
455                         if (oldpath == NULL)
456                                 oldpath = fname;
457
458                         if (rename(oldpath, fname) < 0) {
459                                 save_errno = errno;
460                                 perror("rename()");
461                                 exit(save_errno);
462                         }
463                         break;
464                 case 'N':
465                         newfile = POP_ARG();
466                         if (!newfile)
467                                 newfile = fname;
468                         if (rename (fname, newfile)) {
469                                 save_errno = errno;
470                                 perror("rename()");
471                                 exit(save_errno);
472                         }
473                         break;
474                 case 'O':
475                         fd = open(fname, O_CREAT|O_RDWR, 0644);
476                         if (fd == -1) {
477                                 save_errno = errno;
478                                 perror("open(O_RDWR|O_CREAT)");
479                                 exit(save_errno);
480                         }
481                         break;
482                 case 'o':
483                         len = get_flags(commands+1, &flags);
484                         commands += len;
485                         if (flags & O_CREAT)
486                                 fd = open(fname, flags, 0666);
487                         else
488                                 fd = open(fname, flags);
489                         if (fd == -1) {
490                                 save_errno = errno;
491                                 perror("open");
492                                 exit(save_errno);
493                         }
494                         break;
495                 case 'r':
496                         len = atoi(commands+1);
497                         if (len <= 0)
498                                 len = 1;
499                         if (bufsize < len) {
500                                 buf = realloc(buf, len + ALIGN_LEN);
501                                 if (buf == NULL) {
502                                         save_errno = errno;
503                                         perror("allocating buf for read\n");
504                                         exit(save_errno);
505                                 }
506                                 bufsize = len;
507                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
508                                                      ~ALIGN_LEN);
509                         }
510                         while (len > 0) {
511                                 rc = read(fd, buf_align, len);
512                                 if (rc == -1) {
513                                         save_errno = errno;
514                                         perror("read");
515                                         exit(save_errno);
516                                 }
517                                 if (rc < len) {
518                                         fprintf(stderr, "short read: %u/%u\n",
519                                                 rc, len);
520                                         if (rc == 0)
521                                                 exit(ENODATA);
522                                 }
523                                 len -= rc;
524                                 if (verbose >= 2)
525                                         printf("%.*s\n", rc, buf_align);
526                         }
527                         break;
528                 case 'R':
529                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
530                                 junk += mmap_ptr[i];
531                         break;
532                 case 's':
533                         if (stat(fname, &st) == -1) {
534                                 save_errno = errno;
535                                 perror("stat");
536                                 exit(save_errno);
537                         }
538                         break;
539                 case 'S':
540                         if (fstat(fd, &st) == -1) {
541                                 save_errno = errno;
542                                 perror("fstat");
543                                 exit(save_errno);
544                         }
545                         break;
546                 case 't':
547                         if (fchmod(fd, 0) == -1) {
548                                 save_errno = errno;
549                                 perror("fchmod");
550                                 exit(save_errno);
551                         }
552                         break;
553                 case 'T':
554                         len = atoi(commands+1);
555                         if (ftruncate(fd, len) == -1) {
556                                 save_errno = errno;
557                                 printf("ftruncate (%d,%d)\n", fd, len);
558                                 perror("ftruncate");
559                                 exit(save_errno);
560                         }
561                         break;
562                 case 'u':
563                         if (unlink(fname) == -1) {
564                                 save_errno = errno;
565                                 perror("unlink");
566                                 exit(save_errno);
567                         }
568                         break;
569                 case 'U':
570                         if (munmap(mmap_ptr, mmap_len)) {
571                                 save_errno = errno;
572                                 perror("munmap");
573                                 exit(save_errno);
574                         }
575                         break;
576                 case 'v':
577                         verbose++;
578                         break;
579                 case 'V':
580                         len = get_flags(commands + 1, &flags);
581                         commands += len;
582                         fd = llapi_create_volatile(fname, flags);
583                         if (fd < 0) {
584                                 perror("llapi_create_volatile");
585                                 exit(fd);
586                         }
587                         break;
588                 case 'w':
589                         len = atoi(commands+1);
590                         if (len <= 0)
591                                 len = 1;
592                         if (bufsize < len) {
593                                 buf = realloc(buf, len + ALIGN_LEN);
594                                 if (buf == NULL) {
595                                         save_errno = errno;
596                                         perror("allocating buf for write\n");
597                                         exit(save_errno);
598                                 }
599                                 bufsize = len;
600                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
601                                                      ~ALIGN_LEN);
602                                 strncpy(buf_align, msg, bufsize);
603                         }
604                         while (len > 0) {
605                                 rc = write(fd, buf_align, len);
606                                 if (rc == -1) {
607                                         save_errno = errno;
608                                         perror("write");
609                                         exit(save_errno);
610                                 }
611                                 if (rc < len)
612                                         fprintf(stderr, "short write: %u/%u\n",
613                                                 rc, len);
614                                 len -= rc;
615                         }
616                         break;
617                 case 'W':
618                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
619                                 mmap_ptr[i] += junk++;
620                         break;
621                 case 'x':
622                         rc = llapi_get_data_version(fd, &dv, 0);
623                         if (rc) {
624                                 fprintf(stderr, "cannot get file data version"
625                                         " %d\n", rc);
626                                 exit(-rc);
627                         }
628                         printf("dataversion is "LPU64"\n", dv);
629                         break;
630                 case 'y':
631                         if (fsync(fd) == -1) {
632                                 save_errno = errno;
633                                 perror("fsync");
634                                 exit(save_errno);
635                         }
636                         break;
637                 case 'Y':
638                         if (fdatasync(fd) == -1) {
639                                 save_errno = errno;
640                                 perror("fdatasync");
641                                 exit(save_errno);
642                         }
643                         break;
644                 case 'z':
645                         len = atoi(commands+1);
646                         if (lseek(fd, len, SEEK_SET) == -1) {
647                                 save_errno = errno;
648                                 perror("lseek");
649                                 exit(save_errno);
650                         }
651                         break;
652                 case '-':
653                 case '0':
654                 case '1':
655                 case '2':
656                 case '3':
657                 case '4':
658                 case '5':
659                 case '6':
660                 case '7':
661                 case '8':
662                 case '9':
663                         break;
664                 default:
665                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
666                         fprintf(stderr, usage, argv[0]);
667                         exit(1);
668                 }
669         }
670
671         if (buf)
672                 free(buf);
673
674         return 0;
675 }