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