Whamcloud - gitweb
LU-787 clio: ftruncate shouldn't block when grouplock is hold
[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 (c) 2003, 2010, Oracle and/or its affiliates. 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 "        G gid get grouplock\n"
72 "        g gid put grouplock\n"
73 "        L  link\n"
74 "        l  symlink\n"
75 "        m  mknod\n"
76 "        M  rw mmap to EOF (must open and stat prior)\n"
77 "        N  rename\n"
78 "        o  open(O_RDONLY)\n"
79 "        O  open(O_CREAT|O_RDWR)\n"
80 "        r[num] read [optional length]\n"
81 "        R  reference entire mmap-ed region\n"
82 "        s  stat\n"
83 "        S  fstat\n"
84 "        t  fchmod\n"
85 "        T[num] ftruncate [optional position, default 0]\n"
86 "        u  unlink\n"
87 "        U  munmap\n"
88 "        v  verbose\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
187 int main(int argc, char **argv)
188 {
189         char *fname, *commands;
190         const char *newfile;
191         struct stat st;
192         struct statfs stfs;
193         size_t mmap_len = 0, i;
194         unsigned char *mmap_ptr = NULL, junk = 0;
195         int rc, len, fd = -1;
196         int flags;
197         int save_errno;
198         int verbose = 0;
199         int gid = 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
212         fname = argv[1];
213
214         for (commands = argv[2]; *commands; commands++) {
215                 switch (*commands) {
216                 case '_':
217                         if (verbose) {
218                                 printf("PAUSING\n");
219                                 fflush(stdout);
220                         }
221                         while (sem_wait(&sem) == -1 && errno == EINTR);
222                         break;
223                 case 'c':
224                         if (close(fd) == -1) {
225                                 save_errno = errno;
226                                 perror("close");
227                                 exit(save_errno);
228                         }
229                         fd = -1;
230                         break;
231                 case 'C':
232                         len = atoi(commands+1);
233                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
234                                              0, 0, len, 0);
235                         if (fd == -1) {
236                                 save_errno = errno;
237                                 perror("create stripe file");
238                                 exit(save_errno);
239                         }
240                         break;
241                 case 'd':
242                         if (mkdir(fname, 0755) == -1) {
243                                 save_errno = errno;
244                                 perror("mkdir(0755)");
245                                 exit(save_errno);
246                         }
247                         break;
248                 case 'D':
249                         fd = open(fname, O_DIRECTORY);
250                         if (fd == -1) {
251                                 save_errno = errno;
252                                 perror("open(O_DIRECTORY)");
253                                 exit(save_errno);
254                         }
255                         break;
256                 case 'f':
257                         if (statfs(fname, &stfs) == -1) {
258                                 save_errno = errno;
259                                 perror("statfs()");
260                                 exit(save_errno);
261                         }
262                         break;
263                 case 'G':
264                         gid = atoi(commands+1);
265                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
266                                 save_errno = errno;
267                                 perror("ioctl(GROUP_LOCK)");
268                                 exit(save_errno);
269                         }
270                         break;
271                 case 'g':
272                         gid = atoi(commands+1);
273                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
274                                 save_errno = errno;
275                                 perror("ioctl(GROUP_UNLOCK)");
276                                 exit(save_errno);
277                         }
278                         break;
279                 case 'l':
280                         newfile = POP_ARG();
281                         if (!newfile)
282                                 newfile = fname;
283                         if (symlink(fname, newfile)) {
284                                 save_errno = errno;
285                                 perror("symlink()");
286                                 exit(save_errno);
287                         }
288                         break;
289                 case 'L':
290                         newfile = POP_ARG();
291                         if (!newfile)
292                                 newfile = fname;
293                         if (link(fname, newfile)) {
294                                 save_errno = errno;
295                                 perror("symlink()");
296                                 exit(save_errno);
297                         }
298                         break;
299                 case 'm':
300                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
301                                 save_errno = errno;
302                                 perror("mknod(S_IFREG|0644, 0)");
303                                 exit(save_errno);
304                         }
305                         break;
306                 case 'M':
307                         if (st.st_size == 0) {
308                                 fprintf(stderr, "mmap without preceeding stat, or on"
309                                         " zero length file.\n");
310                                 exit(-1);
311                         }
312                         mmap_len = st.st_size;
313                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
314                                         MAP_SHARED, fd, 0);
315                         if (mmap_ptr == MAP_FAILED) {
316                                 save_errno = errno;
317                                 perror("mmap");
318                                 exit(save_errno);
319                         }
320                         break;
321                 case 'N':
322                         newfile = POP_ARG();
323                         if (!newfile)
324                                 newfile = fname;
325                         if (rename (fname, newfile)) {
326                                 save_errno = errno;
327                                 perror("rename()");
328                                 exit(save_errno);
329                         }
330                         break;
331                 case 'O':
332                         fd = open(fname, O_CREAT|O_RDWR, 0644);
333                         if (fd == -1) {
334                                 save_errno = errno;
335                                 perror("open(O_RDWR|O_CREAT)");
336                                 exit(save_errno);
337                         }
338                         break;
339                 case 'o':
340                         len = get_flags(commands+1, &flags);
341                         commands += len;
342                         if (flags & O_CREAT)
343                                 fd = open(fname, flags, 0666);
344                         else
345                                 fd = open(fname, flags);
346                         if (fd == -1) {
347                                 save_errno = errno;
348                                 perror("open");
349                                 exit(save_errno);
350                         }
351                         break;
352                 case 'r':
353                         len = atoi(commands+1);
354                         if (len <= 0)
355                                 len = 1;
356                         if (bufsize < len) {
357                                 buf = realloc(buf, len + ALIGN);
358                                 if (buf == NULL) {
359                                         save_errno = errno;
360                                         perror("allocating buf for read\n");
361                                         exit(save_errno);
362                                 }
363                                 bufsize = len;
364                                 buf_align = (char *)((long)(buf + ALIGN) &
365                                                      ~ALIGN);
366                         }
367                         while (len > 0) {
368                                 rc = read(fd, buf_align, len);
369                                 if (rc == -1) {
370                                         save_errno = errno;
371                                         perror("read");
372                                         exit(save_errno);
373                                 }
374                                 if (rc < len)
375                                         fprintf(stderr, "short read: %u/%u\n",
376                                                 rc, len);
377                                 len -= rc;
378                                 if (verbose >= 2)
379                                         printf("%.*s\n", rc, buf_align);
380                         }
381                         break;
382                 case 'R':
383                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
384                                 junk += mmap_ptr[i];
385                         break;
386                 case 's':
387                         if (stat(fname, &st) == -1) {
388                                 save_errno = errno;
389                                 perror("stat");
390                                 exit(save_errno);
391                         }
392                         break;
393                 case 'S':
394                         if (fstat(fd, &st) == -1) {
395                                 save_errno = errno;
396                                 perror("fstat");
397                                 exit(save_errno);
398                         }
399                         break;
400                 case 't':
401                         if (fchmod(fd, 0) == -1) {
402                                 save_errno = errno;
403                                 perror("fchmod");
404                                 exit(save_errno);
405                         }
406                         break;
407                 case 'T':
408                         len = atoi(commands+1);
409                         if (ftruncate(fd, len) == -1) {
410                                 save_errno = errno;
411                                 printf("ftruncate (%d,%d)\n", fd, len);
412                                 perror("ftruncate");
413                                 exit(save_errno);
414                         }
415                         break;
416                 case 'u':
417                         if (unlink(fname) == -1) {
418                                 save_errno = errno;
419                                 perror("unlink");
420                                 exit(save_errno);
421                         }
422                         break;
423                 case 'U':
424                         if (munmap(mmap_ptr, mmap_len)) {
425                                 save_errno = errno;
426                                 perror("munmap");
427                                 exit(save_errno);
428                         }
429                         break;
430                 case 'v':
431                         verbose++;
432                         break;
433                 case 'w':
434                         len = atoi(commands+1);
435                         if (len <= 0)
436                                 len = 1;
437                         if (bufsize < len) {
438                                 buf = realloc(buf, len + ALIGN);
439                                 if (buf == NULL) {
440                                         save_errno = errno;
441                                         perror("allocating buf for write\n");
442                                         exit(save_errno);
443                                 }
444                                 bufsize = len;
445                                 buf_align = (char *)((long)(buf + ALIGN) &
446                                                      ~ALIGN);
447                                 strncpy(buf_align, msg, bufsize);
448                         }
449                         while (len > 0) {
450                                 rc = write(fd, buf_align, len);
451                                 if (rc == -1) {
452                                         save_errno = errno;
453                                         perror("write");
454                                         exit(save_errno);
455                                 }
456                                 if (rc < len)
457                                         fprintf(stderr, "short write: %u/%u\n",
458                                                 rc, len);
459                                 len -= rc;
460                         }
461                         break;
462                 case 'W':
463                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
464                                 mmap_ptr[i] += junk++;
465                         break;
466                 case 'y':
467                         if (fsync(fd) == -1) {
468                                 save_errno = errno;
469                                 perror("fsync");
470                                 exit(save_errno);
471                         }
472                         break;
473                 case 'Y':
474                         if (fdatasync(fd) == -1) {
475                                 save_errno = errno;
476                                 perror("fdatasync");
477                                 exit(save_errno);
478                         }
479                 case 'z':
480                         len = atoi(commands+1);
481                         if (lseek(fd, len, SEEK_SET) == -1) {
482                                 save_errno = errno;
483                                 perror("lseek");
484                                 exit(save_errno);
485                         }
486                         break;
487                 case '0':
488                 case '1':
489                 case '2':
490                 case '3':
491                 case '4':
492                 case '5':
493                 case '6':
494                 case '7':
495                 case '8':
496                 case '9':
497                         break;
498                 default:
499                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
500                         fprintf(stderr, usage, argv[0]);
501                         exit(1);
502                 }
503         }
504
505         if (buf)
506                 free(buf);
507
508         return 0;
509 }