Whamcloud - gitweb
LU-14361 statahead: increase the initial statahead count
[fs/lustre-release.git] / lustre / tests / aheadmany.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2023, Whamcloud DDN Storage Corporation.
24  */
25 /*
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.
29  *
30  * Author: Qian Yingjin <qian@ddn.com>
31  */
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <errno.h>
36 #include <getopt.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <time.h>
40 #include <stdbool.h>
41 #include <string.h>
42 #include <dirent.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <linux/unistd.h>
46 #include <libgen.h>
47 #include <sys/ioctl.h>
48
49 #include <linux/lustre/lustre_user.h>
50
51 static char *progname;
52
53 static void usage(void)
54 {
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--noadvise|-N:No ahead advise hint IOCTL\n"
63                "\t--batch_max|-B: max batch count for ahead operations\n"
64                "\t--directory|-d: under this directory do ahead operations\n",
65                progname);
66         exit(0);
67 }
68
69 static char *get_file_name(const char *dirpath, const char *basename, long n)
70 {
71         static char filename[PATH_MAX];
72         int bytes;
73
74         bytes = snprintf(filename, PATH_MAX - 1, "%s/%s%ld",
75                          dirpath, basename, n);
76         if (bytes >= PATH_MAX - 1) {
77                 fprintf(stderr, "%s: file name too long\n", progname);
78                 exit(EXIT_FAILURE);
79         }
80
81         return filename;
82 }
83
84 static int ll_batch_io_by_name(const char *dirpath, const char *fname,
85                                enum lu_access_flags flags, __u64 start,
86                                __u64 end)
87 {
88         int rc = 0;
89         int i;
90
91         for (i = start; i < end; i++) {
92                 char *filename;
93                 struct stat st;
94
95                 filename = get_file_name(dirpath, fname, i);
96                 if (flags & ACCESS_FL_STAT) {
97                         rc = stat(filename, &st);
98                         if (rc < 0) {
99                                 rc = -errno;
100                                 fprintf(stderr,
101                                         "%s: stat(%s) failed: rc = %d\n",
102                                         progname, filename, errno);
103                                 break;
104                         }
105                 }
106         }
107
108         return rc;
109 }
110
111 static int ll_ahead_by_name_index(const char *dirpath, const char *fname,
112                                   enum lu_access_flags flags, __u64 start,
113                                   __u64 end, __u32 batch_max)
114 {
115         struct llapi_lu_ladvise2 ladvise;
116         int dir_fd;
117         int rc;
118
119         dir_fd = open(dirpath, O_DIRECTORY | O_RDONLY);
120         if (dir_fd < 0) {
121                 rc = -errno;
122                 fprintf(stderr, "%s: failed to open dir '%s': rc = %d\n",
123                         progname, dirpath, rc);
124                 return rc;
125         }
126
127         ladvise.lla_advice = LU_LADVISE_AHEAD;
128         ladvise.lla_ahead_mode = LU_AH_NAME_INDEX;
129         ladvise.lla_access_flags = flags;
130         ladvise.lla_start = start;
131         ladvise.lla_end = end;
132         ladvise.lla_batch_max = batch_max;
133         strncpy(ladvise.lla_fname, fname, sizeof(ladvise.lla_fname) - 1);
134         rc = ioctl(dir_fd, LL_IOC_LADVISE2, &ladvise);
135         if (rc < 0) {
136                 fprintf(stderr, "%s: failed to ahead for '%s': rc = %d\n",
137                         progname, dirpath, rc);
138                 close(dir_fd);
139                 return rc;
140         }
141
142         rc = ll_batch_io_by_name(dirpath, fname, flags, start, end);
143         close(dir_fd);
144         return rc;
145 }
146
147 int main(int argc, char **argv)
148 {
149         struct option long_opts[] = {
150         { .val = 'c',   .name = "iocall",       .has_arg = required_argument },
151         { .val = 's',   .name = "start",        .has_arg = required_argument },
152         { .val = 'e',   .name = "end",          .has_arg = required_argument },
153         { .val = 'b',   .name = "basename",     .has_arg = required_argument },
154         { .val = 'd',   .name = "directory",    .has_arg = required_argument },
155         { .val = 'B',   .name = "batch_max",    .has_arg = required_argument },
156         { .val = 'N',   .name = "noadvise",     .has_arg = no_argument },
157         { .val = 'h',   .name = "help",         .has_arg = no_argument },
158         { .name = NULL } };
159         enum lu_access_flags flags = ACCESS_FL_NONE;
160         enum lu_ahead_mode mode = LU_AH_NAME_INDEX;
161         __u32 batch_max = 0;
162         const char *dirpath = NULL;
163         char *fname = NULL;
164         __u64 start_index = 0;
165         __u64 end_index = 0;
166         bool has_advise = true;
167         char *end;
168         int rc = 0;
169         int c;
170
171         progname = basename(argv[0]);
172         while ((c = getopt_long(argc, argv, "c:s:e:b:d:B:Nh",
173                                 long_opts, NULL)) != -1) {
174                 switch (c) {
175                 case 'c':
176                         if (strcmp(optarg, "stat") == 0) {
177                                 flags |= ACCESS_FL_STAT;
178                         } else if (strcmp(optarg, "open") == 0) {
179                                 flags |= ACCESS_FL_OPEN;
180                         } else if (strcmp(optarg, "creat") == 0 ||
181                                  strcmp(optarg, "create") == 0) {
182                                 flags |= ACCESS_FL_CREAT;
183                         } else if (strcmp(optarg, "read") == 0) {
184                                 flags |= ACCESS_FL_READ;
185                         } else if (strcmp(optarg, "write") == 0) {
186                                 flags |= ACCESS_FL_WRITE;
187                         } else {
188                                 fprintf(stderr, "%s %s: bad access type '%s'\n",
189                                         progname, argv[0], optarg);
190                                 return -EINVAL;
191                         }
192                         break;
193                 case 's':
194                         start_index = strtoull(optarg, &end, 0);
195                         if (*end) {
196                                 fprintf(stderr, "%s %s: bad start index '%s'\n",
197                                         progname, argv[0], optarg);
198                                 return -EINVAL;
199                         }
200                         break;
201                 case 'e':
202                         end_index = strtoull(optarg, &end, 0);
203                         if (*end) {
204                                 fprintf(stderr, "%s %s: bad start index '%s'\n",
205                                         progname, argv[0], optarg);
206                                 return -EINVAL;
207                         }
208                         break;
209                 case 'B':
210                         batch_max = strtoul(optarg, &end, 0);
211                         if (*end) {
212                                 fprintf(stderr, "%s %s: bad batch count '%s'\n",
213                                         progname, argv[0], optarg);
214                                 return -EINVAL;
215                         }
216                         break;
217                 case 'N':
218                         has_advise = false;
219                         break;
220                 case 'b':
221                         fname = optarg;
222                         break;
223                 case 'd':
224                         dirpath = optarg;
225                         break;
226                 default:
227                         fprintf(stderr, "%s: unrecognized option '%s'\n",
228                                 progname, argv[optind - 1]);
229                         return -EOPNOTSUPP;
230                 case 'h':
231                         usage();
232                 }
233         }
234
235         if (flags == ACCESS_FL_NONE) {
236                 fprintf(stderr, "%s: must specify access mode\n", progname);
237                 return -EINVAL;
238         }
239
240         if (!dirpath) {
241                 fprintf(stderr, "%s: must specify directory path\n", progname);
242                 return -EINVAL;
243         }
244
245         if (mode == LU_AH_NAME_INDEX) {
246                 if (!fname) {
247                         fprintf(stderr, "%s: must specify base file name\n",
248                                 progname);
249                         return -EINVAL;
250                 }
251
252                 if (end_index == 0) {
253                         fprintf(stderr, "%s: must specify end index\n",
254                                 progname);
255                         return -EINVAL;
256                 }
257
258                 if (flags != ACCESS_FL_STAT) {
259                         fprintf(stderr, "%s: only support stat-ahead\n",
260                                 progname);
261                         return -EINVAL;
262                 }
263
264                 if (has_advise)
265                         rc = ll_ahead_by_name_index(dirpath, fname, flags,
266                                                     start_index, end_index,
267                                                     batch_max);
268                 else
269                         rc = ll_batch_io_by_name(dirpath, fname, flags,
270                                                  start_index, end_index);
271         } else {
272                 rc = -EOPNOTSUPP;
273                 fprintf(stderr, "%s: unsupported ahead type %d\n",
274                         progname, mode);
275         }
276
277         return rc;
278 }
279