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 <signal.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <semaphore.h>
51 #include <libcfs/libcfs.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 "        L  link\n"
70 "        l  symlink\n"
71 "        m  mknod\n"
72 "        M  rw mmap to EOF (must open and stat prior)\n"
73 "        N  rename\n"
74 "        o  open(O_RDONLY)\n"
75 "        O  open(O_CREAT|O_RDWR)\n"
76 "        r[num] read [optional length]\n"
77 "        R  reference entire mmap-ed region\n"
78 "        s  stat\n"
79 "        S  fstat\n"
80 "        t  fchmod\n"
81 "        T[num] ftruncate [optional position, default 0]\n"
82 "        u  unlink\n"
83 "        U  munmap\n"
84 "        v  verbose\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         size_t mmap_len = 0, i;
190         unsigned char *mmap_ptr = NULL, junk = 0;
191         int rc, len, fd = -1;
192         int flags;
193         int save_errno;
194         int verbose = 0;
195
196         if (argc < 3) {
197                 fprintf(stderr, usage, argv[0]);
198                 exit(1);
199         }
200
201         memset(&st, 0, sizeof(st));
202         sem_init(&sem, 0, 0);
203         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
204         sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
205                   NULL);
206
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 'l':
252                         newfile = POP_ARG();
253                         if (!newfile)
254                                 newfile = fname;
255                         if (symlink(fname, newfile)) {
256                                 save_errno = errno;
257                                 perror("symlink()");
258                                 exit(save_errno);
259                         }
260                         break;
261                 case 'L':
262                         newfile = POP_ARG();
263                         if (!newfile)
264                                 newfile = fname;
265                         if (link(fname, newfile)) {
266                                 save_errno = errno;
267                                 perror("symlink()");
268                                 exit(save_errno);
269                         }
270                         break;
271                 case 'm':
272                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
273                                 save_errno = errno;
274                                 perror("mknod(S_IFREG|0644, 0)");
275                                 exit(save_errno);
276                         }
277                         break;
278                 case 'M':
279                         if (st.st_size == 0) {
280                                 fprintf(stderr, "mmap without preceeding stat, or on"
281                                         " zero length file.\n");
282                                 exit(-1);
283                         }
284                         mmap_len = st.st_size;
285                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
286                                         MAP_SHARED, fd, 0);
287                         if (mmap_ptr == MAP_FAILED) {
288                                 save_errno = errno;
289                                 perror("mmap");
290                                 exit(save_errno);
291                         }
292                         break;
293                 case 'N':
294                         newfile = POP_ARG();
295                         if (!newfile)
296                                 newfile = fname;
297                         if (rename (fname, newfile)) {
298                                 save_errno = errno;
299                                 perror("rename()");
300                                 exit(save_errno);
301                         }
302                         break;
303                 case 'O':
304                         fd = open(fname, O_CREAT|O_RDWR, 0644);
305                         if (fd == -1) {
306                                 save_errno = errno;
307                                 perror("open(O_RDWR|O_CREAT)");
308                                 exit(save_errno);
309                         }
310                         break;
311                 case 'o':
312                         len = get_flags(commands+1, &flags);
313                         commands += len;
314                         fd = open(fname, flags);
315                         if (fd == -1) {
316                                 save_errno = errno;
317                                 perror("open");
318                                 exit(save_errno);
319                         }
320                         break;
321                 case 'r':
322                         len = atoi(commands+1);
323                         if (len <= 0)
324                                 len = 1;
325                         if (bufsize < len) {
326                                 buf = realloc(buf, len + ALIGN);
327                                 if (buf == NULL) {
328                                         save_errno = errno;
329                                         perror("allocating buf for read\n");
330                                         exit(save_errno);
331                                 }
332                                 bufsize = len;
333                                 buf_align = (char *)((long)(buf + ALIGN) &
334                                                      ~ALIGN);
335                         }
336                         while (len > 0) {
337                                 rc = read(fd, buf_align, len);
338                                 if (rc == -1) {
339                                         save_errno = errno;
340                                         perror("read");
341                                         exit(save_errno);
342                                 }
343                                 if (rc < len)
344                                         fprintf(stderr, "short read: %u/%u\n",
345                                                 rc, len);
346                                 len -= rc;
347                                 if (verbose >= 2)
348                                         printf("%.*s\n", rc, buf_align);
349                         }
350                         break;
351                 case 'R':
352                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
353                                 junk += mmap_ptr[i];
354                         break;
355                 case 's':
356                         if (stat(fname, &st) == -1) {
357                                 save_errno = errno;
358                                 perror("stat");
359                                 exit(save_errno);
360                         }
361                         break;
362                 case 'S':
363                         if (fstat(fd, &st) == -1) {
364                                 save_errno = errno;
365                                 perror("fstat");
366                                 exit(save_errno);
367                         }
368                         break;
369                 case 't':
370                         if (fchmod(fd, 0) == -1) {
371                                 save_errno = errno;
372                                 perror("fchmod");
373                                 exit(save_errno);
374                         }
375                         break;
376                 case 'T':
377                         len = atoi(commands+1);
378                         if (ftruncate(fd, len) == -1) {
379                                 save_errno = errno;
380                                 printf("ftruncate (%d,%d)\n", fd, len);
381                                 perror("ftruncate");
382                                 exit(save_errno);
383                         }
384                         break;
385                 case 'u':
386                         if (unlink(fname) == -1) {
387                                 save_errno = errno;
388                                 perror("unlink");
389                                 exit(save_errno);
390                         }
391                         break;
392                 case 'U':
393                         if (munmap(mmap_ptr, mmap_len)) {
394                                 save_errno = errno;
395                                 perror("munmap");
396                                 exit(save_errno);
397                         }
398                         break;
399                 case 'v':
400                         verbose++;
401                         break;
402                 case 'w':
403                         len = atoi(commands+1);
404                         if (len <= 0)
405                                 len = 1;
406                         if (bufsize < len) {
407                                 buf = realloc(buf, len + ALIGN);
408                                 if (buf == NULL) {
409                                         save_errno = errno;
410                                         perror("allocating buf for write\n");
411                                         exit(save_errno);
412                                 }
413                                 bufsize = len;
414                                 buf_align = (char *)((long)(buf + ALIGN) &
415                                                      ~ALIGN);
416                                 strncpy(buf_align, msg, bufsize);
417                         }
418                         while (len > 0) {
419                                 rc = write(fd, buf_align, len);
420                                 if (rc == -1) {
421                                         save_errno = errno;
422                                         perror("write");
423                                         exit(save_errno);
424                                 }
425                                 if (rc < len)
426                                         fprintf(stderr, "short write: %u/%u\n",
427                                                 rc, len);
428                                 len -= rc;
429                         }
430                         break;
431                 case 'W':
432                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
433                                 mmap_ptr[i] += junk++;
434                         break;
435                 case 'y':
436                         if (fsync(fd) == -1) {
437                                 save_errno = errno;
438                                 perror("fsync");
439                                 exit(save_errno);
440                         }
441                         break;
442                 case 'Y':
443                         if (fdatasync(fd) == -1) {
444                                 save_errno = errno;
445                                 perror("fdatasync");
446                                 exit(save_errno);
447                         }
448                 case 'z':
449                         len = atoi(commands+1);
450                         if (lseek(fd, len, SEEK_SET) == -1) {
451                                 save_errno = errno;
452                                 perror("lseek");
453                                 exit(save_errno);
454                         }
455                         break;
456                 case '0':
457                 case '1':
458                 case '2':
459                 case '3':
460                 case '4':
461                 case '5':
462                 case '6':
463                 case '7':
464                 case '8':
465                 case '9':
466                         break;
467                 default:
468                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
469                         fprintf(stderr, usage, argv[0]);
470                         exit(1);
471                 }
472         }
473
474         if (buf)
475                 free(buf);
476
477         return 0;
478 }