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