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);
178 if (cloned_flags == NULL) {
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 = 0;
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 */
269 sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
274 for (commands = argv[2]; *commands; commands++) {
275 /* XXX Most commands return 0 or we exit so we only
276 * update rc where really needed. */
286 len = atoi(commands+1);
288 len = 3600; /* 1 hour */
289 ts.tv_sec = time(NULL) + len;
291 while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR);
294 if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
301 len = atoi(commands + 1);
302 if (xattr_buf_size < len) {
303 xattr_buf = realloc(xattr_buf, len);
304 if (xattr_buf == NULL) {
306 perror("allocating xattr buffer\n");
310 xattr_buf_size = len;
313 rc = fgetxattr(fd, XATTR, xattr_buf, len);
321 if (close(fd) == -1) {
329 lum = (struct lov_user_md_v3) {
330 .lmm_magic = LOV_USER_MAGIC_V3,
331 .lmm_stripe_count = atoi(commands + 1),
334 if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
336 perror("LL_IOC_LOV_SETSTRIPE");
341 len = atoi(commands+1);
342 fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
346 perror("create stripe file");
352 if (mkdir(fname, 0755) == -1) {
354 perror("mkdir(0755)");
359 fd = open(fname, O_DIRECTORY);
362 perror("open(O_DIRECTORY)");
371 rc = llapi_lease_release(fd);
374 rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
377 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
380 errx(-1, "unknown mode: %c", *commands);
383 err(errno, "apply/unlock lease error");
385 if (flags != LL_LEASE_UNLCK)
388 /* F_UNLCK, interpret return code */
390 const char *str = "unknown";
391 if (rc == LL_LEASE_RDLCK)
393 else if (rc == LL_LEASE_WRLCK)
395 fprintf(stdout, "%s lease(%lld) released.\n",
397 } else if (rc == 0) {
398 fprintf(stdout, "lease already broken.\n");
403 if (*commands != '-' && *commands != '+')
404 errx(-1, "unknown mode: %c\n", *commands);
406 rc = llapi_lease_check(fd);
408 const char *str = "unknown";
410 if (rc == LL_LEASE_RDLCK)
412 else if (rc == LL_LEASE_WRLCK)
414 fprintf(stdout, "%s lease(%lld) has applied.\n",
416 if (*commands == '-')
417 errx(-1, "expect lease to not exist");
418 } else if (rc == 0) {
419 fprintf(stdout, "no lease applied.\n");
420 if (*commands == '+')
421 errx(-1, "expect lease exists");
423 err(errno, "free lease error");
427 if (statfs(fname, &stfs) == -1)
428 errx(-1, "statfs()");
432 rc = llapi_path2fid(fname, &fid);
434 rc = llapi_fd2fid(fd, &fid);
437 "llapi_path/fd2fid() on %d, rc=%lld\n",
440 printf(DFID"\n", PFID(&fid));
444 gid = atoi(commands+1);
445 if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
447 perror("ioctl(GROUP_LOCK)");
452 gid = atoi(commands+1);
453 if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
455 perror("ioctl(GROUP_UNLOCK)");
460 len = atoi(commands+1);
461 fd = llapi_file_open(fname, O_CREAT | O_WRONLY,
463 LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED);
466 perror("create stripe file");
472 if (flock(fd, LOCK_EX) == -1)
480 if (link(oldpath, fname)) {
490 if (symlink(fname, newfile)) {
501 if (link(fname, newfile)) {
508 if (mknod(fname, S_IFREG | 0644, 0) == -1) {
510 perror("mknod(S_IFREG|0644, 0)");
515 if (st.st_size == 0) {
516 fprintf(stderr, "mmap without preceeding stat, or on"
517 " zero length file.\n");
520 mmap_len = st.st_size;
521 mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
523 if (mmap_ptr == MAP_FAILED) {
534 if (rename(oldpath, fname) < 0) {
544 if (rename (fname, newfile)) {
551 fd = open(fname, O_CREAT|O_RDWR, 0644);
554 perror("open(O_RDWR|O_CREAT)");
560 len = get_flags(commands+1, &flags);
563 fd = open(fname, flags, 0666);
565 fd = open(fname, flags);
574 printf("%lld\n", last_rc);
577 save_errno = statahead(fname);
584 len = atoi(commands+1);
589 tmp = realloc(buf, len + ALIGN_LEN);
593 perror("allocating buf for read\n");
598 buf_align = (char *)((long)(buf + ALIGN_LEN) &
602 rc = read(fd, buf_align, len);
609 fprintf(stderr, "short read: %lld/%u\n",
616 printf("%.*s\n", (int)rc, buf_align);
620 for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
624 if (stat(fname, &st) == -1) {
631 if (fstat(fd, &st) == -1) {
638 if (fchmod(fd, 0) == -1) {
645 len = atoi(commands+1);
646 if (ftruncate(fd, len) == -1) {
648 printf("ftruncate (%d,%d)\n", fd, len);
654 if (unlink(fname) == -1) {
661 if (munmap(mmap_ptr, mmap_len)) {
671 len = get_flags(commands + 1, &flags);
673 len = -1; /* mdt index */
674 if (commands[1] >= '0' && commands[1] <= '9')
675 len = atoi(commands+1);
676 fd = llapi_create_volatile_idx(fname, len, flags);
678 perror("llapi_create_volatile");
684 len = atoi(commands+1);
689 tmp = realloc(buf, len + ALIGN_LEN);
693 perror("allocating buf for write\n");
698 buf_align = (char *)((long)(buf + ALIGN_LEN) &
700 strncpy(buf_align, msg, bufsize);
703 rc = write(fd, buf_align, len);
710 fprintf(stderr, "short write: %lld/%u\n",
716 for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
717 mmap_ptr[i] += junk++;
722 rc = llapi_get_data_version(fd, &dv, 0);
724 fprintf(stderr, "cannot get file data version"
728 printf("dataversion is %ju\n", (uintmax_t)dv);
732 __u32 layout_version;
734 rc = llapi_get_ost_layout_version(fd, &layout_version);
736 fprintf(stderr, "cannot get ost layout version"
740 printf("ostlayoutversion: %u\n", layout_version);
744 if (fsync(fd) == -1) {
751 if (fdatasync(fd) == -1) {
760 len = atoi(commands + 1);
761 off = lseek(fd, len, SEEK_SET);
762 if (off == (off_t)-1) {
774 len = atoi(commands + 1);
775 off = lseek(fd, len, SEEK_CUR);
776 if (off == (off_t)-1) {
798 fprintf(stderr, "unknown command \"%c\"\n", *commands);
799 fprintf(stderr, usage, argv[0]);