Whamcloud - gitweb
LU-1187 tests: Add DNE test cases in sanity.
[fs/lustre-release.git] / lustre / tests / multiop.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  */
34
35 #ifndef _GNU_SOURCE
36 #define _GNU_SOURCE /* pull in O_DIRECTORY in bits/fcntl.h */
37 #endif
38 #include <stdio.h>
39 #include <fcntl.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/mman.h>
45 #include <sys/vfs.h>
46 #include <sys/ioctl.h>
47 #include <signal.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <semaphore.h>
51
52 #include <lustre/lustreapi.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 "        G gid get grouplock\n"
71 "        g gid put grouplock\n"
72 "        L  link\n"
73 "        l  symlink\n"
74 "        m  mknod\n"
75 "        M  rw mmap to EOF (must open and stat prior)\n"
76 "        N  rename\n"
77 "        o  open(O_RDONLY)\n"
78 "        O  open(O_CREAT|O_RDWR)\n"
79 "        r[num] read [optional length]\n"
80 "        R  reference entire mmap-ed region\n"
81 "        s  stat\n"
82 "        S  fstat\n"
83 "        t  fchmod\n"
84 "        T[num] ftruncate [optional position, default 0]\n"
85 "        u  unlink\n"
86 "        U  munmap\n"
87 "        v  verbose\n"
88 "        w[num] write optional length\n"
89 "        W  write entire mmap-ed region\n"
90 "        y  fsync\n"
91 "        Y  fdatasync\n"
92 "        z[num] seek [optional position, default 0]\n"
93 "        _  wait for signal\n";
94
95 void usr1_handler(int unused)
96 {
97         int saved_errno = errno;
98
99         /*
100          * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
101          * that the following functions can be safely called inside a signal
102          * handler:
103          *            sem_post()
104          */
105         sem_post(&sem);
106
107         errno = saved_errno;
108 }
109
110 static const char *
111 pop_arg(int argc, char *argv[])
112 {
113         static int cur_arg = 3;
114
115         if (cur_arg >= argc)
116                 return NULL;
117
118         return argv[cur_arg++];
119 }
120
121 struct flag_mapping {
122        const char *string;
123        const int  flag;
124 } flag_table[] = {
125        {"O_RDONLY", O_RDONLY},
126        {"O_WRONLY", O_WRONLY},
127        {"O_RDWR", O_RDWR},
128        {"O_CREAT", O_CREAT},
129        {"O_EXCL", O_EXCL},
130        {"O_NOCTTY", O_NOCTTY},
131        {"O_TRUNC", O_TRUNC},
132        {"O_APPEND", O_APPEND},
133        {"O_NONBLOCK", O_NONBLOCK},
134        {"O_NDELAY", O_NDELAY},
135        {"O_SYNC", O_SYNC},
136 #ifdef O_DIRECT
137        {"O_DIRECT", O_DIRECT},
138 #endif
139        {"O_LARGEFILE", O_LARGEFILE},
140        {"O_DIRECTORY", O_DIRECTORY},
141        {"O_NOFOLLOW", O_NOFOLLOW},
142        {"", -1}
143 };
144
145 int get_flags(char *data, int *rflags)
146 {
147         char *cloned_flags;
148         char *tmp;
149         int flag_set = 0;
150         int flags = 0;
151         int size = 0;
152
153         cloned_flags = strdup(data);
154         if (cloned_flags == NULL) {
155                 fprintf(stderr, "Insufficient memory.\n");
156                 exit(-1);
157         }
158
159         for (tmp = strtok(cloned_flags, ":"); tmp;
160              tmp = strtok(NULL, ":")) {
161                 int i;
162
163                 size = tmp - cloned_flags;
164                 for (i = 0; flag_table[i].flag != -1; i++) {
165                         if (!strcmp(tmp, flag_table[i].string)){
166                                 flags |= flag_table[i].flag;
167                                 size += strlen(flag_table[i].string);
168                                 flag_set = 1;
169                                 break;
170                         }
171                 }
172         }
173         free(cloned_flags);
174
175         if (!flag_set) {
176                 *rflags = O_RDONLY;
177                 return 0;
178         }
179
180         *rflags = flags;
181         return size;
182 }
183
184 #define POP_ARG() (pop_arg(argc, argv))
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         int gid = 0;
199
200         if (argc < 3) {
201                 fprintf(stderr, usage, argv[0]);
202                 exit(1);
203         }
204
205         memset(&st, 0, sizeof(st));
206         sem_init(&sem, 0, 0);
207         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
208         sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
209                   NULL);
210
211         fname = argv[1];
212
213         for (commands = argv[2]; *commands; commands++) {
214                 switch (*commands) {
215                 case '_':
216                         if (verbose) {
217                                 printf("PAUSING\n");
218                                 fflush(stdout);
219                         }
220                         while (sem_wait(&sem) == -1 && errno == EINTR);
221                         break;
222                 case 'c':
223                         if (close(fd) == -1) {
224                                 save_errno = errno;
225                                 perror("close");
226                                 exit(save_errno);
227                         }
228                         fd = -1;
229                         break;
230                 case 'C':
231                         len = atoi(commands+1);
232                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
233                                              0, 0, len, 0);
234                         if (fd == -1) {
235                                 save_errno = errno;
236                                 perror("create stripe file");
237                                 exit(save_errno);
238                         }
239                         break;
240                 case 'd':
241                         if (mkdir(fname, 0755) == -1) {
242                                 save_errno = errno;
243                                 perror("mkdir(0755)");
244                                 exit(save_errno);
245                         }
246                         break;
247                 case 'D':
248                         fd = open(fname, O_DIRECTORY);
249                         if (fd == -1) {
250                                 save_errno = errno;
251                                 perror("open(O_DIRECTORY)");
252                                 exit(save_errno);
253                         }
254                         break;
255                 case 'f':
256                         if (statfs(fname, &stfs) == -1) {
257                                 save_errno = errno;
258                                 perror("statfs()");
259                                 exit(save_errno);
260                         }
261                         break;
262                 case 'G':
263                         gid = atoi(commands+1);
264                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
265                                 save_errno = errno;
266                                 perror("ioctl(GROUP_LOCK)");
267                                 exit(save_errno);
268                         }
269                         break;
270                 case 'g':
271                         gid = atoi(commands+1);
272                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
273                                 save_errno = errno;
274                                 perror("ioctl(GROUP_UNLOCK)");
275                                 exit(save_errno);
276                         }
277                         break;
278                 case 'l':
279                         newfile = POP_ARG();
280                         if (!newfile)
281                                 newfile = fname;
282                         if (symlink(fname, newfile)) {
283                                 save_errno = errno;
284                                 perror("symlink()");
285                                 exit(save_errno);
286                         }
287                         break;
288                 case 'L':
289                         newfile = POP_ARG();
290                         if (!newfile)
291                                 newfile = fname;
292                         if (link(fname, newfile)) {
293                                 save_errno = errno;
294                                 perror("symlink()");
295                                 exit(save_errno);
296                         }
297                         break;
298                 case 'm':
299                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
300                                 save_errno = errno;
301                                 perror("mknod(S_IFREG|0644, 0)");
302                                 exit(save_errno);
303                         }
304                         break;
305                 case 'M':
306                         if (st.st_size == 0) {
307                                 fprintf(stderr, "mmap without preceeding stat, or on"
308                                         " zero length file.\n");
309                                 exit(-1);
310                         }
311                         mmap_len = st.st_size;
312                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
313                                         MAP_SHARED, fd, 0);
314                         if (mmap_ptr == MAP_FAILED) {
315                                 save_errno = errno;
316                                 perror("mmap");
317                                 exit(save_errno);
318                         }
319                         break;
320                 case 'N':
321                         newfile = POP_ARG();
322                         if (!newfile)
323                                 newfile = fname;
324                         if (rename (fname, newfile)) {
325                                 save_errno = errno;
326                                 perror("rename()");
327                                 exit(save_errno);
328                         }
329                         break;
330                 case 'O':
331                         fd = open(fname, O_CREAT|O_RDWR, 0644);
332                         if (fd == -1) {
333                                 save_errno = errno;
334                                 perror("open(O_RDWR|O_CREAT)");
335                                 exit(save_errno);
336                         }
337                         break;
338                 case 'o':
339                         len = get_flags(commands+1, &flags);
340                         commands += len;
341                         if (flags & O_CREAT)
342                                 fd = open(fname, flags, 0666);
343                         else
344                                 fd = open(fname, flags);
345                         if (fd == -1) {
346                                 save_errno = errno;
347                                 perror("open");
348                                 exit(save_errno);
349                         }
350                         break;
351                 case 'r':
352                         len = atoi(commands+1);
353                         if (len <= 0)
354                                 len = 1;
355                         if (bufsize < len) {
356                                 buf = realloc(buf, len + ALIGN);
357                                 if (buf == NULL) {
358                                         save_errno = errno;
359                                         perror("allocating buf for read\n");
360                                         exit(save_errno);
361                                 }
362                                 bufsize = len;
363                                 buf_align = (char *)((long)(buf + ALIGN) &
364                                                      ~ALIGN);
365                         }
366                         while (len > 0) {
367                                 rc = read(fd, buf_align, len);
368                                 if (rc == -1) {
369                                         save_errno = errno;
370                                         perror("read");
371                                         exit(save_errno);
372                                 }
373                                 if (rc < len) {
374                                         fprintf(stderr, "short read: %u/%u\n",
375                                                 rc, len);
376                                         if (rc == 0)
377                                                 exit(ENODATA);
378                                 }
379                                 len -= rc;
380                                 if (verbose >= 2)
381                                         printf("%.*s\n", rc, buf_align);
382                         }
383                         break;
384                 case 'R':
385                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
386                                 junk += mmap_ptr[i];
387                         break;
388                 case 's':
389                         if (stat(fname, &st) == -1) {
390                                 save_errno = errno;
391                                 perror("stat");
392                                 exit(save_errno);
393                         }
394                         break;
395                 case 'S':
396                         if (fstat(fd, &st) == -1) {
397                                 save_errno = errno;
398                                 perror("fstat");
399                                 exit(save_errno);
400                         }
401                         break;
402                 case 't':
403                         if (fchmod(fd, 0) == -1) {
404                                 save_errno = errno;
405                                 perror("fchmod");
406                                 exit(save_errno);
407                         }
408                         break;
409                 case 'T':
410                         len = atoi(commands+1);
411                         if (ftruncate(fd, len) == -1) {
412                                 save_errno = errno;
413                                 printf("ftruncate (%d,%d)\n", fd, len);
414                                 perror("ftruncate");
415                                 exit(save_errno);
416                         }
417                         break;
418                 case 'u':
419                         if (unlink(fname) == -1) {
420                                 save_errno = errno;
421                                 perror("unlink");
422                                 exit(save_errno);
423                         }
424                         break;
425                 case 'U':
426                         if (munmap(mmap_ptr, mmap_len)) {
427                                 save_errno = errno;
428                                 perror("munmap");
429                                 exit(save_errno);
430                         }
431                         break;
432                 case 'v':
433                         verbose++;
434                         break;
435                 case 'w':
436                         len = atoi(commands+1);
437                         if (len <= 0)
438                                 len = 1;
439                         if (bufsize < len) {
440                                 buf = realloc(buf, len + ALIGN);
441                                 if (buf == NULL) {
442                                         save_errno = errno;
443                                         perror("allocating buf for write\n");
444                                         exit(save_errno);
445                                 }
446                                 bufsize = len;
447                                 buf_align = (char *)((long)(buf + ALIGN) &
448                                                      ~ALIGN);
449                                 strncpy(buf_align, msg, bufsize);
450                         }
451                         while (len > 0) {
452                                 rc = write(fd, buf_align, len);
453                                 if (rc == -1) {
454                                         save_errno = errno;
455                                         perror("write");
456                                         exit(save_errno);
457                                 }
458                                 if (rc < len)
459                                         fprintf(stderr, "short write: %u/%u\n",
460                                                 rc, len);
461                                 len -= rc;
462                         }
463                         break;
464                 case 'W':
465                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
466                                 mmap_ptr[i] += junk++;
467                         break;
468                 case 'y':
469                         if (fsync(fd) == -1) {
470                                 save_errno = errno;
471                                 perror("fsync");
472                                 exit(save_errno);
473                         }
474                         break;
475                 case 'Y':
476                         if (fdatasync(fd) == -1) {
477                                 save_errno = errno;
478                                 perror("fdatasync");
479                                 exit(save_errno);
480                         }
481                 case 'z':
482                         len = atoi(commands+1);
483                         if (lseek(fd, len, SEEK_SET) == -1) {
484                                 save_errno = errno;
485                                 perror("lseek");
486                                 exit(save_errno);
487                         }
488                         break;
489                 case '0':
490                 case '1':
491                 case '2':
492                 case '3':
493                 case '4':
494                 case '5':
495                 case '6':
496                 case '7':
497                 case '8':
498                 case '9':
499                         break;
500                 default:
501                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
502                         fprintf(stderr, usage, argv[0]);
503                         exit(1);
504                 }
505         }
506
507         if (buf)
508                 free(buf);
509
510         return 0;
511 }