Whamcloud - gitweb
LU-17097 osc: delete items in Xarray before its destroy
[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--batch_max|-B: max batch count for ahead operations\n"
63                "\t--directory|-d: under this directory do ahead operations\n",
64                progname);
65         exit(0);
66 }
67
68 static char *get_file_name(const char *dirpath, const char *basename, long n)
69 {
70         static char filename[PATH_MAX];
71         int bytes;
72
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);
77                 exit(EXIT_FAILURE);
78         }
79
80         return filename;
81 }
82
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)
86 {
87         struct llapi_lu_ladvise2 ladvise;
88         struct stat st;
89         int dir_fd;
90         int rc;
91         int i;
92
93         dir_fd = open(dirpath, O_DIRECTORY | O_RDONLY);
94         if (dir_fd < 0) {
95                 rc = -errno;
96                 fprintf(stderr, "%s: failed to open dir '%s': rc = %d\n",
97                         progname, dirpath, rc);
98                 return rc;
99         }
100
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);
109         if (rc < 0) {
110                 fprintf(stderr, "%s: failed to ahead for '%s': rc = %d\n",
111                         progname, dirpath, rc);
112                 close(dir_fd);
113                 return rc;
114         }
115
116         for (i = start; i < end; i++) {
117                 char *filename;
118
119                 filename = get_file_name(dirpath, fname, i);
120                 rc = stat(filename, &st);
121                 if (rc < 0) {
122                         rc = -errno;
123                         fprintf(stderr, "%s: stat(%s) failed: rc = %d\n",
124                                 progname, filename, errno);
125                         break;
126                 }
127         }
128
129         close(dir_fd);
130         return rc;
131 }
132
133 int main(int argc, char **argv)
134 {
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 },
143         { .name = NULL } };
144         enum lu_access_flags flags = ACCESS_FL_NONE;
145         enum lu_ahead_mode mode = LU_AH_NAME_INDEX;
146         __u32 batch_max = 0;
147         const char *dirpath = NULL;
148         char *fname = NULL;
149         __u64 start_index = 0;
150         __u64 end_index = 0;
151         char *end;
152         int rc = 0;
153         int c;
154
155         progname = basename(argv[0]);
156         while ((c = getopt_long(argc, argv, "c:s:e:b:d:B:h",
157                                 long_opts, NULL)) != -1) {
158                 switch (c) {
159                 case 'c':
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;
171                         } else {
172                                 fprintf(stderr, "%s %s: bad access type '%s'\n",
173                                         progname, argv[0], optarg);
174                                 return -EINVAL;
175                         }
176                         break;
177                 case 's':
178                         start_index = strtoull(optarg, &end, 0);
179                         if (*end) {
180                                 fprintf(stderr, "%s %s: bad start index '%s'\n",
181                                         progname, argv[0], optarg);
182                                 return -EINVAL;
183                         }
184                         break;
185                 case 'e':
186                         end_index = strtoull(optarg, &end, 0);
187                         if (*end) {
188                                 fprintf(stderr, "%s %s: bad start index '%s'\n",
189                                         progname, argv[0], optarg);
190                                 return -EINVAL;
191                         }
192                         break;
193                 case 'B':
194                         batch_max = strtoul(optarg, &end, 0);
195                         if (*end) {
196                                 fprintf(stderr, "%s %s: bad batch count '%s'\n",
197                                         progname, argv[0], optarg);
198                                 return -EINVAL;
199                         }
200                         break;
201                 case 'b':
202                         fname = optarg;
203                         break;
204                 case 'd':
205                         dirpath = optarg;
206                         break;
207                 default:
208                         fprintf(stderr, "%s: unrecognized option '%s'\n",
209                                 progname, argv[optind - 1]);
210                         return -EOPNOTSUPP;
211                 case 'h':
212                         usage();
213                 }
214         }
215
216         if (flags == ACCESS_FL_NONE) {
217                 fprintf(stderr, "%s: must specify access mode\n", progname);
218                 return -EINVAL;
219         }
220
221         if (!dirpath) {
222                 fprintf(stderr, "%s: must specify directory path\n", progname);
223                 return -EINVAL;
224         }
225
226         if (mode == LU_AH_NAME_INDEX) {
227                 if (!fname) {
228                         fprintf(stderr, "%s: must specify base file name\n",
229                                 progname);
230                         return -EINVAL;
231                 }
232
233                 if (end_index == 0) {
234                         fprintf(stderr, "%s: must specify end index\n",
235                                 progname);
236                         return -EINVAL;
237                 }
238
239                 if (flags != ACCESS_FL_STAT) {
240                         fprintf(stderr, "%s: only support stat-ahead\n",
241                                 progname);
242                         return -EINVAL;
243                 }
244
245                 rc = ll_ahead_by_name_index(dirpath, fname, flags, start_index,
246                                             end_index, batch_max);
247         } else {
248                 rc = -EOPNOTSUPP;
249                 fprintf(stderr, "%s: unsupported ahead type %d\n",
250                         progname, mode);
251         }
252
253         return rc;
254 }
255