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) 2023, Whamcloud DDN Storage Corporation.
26 * Create|Open|Stat|Read ahead.
27 * This program is mainly used to verify that ahead feature works as
28 * expected for batch file accesses.
30 * Author: Qian Yingjin <qian@ddn.com>
43 #include <sys/types.h>
45 #include <linux/unistd.h>
47 #include <sys/ioctl.h>
49 #include <linux/lustre/lustre_user.h>
51 static char *progname;
53 static void usage(void)
55 printf("Usage: %s {--iocall|-c [stat|open|create|read]}\n"
56 "[--start|-s start] [--end|-e end] [--basename NAME]\n"
57 "[--batch_max|-B] {--dir|-d DIR} dentry ...\n"
58 "\t--iocall|-c: I/O syscall in a predictive batch access\n"
59 "\t--start|-s: Start index of file names\n"
60 "\t--end|-e: End index of file names\n"
61 "\t--basename|-b:Base name for file naming format\n"
62 "\t--batch_max|-B: max batch count for ahead operations\n"
63 "\t--directory|-d: under this directory do ahead operations\n",
68 static char *get_file_name(const char *dirpath, const char *basename, long n)
70 static char filename[PATH_MAX];
73 bytes = snprintf(filename, PATH_MAX - 1, "%s/%s%ld",
74 dirpath, basename, n);
75 if (bytes >= PATH_MAX - 1) {
76 fprintf(stderr, "%s: file name too long\n", progname);
83 static int ll_ahead_by_name_index(const char *dirpath, const char *fname,
84 enum lu_access_flags flags, __u64 start,
85 __u64 end, __u32 batch_max)
87 struct llapi_lu_ladvise2 ladvise;
93 dir_fd = open(dirpath, O_DIRECTORY | O_RDONLY);
96 fprintf(stderr, "%s: failed to open dir '%s': rc = %d\n",
97 progname, dirpath, rc);
101 ladvise.lla_advice = LU_LADVISE_AHEAD;
102 ladvise.lla_ahead_mode = LU_AH_NAME_INDEX;
103 ladvise.lla_access_flags = flags;
104 ladvise.lla_start = start;
105 ladvise.lla_end = end;
106 ladvise.lla_batch_max = batch_max;
107 strncpy(ladvise.lla_fname, fname, sizeof(ladvise.lla_fname) - 1);
108 rc = ioctl(dir_fd, LL_IOC_LADVISE2, &ladvise);
110 fprintf(stderr, "%s: failed to ahead for '%s': rc = %d\n",
111 progname, dirpath, rc);
116 for (i = start; i < end; i++) {
119 filename = get_file_name(dirpath, fname, i);
120 rc = stat(filename, &st);
123 fprintf(stderr, "%s: stat(%s) failed: rc = %d\n",
124 progname, filename, errno);
133 int main(int argc, char **argv)
135 struct option long_opts[] = {
136 { .val = 'c', .name = "iocall", .has_arg = required_argument },
137 { .val = 's', .name = "start", .has_arg = required_argument },
138 { .val = 'e', .name = "end", .has_arg = required_argument },
139 { .val = 'b', .name = "basename", .has_arg = required_argument },
140 { .val = 'd', .name = "directory", .has_arg = required_argument },
141 { .val = 'B', .name = "batch_max", .has_arg = required_argument },
142 { .val = 'h', .name = "help", .has_arg = no_argument },
144 enum lu_access_flags flags = ACCESS_FL_NONE;
145 enum lu_ahead_mode mode = LU_AH_NAME_INDEX;
147 const char *dirpath = NULL;
149 __u64 start_index = 0;
155 progname = basename(argv[0]);
156 while ((c = getopt_long(argc, argv, "c:s:e:b:d:B:h",
157 long_opts, NULL)) != -1) {
160 if (strcmp(optarg, "stat") == 0) {
161 flags |= ACCESS_FL_STAT;
162 } else if (strcmp(optarg, "open") == 0) {
163 flags |= ACCESS_FL_OPEN;
164 } else if (strcmp(optarg, "creat") == 0 ||
165 strcmp(optarg, "create") == 0) {
166 flags |= ACCESS_FL_CREAT;
167 } else if (strcmp(optarg, "read") == 0) {
168 flags |= ACCESS_FL_READ;
169 } else if (strcmp(optarg, "write") == 0) {
170 flags |= ACCESS_FL_WRITE;
172 fprintf(stderr, "%s %s: bad access type '%s'\n",
173 progname, argv[0], optarg);
178 start_index = strtoull(optarg, &end, 0);
180 fprintf(stderr, "%s %s: bad start index '%s'\n",
181 progname, argv[0], optarg);
186 end_index = strtoull(optarg, &end, 0);
188 fprintf(stderr, "%s %s: bad start index '%s'\n",
189 progname, argv[0], optarg);
194 batch_max = strtoul(optarg, &end, 0);
196 fprintf(stderr, "%s %s: bad batch count '%s'\n",
197 progname, argv[0], optarg);
208 fprintf(stderr, "%s: unrecognized option '%s'\n",
209 progname, argv[optind - 1]);
216 if (flags == ACCESS_FL_NONE) {
217 fprintf(stderr, "%s: must specify access mode\n", progname);
222 fprintf(stderr, "%s: must specify directory path\n", progname);
226 if (mode == LU_AH_NAME_INDEX) {
228 fprintf(stderr, "%s: must specify base file name\n",
233 if (end_index == 0) {
234 fprintf(stderr, "%s: must specify end index\n",
239 if (flags != ACCESS_FL_STAT) {
240 fprintf(stderr, "%s: only support stat-ahead\n",
245 rc = ll_ahead_by_name_index(dirpath, fname, flags, start_index,
246 end_index, batch_max);
249 fprintf(stderr, "%s: unsupported ahead type %d\n",