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