Whamcloud - gitweb
4d6fece025512ba38e9952ac5b60864e394098c6
[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  * Copyright (c) 2012, Intel Corporation.
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/ioctl.h>
49 #include <signal.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <semaphore.h>
53
54 #include <lustre/lustreapi.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
64 char usage[] =
65 "Usage: %s filename command-sequence\n"
66 "    command-sequence items:\n"
67 "        c  close\n"
68 "        C[num] create with optional stripes\n"
69 "        d  mkdir\n"
70 "        D  open(O_DIRECTORY)\n"
71 "        f  statfs\n"
72 "        G gid get grouplock\n"
73 "        g gid put grouplock\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 "        v  verbose\n"
90 "        w[num] write optional length\n"
91 "        W  write entire mmap-ed region\n"
92 "        y  fsync\n"
93 "        Y  fdatasync\n"
94 "        z[num] seek [optional position, default 0]\n"
95 "        _  wait for signal\n";
96
97 void usr1_handler(int unused)
98 {
99         int saved_errno = errno;
100
101         /*
102          * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
103          * that the following functions can be safely called inside a signal
104          * handler:
105          *            sem_post()
106          */
107         sem_post(&sem);
108
109         errno = saved_errno;
110 }
111
112 static const char *
113 pop_arg(int argc, char *argv[])
114 {
115         static int cur_arg = 3;
116
117         if (cur_arg >= argc)
118                 return NULL;
119
120         return argv[cur_arg++];
121 }
122
123 struct flag_mapping {
124        const char *string;
125        const int  flag;
126 } flag_table[] = {
127        {"O_RDONLY", O_RDONLY},
128        {"O_WRONLY", O_WRONLY},
129        {"O_RDWR", O_RDWR},
130        {"O_CREAT", O_CREAT},
131        {"O_EXCL", O_EXCL},
132        {"O_NOCTTY", O_NOCTTY},
133        {"O_TRUNC", O_TRUNC},
134        {"O_APPEND", O_APPEND},
135        {"O_NONBLOCK", O_NONBLOCK},
136        {"O_NDELAY", O_NDELAY},
137        {"O_SYNC", O_SYNC},
138 #ifdef O_DIRECT
139        {"O_DIRECT", O_DIRECT},
140 #endif
141        {"O_LARGEFILE", O_LARGEFILE},
142        {"O_DIRECTORY", O_DIRECTORY},
143        {"O_NOFOLLOW", O_NOFOLLOW},
144        {"", -1}
145 };
146
147 int get_flags(char *data, int *rflags)
148 {
149         char *cloned_flags;
150         char *tmp;
151         int flag_set = 0;
152         int flags = 0;
153         int size = 0;
154
155         cloned_flags = strdup(data);
156         if (cloned_flags == NULL) {
157                 fprintf(stderr, "Insufficient memory.\n");
158                 exit(-1);
159         }
160
161         for (tmp = strtok(cloned_flags, ":"); tmp;
162              tmp = strtok(NULL, ":")) {
163                 int i;
164
165                 size = tmp - cloned_flags;
166                 for (i = 0; flag_table[i].flag != -1; i++) {
167                         if (!strcmp(tmp, flag_table[i].string)){
168                                 flags |= flag_table[i].flag;
169                                 size += strlen(flag_table[i].string);
170                                 flag_set = 1;
171                                 break;
172                         }
173                 }
174         }
175         free(cloned_flags);
176
177         if (!flag_set) {
178                 *rflags = O_RDONLY;
179                 return 0;
180         }
181
182         *rflags = flags;
183         return size;
184 }
185
186 #define POP_ARG() (pop_arg(argc, argv))
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         int gid = 0;
201
202         if (argc < 3) {
203                 fprintf(stderr, usage, argv[0]);
204                 exit(1);
205         }
206
207         memset(&st, 0, sizeof(st));
208         sem_init(&sem, 0, 0);
209         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
210         sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
211                   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 'G':
265                         gid = atoi(commands+1);
266                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
267                                 save_errno = errno;
268                                 perror("ioctl(GROUP_LOCK)");
269                                 exit(save_errno);
270                         }
271                         break;
272                 case 'g':
273                         gid = atoi(commands+1);
274                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
275                                 save_errno = errno;
276                                 perror("ioctl(GROUP_UNLOCK)");
277                                 exit(save_errno);
278                         }
279                         break;
280                 case 'l':
281                         newfile = POP_ARG();
282                         if (!newfile)
283                                 newfile = fname;
284                         if (symlink(fname, newfile)) {
285                                 save_errno = errno;
286                                 perror("symlink()");
287                                 exit(save_errno);
288                         }
289                         break;
290                 case 'L':
291                         newfile = POP_ARG();
292                         if (!newfile)
293                                 newfile = fname;
294                         if (link(fname, newfile)) {
295                                 save_errno = errno;
296                                 perror("symlink()");
297                                 exit(save_errno);
298                         }
299                         break;
300                 case 'm':
301                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
302                                 save_errno = errno;
303                                 perror("mknod(S_IFREG|0644, 0)");
304                                 exit(save_errno);
305                         }
306                         break;
307                 case 'M':
308                         if (st.st_size == 0) {
309                                 fprintf(stderr, "mmap without preceeding stat, or on"
310                                         " zero length file.\n");
311                                 exit(-1);
312                         }
313                         mmap_len = st.st_size;
314                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
315                                         MAP_SHARED, fd, 0);
316                         if (mmap_ptr == MAP_FAILED) {
317                                 save_errno = errno;
318                                 perror("mmap");
319                                 exit(save_errno);
320                         }
321                         break;
322                 case 'N':
323                         newfile = POP_ARG();
324                         if (!newfile)
325                                 newfile = fname;
326                         if (rename (fname, newfile)) {
327                                 save_errno = errno;
328                                 perror("rename()");
329                                 exit(save_errno);
330                         }
331                         break;
332                 case 'O':
333                         fd = open(fname, O_CREAT|O_RDWR, 0644);
334                         if (fd == -1) {
335                                 save_errno = errno;
336                                 perror("open(O_RDWR|O_CREAT)");
337                                 exit(save_errno);
338                         }
339                         break;
340                 case 'o':
341                         len = get_flags(commands+1, &flags);
342                         commands += len;
343                         if (flags & O_CREAT)
344                                 fd = open(fname, flags, 0666);
345                         else
346                                 fd = open(fname, flags);
347                         if (fd == -1) {
348                                 save_errno = errno;
349                                 perror("open");
350                                 exit(save_errno);
351                         }
352                         break;
353                 case 'r':
354                         len = atoi(commands+1);
355                         if (len <= 0)
356                                 len = 1;
357                         if (bufsize < len) {
358                                 buf = realloc(buf, len + ALIGN);
359                                 if (buf == NULL) {
360                                         save_errno = errno;
361                                         perror("allocating buf for read\n");
362                                         exit(save_errno);
363                                 }
364                                 bufsize = len;
365                                 buf_align = (char *)((long)(buf + ALIGN) &
366                                                      ~ALIGN);
367                         }
368                         while (len > 0) {
369                                 rc = read(fd, buf_align, len);
370                                 if (rc == -1) {
371                                         save_errno = errno;
372                                         perror("read");
373                                         exit(save_errno);
374                                 }
375                                 if (rc < len) {
376                                         fprintf(stderr, "short read: %u/%u\n",
377                                                 rc, len);
378                                         if (rc == 0)
379                                                 exit(ENODATA);
380                                 }
381                                 len -= rc;
382                                 if (verbose >= 2)
383                                         printf("%.*s\n", rc, buf_align);
384                         }
385                         break;
386                 case 'R':
387                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
388                                 junk += mmap_ptr[i];
389                         break;
390                 case 's':
391                         if (stat(fname, &st) == -1) {
392                                 save_errno = errno;
393                                 perror("stat");
394                                 exit(save_errno);
395                         }
396                         break;
397                 case 'S':
398                         if (fstat(fd, &st) == -1) {
399                                 save_errno = errno;
400                                 perror("fstat");
401                                 exit(save_errno);
402                         }
403                         break;
404                 case 't':
405                         if (fchmod(fd, 0) == -1) {
406                                 save_errno = errno;
407                                 perror("fchmod");
408                                 exit(save_errno);
409                         }
410                         break;
411                 case 'T':
412                         len = atoi(commands+1);
413                         if (ftruncate(fd, len) == -1) {
414                                 save_errno = errno;
415                                 printf("ftruncate (%d,%d)\n", fd, len);
416                                 perror("ftruncate");
417                                 exit(save_errno);
418                         }
419                         break;
420                 case 'u':
421                         if (unlink(fname) == -1) {
422                                 save_errno = errno;
423                                 perror("unlink");
424                                 exit(save_errno);
425                         }
426                         break;
427                 case 'U':
428                         if (munmap(mmap_ptr, mmap_len)) {
429                                 save_errno = errno;
430                                 perror("munmap");
431                                 exit(save_errno);
432                         }
433                         break;
434                 case 'v':
435                         verbose++;
436                         break;
437                 case 'w':
438                         len = atoi(commands+1);
439                         if (len <= 0)
440                                 len = 1;
441                         if (bufsize < len) {
442                                 buf = realloc(buf, len + ALIGN);
443                                 if (buf == NULL) {
444                                         save_errno = errno;
445                                         perror("allocating buf for write\n");
446                                         exit(save_errno);
447                                 }
448                                 bufsize = len;
449                                 buf_align = (char *)((long)(buf + ALIGN) &
450                                                      ~ALIGN);
451                                 strncpy(buf_align, msg, bufsize);
452                         }
453                         while (len > 0) {
454                                 rc = write(fd, buf_align, len);
455                                 if (rc == -1) {
456                                         save_errno = errno;
457                                         perror("write");
458                                         exit(save_errno);
459                                 }
460                                 if (rc < len)
461                                         fprintf(stderr, "short write: %u/%u\n",
462                                                 rc, len);
463                                 len -= rc;
464                         }
465                         break;
466                 case 'W':
467                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
468                                 mmap_ptr[i] += junk++;
469                         break;
470                 case 'y':
471                         if (fsync(fd) == -1) {
472                                 save_errno = errno;
473                                 perror("fsync");
474                                 exit(save_errno);
475                         }
476                         break;
477                 case 'Y':
478                         if (fdatasync(fd) == -1) {
479                                 save_errno = errno;
480                                 perror("fdatasync");
481                                 exit(save_errno);
482                         }
483                 case 'z':
484                         len = atoi(commands+1);
485                         if (lseek(fd, len, SEEK_SET) == -1) {
486                                 save_errno = errno;
487                                 perror("lseek");
488                                 exit(save_errno);
489                         }
490                         break;
491                 case '0':
492                 case '1':
493                 case '2':
494                 case '3':
495                 case '4':
496                 case '5':
497                 case '6':
498                 case '7':
499                 case '8':
500                 case '9':
501                         break;
502                 default:
503                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
504                         fprintf(stderr, usage, argv[0]);
505                         exit(1);
506                 }
507         }
508
509         if (buf)
510                 free(buf);
511
512         return 0;
513 }