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