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