Whamcloud - gitweb
b=19702
[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 <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 #define min(a,b) ((a)>(b)?(b):(a))
185
186 int main(int argc, char **argv)
187 {
188         char *fname, *commands;
189         const char *newfile;
190         struct stat st;
191         struct statfs stfs;
192         size_t mmap_len = 0, i;
193         unsigned char *mmap_ptr = NULL, junk = 0;
194         int rc, len, fd = -1;
195         int flags;
196         int save_errno;
197         int verbose = 0;
198
199         if (argc < 3) {
200                 fprintf(stderr, usage, argv[0]);
201                 exit(1);
202         }
203
204         memset(&st, 0, sizeof(st));
205         sem_init(&sem, 0, 0);
206         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
207         sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
208                   NULL);
209
210         fname = argv[1];
211
212         for (commands = argv[2]; *commands; commands++) {
213                 switch (*commands) {
214                 case '_':
215                         if (verbose) {
216                                 printf("PAUSING\n");
217                                 fflush(stdout);
218                         }
219                         while (sem_wait(&sem) == -1 && errno == EINTR);
220                         break;
221                 case 'c':
222                         if (close(fd) == -1) {
223                                 save_errno = errno;
224                                 perror("close");
225                                 exit(save_errno);
226                         }
227                         fd = -1;
228                         break;
229                 case 'C':
230                         len = atoi(commands+1);
231                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
232                                              0, 0, len, 0);
233                         if (fd == -1) {
234                                 save_errno = errno;
235                                 perror("create stripe file");
236                                 exit(save_errno);
237                         }
238                         break;
239                 case 'd':
240                         if (mkdir(fname, 0755) == -1) {
241                                 save_errno = errno;
242                                 perror("mkdir(0755)");
243                                 exit(save_errno);
244                         }
245                         break;
246                 case 'D':
247                         fd = open(fname, O_DIRECTORY);
248                         if (fd == -1) {
249                                 save_errno = errno;
250                                 perror("open(O_DIRECTORY)");
251                                 exit(save_errno);
252                         }
253                         break;
254                 case 'f':
255                         if (statfs(fname, &stfs) == -1) {
256                                 save_errno = errno;
257                                 perror("statfs()");
258                                 exit(save_errno);
259                         }
260                         break;
261                 case 'l':
262                         newfile = POP_ARG();
263                         if (!newfile)
264                                 newfile = fname;
265                         if (symlink(fname, newfile)) {
266                                 save_errno = errno;
267                                 perror("symlink()");
268                                 exit(save_errno);
269                         }
270                         break;
271                 case 'L':
272                         newfile = POP_ARG();
273                         if (!newfile)
274                                 newfile = fname;
275                         if (link(fname, newfile)) {
276                                 save_errno = errno;
277                                 perror("symlink()");
278                                 exit(save_errno);
279                         }
280                         break;
281                 case 'm':
282                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
283                                 save_errno = errno;
284                                 perror("mknod(S_IFREG|0644, 0)");
285                                 exit(save_errno);
286                         }
287                         break;
288                 case 'M':
289                         if (st.st_size == 0) {
290                                 fprintf(stderr, "mmap without preceeding stat, or on"
291                                         " zero length file.\n");
292                                 exit(-1);
293                         }
294                         mmap_len = st.st_size;
295                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
296                                         MAP_SHARED, fd, 0);
297                         if (mmap_ptr == MAP_FAILED) {
298                                 save_errno = errno;
299                                 perror("mmap");
300                                 exit(save_errno);
301                         }
302                         break;
303                 case 'N':
304                         newfile = POP_ARG();
305                         if (!newfile)
306                                 newfile = fname;
307                         if (rename (fname, newfile)) {
308                                 save_errno = errno;
309                                 perror("rename()");
310                                 exit(save_errno);
311                         }
312                         break;
313                 case 'O':
314                         fd = open(fname, O_CREAT|O_RDWR, 0644);
315                         if (fd == -1) {
316                                 save_errno = errno;
317                                 perror("open(O_RDWR|O_CREAT)");
318                                 exit(save_errno);
319                         }
320                         break;
321                 case 'o':
322                         len = get_flags(commands+1, &flags);
323                         commands += len;
324                         if (flags & O_CREAT)
325                                 fd = open(fname, flags, 0666);
326                         else
327                                 fd = open(fname, flags);
328                         if (fd == -1) {
329                                 save_errno = errno;
330                                 perror("open");
331                                 exit(save_errno);
332                         }
333                         break;
334                 case 'r':
335                         len = atoi(commands+1);
336                         if (len <= 0)
337                                 len = 1;
338                         if (bufsize < len) {
339                                 buf = realloc(buf, len + ALIGN);
340                                 if (buf == NULL) {
341                                         save_errno = errno;
342                                         perror("allocating buf for read\n");
343                                         exit(save_errno);
344                                 }
345                                 bufsize = len;
346                                 buf_align = (char *)((long)(buf + ALIGN) &
347                                                      ~ALIGN);
348                         }
349                         while (len > 0) {
350                                 rc = read(fd, buf_align, len);
351                                 if (rc == -1) {
352                                         save_errno = errno;
353                                         perror("read");
354                                         exit(save_errno);
355                                 }
356                                 if (rc < len)
357                                         fprintf(stderr, "short read: %u/%u\n",
358                                                 rc, len);
359                                 len -= rc;
360                                 if (verbose >= 2)
361                                         printf("%.*s\n", rc, buf_align);
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++;
414                         break;
415                 case 'w':
416                         len = atoi(commands+1);
417                         if (len <= 0)
418                                 len = 1;
419                         if (bufsize < len) {
420                                 buf = realloc(buf, len + ALIGN);
421                                 if (buf == NULL) {
422                                         save_errno = errno;
423                                         perror("allocating buf for write\n");
424                                         exit(save_errno);
425                                 }
426                                 bufsize = len;
427                                 buf_align = (char *)((long)(buf + ALIGN) &
428                                                      ~ALIGN);
429                                 strncpy(buf_align, msg, bufsize);
430                         }
431                         while (len > 0) {
432                                 rc = write(fd, buf_align, len);
433                                 if (rc == -1) {
434                                         save_errno = errno;
435                                         perror("write");
436                                         exit(save_errno);
437                                 }
438                                 if (rc < len)
439                                         fprintf(stderr, "short write: %u/%u\n",
440                                                 rc, len);
441                                 len -= rc;
442                         }
443                         break;
444                 case 'W':
445                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
446                                 mmap_ptr[i] += junk++;
447                         break;
448                 case 'y':
449                         if (fsync(fd) == -1) {
450                                 save_errno = errno;
451                                 perror("fsync");
452                                 exit(save_errno);
453                         }
454                         break;
455                 case 'Y':
456                         if (fdatasync(fd) == -1) {
457                                 save_errno = errno;
458                                 perror("fdatasync");
459                                 exit(save_errno);
460                         }
461                 case 'z':
462                         len = atoi(commands+1);
463                         if (lseek(fd, len, SEEK_SET) == -1) {
464                                 save_errno = errno;
465                                 perror("lseek");
466                                 exit(save_errno);
467                         }
468                         break;
469                 case '0':
470                 case '1':
471                 case '2':
472                 case '3':
473                 case '4':
474                 case '5':
475                 case '6':
476                 case '7':
477                 case '8':
478                 case '9':
479                         break;
480                 default:
481                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
482                         fprintf(stderr, usage, argv[0]);
483                         exit(1);
484                 }
485         }
486
487         if (buf)
488                 free(buf);
489
490         return 0;
491 }