*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
*
* GPL HEADER END
*/
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2012, 2013, Intel Corporation.
+ * Copyright (c) 2012, 2017, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* pull in O_DIRECTORY in bits/fcntl.h */
#endif
-#include <stdio.h>
+#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdio.h>
#include <string.h>
-#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/vfs.h>
#include <sys/ioctl.h>
+#include <sys/xattr.h>
+#include <sys/file.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <time.h>
+#include <err.h>
-#include <lustre/lustre_idl.h>
#include <lustre/lustreapi.h>
#define T1 "write data before unlink\n"
int bufsize = 0;
sem_t sem;
#define ALIGN_LEN 65535
+#define XATTR "user.multiop"
char usage[] =
"Usage: %s filename command-sequence [path...]\n"
" command-sequence items:\n"
+" A fsetxattr(\"user.multiop\")\n"
+" a[num] fgetxattr(\"user.multiop\") [optional buffer size, default 0]\n"
" c close\n"
" B[num] call setstripe ioctl to create stripes\n"
" C[num] create with optional stripes\n"
" d mkdir\n"
" D open(O_DIRECTORY)\n"
+" e[R|W|U] apply lease. R: Read; W: Write; U: Unlock\n"
+" E[+|-] get lease. +/-: expect lease to (not) exist\n"
" f statfs\n"
" F print FID\n"
" H[num] create HSM released file with num stripes\n"
" N rename filename to path\n"
" o open(O_RDONLY)\n"
" O open(O_CREAT|O_RDWR)\n"
+" p print return value of last command\n"
" r[num] read [optional length]\n"
" R reference entire mmap-ed region\n"
" s stat\n"
" W write entire mmap-ed region\n"
" y fsync\n"
" Y fdatasync\n"
-" z[num] seek [optional position, default 0]\n"
+" z[num] lseek(SEEK_SET) [optional offset, default 0]\n"
+" Z[num] lseek(SEEK_CUR) [optional offset, default 0]\n"
" _ wait for signal\n";
void usr1_handler(int unused)
#ifdef O_DIRECT
{"O_DIRECT", O_DIRECT},
#endif
+#ifdef O_NOATIME
+ {"O_NOATIME", O_NOATIME},
+#endif
{"O_LARGEFILE", O_LARGEFILE},
{"O_DIRECTORY", O_DIRECTORY},
{"O_NOFOLLOW", O_NOFOLLOW},
struct statfs stfs;
size_t mmap_len = 0, i;
unsigned char *mmap_ptr = NULL, junk = 0;
- int rc, len, fd = -1;
+ int len, fd = -1;
int flags;
int save_errno;
int verbose = 0;
int gid = 0;
- lustre_fid fid;
+ struct lu_fid fid;
struct timespec ts;
struct lov_user_md_v3 lum;
- __u64 dv;
+ char *xattr_buf = NULL;
+ size_t xattr_buf_size = 0;
+ long long rc = 0;
+ long long last_rc;
if (argc < 3) {
fprintf(stderr, usage, argv[0]);
fname = argv[1];
for (commands = argv[2]; *commands; commands++) {
+ /* XXX Most commands return 0 or we exit so we only
+ * update rc where really needed. */
+ last_rc = rc;
+ rc = 0;
+
switch (*commands) {
case '_':
if (verbose) {
ts.tv_nsec = 0;
while (sem_timedwait(&sem, &ts) < 0 && errno == EINTR);
break;
+ case 'A':
+ if (fsetxattr(fd, XATTR, "multiop", 8, 0)) {
+ save_errno = errno;
+ perror("fsetxattr");
+ exit(save_errno);
+ }
+ break;
+ case 'a':
+ len = atoi(commands + 1);
+ if (xattr_buf_size < len) {
+ xattr_buf = realloc(xattr_buf, len);
+ if (xattr_buf == NULL) {
+ save_errno = errno;
+ perror("allocating xattr buffer\n");
+ exit(save_errno);
+ }
+
+ xattr_buf_size = len;
+ }
+
+ rc = fgetxattr(fd, XATTR, xattr_buf, len);
+ if (rc < 0) {
+ save_errno = errno;
+ perror("fgetxattr");
+ exit(save_errno);
+ }
+ break;
case 'c':
if (close(fd) == -1) {
save_errno = errno;
perror("create stripe file");
exit(save_errno);
}
+ rc = fd;
break;
case 'd':
if (mkdir(fname, 0755) == -1) {
perror("open(O_DIRECTORY)");
exit(save_errno);
}
+ rc = fd;
break;
- case 'f':
- if (statfs(fname, &stfs) == -1) {
- save_errno = errno;
- perror("statfs()");
- exit(save_errno);
- }
- break;
+ case 'e':
+ commands++;
+ switch (*commands) {
+ case 'U':
+ rc = llapi_lease_release(fd);
+ break;
+ case 'R':
+ rc = llapi_lease_acquire(fd, LL_LEASE_RDLCK);
+ break;
+ case 'W':
+ rc = llapi_lease_acquire(fd, LL_LEASE_WRLCK);
+ break;
+ default:
+ errx(-1, "unknown mode: %c", *commands);
+ }
+ if (rc < 0)
+ err(errno, "apply/unlock lease error");
+
+ if (flags != LL_LEASE_UNLCK)
+ break;
+
+ /* F_UNLCK, interpret return code */
+ if (rc > 0) {
+ const char *str = "unknown";
+ if (rc == LL_LEASE_RDLCK)
+ str = "read";
+ else if (rc == LL_LEASE_WRLCK)
+ str = "write";
+ fprintf(stdout, "%s lease(%lld) released.\n",
+ str, rc);
+ } else if (rc == 0) {
+ fprintf(stdout, "lease already broken.\n");
+ }
+ break;
+ case 'E':
+ commands++;
+ if (*commands != '-' && *commands != '+')
+ errx(-1, "unknown mode: %c\n", *commands);
+
+ rc = llapi_lease_check(fd);
+ if (rc > 0) {
+ const char *str = "unknown";
+
+ if (rc == LL_LEASE_RDLCK)
+ str = "read";
+ else if (rc == LL_LEASE_WRLCK)
+ str = "write";
+ fprintf(stdout, "%s lease(%lld) has applied.\n",
+ str, rc);
+ if (*commands == '-')
+ errx(-1, "expect lease to not exist");
+ } else if (rc == 0) {
+ fprintf(stdout, "no lease applied.\n");
+ if (*commands == '+')
+ errx(-1, "expect lease exists");
+ } else {
+ err(errno, "free lease error");
+ }
+ break;
+ case 'f':
+ if (statfs(fname, &stfs) == -1)
+ errx(-1, "statfs()");
+ break;
case 'F':
if (fd == -1)
rc = llapi_path2fid(fname, &fid);
rc = llapi_fd2fid(fd, &fid);
if (rc != 0)
fprintf(stderr,
- "llapi_path/fd2fid() on %d, rc=%d\n",
+ "llapi_path/fd2fid() on %d, rc=%lld\n",
fd, rc);
else
printf(DFID"\n", PFID(&fid));
perror("create stripe file");
exit(save_errno);
}
+ rc = fd;
+ break;
+ case 'j':
+ if (flock(fd, LOCK_EX) == -1)
+ errx(-1, "flock()");
break;
case 'K':
oldpath = POP_ARG();
perror("open(O_RDWR|O_CREAT)");
exit(save_errno);
}
+ rc = fd;
break;
case 'o':
len = get_flags(commands+1, &flags);
perror("open");
exit(save_errno);
}
+ rc = fd;
break;
+ case 'p':
+ printf("%lld\n", last_rc);
+ break;
case 'r':
len = atoi(commands+1);
if (len <= 0)
len = 1;
if (bufsize < len) {
- buf = realloc(buf, len + ALIGN_LEN);
- if (buf == NULL) {
+ void *tmp;
+ tmp = realloc(buf, len + ALIGN_LEN);
+ if (tmp == NULL) {
+ free(buf);
save_errno = errno;
perror("allocating buf for read\n");
exit(save_errno);
}
+ buf = tmp;
bufsize = len;
buf_align = (char *)((long)(buf + ALIGN_LEN) &
~ALIGN_LEN);
exit(save_errno);
}
if (rc < len) {
- fprintf(stderr, "short read: %u/%u\n",
+ fprintf(stderr, "short read: %lld/%u\n",
rc, len);
if (rc == 0)
exit(ENODATA);
}
len -= rc;
if (verbose >= 2)
- printf("%.*s\n", rc, buf_align);
+ printf("%.*s\n", (int)rc, buf_align);
}
break;
case 'R':
perror("llapi_create_volatile");
exit(fd);
}
+ rc = fd;
break;
case 'w':
len = atoi(commands+1);
if (len <= 0)
len = 1;
if (bufsize < len) {
- buf = realloc(buf, len + ALIGN_LEN);
- if (buf == NULL) {
+ void *tmp;
+ tmp = realloc(buf, len + ALIGN_LEN);
+ if (tmp == NULL) {
+ free(buf);
save_errno = errno;
perror("allocating buf for write\n");
exit(save_errno);
}
+ buf = tmp;
bufsize = len;
buf_align = (char *)((long)(buf + ALIGN_LEN) &
~ALIGN_LEN);
exit(save_errno);
}
if (rc < len)
- fprintf(stderr, "short write: %u/%u\n",
+ fprintf(stderr, "short write: %lld/%u\n",
rc, len);
len -= rc;
}
for (i = 0; i < mmap_len && mmap_ptr; i += 4096)
mmap_ptr[i] += junk++;
break;
- case 'x':
+ case 'x': {
+ __u64 dv;
+
rc = llapi_get_data_version(fd, &dv, 0);
if (rc) {
fprintf(stderr, "cannot get file data version"
- " %d\n", rc);
+ " %lld\n", rc);
+ exit(-rc);
+ }
+ printf("dataversion is %ju\n", (uintmax_t)dv);
+ break;
+ }
+ case 'X': {
+ __u32 layout_version;
+
+ rc = llapi_get_ost_layout_version(fd, &layout_version);
+ if (rc) {
+ fprintf(stderr, "cannot get ost layout version"
+ " %lld\n", rc);
exit(-rc);
}
- printf("dataversion is "LPU64"\n", dv);
+ printf("ostlayoutversion: %u\n", layout_version);
break;
+ }
case 'y':
if (fsync(fd) == -1) {
save_errno = errno;
}
break;
case 'Y':
- if (fdatasync(fd) == -1) {
- save_errno = errno;
- perror("fdatasync");
- exit(save_errno);
- }
- case 'z':
- len = atoi(commands+1);
- if (lseek(fd, len, SEEK_SET) == -1) {
- save_errno = errno;
- perror("lseek");
- exit(save_errno);
- }
- break;
+ if (fdatasync(fd) == -1) {
+ save_errno = errno;
+ perror("fdatasync");
+ exit(save_errno);
+ }
+ break;
+ case 'z': {
+ off_t off;
+
+ len = atoi(commands + 1);
+ off = lseek(fd, len, SEEK_SET);
+ if (off == (off_t)-1) {
+ save_errno = errno;
+ perror("lseek");
+ exit(save_errno);
+ }
+
+ rc = off;
+ break;
+ }
+ case 'Z': {
+ off_t off;
+
+ len = atoi(commands + 1);
+ off = lseek(fd, len, SEEK_CUR);
+ if (off == (off_t)-1) {
+ save_errno = errno;
+ perror("lseek");
+ exit(save_errno);
+ }
+
+ rc = off;
+ break;
+ }
case '-':
case '0':
case '1':