Whamcloud - gitweb
b1a157db653519083c81bac957bd6ed5999cd7f6
[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
55 #include <lustre/lustre_idl.h>
56 #include <lustre/lustreapi.h>
57
58 #define T1 "write data before unlink\n"
59 #define T2 "write data after unlink\n"
60 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";
61 char *buf, *buf_align;
62 int bufsize = 0;
63 sem_t sem;
64 #define ALIGN_LEN 65535
65
66 char usage[] =
67 "Usage: %s filename command-sequence [path...]\n"
68 "    command-sequence items:\n"
69 "        c  close\n"
70 "        B[num] call setstripe ioctl to create stripes\n"
71 "        C[num] create with optional stripes\n"
72 "        d  mkdir\n"
73 "        D  open(O_DIRECTORY)\n"
74 "        f  statfs\n"
75 "        F  print FID\n"
76 "        G gid get grouplock\n"
77 "        g gid put grouplock\n"
78 "        K  link path to filename\n"
79 "        L  link\n"
80 "        l  symlink filename to path\n"
81 "        m  mknod\n"
82 "        M  rw mmap to EOF (must open and stat prior)\n"
83 "        n  rename path to filename\n"
84 "        N  rename filename to path\n"
85 "        o  open(O_RDONLY)\n"
86 "        O  open(O_CREAT|O_RDWR)\n"
87 "        r[num] read [optional length]\n"
88 "        R  reference entire mmap-ed region\n"
89 "        s  stat\n"
90 "        S  fstat\n"
91 "        t  fchmod\n"
92 "        T[num] ftruncate [optional position, default 0]\n"
93 "        u  unlink\n"
94 "        U  munmap\n"
95 "        v  verbose\n"
96 "        V  open a volatile file\n"
97 "        w[num] write optional length\n"
98 "        x  get file data version\n"
99 "        W  write entire mmap-ed region\n"
100 "        y  fsync\n"
101 "        Y  fdatasync\n"
102 "        z[num] seek [optional position, default 0]\n"
103 "        _  wait for signal\n";
104
105 void usr1_handler(int unused)
106 {
107         int saved_errno = errno;
108
109         /*
110          * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
111          * that the following functions can be safely called inside a signal
112          * handler:
113          *            sem_post()
114          */
115         sem_post(&sem);
116
117         errno = saved_errno;
118 }
119
120 static const char *
121 pop_arg(int argc, char *argv[])
122 {
123         static int cur_arg = 3;
124
125         if (cur_arg >= argc)
126                 return NULL;
127
128         return argv[cur_arg++];
129 }
130
131 struct flag_mapping {
132         const char *string;
133         const int  flag;
134 } flag_table[] = {
135         {"O_RDONLY", O_RDONLY},
136         {"O_WRONLY", O_WRONLY},
137         {"O_RDWR", O_RDWR},
138         {"O_CREAT", O_CREAT},
139         {"O_EXCL", O_EXCL},
140         {"O_NOCTTY", O_NOCTTY},
141         {"O_TRUNC", O_TRUNC},
142         {"O_APPEND", O_APPEND},
143         {"O_NONBLOCK", O_NONBLOCK},
144         {"O_NDELAY", O_NDELAY},
145         {"O_SYNC", O_SYNC},
146 #ifdef O_DIRECT
147         {"O_DIRECT", O_DIRECT},
148 #endif
149         {"O_LARGEFILE", O_LARGEFILE},
150         {"O_DIRECTORY", O_DIRECTORY},
151         {"O_NOFOLLOW", O_NOFOLLOW},
152         {"O_LOV_DELAY_CREATE", O_LOV_DELAY_CREATE},
153         {"", -1}
154 };
155
156 int get_flags(char *data, int *rflags)
157 {
158         char *cloned_flags;
159         char *tmp;
160         int flag_set = 0;
161         int flags = 0;
162         int size = 0;
163
164         cloned_flags = strdup(data);
165         if (cloned_flags == NULL) {
166                 fprintf(stderr, "Insufficient memory.\n");
167                 exit(-1);
168         }
169
170         for (tmp = strtok(cloned_flags, ":"); tmp;
171              tmp = strtok(NULL, ":")) {
172                 int i;
173
174                 size = tmp - cloned_flags;
175                 for (i = 0; flag_table[i].flag != -1; i++) {
176                         if (!strcmp(tmp, flag_table[i].string)){
177                                 flags |= flag_table[i].flag;
178                                 size += strlen(flag_table[i].string);
179                                 flag_set = 1;
180                                 break;
181                         }
182                 }
183         }
184         free(cloned_flags);
185
186         if (!flag_set) {
187                 *rflags = O_RDONLY;
188                 return 0;
189         }
190
191         *rflags = flags;
192         return size;
193 }
194
195 #define POP_ARG() (pop_arg(argc, argv))
196
197 int main(int argc, char **argv)
198 {
199         char                    *fname, *commands;
200         const char              *newfile;
201         const char              *oldpath;
202         struct stat              st;
203         struct statfs            stfs;
204         size_t                   mmap_len = 0, i;
205         unsigned char           *mmap_ptr = NULL, junk = 0;
206         int                      rc, len, fd = -1;
207         int                      flags;
208         int                      save_errno;
209         int                      verbose = 0;
210         int                      gid = 0;
211         lustre_fid               fid;
212         struct timespec          ts;
213         struct lov_user_md_v3    lum;
214         __u64                    dv;
215
216         if (argc < 3) {
217                 fprintf(stderr, usage, argv[0]);
218                 exit(1);
219         }
220
221         memset(&st, 0, sizeof(st));
222         sem_init(&sem, 0, 0);
223         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
224         sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
225                   NULL);
226
227         fname = argv[1];
228
229         for (commands = argv[2]; *commands; commands++) {
230                 switch (*commands) {
231                 case '_':
232                         if (verbose) {
233                                 printf("PAUSING\n");
234                                 fflush(stdout);
235                         }
236                         len = atoi(commands+1);
237                         if (len <= 0)
238                                 len = 3600; /* 1 hour */
239                         ts.tv_sec = time(NULL) + len;
240                         ts.tv_nsec = 0;
241                         while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR);
242                         break;
243                 case 'c':
244                         if (close(fd) == -1) {
245                                 save_errno = errno;
246                                 perror("close");
247                                 exit(save_errno);
248                         }
249                         fd = -1;
250                         break;
251                 case 'B':
252                         lum = (struct lov_user_md_v3) {
253                                 .lmm_magic = LOV_USER_MAGIC_V3,
254                                 .lmm_stripe_count = atoi(commands + 1),
255                         };
256
257                         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
258                                 save_errno = errno;
259                                 perror("LL_IOC_LOV_SETSTRIPE");
260                                 exit(save_errno);
261                         }
262                         break;
263                 case 'C':
264                         len = atoi(commands+1);
265                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
266                                              0, 0, len, 0);
267                         if (fd == -1) {
268                                 save_errno = errno;
269                                 perror("create stripe file");
270                                 exit(save_errno);
271                         }
272                         break;
273                 case 'd':
274                         if (mkdir(fname, 0755) == -1) {
275                                 save_errno = errno;
276                                 perror("mkdir(0755)");
277                                 exit(save_errno);
278                         }
279                         break;
280                 case 'D':
281                         fd = open(fname, O_DIRECTORY);
282                         if (fd == -1) {
283                                 save_errno = errno;
284                                 perror("open(O_DIRECTORY)");
285                                 exit(save_errno);
286                         }
287                         break;
288                 case 'f':
289                         if (statfs(fname, &stfs) == -1) {
290                                 save_errno = errno;
291                                 perror("statfs()");
292                                 exit(save_errno);
293                         }
294                         break;
295                 case 'F':
296                         if (fd == -1)
297                                 rc = llapi_path2fid(fname, &fid);
298                         else
299                                 rc = llapi_fd2fid(fd, &fid);
300                         if (rc != 0)
301                                 fprintf(stderr,
302                                         "llapi_path/fd2fid() on %d, rc=%d\n",
303                                         fd, rc);
304                         else
305                                 printf(DFID"\n", PFID(&fid));
306                         break;
307                 case 'G':
308                         gid = atoi(commands+1);
309                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
310                                 save_errno = errno;
311                                 perror("ioctl(GROUP_LOCK)");
312                                 exit(save_errno);
313                         }
314                         break;
315                 case 'g':
316                         gid = atoi(commands+1);
317                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
318                                 save_errno = errno;
319                                 perror("ioctl(GROUP_UNLOCK)");
320                                 exit(save_errno);
321                         }
322                         break;
323                 case 'K':
324                         oldpath = POP_ARG();
325                         if (oldpath == NULL)
326                                 oldpath = fname;
327
328                         if (link(oldpath, fname)) {
329                                 save_errno = errno;
330                                 perror("link()");
331                                 exit(save_errno);
332                         }
333                         break;
334                 case 'l':
335                         newfile = POP_ARG();
336                         if (!newfile)
337                                 newfile = fname;
338                         if (symlink(fname, newfile)) {
339                                 save_errno = errno;
340                                 perror("symlink()");
341                                 exit(save_errno);
342                         }
343                         break;
344                 case 'L':
345                         newfile = POP_ARG();
346                         if (newfile == NULL)
347                                 newfile = fname;
348
349                         if (link(fname, newfile)) {
350                                 save_errno = errno;
351                                 perror("link()");
352                                 exit(save_errno);
353                         }
354                         break;
355                 case 'm':
356                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
357                                 save_errno = errno;
358                                 perror("mknod(S_IFREG|0644, 0)");
359                                 exit(save_errno);
360                         }
361                         break;
362                 case 'M':
363                         if (st.st_size == 0) {
364                                 fprintf(stderr, "mmap without preceeding stat, or on"
365                                         " zero length file.\n");
366                                 exit(-1);
367                         }
368                         mmap_len = st.st_size;
369                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
370                                         MAP_SHARED, fd, 0);
371                         if (mmap_ptr == MAP_FAILED) {
372                                 save_errno = errno;
373                                 perror("mmap");
374                                 exit(save_errno);
375                         }
376                         break;
377                 case 'n':
378                         oldpath = POP_ARG();
379                         if (oldpath == NULL)
380                                 oldpath = fname;
381
382                         if (rename(oldpath, fname) < 0) {
383                                 save_errno = errno;
384                                 perror("rename()");
385                                 exit(save_errno);
386                         }
387                         break;
388                 case 'N':
389                         newfile = POP_ARG();
390                         if (!newfile)
391                                 newfile = fname;
392                         if (rename (fname, newfile)) {
393                                 save_errno = errno;
394                                 perror("rename()");
395                                 exit(save_errno);
396                         }
397                         break;
398                 case 'O':
399                         fd = open(fname, O_CREAT|O_RDWR, 0644);
400                         if (fd == -1) {
401                                 save_errno = errno;
402                                 perror("open(O_RDWR|O_CREAT)");
403                                 exit(save_errno);
404                         }
405                         break;
406                 case 'o':
407                         len = get_flags(commands+1, &flags);
408                         commands += len;
409                         if (flags & O_CREAT)
410                                 fd = open(fname, flags, 0666);
411                         else
412                                 fd = open(fname, flags);
413                         if (fd == -1) {
414                                 save_errno = errno;
415                                 perror("open");
416                                 exit(save_errno);
417                         }
418                         break;
419                 case 'r':
420                         len = atoi(commands+1);
421                         if (len <= 0)
422                                 len = 1;
423                         if (bufsize < len) {
424                                 buf = realloc(buf, len + ALIGN_LEN);
425                                 if (buf == NULL) {
426                                         save_errno = errno;
427                                         perror("allocating buf for read\n");
428                                         exit(save_errno);
429                                 }
430                                 bufsize = len;
431                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
432                                                      ~ALIGN_LEN);
433                         }
434                         while (len > 0) {
435                                 rc = read(fd, buf_align, len);
436                                 if (rc == -1) {
437                                         save_errno = errno;
438                                         perror("read");
439                                         exit(save_errno);
440                                 }
441                                 if (rc < len) {
442                                         fprintf(stderr, "short read: %u/%u\n",
443                                                 rc, len);
444                                         if (rc == 0)
445                                                 exit(ENODATA);
446                                 }
447                                 len -= rc;
448                                 if (verbose >= 2)
449                                         printf("%.*s\n", rc, buf_align);
450                         }
451                         break;
452                 case 'R':
453                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
454                                 junk += mmap_ptr[i];
455                         break;
456                 case 's':
457                         if (stat(fname, &st) == -1) {
458                                 save_errno = errno;
459                                 perror("stat");
460                                 exit(save_errno);
461                         }
462                         break;
463                 case 'S':
464                         if (fstat(fd, &st) == -1) {
465                                 save_errno = errno;
466                                 perror("fstat");
467                                 exit(save_errno);
468                         }
469                         break;
470                 case 't':
471                         if (fchmod(fd, 0) == -1) {
472                                 save_errno = errno;
473                                 perror("fchmod");
474                                 exit(save_errno);
475                         }
476                         break;
477                 case 'T':
478                         len = atoi(commands+1);
479                         if (ftruncate(fd, len) == -1) {
480                                 save_errno = errno;
481                                 printf("ftruncate (%d,%d)\n", fd, len);
482                                 perror("ftruncate");
483                                 exit(save_errno);
484                         }
485                         break;
486                 case 'u':
487                         if (unlink(fname) == -1) {
488                                 save_errno = errno;
489                                 perror("unlink");
490                                 exit(save_errno);
491                         }
492                         break;
493                 case 'U':
494                         if (munmap(mmap_ptr, mmap_len)) {
495                                 save_errno = errno;
496                                 perror("munmap");
497                                 exit(save_errno);
498                         }
499                         break;
500                 case 'v':
501                         verbose++;
502                         break;
503                 case 'V':
504                         len = get_flags(commands + 1, &flags);
505                         commands += len;
506                         fd = llapi_create_volatile(fname, flags);
507                         if (fd < 0) {
508                                 perror("llapi_create_volatile");
509                                 exit(fd);
510                         }
511                         break;
512                 case 'w':
513                         len = atoi(commands+1);
514                         if (len <= 0)
515                                 len = 1;
516                         if (bufsize < len) {
517                                 buf = realloc(buf, len + ALIGN_LEN);
518                                 if (buf == NULL) {
519                                         save_errno = errno;
520                                         perror("allocating buf for write\n");
521                                         exit(save_errno);
522                                 }
523                                 bufsize = len;
524                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
525                                                      ~ALIGN_LEN);
526                                 strncpy(buf_align, msg, bufsize);
527                         }
528                         while (len > 0) {
529                                 rc = write(fd, buf_align, len);
530                                 if (rc == -1) {
531                                         save_errno = errno;
532                                         perror("write");
533                                         exit(save_errno);
534                                 }
535                                 if (rc < len)
536                                         fprintf(stderr, "short write: %u/%u\n",
537                                                 rc, len);
538                                 len -= rc;
539                         }
540                         break;
541                 case 'W':
542                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
543                                 mmap_ptr[i] += junk++;
544                         break;
545                 case 'x':
546                         rc = llapi_get_data_version(fd, &dv, 0);
547                         if (rc) {
548                                 fprintf(stderr, "cannot get file data version"
549                                         " %d\n", rc);
550                                 exit(-rc);
551                         }
552                         printf("dataversion is "LPU64"\n", dv);
553                         break;
554                 case 'y':
555                         if (fsync(fd) == -1) {
556                                 save_errno = errno;
557                                 perror("fsync");
558                                 exit(save_errno);
559                         }
560                         break;
561                 case 'Y':
562                         if (fdatasync(fd) == -1) {
563                                 save_errno = errno;
564                                 perror("fdatasync");
565                                 exit(save_errno);
566                         }
567                 case 'z':
568                         len = atoi(commands+1);
569                         if (lseek(fd, len, SEEK_SET) == -1) {
570                                 save_errno = errno;
571                                 perror("lseek");
572                                 exit(save_errno);
573                         }
574                         break;
575                 case '-':
576                 case '0':
577                 case '1':
578                 case '2':
579                 case '3':
580                 case '4':
581                 case '5':
582                 case '6':
583                 case '7':
584                 case '8':
585                 case '9':
586                         break;
587                 default:
588                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
589                         fprintf(stderr, usage, argv[0]);
590                         exit(1);
591                 }
592         }
593
594         if (buf)
595                 free(buf);
596
597         return 0;
598 }