Whamcloud - gitweb
Branch HEAD
[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                         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                                 if (verbose >= 2)
358                                         printf("%.*s\n", rc, buf_align);
359                         }
360                         break;
361                 case 'R':
362                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
363                                 junk += mmap_ptr[i];
364                         break;
365                 case 's':
366                         if (stat(fname, &st) == -1) {
367                                 save_errno = errno;
368                                 perror("stat");
369                                 exit(save_errno);
370                         }
371                         break;
372                 case 'S':
373                         if (fstat(fd, &st) == -1) {
374                                 save_errno = errno;
375                                 perror("fstat");
376                                 exit(save_errno);
377                         }
378                         break;
379                 case 't':
380                         if (fchmod(fd, 0) == -1) {
381                                 save_errno = errno;
382                                 perror("fchmod");
383                                 exit(save_errno);
384                         }
385                         break;
386                 case 'T':
387                         len = atoi(commands+1);
388                         if (ftruncate(fd, len) == -1) {
389                                 save_errno = errno;
390                                 printf("ftruncate (%d,%d)\n", fd, len);
391                                 perror("ftruncate");
392                                 exit(save_errno);
393                         }
394                         break;
395                 case 'u':
396                         if (unlink(fname) == -1) {
397                                 save_errno = errno;
398                                 perror("unlink");
399                                 exit(save_errno);
400                         }
401                         break;
402                 case 'U':
403                         if (munmap(mmap_ptr, mmap_len)) {
404                                 save_errno = errno;
405                                 perror("munmap");
406                                 exit(save_errno);
407                         }
408                         break;
409                 case 'v':
410                         verbose++;
411                         break;
412                 case 'w':
413                         len = atoi(commands+1);
414                         if (len <= 0)
415                                 len = 1;
416                         if (bufsize < len) {
417                                 buf = realloc(buf, len + ALIGN);
418                                 if (buf == NULL) {
419                                         save_errno = errno;
420                                         perror("allocating buf for write\n");
421                                         exit(save_errno);
422                                 }
423                                 bufsize = len;
424                                 buf_align = (char *)((long)(buf + ALIGN) &
425                                                      ~ALIGN);
426                                 strncpy(buf_align, msg, bufsize);
427                         }
428                         while (len > 0) {
429                                 rc = write(fd, buf_align, len);
430                                 if (rc == -1) {
431                                         save_errno = errno;
432                                         perror("write");
433                                         exit(save_errno);
434                                 }
435                                 if (rc < len)
436                                         fprintf(stderr, "short write: %u/%u\n",
437                                                 rc, len);
438                                 len -= rc;
439                         }
440                         break;
441                 case 'W':
442                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
443                                 mmap_ptr[i] += junk++;
444                         break;
445                 case 'y':
446                         if (fsync(fd) == -1) {
447                                 save_errno = errno;
448                                 perror("fsync");
449                                 exit(save_errno);
450                         }
451                         break;
452                 case 'Y':
453                         if (fdatasync(fd) == -1) {
454                                 save_errno = errno;
455                                 perror("fdatasync");
456                                 exit(save_errno);
457                         }
458                 case 'z':
459                         len = atoi(commands+1);
460                         if (lseek(fd, len, SEEK_SET) == -1) {
461                                 save_errno = errno;
462                                 perror("lseek");
463                                 exit(save_errno);
464                         }
465                         break;
466                 case '0':
467                 case '1':
468                 case '2':
469                 case '3':
470                 case '4':
471                 case '5':
472                 case '6':
473                 case '7':
474                 case '8':
475                 case '9':
476                         break;
477                 default:
478                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
479                         fprintf(stderr, usage, argv[0]);
480                         exit(1);
481                 }
482         }
483
484         if (buf)
485                 free(buf);
486
487         return 0;
488 }