4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2012, 2017, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
33 #define _GNU_SOURCE /* pull in O_DIRECTORY in bits/fcntl.h */
41 #include <sys/types.h>
45 #include <sys/ioctl.h>
46 #include <sys/xattr.h>
51 #include <semaphore.h>
57 #include <lustre/lustreapi.h>
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;
65 #define ALIGN_LEN 65535
66 #define XATTR "user.multiop"
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"
74 " B[num] call setstripe ioctl to create stripes\n"
75 " C[num] create with optional stripes\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"
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"
87 " l symlink filename to path\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"
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"
101 " T[num] ftruncate [optional position, default 0]\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"
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";
116 static void usr1_handler(int unused)
118 int saved_errno = errno;
121 * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
122 * that the following functions can be safely called inside a signal
132 pop_arg(int argc, char *argv[])
134 static int cur_arg = 3;
139 return argv[cur_arg++];
142 struct flag_mapping {
146 {"O_RDONLY", O_RDONLY},
147 {"O_WRONLY", O_WRONLY},
149 {"O_CREAT", O_CREAT},
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},
158 {"O_DIRECT", O_DIRECT},
161 {"O_NOATIME", O_NOATIME},
163 {"O_LARGEFILE", O_LARGEFILE},
164 {"O_DIRECTORY", O_DIRECTORY},
165 {"O_NOFOLLOW", O_NOFOLLOW},
166 {"O_LOV_DELAY_CREATE", O_LOV_DELAY_CREATE},
170 static int get_flags(char *data, int *rflags)
178 cloned_flags = strdup(data);
180 fprintf(stderr, "Insufficient memory.\n");
184 for (tmp = strtok(cloned_flags, ":"); tmp;
185 tmp = strtok(NULL, ":")) {
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);
209 static int statahead(char *dname)
226 if (asprintf(&buf, "%s/%s", dname, dent->d_name) == -1) {
238 #define POP_ARG() (pop_arg(argc, argv))
240 int main(int argc, char **argv)
242 char *fname, *commands;
247 size_t mmap_len = 0, i;
248 unsigned char *mmap_ptr = NULL, junk = 1;
256 struct lov_user_md_v3 lum;
257 char *xattr_buf = NULL;
258 size_t xattr_buf_size = 0;
262 int msg_len = strlen(msg);
266 fprintf(stderr, usage, argv[0]);
270 memset(&st, 0, sizeof(st));
271 sem_init(&sem, 0, 0);
272 /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
274 &(const struct sigaction){.sa_handler = &usr1_handler}, NULL);
278 for (commands = argv[2]; *commands; commands++) {
280 * XXX Most commands return 0 or we exit so we only
281 * update rc where really needed.
294 len = atoi(commands + 1);
296 len = 3600; /* 1 hour */
297 ts.tv_sec = time(NULL) + len;
299 while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR)
303 if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
310 len = atoi(commands + 1);
311 if (xattr_buf_size < len) {
312 xattr_buf = realloc(xattr_buf, len);
315 perror("allocating xattr buffer\n");
319 xattr_buf_size = len;
322 rc = fgetxattr(fd, XATTR, xattr_buf, len);
330 if (close(fd) == -1) {
338 lum = (struct lov_user_md_v3) {
339 .lmm_magic = LOV_USER_MAGIC_V3,
340 .lmm_stripe_count = atoi(commands + 1),
343 if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
345 perror("LL_IOC_LOV_SETSTRIPE");
350 len = atoi(commands + 1);
351 fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
355 perror("create stripe file");
361 if (mkdir(fname, 0755) == -1) {
363 perror("mkdir(0755)");
368 fd = open(fname, O_DIRECTORY);
371 perror("open(O_DIRECTORY)");
380 rc = llapi_lease_release(fd);
383 rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
386 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
389 errx(-1, "unknown mode: %c", *commands);
392 err(errno, "apply/unlock lease error");
394 if (flags != LL_LEASE_UNLCK)
397 /* F_UNLCK, interpret return code */
399 const char *str = "unknown";
401 if (rc == LL_LEASE_RDLCK)
403 else if (rc == LL_LEASE_WRLCK)
405 fprintf(stdout, "%s lease(%lld) released.\n",
407 } else if (rc == 0) {
408 fprintf(stdout, "lease already broken.\n");
413 if (*commands != '-' && *commands != '+')
414 errx(-1, "unknown mode: %c\n", *commands);
416 rc = llapi_lease_check(fd);
418 const char *str = "unknown";
420 if (rc == LL_LEASE_RDLCK)
422 else if (rc == LL_LEASE_WRLCK)
424 fprintf(stdout, "%s lease(%lld) has applied.\n",
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");
433 err(errno, "free lease error");
437 if (statfs(fname, &stfs) == -1)
438 errx(-1, "statfs()");
442 rc = llapi_path2fid(fname, &fid);
444 rc = llapi_fd2fid(fd, &fid);
447 "llapi_path/fd2fid() on %d, rc=%lld\n",
450 printf(DFID"\n", PFID(&fid));
454 gid = atoi(commands + 1);
455 if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
457 perror("ioctl(GROUP_LOCK)");
462 gid = atoi(commands + 1);
463 if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
465 perror("ioctl(GROUP_UNLOCK)");
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);
476 perror("create stripe file");
482 if (flock(fd, LOCK_EX) == -1)
490 if (link(oldpath, fname)) {
500 if (symlink(fname, newfile)) {
511 if (link(fname, newfile)) {
518 if (mknod(fname, S_IFREG | 0644, 0) == -1) {
520 perror("mknod(S_IFREG|0644, 0)");
525 if (st.st_size == 0) {
527 "mmap without preceeding stat, or on zero length file.\n");
530 mmap_len = st.st_size;
531 mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
533 if (mmap_ptr == MAP_FAILED) {
544 if (rename(oldpath, fname) < 0) {
554 if (rename(fname, newfile)) {
561 fd = open(fname, O_CREAT | O_RDWR, 0644);
564 perror("open(O_RDWR|O_CREAT)");
570 len = get_flags(commands + 1, &flags);
573 fd = open(fname, flags, 0666);
575 fd = open(fname, flags);
584 printf("%lld\n", last_rc);
587 save_errno = statahead(fname);
594 if (*(commands + 1) == 'u') {
598 len = atoi(commands + 1);
601 /* for unaligned, we realloc every time, so the
602 * buffer alignment is variable
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
608 if (bufsize < len || unaligned ||
610 (char *)((long)(buf + ALIGN_LEN) & ~ALIGN_LEN)) {
613 /* We add a margin of + ALIGN_LEN to let us
614 * unalign and stay in the buffer
616 tmp = realloc(buf, len + ALIGN_LEN*2);
620 perror("allocating buf for write\n");
625 buf_align = (char *)((long)(buf + ALIGN_LEN) &
627 /* if the original buffer was aligned, we
628 * manually unalign it. Otherwise, we use
629 * the unalignment from the allocator.
631 * Add + 1 to avoid ever hitting 0, and use
632 * mod 255 to avoid 255 + 1 = 256
634 if (unaligned && buf_align == buf)
635 buf_align += rand() % 255 + 1;
641 rc = read(fd, buf_align, len);
648 fprintf(stderr, "short read: %lld/%u\n",
655 printf("Buffer address %s: %p\n",
656 unaligned ? "(unaligned)" : "",
658 printf("Read this (%lld bytes):\n", rc);
659 printf("%.*s\n", (int)rc, buf_align);
664 for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
668 if (stat(fname, &st) == -1) {
675 if (fstat(fd, &st) == -1) {
682 if (fchmod(fd, 0) == -1) {
689 len = atoi(commands + 1);
690 if (ftruncate(fd, len) == -1) {
692 printf("ftruncate (%d,%d)\n", fd, len);
698 if (unlink(fname) == -1) {
705 if (munmap(mmap_ptr, mmap_len)) {
715 len = get_flags(commands + 1, &flags);
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);
722 perror("llapi_create_volatile");
729 if (*(commands + 1) == 'u') {
733 len = atoi(commands + 1);
736 /* for unaligned, we realloc every time, so the
737 * buffer alignment is variable
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
743 if (bufsize < len || unaligned ||
745 (char *)((long)(buf + ALIGN_LEN) & ~ALIGN_LEN)) {
748 /* We add a margin of + ALIGN_LEN to let us
749 * unalign and stay in the buffer
751 tmp = realloc(buf, len + ALIGN_LEN*2);
755 perror("allocating buf for write\n");
760 buf_align = (char *)((long)(buf + ALIGN_LEN) &
762 /* if the original buffer was aligned, we
763 * manually unalign it. Otherwise, we use
764 * the unalignment from the allocator.
766 * Add + 1 to avoid ever hitting 0, and use
767 * mod 255 to avoid 255 + 1 = 256
769 if (unaligned && buf_align == buf)
770 buf_align += rand() % 255 + 1;
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
780 strncpy(buf_align + total_bytes, msg,
781 bufsize - total_bytes);
782 total_bytes += msg_len;
786 rc = write(fd, buf_align, len);
794 "short write: %lld/%u\n",
796 if (commands[0] == 'P')
800 printf("Buffer address %s: %p\n",
801 unaligned ? "(unaligned)" : "",
803 printf("Wrote this (%lld bytes):\n",
805 printf("%.*s\n", (int)rc, buf_align);
810 for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
811 mmap_ptr[i] += junk++;
816 rc = llapi_get_data_version(fd, &dv, 0);
819 "cannot get file data version %lld\n",
823 printf("dataversion is %ju\n", (uintmax_t)dv);
827 __u32 layout_version;
829 rc = llapi_get_ost_layout_version(fd, &layout_version);
832 "cannot get ost layout version %lld\n",
836 printf("ostlayoutversion: %u\n", layout_version);
840 if (fsync(fd) == -1) {
847 if (fdatasync(fd) == -1) {
856 len = atoi(commands + 1);
857 off = lseek(fd, len, SEEK_SET);
858 if (off == (off_t)-1) {
870 len = atoi(commands + 1);
871 off = lseek(fd, len, SEEK_CUR);
872 if (off == (off_t)-1) {
894 fprintf(stderr, "unknown command \"%c\"\n", *commands);
895 fprintf(stderr, usage, argv[0]);