Whamcloud - gitweb
Mass conversion of all copyright messages to Oracle.
[fs/lustre-release.git] / lustre / tests / multiop.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
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 <signal.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <semaphore.h>
52 #include <libcfs/libcfs.h>
53 #include <lustre/liblustreapi.h>
54
55 #define T1 "write data before unlink\n"
56 #define T2 "write data after unlink\n"
57 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";
58 char *buf, *buf_align;
59 int bufsize = 0;
60 sem_t sem;
61 #define ALIGN 65535
62
63 char usage[] =
64 "Usage: %s filename command-sequence\n"
65 "    command-sequence items:\n"
66 "        c  close\n"
67 "        C[num] create with optional stripes\n"
68 "        d  mkdir\n"
69 "        D  open(O_DIRECTORY)\n"
70 "        f  statfs\n"
71 "        L  link\n"
72 "        l  symlink\n"
73 "        m  mknod\n"
74 "        M  rw mmap to EOF (must open and stat prior)\n"
75 "        N  rename\n"
76 "        o  open(O_RDONLY)\n"
77 "        O  open(O_CREAT|O_RDWR)\n"
78 "        r[num] read [optional length]\n"
79 "        R  reference entire mmap-ed region\n"
80 "        s  stat\n"
81 "        S  fstat\n"
82 "        t  fchmod\n"
83 "        T[num] ftruncate [optional position, default 0]\n"
84 "        u  unlink\n"
85 "        U  munmap\n"
86 "        v  verbose\n"
87 "        w[num] write optional length\n"
88 "        W  write entire mmap-ed region\n"
89 "        y  fsync\n"
90 "        Y  fdatasync\n"
91 "        z[num] seek [optional position, default 0]\n"
92 "        _  wait for signal\n";
93
94 void usr1_handler(int unused)
95 {
96         int saved_errno = errno;
97
98         /*
99          * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
100          * that the following functions can be safely called inside a signal
101          * handler:
102          *            sem_post()
103          */
104         sem_post(&sem);
105
106         errno = saved_errno;
107 }
108
109 static const char *
110 pop_arg(int argc, char *argv[])
111 {
112         static int cur_arg = 3;
113
114         if (cur_arg >= argc)
115                 return NULL;
116
117         return argv[cur_arg++];
118 }
119
120 struct flag_mapping {
121        const char *string;
122        const int  flag;
123 } flag_table[] = {
124        {"O_RDONLY", O_RDONLY},
125        {"O_WRONLY", O_WRONLY},
126        {"O_RDWR", O_RDWR},
127        {"O_CREAT", O_CREAT},
128        {"O_EXCL", O_EXCL},
129        {"O_NOCTTY", O_NOCTTY},
130        {"O_TRUNC", O_TRUNC},
131        {"O_APPEND", O_APPEND},
132        {"O_NONBLOCK", O_NONBLOCK},
133        {"O_NDELAY", O_NDELAY},
134        {"O_SYNC", O_SYNC},
135 #ifdef O_DIRECT
136        {"O_DIRECT", O_DIRECT},
137 #endif
138        {"O_LARGEFILE", O_LARGEFILE},
139        {"O_DIRECTORY", O_DIRECTORY},
140        {"O_NOFOLLOW", O_NOFOLLOW},
141        {"", -1}
142 };
143
144 int get_flags(char *data, int *rflags)
145 {
146         char *cloned_flags;
147         char *tmp;
148         int flag_set = 0;
149         int flags = 0;
150         int size = 0;
151
152         cloned_flags = strdup(data);
153         if (cloned_flags == NULL) {
154                 fprintf(stderr, "Insufficient memory.\n");
155                 exit(-1);
156         }
157
158         for (tmp = strtok(cloned_flags, ":"); tmp;
159              tmp = strtok(NULL, ":")) {
160                 int i;
161
162                 size = tmp - cloned_flags;
163                 for (i = 0; flag_table[i].flag != -1; i++) {
164                         if (!strcmp(tmp, flag_table[i].string)){
165                                 flags |= flag_table[i].flag;
166                                 size += strlen(flag_table[i].string);
167                                 flag_set = 1;
168                                 break;
169                         }
170                 }
171         }
172         free(cloned_flags);
173
174         if (!flag_set) {
175                 *rflags = O_RDONLY;
176                 return 0;
177         }
178
179         *rflags = flags;
180         return size;
181 }
182
183 #define POP_ARG() (pop_arg(argc, argv))
184
185 int main(int argc, char **argv)
186 {
187         char *fname, *commands;
188         const char *newfile;
189         struct stat st;
190         struct statfs stfs;
191         size_t mmap_len = 0, i;
192         unsigned char *mmap_ptr = NULL, junk = 0;
193         int rc, len, fd = -1;
194         int flags;
195         int save_errno;
196         int verbose = 0;
197
198         if (argc < 3) {
199                 fprintf(stderr, usage, argv[0]);
200                 exit(1);
201         }
202
203         memset(&st, 0, sizeof(st));
204         sem_init(&sem, 0, 0);
205         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
206         sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
207                   NULL);
208
209         fname = argv[1];
210
211         for (commands = argv[2]; *commands; commands++) {
212                 switch (*commands) {
213                 case '_':
214                         if (verbose) {
215                                 printf("PAUSING\n");
216                                 fflush(stdout);
217                         }
218                         while (sem_wait(&sem) == -1 && errno == EINTR);
219                         break;
220                 case 'c':
221                         if (close(fd) == -1) {
222                                 save_errno = errno;
223                                 perror("close");
224                                 exit(save_errno);
225                         }
226                         fd = -1;
227                         break;
228                 case 'C':
229                         len = atoi(commands+1);
230                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
231                                              0, 0, len, 0);
232                         if (fd == -1) {
233                                 save_errno = errno;
234                                 perror("create stripe file");
235                                 exit(save_errno);
236                         }
237                         break;
238                 case 'd':
239                         if (mkdir(fname, 0755) == -1) {
240                                 save_errno = errno;
241                                 perror("mkdir(0755)");
242                                 exit(save_errno);
243                         }
244                         break;
245                 case 'D':
246                         fd = open(fname, O_DIRECTORY);
247                         if (fd == -1) {
248                                 save_errno = errno;
249                                 perror("open(O_DIRECTORY)");
250                                 exit(save_errno);
251                         }
252                         break;
253                 case 'f':
254                         if (statfs(fname, &stfs) == -1) {
255                                 save_errno = errno;
256                                 perror("statfs()");
257                                 exit(save_errno);
258                         }
259                         break;
260                 case 'l':
261                         newfile = POP_ARG();
262                         if (!newfile)
263                                 newfile = fname;
264                         if (symlink(fname, newfile)) {
265                                 save_errno = errno;
266                                 perror("symlink()");
267                                 exit(save_errno);
268                         }
269                         break;
270                 case 'L':
271                         newfile = POP_ARG();
272                         if (!newfile)
273                                 newfile = fname;
274                         if (link(fname, newfile)) {
275                                 save_errno = errno;
276                                 perror("symlink()");
277                                 exit(save_errno);
278                         }
279                         break;
280                 case 'm':
281                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
282                                 save_errno = errno;
283                                 perror("mknod(S_IFREG|0644, 0)");
284                                 exit(save_errno);
285                         }
286                         break;
287                 case 'M':
288                         if (st.st_size == 0) {
289                                 fprintf(stderr, "mmap without preceeding stat, or on"
290                                         " zero length file.\n");
291                                 exit(-1);
292                         }
293                         mmap_len = st.st_size;
294                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
295                                         MAP_SHARED, fd, 0);
296                         if (mmap_ptr == MAP_FAILED) {
297                                 save_errno = errno;
298                                 perror("mmap");
299                                 exit(save_errno);
300                         }
301                         break;
302                 case 'N':
303                         newfile = POP_ARG();
304                         if (!newfile)
305                                 newfile = fname;
306                         if (rename (fname, newfile)) {
307                                 save_errno = errno;
308                                 perror("rename()");
309                                 exit(save_errno);
310                         }
311                         break;
312                 case 'O':
313                         fd = open(fname, O_CREAT|O_RDWR, 0644);
314                         if (fd == -1) {
315                                 save_errno = errno;
316                                 perror("open(O_RDWR|O_CREAT)");
317                                 exit(save_errno);
318                         }
319                         break;
320                 case 'o':
321                         len = get_flags(commands+1, &flags);
322                         commands += len;
323                         if (flags & O_CREAT)
324                                 fd = open(fname, flags, 0666);
325                         else
326                                 fd = open(fname, flags);
327                         if (fd == -1) {
328                                 save_errno = errno;
329                                 perror("open");
330                                 exit(save_errno);
331                         }
332                         break;
333                 case 'r':
334                         len = atoi(commands+1);
335                         if (len <= 0)
336                                 len = 1;
337                         if (bufsize < len) {
338                                 buf = realloc(buf, len + ALIGN);
339                                 if (buf == NULL) {
340                                         save_errno = errno;
341                                         perror("allocating buf for read\n");
342                                         exit(save_errno);
343                                 }
344                                 bufsize = len;
345                                 buf_align = (char *)((long)(buf + ALIGN) &
346                                                      ~ALIGN);
347                         }
348                         while (len > 0) {
349                                 rc = read(fd, buf_align, len);
350                                 if (rc == -1) {
351                                         save_errno = errno;
352                                         perror("read");
353                                         exit(save_errno);
354                                 }
355                                 if (rc < len)
356                                         fprintf(stderr, "short read: %u/%u\n",
357                                                 rc, len);
358                                 len -= rc;
359                                 if (verbose >= 2)
360                                         printf("%.*s\n", rc, buf_align);
361                         }
362                         break;
363                 case 'R':
364                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
365                                 junk += mmap_ptr[i];
366                         break;
367                 case 's':
368                         if (stat(fname, &st) == -1) {
369                                 save_errno = errno;
370                                 perror("stat");
371                                 exit(save_errno);
372                         }
373                         break;
374                 case 'S':
375                         if (fstat(fd, &st) == -1) {
376                                 save_errno = errno;
377                                 perror("fstat");
378                                 exit(save_errno);
379                         }
380                         break;
381                 case 't':
382                         if (fchmod(fd, 0) == -1) {
383                                 save_errno = errno;
384                                 perror("fchmod");
385                                 exit(save_errno);
386                         }
387                         break;
388                 case 'T':
389                         len = atoi(commands+1);
390                         if (ftruncate(fd, len) == -1) {
391                                 save_errno = errno;
392                                 printf("ftruncate (%d,%d)\n", fd, len);
393                                 perror("ftruncate");
394                                 exit(save_errno);
395                         }
396                         break;
397                 case 'u':
398                         if (unlink(fname) == -1) {
399                                 save_errno = errno;
400                                 perror("unlink");
401                                 exit(save_errno);
402                         }
403                         break;
404                 case 'U':
405                         if (munmap(mmap_ptr, mmap_len)) {
406                                 save_errno = errno;
407                                 perror("munmap");
408                                 exit(save_errno);
409                         }
410                         break;
411                 case 'v':
412                         verbose++;
413                         break;
414                 case 'w':
415                         len = atoi(commands+1);
416                         if (len <= 0)
417                                 len = 1;
418                         if (bufsize < len) {
419                                 buf = realloc(buf, len + ALIGN);
420                                 if (buf == NULL) {
421                                         save_errno = errno;
422                                         perror("allocating buf for write\n");
423                                         exit(save_errno);
424                                 }
425                                 bufsize = len;
426                                 buf_align = (char *)((long)(buf + ALIGN) &
427                                                      ~ALIGN);
428                                 strncpy(buf_align, msg, bufsize);
429                         }
430                         while (len > 0) {
431                                 rc = write(fd, buf_align, len);
432                                 if (rc == -1) {
433                                         save_errno = errno;
434                                         perror("write");
435                                         exit(save_errno);
436                                 }
437                                 if (rc < len)
438                                         fprintf(stderr, "short write: %u/%u\n",
439                                                 rc, len);
440                                 len -= rc;
441                         }
442                         break;
443                 case 'W':
444                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
445                                 mmap_ptr[i] += junk++;
446                         break;
447                 case 'y':
448                         if (fsync(fd) == -1) {
449                                 save_errno = errno;
450                                 perror("fsync");
451                                 exit(save_errno);
452                         }
453                         break;
454                 case 'Y':
455                         if (fdatasync(fd) == -1) {
456                                 save_errno = errno;
457                                 perror("fdatasync");
458                                 exit(save_errno);
459                         }
460                 case 'z':
461                         len = atoi(commands+1);
462                         if (lseek(fd, len, SEEK_SET) == -1) {
463                                 save_errno = errno;
464                                 perror("lseek");
465                                 exit(save_errno);
466                         }
467                         break;
468                 case '0':
469                 case '1':
470                 case '2':
471                 case '3':
472                 case '4':
473                 case '5':
474                 case '6':
475                 case '7':
476                 case '8':
477                 case '9':
478                         break;
479                 default:
480                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
481                         fprintf(stderr, usage, argv[0]);
482                         exit(1);
483                 }
484         }
485
486         if (buf)
487                 free(buf);
488
489         return 0;
490 }