Whamcloud - gitweb
LU-17038 tests: remove mlink utility
[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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  */
31
32 #ifndef _GNU_SOURCE
33 #define _GNU_SOURCE /* pull in O_DIRECTORY in bits/fcntl.h */
34 #endif
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <limits.h>
38 #include <malloc.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/mman.h>
44 #include <sys/vfs.h>
45 #include <sys/ioctl.h>
46 #include <sys/xattr.h>
47 #include <sys/file.h>
48 #include <signal.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <semaphore.h>
52 #include <time.h>
53 #include <err.h>
54 #include <dirent.h>
55 #include <ctype.h>
56
57 #include <lustre/lustreapi.h>
58
59 #define T1 "write data before unlink\n"
60 #define T2 "write data after unlink\n"
61 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";
62 char *buf, *buf_align;
63 int bufsize;
64 sem_t sem;
65 #define ALIGN_LEN 65535
66 #define XATTR "user.multiop"
67
68 char usage[] =
69 "Usage: %s filename command-sequence [path...]\n"
70 "    command-sequence items:\n"
71 "        A  fsetxattr(\"user.multiop\")\n"
72 "        a[num] fgetxattr(\"user.multiop\") [optional buffer size, default 0]\n"
73 "        c  close\n"
74 "        B[num] call setstripe ioctl to create stripes\n"
75 "        C[num] create with optional stripes\n"
76 "        d  mkdir\n"
77 "        D  open(O_DIRECTORY)\n"
78 "        e[R|W|U] apply lease. R: Read; W: Write; U: Unlock\n"
79 "        E[+|-] get lease. +/-: expect lease to (not) exist\n"
80 "        f  statfs\n"
81 "        F  print FID\n"
82 "        G gid get grouplock\n"
83 "        g gid put grouplock\n"
84 "        H[num] create HSM released file with num stripes\n"
85 "        K  link path to filename\n"
86 "        L  link\n"
87 "        l  symlink filename to path\n"
88 "        m  mknod\n"
89 "        M  rw mmap to EOF (must open and stat prior)\n"
90 "        n  rename path to filename\n"
91 "        N  rename filename to path\n"
92 "        o  open(O_RDONLY)\n"
93 "        O  open(O_CREAT|O_RDWR)\n"
94 "        p  print return value of last command\n"
95 "        Q  open filename (should be dir), stat first entry to init statahead"
96 "        r[num] read [optional length]\n"
97 "        R  reference entire mmap-ed region\n"
98 "        s  stat\n"
99 "        S  fstat\n"
100 "        t  fchmod\n"
101 "        T[num] ftruncate [optional position, default 0]\n"
102 "        u  unlink\n"
103 "        U  munmap\n"
104 "        v  verbose\n"
105 "        V  open a volatile file\n"
106 "        w[num] write optional length\n"
107 "        P[num] like w, but only one write call\n"
108 "        x  get file data version\n"
109 "        W  write entire mmap-ed region\n"
110 "        y  fsync\n"
111 "        Y  fdatasync\n"
112 "        z[num] lseek(SEEK_SET) [optional offset, default 0]\n"
113 "        Z[num] lseek(SEEK_CUR) [optional offset, default 0]\n"
114 "        _  wait for signal\n";
115
116 static void usr1_handler(int unused)
117 {
118         int saved_errno = errno;
119
120         /*
121          * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
122          * that the following functions can be safely called inside a signal
123          * handler:
124          *            sem_post()
125          */
126         sem_post(&sem);
127
128         errno = saved_errno;
129 }
130
131 static const char *
132 pop_arg(int argc, char *argv[])
133 {
134         static int cur_arg = 3;
135
136         if (cur_arg >= argc)
137                 return NULL;
138
139         return argv[cur_arg++];
140 }
141
142 struct flag_mapping {
143         const char *string;
144         const int  flag;
145 } flag_table[] = {
146         {"O_RDONLY", O_RDONLY},
147         {"O_WRONLY", O_WRONLY},
148         {"O_RDWR", O_RDWR},
149         {"O_CREAT", O_CREAT},
150         {"O_EXCL", O_EXCL},
151         {"O_NOCTTY", O_NOCTTY},
152         {"O_TRUNC", O_TRUNC},
153         {"O_APPEND", O_APPEND},
154         {"O_NONBLOCK", O_NONBLOCK},
155         {"O_NDELAY", O_NDELAY},
156         {"O_SYNC", O_SYNC},
157 #ifdef O_DIRECT
158         {"O_DIRECT", O_DIRECT},
159 #endif
160 #ifdef O_NOATIME
161         {"O_NOATIME", O_NOATIME},
162 #endif
163         {"O_LARGEFILE", O_LARGEFILE},
164         {"O_DIRECTORY", O_DIRECTORY},
165         {"O_NOFOLLOW", O_NOFOLLOW},
166         {"O_LOV_DELAY_CREATE", O_LOV_DELAY_CREATE},
167         {"", -1}
168 };
169
170 static int get_flags(char *data, int *rflags)
171 {
172         char *cloned_flags;
173         char *tmp;
174         int flag_set = 0;
175         int flags = 0;
176         int size = 0;
177
178         cloned_flags = strdup(data);
179         if (!cloned_flags) {
180                 fprintf(stderr, "Insufficient memory.\n");
181                 exit(-1);
182         }
183
184         for (tmp = strtok(cloned_flags, ":"); tmp;
185              tmp = strtok(NULL, ":")) {
186                 int i;
187
188                 size = tmp - cloned_flags;
189                 for (i = 0; flag_table[i].flag != -1; i++) {
190                         if (!strcmp(tmp, flag_table[i].string)) {
191                                 flags |= flag_table[i].flag;
192                                 size += strlen(flag_table[i].string);
193                                 flag_set = 1;
194                                 break;
195                         }
196                 }
197         }
198         free(cloned_flags);
199
200         if (!flag_set) {
201                 *rflags = O_RDONLY;
202                 return 0;
203         }
204
205         *rflags = flags;
206         return size;
207 }
208
209 static int statahead(char *dname)
210 {
211         DIR *d;
212         struct dirent *dent;
213         struct stat st;
214         char *buf;
215         int rc;
216
217         rc = 0;
218         d = opendir(dname);
219         if (!d)
220                 return errno;
221         dent = readdir(d);
222         if (!dent) {
223                 rc = errno;
224                 goto out_closedir;
225         }
226         if (asprintf(&buf, "%s/%s", dname, dent->d_name) == -1) {
227                 rc = errno;
228                 goto out_closedir;
229         }
230         if (stat(buf, &st))
231                 rc = errno;
232         free(buf);
233 out_closedir:
234         closedir(d);
235         return rc;
236 }
237
238 #define POP_ARG() (pop_arg(argc, argv))
239
240 int main(int argc, char **argv)
241 {
242         char *fname, *commands;
243         const char *newfile;
244         const char *oldpath;
245         struct stat st;
246         struct statfs stfs;
247         size_t mmap_len = 0, i;
248         unsigned char *mmap_ptr = NULL, junk = 1;
249         int len, fd = -1;
250         int flags;
251         int save_errno;
252         int verbose = 0;
253         int gid = 0;
254         struct lu_fid fid;
255         struct timespec ts;
256         struct lov_user_md_v3 lum;
257         char *xattr_buf = NULL;
258         size_t xattr_buf_size = 0;
259         long long rc = 0;
260         long long last_rc;
261         bool unaligned;
262         int msg_len = strlen(msg);
263         size_t total_bytes;
264
265         if (argc < 3) {
266                 fprintf(stderr, usage, argv[0]);
267                 exit(1);
268         }
269
270         memset(&st, 0, sizeof(st));
271         sem_init(&sem, 0, 0);
272         /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
273         sigaction(SIGUSR1,
274                   &(const struct sigaction){.sa_handler = &usr1_handler}, NULL);
275
276         fname = argv[1];
277
278         for (commands = argv[2]; *commands; commands++) {
279                 /*
280                  * XXX Most commands return 0 or we exit so we only
281                  * update rc where really needed.
282                  */
283                 last_rc = rc;
284                 rc = 0;
285                 total_bytes = 0;
286                 unaligned = false;
287
288                 switch (*commands) {
289                 case '_':
290                         if (verbose) {
291                                 printf("PAUSING\n");
292                                 fflush(stdout);
293                         }
294                         len = atoi(commands + 1);
295                         if (len <= 0)
296                                 len = 3600; /* 1 hour */
297                         ts.tv_sec = time(NULL) + len;
298                         ts.tv_nsec = 0;
299                         while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR)
300                                 ;
301                         break;
302                 case 'A':
303                         if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
304                                 save_errno = errno;
305                                 perror("fsetxattr");
306                                 exit(save_errno);
307                         }
308                         break;
309                 case 'a':
310                         len = atoi(commands + 1);
311                         if (xattr_buf_size < len) {
312                                 xattr_buf = realloc(xattr_buf, len);
313                                 if (!xattr_buf) {
314                                         save_errno = errno;
315                                         perror("allocating xattr buffer\n");
316                                         exit(save_errno);
317                                 }
318
319                                 xattr_buf_size = len;
320                         }
321
322                         rc = fgetxattr(fd, XATTR, xattr_buf, len);
323                         if (rc < 0) {
324                                 save_errno = errno;
325                                 perror("fgetxattr");
326                                 exit(save_errno);
327                         }
328                         break;
329                 case 'c':
330                         if (close(fd) == -1) {
331                                 save_errno = errno;
332                                 perror("close");
333                                 exit(save_errno);
334                         }
335                         fd = -1;
336                         break;
337                 case 'B':
338                         lum = (struct lov_user_md_v3) {
339                                 .lmm_magic = LOV_USER_MAGIC_V3,
340                                 .lmm_stripe_count = atoi(commands + 1),
341                         };
342
343                         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
344                                 save_errno = errno;
345                                 perror("LL_IOC_LOV_SETSTRIPE");
346                                 exit(save_errno);
347                         }
348                         break;
349                 case 'C':
350                         len = atoi(commands + 1);
351                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
352                                              0, 0, len, 0);
353                         if (fd == -1) {
354                                 save_errno = errno;
355                                 perror("create stripe file");
356                                 exit(save_errno);
357                         }
358                         rc = fd;
359                         break;
360                 case 'd':
361                         if (mkdir(fname, 0755) == -1) {
362                                 save_errno = errno;
363                                 perror("mkdir(0755)");
364                                 exit(save_errno);
365                         }
366                         break;
367                 case 'D':
368                         fd = open(fname, O_DIRECTORY);
369                         if (fd == -1) {
370                                 save_errno = errno;
371                                 perror("open(O_DIRECTORY)");
372                                 exit(save_errno);
373                         }
374                         rc = fd;
375                         break;
376                 case 'e':
377                         commands++;
378                         switch (*commands) {
379                         case 'U':
380                                 rc = llapi_lease_release(fd);
381                                 break;
382                         case 'R':
383                                 rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
384                                 break;
385                         case 'W':
386                                 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
387                                 break;
388                         default:
389                                 errx(-1, "unknown mode: %c", *commands);
390                         }
391                         if (rc < 0)
392                                 err(errno, "apply/unlock lease error");
393
394                         if (flags != LL_LEASE_UNLCK)
395                                 break;
396
397                         /* F_UNLCK, interpret return code */
398                         if (rc > 0) {
399                                 const char *str = "unknown";
400
401                                 if (rc == LL_LEASE_RDLCK)
402                                         str = "read";
403                                 else if (rc == LL_LEASE_WRLCK)
404                                         str = "write";
405                                 fprintf(stdout, "%s lease(%lld) released.\n",
406                                         str, rc);
407                         } else if (rc == 0) {
408                                 fprintf(stdout, "lease already broken.\n");
409                         }
410                         break;
411                 case 'E':
412                         commands++;
413                         if (*commands != '-' && *commands != '+')
414                                 errx(-1, "unknown mode: %c\n", *commands);
415
416                         rc = llapi_lease_check(fd);
417                         if (rc > 0) {
418                                 const char *str = "unknown";
419
420                                 if (rc == LL_LEASE_RDLCK)
421                                         str = "read";
422                                 else if (rc == LL_LEASE_WRLCK)
423                                         str = "write";
424                                 fprintf(stdout, "%s lease(%lld) has applied.\n",
425                                         str, rc);
426                                 if (*commands == '-')
427                                         errx(-1, "expect lease to not exist");
428                         } else if (rc == 0) {
429                                 fprintf(stdout, "no lease applied.\n");
430                                 if (*commands == '+')
431                                         errx(-1, "expect lease exists");
432                         } else {
433                                 err(errno, "free lease error");
434                         }
435                         break;
436                 case 'f':
437                         if (statfs(fname, &stfs) == -1)
438                                 errx(-1, "statfs()");
439                         break;
440                 case 'F':
441                         if (fd == -1)
442                                 rc = llapi_path2fid(fname, &fid);
443                         else
444                                 rc = llapi_fd2fid(fd, &fid);
445                         if (rc != 0)
446                                 fprintf(stderr,
447                                         "llapi_path/fd2fid() on %d, rc=%lld\n",
448                                         fd, rc);
449                         else
450                                 printf(DFID"\n", PFID(&fid));
451                         fflush(stdout);
452                         break;
453                 case 'G':
454                         gid = atoi(commands + 1);
455                         if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
456                                 save_errno = errno;
457                                 perror("ioctl(GROUP_LOCK)");
458                                 exit(save_errno);
459                         }
460                         break;
461                 case 'g':
462                         gid = atoi(commands + 1);
463                         if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
464                                 save_errno = errno;
465                                 perror("ioctl(GROUP_UNLOCK)");
466                                 exit(save_errno);
467                         }
468                         break;
469                 case 'H':
470                         len = atoi(commands + 1);
471                         fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
472                                              0, 0, len, LOV_PATTERN_RAID0 |
473                                              LOV_PATTERN_F_RELEASED);
474                         if (fd == -1) {
475                                 save_errno = errno;
476                                 perror("create stripe file");
477                                 exit(save_errno);
478                         }
479                         rc = fd;
480                         break;
481                 case 'j':
482                         if (flock(fd, LOCK_EX) == -1)
483                                 errx(-1, "flock()");
484                         break;
485                 case 'K':
486                         oldpath = POP_ARG();
487                         if (!oldpath)
488                                 oldpath = fname;
489
490                         if (link(oldpath, fname)) {
491                                 save_errno = errno;
492                                 perror("link()");
493                                 exit(save_errno);
494                         }
495                         break;
496                 case 'l':
497                         newfile = POP_ARG();
498                         if (!newfile)
499                                 newfile = fname;
500                         if (symlink(fname, newfile)) {
501                                 save_errno = errno;
502                                 perror("symlink()");
503                                 exit(save_errno);
504                         }
505                         break;
506                 case 'L':
507                         newfile = POP_ARG();
508                         if (!newfile)
509                                 newfile = fname;
510
511                         if (link(fname, newfile)) {
512                                 save_errno = errno;
513                                 perror("link()");
514                                 exit(save_errno);
515                         }
516                         break;
517                 case 'm':
518                         if (mknod(fname, S_IFREG | 0644, 0) == -1) {
519                                 save_errno = errno;
520                                 perror("mknod(S_IFREG|0644, 0)");
521                                 exit(save_errno);
522                         }
523                         break;
524                 case 'M':
525                         if (st.st_size == 0) {
526                                 fprintf(stderr,
527                                         "mmap without preceeding stat, or on zero length file.\n");
528                                 exit(-1);
529                         }
530                         mmap_len = st.st_size;
531                         mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
532                                         MAP_SHARED, fd, 0);
533                         if (mmap_ptr == MAP_FAILED) {
534                                 save_errno = errno;
535                                 perror("mmap");
536                                 exit(save_errno);
537                         }
538                         break;
539                 case 'n':
540                         oldpath = POP_ARG();
541                         if (!oldpath)
542                                 oldpath = fname;
543
544                         if (rename(oldpath, fname) < 0) {
545                                 save_errno = errno;
546                                 perror("rename()");
547                                 exit(save_errno);
548                         }
549                         break;
550                 case 'N':
551                         newfile = POP_ARG();
552                         if (!newfile)
553                                 newfile = fname;
554                         if (rename(fname, newfile)) {
555                                 save_errno = errno;
556                                 perror("rename()");
557                                 exit(save_errno);
558                         }
559                         break;
560                 case 'O':
561                         fd = open(fname, O_CREAT | O_RDWR, 0644);
562                         if (fd == -1) {
563                                 save_errno = errno;
564                                 perror("open(O_RDWR|O_CREAT)");
565                                 exit(save_errno);
566                         }
567                         rc = fd;
568                         break;
569                 case 'o':
570                         len = get_flags(commands + 1, &flags);
571                         commands += len;
572                         if (flags & O_CREAT)
573                                 fd = open(fname, flags, 0666);
574                         else
575                                 fd = open(fname, flags);
576                         if (fd == -1) {
577                                 save_errno = errno;
578                                 perror("open");
579                                 exit(save_errno);
580                         }
581                         rc = fd;
582                         break;
583                 case 'p':
584                         printf("%lld\n", last_rc);
585                         break;
586                 case 'Q':
587                         save_errno = statahead(fname);
588                         if (save_errno) {
589                                 perror("statahead");
590                                 exit(save_errno);
591                         }
592                         break;
593                 case 'r':
594                         if (*(commands + 1) == 'u') {
595                                 unaligned = true;
596                                 commands++;
597                         }
598                         len = atoi(commands + 1);
599                         if (len <= 0)
600                                 len = 1;
601                         /* for unaligned, we realloc every time, so the
602                          * buffer alignment is variable
603                          *
604                          * the last condition is "if buf is unaligned", so when
605                          * unaligned is not set, we realloc if the buf is
606                          * unaligned to create an aligned buffer
607                          */
608                         if (bufsize < len || unaligned ||
609                             buf !=
610                             (char *)((long)(buf + ALIGN_LEN) & ~ALIGN_LEN)) {
611                                 void *tmp;
612
613                                 /* We add a margin of + ALIGN_LEN to let us
614                                  * unalign and stay in the buffer
615                                  */
616                                 tmp = realloc(buf, len + ALIGN_LEN*2);
617                                 if (!tmp) {
618                                         free(buf);
619                                         save_errno = errno;
620                                         perror("allocating buf for write\n");
621                                         exit(save_errno);
622                                 }
623                                 buf = tmp;
624                                 bufsize = len;
625                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
626                                                      ~ALIGN_LEN);
627                                 /* if the original buffer was aligned, we
628                                  * manually unalign it.  Otherwise, we use
629                                  * the unalignment from the allocator.
630                                  *
631                                  * Add + 1 to avoid ever hitting 0, and use
632                                  * mod 255 to avoid 255 + 1 = 256
633                                  */
634                                 if (unaligned && buf_align == buf)
635                                         buf_align += rand() % 255 + 1;
636                                 else if (unaligned)
637                                         buf_align = buf;
638                         }
639
640                         while (len > 0) {
641                                 rc = read(fd, buf_align, len);
642                                 if (rc == -1) {
643                                         save_errno = errno;
644                                         perror("read");
645                                         exit(save_errno);
646                                 }
647                                 if (rc < len) {
648                                         fprintf(stderr, "short read: %lld/%u\n",
649                                                 rc, len);
650                                         if (rc == 0)
651                                                 break;
652                                 }
653                                 len -= rc;
654                                 if (verbose >= 2) {
655                                         printf("Buffer address %s: %p\n",
656                                                 unaligned ? "(unaligned)" : "",
657                                                 buf_align);
658                                         printf("Read this (%lld bytes):\n", rc);
659                                         printf("%.*s\n", (int)rc, buf_align);
660                                 }
661                         }
662                         break;
663                 case 'R':
664                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
665                                 junk += mmap_ptr[i];
666                         break;
667                 case 's':
668                         if (stat(fname, &st) == -1) {
669                                 save_errno = errno;
670                                 perror("stat");
671                                 exit(save_errno);
672                         }
673                         break;
674                 case 'S':
675                         if (fstat(fd, &st) == -1) {
676                                 save_errno = errno;
677                                 perror("fstat");
678                                 exit(save_errno);
679                         }
680                         break;
681                 case 't':
682                         if (fchmod(fd, 0) == -1) {
683                                 save_errno = errno;
684                                 perror("fchmod");
685                                 exit(save_errno);
686                         }
687                         break;
688                 case 'T':
689                         len = atoi(commands + 1);
690                         if (ftruncate(fd, len) == -1) {
691                                 save_errno = errno;
692                                 printf("ftruncate (%d,%d)\n", fd, len);
693                                 perror("ftruncate");
694                                 exit(save_errno);
695                         }
696                         break;
697                 case 'u':
698                         if (unlink(fname) == -1) {
699                                 save_errno = errno;
700                                 perror("unlink");
701                                 exit(save_errno);
702                         }
703                         break;
704                 case 'U':
705                         if (munmap(mmap_ptr, mmap_len)) {
706                                 save_errno = errno;
707                                 perror("munmap");
708                                 exit(save_errno);
709                         }
710                         break;
711                 case 'v':
712                         verbose++;
713                         break;
714                 case 'V':
715                         len = get_flags(commands + 1, &flags);
716                         commands += len;
717                         len = -1; /* mdt index */
718                         if (commands[1] >= '0' && commands[1] <= '9')
719                                 len = atoi(commands + 1);
720                         fd = llapi_create_volatile_idx(fname, len, flags);
721                         if (fd < 0) {
722                                 perror("llapi_create_volatile");
723                                 exit(fd);
724                         }
725                         rc = fd;
726                         break;
727                 case 'w':
728                 case 'P':
729                         if (*(commands + 1) == 'u') {
730                                 unaligned = true;
731                                 commands++;
732                         }
733                         len = atoi(commands + 1);
734                         if (len <= 0)
735                                 len = 1;
736                         /* for unaligned, we realloc every time, so the
737                          * buffer alignment is variable
738                          *
739                          * the last condition is "if buf is unaligned", so when
740                          * unaligned is not set, we realloc if the buf is
741                          * unaligned to create an aligned buffer
742                          */
743                         if (bufsize < len || unaligned ||
744                             buf !=
745                             (char *)((long)(buf + ALIGN_LEN) & ~ALIGN_LEN)) {
746                                 void *tmp;
747
748                                 /* We add a margin of + ALIGN_LEN to let us
749                                  * unalign and stay in the buffer
750                                  */
751                                 tmp = realloc(buf, len + ALIGN_LEN*2);
752                                 if (!tmp) {
753                                         free(buf);
754                                         save_errno = errno;
755                                         perror("allocating buf for write\n");
756                                         exit(save_errno);
757                                 }
758                                 buf = tmp;
759                                 bufsize = len;
760                                 buf_align = (char *)((long)(buf + ALIGN_LEN) &
761                                                      ~ALIGN_LEN);
762                                 /* if the original buffer was aligned, we
763                                  * manually unalign it.  Otherwise, we use
764                                  * the unalignment from the allocator.
765                                  *
766                                  * Add + 1 to avoid ever hitting 0, and use
767                                  * mod 255 to avoid 255 + 1 = 256
768                                  */
769                                 if (unaligned && buf_align == buf)
770                                         buf_align += rand() % 255 + 1;
771                                 else if (unaligned)
772                                         buf_align = buf;
773
774                                 /* fill the buffer with our string */
775                                 while (total_bytes < bufsize) {
776                                         /* msg_len does not include the
777                                          * terminating nul, deliberately,
778                                          * so all the additions are one string
779                                          */
780                                         strncpy(buf_align + total_bytes, msg,
781                                                 bufsize - total_bytes);
782                                         total_bytes += msg_len;
783                                 }
784                         }
785                         while (len > 0) {
786                                 rc = write(fd, buf_align, len);
787                                 if (rc == -1) {
788                                         save_errno = errno;
789                                         perror("write");
790                                         exit(save_errno);
791                                 }
792                                 if (rc < len)
793                                         fprintf(stderr,
794                                                 "short write: %lld/%u\n",
795                                                 rc, len);
796                                 if (commands[0] == 'P')
797                                         break;
798                                 len -= rc;
799                                 if (verbose >= 2) {
800                                         printf("Buffer address %s: %p\n",
801                                                 unaligned ? "(unaligned)" : "",
802                                                 buf_align);
803                                         printf("Wrote this (%lld bytes):\n",
804                                                rc);
805                                         printf("%.*s\n", (int)rc, buf_align);
806                                 }
807                         }
808                         break;
809                 case 'W':
810                         for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
811                                 mmap_ptr[i] += junk++;
812                         break;
813                 case 'x': {
814                         __u64 dv;
815
816                         rc = llapi_get_data_version(fd, &dv, 0);
817                         if (rc) {
818                                 fprintf(stderr,
819                                         "cannot get file data version %lld\n",
820                                         rc);
821                                 exit(-rc);
822                         }
823                         printf("dataversion is %ju\n", (uintmax_t)dv);
824                         break;
825                 }
826                 case 'X': {
827                         __u32 layout_version;
828
829                         rc = llapi_get_ost_layout_version(fd, &layout_version);
830                         if (rc) {
831                                 fprintf(stderr,
832                                         "cannot get ost layout version %lld\n",
833                                         rc);
834                                 exit(-rc);
835                         }
836                         printf("ostlayoutversion: %u\n", layout_version);
837                         break;
838                 }
839                 case 'y':
840                         if (fsync(fd) == -1) {
841                                 save_errno = errno;
842                                 perror("fsync");
843                                 exit(save_errno);
844                         }
845                         break;
846                 case 'Y':
847                         if (fdatasync(fd) == -1) {
848                                 save_errno = errno;
849                                 perror("fdatasync");
850                                 exit(save_errno);
851                         }
852                         break;
853                 case 'z': {
854                         off_t off;
855
856                         len = atoi(commands + 1);
857                         off = lseek(fd, len, SEEK_SET);
858                         if (off == (off_t)-1) {
859                                 save_errno = errno;
860                                 perror("lseek");
861                                 exit(save_errno);
862                         }
863
864                         rc = off;
865                         break;
866                 }
867                 case 'Z': {
868                         off_t off;
869
870                         len = atoi(commands + 1);
871                         off = lseek(fd, len, SEEK_CUR);
872                         if (off == (off_t)-1) {
873                                 save_errno = errno;
874                                 perror("lseek");
875                                 exit(save_errno);
876                         }
877
878                         rc = off;
879                         break;
880                 }
881                 case '-':
882                 case '0':
883                 case '1':
884                 case '2':
885                 case '3':
886                 case '4':
887                 case '5':
888                 case '6':
889                 case '7':
890                 case '8':
891                 case '9':
892                         break;
893                 default:
894                         fprintf(stderr, "unknown command \"%c\"\n", *commands);
895                         fprintf(stderr, usage, argv[0]);
896                         exit(1);
897                 }
898         }
899
900         if (buf)
901                 free(buf);
902
903         return 0;
904 }