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