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 */
41 #include <sys/types.h>
45 #include <sys/ioctl.h>
46 #include <sys/xattr.h>
51 #include <semaphore.h>
55 #include <lustre/lustreapi.h>
57 #define T1 "write data before unlink\n"
58 #define T2 "write data after unlink\n"
59 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";
60 char *buf, *buf_align;
63 #define ALIGN_LEN 65535
64 #define XATTR "user.multiop"
67 "Usage: %s filename command-sequence [path...]\n"
68 " command-sequence items:\n"
69 " A fsetxattr(\"user.multiop\")\n"
70 " a fgetxattr(\"user.multiop\")\n"
72 " B[num] call setstripe ioctl to create stripes\n"
73 " C[num] create with optional stripes\n"
75 " D open(O_DIRECTORY)\n"
76 " e[R|W|U] apply lease. R: Read; W: Write; U: Unlock\n"
77 " E[+|-] get lease. +/-: expect lease to (not) exist\n"
80 " H[num] create HSM released file with num stripes\n"
81 " G gid get grouplock\n"
82 " g gid put grouplock\n"
83 " K link path to filename\n"
85 " l symlink filename to path\n"
87 " M rw mmap to EOF (must open and stat prior)\n"
88 " n rename path to filename\n"
89 " N rename filename to path\n"
91 " O open(O_CREAT|O_RDWR)\n"
92 " p print return value of last command\n"
93 " r[num] read [optional length]\n"
94 " R reference entire mmap-ed region\n"
98 " T[num] ftruncate [optional position, default 0]\n"
102 " V open a volatile file\n"
103 " w[num] write optional length\n"
104 " x get file data version\n"
105 " W write entire mmap-ed region\n"
108 " z[num] lseek(SEEK_SET) [optional offset, default 0]\n"
109 " Z[num] lseek(SEEK_CUR) [optional offset, default 0]\n"
110 " _ wait for signal\n";
112 void usr1_handler(int unused)
114 int saved_errno = errno;
117 * signal(7): POSIX.1-2004 ...requires an implementation to guarantee
118 * that the following functions can be safely called inside a signal
128 pop_arg(int argc, char *argv[])
130 static int cur_arg = 3;
135 return argv[cur_arg++];
138 struct flag_mapping {
142 {"O_RDONLY", O_RDONLY},
143 {"O_WRONLY", O_WRONLY},
145 {"O_CREAT", O_CREAT},
147 {"O_NOCTTY", O_NOCTTY},
148 {"O_TRUNC", O_TRUNC},
149 {"O_APPEND", O_APPEND},
150 {"O_NONBLOCK", O_NONBLOCK},
151 {"O_NDELAY", O_NDELAY},
154 {"O_DIRECT", O_DIRECT},
157 {"O_NOATIME", O_NOATIME},
159 {"O_LARGEFILE", O_LARGEFILE},
160 {"O_DIRECTORY", O_DIRECTORY},
161 {"O_NOFOLLOW", O_NOFOLLOW},
162 {"O_LOV_DELAY_CREATE", O_LOV_DELAY_CREATE},
166 int get_flags(char *data, int *rflags)
174 cloned_flags = strdup(data);
175 if (cloned_flags == NULL) {
176 fprintf(stderr, "Insufficient memory.\n");
180 for (tmp = strtok(cloned_flags, ":"); tmp;
181 tmp = strtok(NULL, ":")) {
184 size = tmp - cloned_flags;
185 for (i = 0; flag_table[i].flag != -1; i++) {
186 if (!strcmp(tmp, flag_table[i].string)){
187 flags |= flag_table[i].flag;
188 size += strlen(flag_table[i].string);
205 #define POP_ARG() (pop_arg(argc, argv))
207 int main(int argc, char **argv)
209 char *fname, *commands;
214 size_t mmap_len = 0, i;
215 unsigned char *mmap_ptr = NULL, junk = 0;
223 struct lov_user_md_v3 lum;
228 fprintf(stderr, usage, argv[0]);
232 memset(&st, 0, sizeof(st));
233 sem_init(&sem, 0, 0);
234 /* use sigaction instead of signal to avoid SA_ONESHOT semantics */
235 sigaction(SIGUSR1, &(const struct sigaction){.sa_handler = &usr1_handler},
240 for (commands = argv[2]; *commands; commands++) {
241 /* XXX Most commands return 0 or we exit so we only
242 * update rc where really needed. */
252 len = atoi(commands+1);
254 len = 3600; /* 1 hour */
255 ts.tv_sec = time(NULL) + len;
257 while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR);
260 if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
267 rc = fgetxattr(fd, XATTR, NULL, 0);
275 if (close(fd) == -1) {
283 lum = (struct lov_user_md_v3) {
284 .lmm_magic = LOV_USER_MAGIC_V3,
285 .lmm_stripe_count = atoi(commands + 1),
288 if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum) < 0) {
290 perror("LL_IOC_LOV_SETSTRIPE");
295 len = atoi(commands+1);
296 fd = llapi_file_open(fname, O_CREAT | O_WRONLY, 0644,
300 perror("create stripe file");
306 if (mkdir(fname, 0755) == -1) {
308 perror("mkdir(0755)");
313 fd = open(fname, O_DIRECTORY);
316 perror("open(O_DIRECTORY)");
325 rc = llapi_lease_release(fd);
328 rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
331 rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
334 errx(-1, "unknown mode: %c", *commands);
337 err(errno, "apply/unlock lease error");
339 if (flags != LL_LEASE_UNLCK)
342 /* F_UNLCK, interpret return code */
344 const char *str = "unknown";
345 if (rc == LL_LEASE_RDLCK)
347 else if (rc == LL_LEASE_WRLCK)
349 fprintf(stdout, "%s lease(%lld) released.\n",
351 } else if (rc == 0) {
352 fprintf(stdout, "lease already broken.\n");
357 if (*commands != '-' && *commands != '+')
358 errx(-1, "unknown mode: %c\n", *commands);
360 rc = llapi_lease_check(fd);
362 const char *str = "unknown";
364 if (rc == LL_LEASE_RDLCK)
366 else if (rc == LL_LEASE_WRLCK)
368 fprintf(stdout, "%s lease(%lld) has applied.\n",
370 if (*commands == '-')
371 errx(-1, "expect lease to not exist");
372 } else if (rc == 0) {
373 fprintf(stdout, "no lease applied.\n");
374 if (*commands == '+')
375 errx(-1, "expect lease exists");
377 err(errno, "free lease error");
381 if (statfs(fname, &stfs) == -1)
382 errx(-1, "statfs()");
386 rc = llapi_path2fid(fname, &fid);
388 rc = llapi_fd2fid(fd, &fid);
391 "llapi_path/fd2fid() on %d, rc=%lld\n",
394 printf(DFID"\n", PFID(&fid));
397 gid = atoi(commands+1);
398 if (ioctl(fd, LL_IOC_GROUP_LOCK, gid) == -1) {
400 perror("ioctl(GROUP_LOCK)");
405 gid = atoi(commands+1);
406 if (ioctl(fd, LL_IOC_GROUP_UNLOCK, gid) == -1) {
408 perror("ioctl(GROUP_UNLOCK)");
413 len = atoi(commands+1);
414 fd = llapi_file_open(fname, O_CREAT | O_WRONLY,
416 LOV_PATTERN_RAID0 | LOV_PATTERN_F_RELEASED);
419 perror("create stripe file");
425 if (flock(fd, LOCK_EX) == -1)
433 if (link(oldpath, fname)) {
443 if (symlink(fname, newfile)) {
454 if (link(fname, newfile)) {
461 if (mknod(fname, S_IFREG | 0644, 0) == -1) {
463 perror("mknod(S_IFREG|0644, 0)");
468 if (st.st_size == 0) {
469 fprintf(stderr, "mmap without preceeding stat, or on"
470 " zero length file.\n");
473 mmap_len = st.st_size;
474 mmap_ptr = mmap(NULL, mmap_len, PROT_WRITE | PROT_READ,
476 if (mmap_ptr == MAP_FAILED) {
487 if (rename(oldpath, fname) < 0) {
497 if (rename (fname, newfile)) {
504 fd = open(fname, O_CREAT|O_RDWR, 0644);
507 perror("open(O_RDWR|O_CREAT)");
513 len = get_flags(commands+1, &flags);
516 fd = open(fname, flags, 0666);
518 fd = open(fname, flags);
527 printf("%lld\n", last_rc);
530 len = atoi(commands+1);
535 tmp = realloc(buf, len + ALIGN_LEN);
539 perror("allocating buf for read\n");
544 buf_align = (char *)((long)(buf + ALIGN_LEN) &
548 rc = read(fd, buf_align, len);
555 fprintf(stderr, "short read: %lld/%u\n",
562 printf("%.*s\n", (int)rc, buf_align);
566 for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
570 if (stat(fname, &st) == -1) {
577 if (fstat(fd, &st) == -1) {
584 if (fchmod(fd, 0) == -1) {
591 len = atoi(commands+1);
592 if (ftruncate(fd, len) == -1) {
594 printf("ftruncate (%d,%d)\n", fd, len);
600 if (unlink(fname) == -1) {
607 if (munmap(mmap_ptr, mmap_len)) {
617 len = get_flags(commands + 1, &flags);
619 fd = llapi_create_volatile(fname, flags);
621 perror("llapi_create_volatile");
627 len = atoi(commands+1);
632 tmp = realloc(buf, len + ALIGN_LEN);
636 perror("allocating buf for write\n");
641 buf_align = (char *)((long)(buf + ALIGN_LEN) &
643 strncpy(buf_align, msg, bufsize);
646 rc = write(fd, buf_align, len);
653 fprintf(stderr, "short write: %lld/%u\n",
659 for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
660 mmap_ptr[i] += junk++;
665 rc = llapi_get_data_version(fd, &dv, 0);
667 fprintf(stderr, "cannot get file data version"
671 printf("dataversion is %ju\n", (uintmax_t)dv);
675 __u32 layout_version;
677 rc = llapi_get_ost_layout_version(fd, &layout_version);
679 fprintf(stderr, "cannot get ost layout version"
683 printf("ostlayoutversion: %u\n", layout_version);
687 if (fsync(fd) == -1) {
694 if (fdatasync(fd) == -1) {
703 len = atoi(commands + 1);
704 off = lseek(fd, len, SEEK_SET);
705 if (off == (off_t)-1) {
717 len = atoi(commands + 1);
718 off = lseek(fd, len, SEEK_CUR);
719 if (off == (off_t)-1) {
741 fprintf(stderr, "unknown command \"%c\"\n", *commands);
742 fprintf(stderr, usage, argv[0]);