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/
30 * Lustre is a trademark of Sun Microsystems, Inc.
34 #define _GNU_SOURCE /* pull in O_DIRECTORY in bits/fcntl.h */
42 #include <sys/types.h>
46 #include <sys/ioctl.h>
47 #include <sys/xattr.h>
52 #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 " x get file data version\n"
108 " W write entire mmap-ed region\n"
111 " z[num] lseek(SEEK_SET) [optional offset, default 0]\n"
112 " Z[num] lseek(SEEK_CUR) [optional offset, default 0]\n"
113 " _ wait for signal\n";
115 void usr1_handler(int unused)
117 int saved_errno = errno;
120 * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
121 * that the following functions can be safely called inside a signal
131 pop_arg(int argc, char *argv[])
133 static int cur_arg = 3;
138 return argv[cur_arg++];
141 struct flag_mapping {
145 {"O_RDONLY", O_RDONLY},
146 {"O_WRONLY", O_WRONLY},
148 {"O_CREAT", O_CREAT},
150 {"O_NOCTTY", O_NOCTTY},
151 {"O_TRUNC", O_TRUNC},
152 {"O_APPEND", O_APPEND},
153 {"O_NONBLOCK", O_NONBLOCK},
154 {"O_NDELAY", O_NDELAY},
157 {"O_DIRECT", O_DIRECT},
160 {"O_NOATIME", O_NOATIME},
162 {"O_LARGEFILE", O_LARGEFILE},
163 {"O_DIRECTORY", O_DIRECTORY},
164 {"O_NOFOLLOW", O_NOFOLLOW},
165 {"O_LOV_DELAY_CREATE", O_LOV_DELAY_CREATE},
169 int get_flags(char *data, int *rflags)
177 cloned_flags = strdup(data);
179 fprintf(stderr, "Insufficient memory.\n");
183 for (tmp = strtok(cloned_flags, ":"); tmp;
184 tmp = strtok(NULL, ":")) {
187 size = tmp - cloned_flags;
188 for (i = 0; flag_table[i].flag != -1; i++) {
189 if (!strcmp(tmp, flag_table[i].string)) {
190 flags |= flag_table[i].flag;
191 size += strlen(flag_table[i].string);
208 static int statahead(char *dname)
225 if (asprintf(&buf, "%s/%s", dname, dent->d_name) == -1) {
237 #define POP_ARG() (pop_arg(argc, argv))
239 int main(int argc, char **argv)
241 char *fname, *commands;
246 size_t mmap_len = 0, i;
247 unsigned char *mmap_ptr = NULL, junk = 1;
255 struct lov_user_md_v3 lum;
256 char *xattr_buf = NULL;
257 size_t xattr_buf_size = 0;
262 fprintf(stderr, usage, argv[0]);
266 memset(&st, 0, sizeof(st));
267 sem_init(&sem, 0, 0);
268 /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
270 &(const struct sigaction){.sa_handler = &usr1_handler}, NULL);
274 for (commands = argv[2]; *commands; commands++) {
276 * XXX Most commands return 0 or we exit so we only
277 * update rc where really needed.
288 len = atoi(commands + 1);
290 len = 3600; /* 1 hour */
291 ts.tv_sec = time(NULL) + len;
293 while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR)
297 if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
304 len = atoi(commands + 1);
305 if (xattr_buf_size < len) {
306 xattr_buf = realloc(xattr_buf, len);
309 perror("allocating xattr buffer\n");
313 xattr_buf_size = len;
316 rc = fgetxattr(fd, XATTR, xattr_buf, len);
324 if (close(fd) == -1) {
332 lum = (struct lov_user_md_v3) {
333 .lmm_magic = LOV_USER_MAGIC_V3,
334 .lmm_stripe_count = atoi(commands + 1),
337 if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
339 perror("LL_IOC_LOV_SETSTRIPE");
344 len = atoi(commands + 1);
345 fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
349 perror("create stripe file");
355 if (mkdir(fname, 0755) == -1) {
357 perror("mkdir(0755)");
362 fd = open(fname, O_DIRECTORY);
365 perror("open(O_DIRECTORY)");
374 rc = llapi_lease_release(fd);
377 rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
380 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
383 errx(-1, "unknown mode: %c", *commands);
386 err(errno, "apply/unlock lease error");
388 if (flags != LL_LEASE_UNLCK)
391 /* F_UNLCK, interpret return code */
393 const char *str = "unknown";
395 if (rc == LL_LEASE_RDLCK)
397 else if (rc == LL_LEASE_WRLCK)
399 fprintf(stdout, "%s lease(%lld) released.\n",
401 } else if (rc == 0) {
402 fprintf(stdout, "lease already broken.\n");
407 if (*commands != '-' && *commands != '+')
408 errx(-1, "unknown mode: %c\n", *commands);
410 rc = llapi_lease_check(fd);
412 const char *str = "unknown";
414 if (rc == LL_LEASE_RDLCK)
416 else if (rc == LL_LEASE_WRLCK)
418 fprintf(stdout, "%s lease(%lld) has applied.\n",
420 if (*commands == '-')
421 errx(-1, "expect lease to not exist");
422 } else if (rc == 0) {
423 fprintf(stdout, "no lease applied.\n");
424 if (*commands == '+')
425 errx(-1, "expect lease exists");
427 err(errno, "free lease error");
431 if (statfs(fname, &stfs) == -1)
432 errx(-1, "statfs()");
436 rc = llapi_path2fid(fname, &fid);
438 rc = llapi_fd2fid(fd, &fid);
441 "llapi_path/fd2fid() on %d, rc=%lld\n",
444 printf(DFID"\n", PFID(&fid));
448 gid = atoi(commands + 1);
449 if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
451 perror("ioctl(GROUP_LOCK)");
456 gid = atoi(commands + 1);
457 if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
459 perror("ioctl(GROUP_UNLOCK)");
464 len = atoi(commands + 1);
465 fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
466 0, 0, len, LOV_PATTERN_RAID0 |
467 LOV_PATTERN_F_RELEASED);
470 perror("create stripe file");
476 if (flock(fd, LOCK_EX) == -1)
484 if (link(oldpath, fname)) {
494 if (symlink(fname, newfile)) {
505 if (link(fname, newfile)) {
512 if (mknod(fname, S_IFREG | 0644, 0) == -1) {
514 perror("mknod(S_IFREG|0644, 0)");
519 if (st.st_size == 0) {
521 "mmap without preceeding stat, or on zero length file.\n");
524 mmap_len = st.st_size;
525 mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
527 if (mmap_ptr == MAP_FAILED) {
538 if (rename(oldpath, fname) < 0) {
548 if (rename(fname, newfile)) {
555 fd = open(fname, O_CREAT | O_RDWR, 0644);
558 perror("open(O_RDWR|O_CREAT)");
564 len = get_flags(commands + 1, &flags);
567 fd = open(fname, flags, 0666);
569 fd = open(fname, flags);
578 printf("%lld\n", last_rc);
581 save_errno = statahead(fname);
588 len = atoi(commands + 1);
594 tmp = realloc(buf, len + ALIGN_LEN);
598 perror("allocating buf for read\n");
603 buf_align = (char *)((long)(buf + ALIGN_LEN) &
607 rc = read(fd, buf_align, len);
614 fprintf(stderr, "short read: %lld/%u\n",
621 printf("%.*s\n", (int)rc, buf_align);
625 for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
629 if (stat(fname, &st) == -1) {
636 if (fstat(fd, &st) == -1) {
643 if (fchmod(fd, 0) == -1) {
650 len = atoi(commands + 1);
651 if (ftruncate(fd, len) == -1) {
653 printf("ftruncate (%d,%d)\n", fd, len);
659 if (unlink(fname) == -1) {
666 if (munmap(mmap_ptr, mmap_len)) {
676 len = get_flags(commands + 1, &flags);
678 len = -1; /* mdt index */
679 if (commands[1] >= '0' && commands[1] <= '9')
680 len = atoi(commands + 1);
681 fd = llapi_create_volatile_idx(fname, len, flags);
683 perror("llapi_create_volatile");
689 len = atoi(commands + 1);
695 tmp = realloc(buf, len + ALIGN_LEN);
699 perror("allocating buf for write\n");
704 buf_align = (char *)((long)(buf + ALIGN_LEN) &
706 strncpy(buf_align, msg, bufsize);
709 rc = write(fd, buf_align, len);
717 "short write: %lld/%u\n",
723 for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
724 mmap_ptr[i] += junk++;
729 rc = llapi_get_data_version(fd, &dv, 0);
732 "cannot get file data version %lld\n",
736 printf("dataversion is %ju\n", (uintmax_t)dv);
740 __u32 layout_version;
742 rc = llapi_get_ost_layout_version(fd, &layout_version);
745 "cannot get ost layout version %lld\n",
749 printf("ostlayoutversion: %u\n", layout_version);
753 if (fsync(fd) == -1) {
760 if (fdatasync(fd) == -1) {
769 len = atoi(commands + 1);
770 off = lseek(fd, len, SEEK_SET);
771 if (off == (off_t)-1) {
783 len = atoi(commands + 1);
784 off = lseek(fd, len, SEEK_CUR);
785 if (off == (off_t)-1) {
807 fprintf(stderr, "unknown command \"%c\"\n", *commands);
808 fprintf(stderr, usage, argv[0]);