Whamcloud - gitweb
LU-11085 tests: Add performance test for ldlm_extent code
[fs/lustre-release.git] / lustre / tests / check_fallocate.c
1 /* GPL HEADER START
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 only,
7  * as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License version 2 for more details (a copy is included
13  * in the LICENSE file that accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License
16  * version 2 along with this program; If not, see
17  * http://www.gnu.org/licenses/gpl-2.0.html
18  *
19  * GPL HEADER END
20  */
21
22 /*
23  * Copyright (C) 2014, DataDirect Networks, Inc.
24  * Author: Swapnil Pimpale <spimpale@ddn.com>
25  */
26
27 /*
28  * This test case tests the following scenarios
29  * 1) Preallocate: try to fallocate memory blocks and write to it
30  *      i) Non-sparse file
31  *              - DEFAULT MODE
32  *      ii) Sparse file
33  *              - create a hole in a file and preallocate using both the
34  *              modes
35  * Rest of mode flags is not supported currenlty
36  */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 #include <string.h>
45 #include <mntent.h>
46 #include <lustre/lustreapi.h>
47
48 #define WRITE_BLOCKS    10
49 #define HOLE_BLOCKS     10
50
51 /* global */
52 loff_t  blksize;
53
54 static void usage(char *prog)
55 {
56         fprintf(stderr, "usage: %s <filepath>\n", prog);
57         fprintf(stderr, "filepath: absolute pathname of Lustre file\n");
58         exit(1);
59 }
60
61 static int write_data_to_file(int fd)
62 {
63         char buf[blksize + 1];
64         int rc, i, j;
65
66         for (i = 0; i < WRITE_BLOCKS; i++) {
67                 for (j = 0; j < blksize; j++)
68                         buf[j] = 'X';
69                 buf[j] = '\0';
70                 rc = write(fd, buf, blksize);
71                 if (rc < 0) {
72                         fprintf(stderr, "write failed error %s\n",
73                                 strerror(errno));
74                         return errno;
75                 }
76         }
77         return 0;
78 }
79
80 static int get_stat(int fd, struct stat *st)
81 {
82         int rc = 0;
83
84         bzero(st, sizeof(struct stat));
85         if (fstat(fd, st)) {
86                 fprintf(stderr, "stat file error: %s\n", strerror(errno));
87                 rc = errno;
88         }
89         return rc;
90 }
91
92 static int __do_fallocate(int fd, int mode, loff_t offset, loff_t len)
93 {
94         int rc;
95
96         rc = fallocate(fd, mode, offset, len);
97         if (rc != 0) {
98                 fprintf(stderr,
99                         "fallocate failed, error %s, mode %d, offset %llu, len %llu\n",
100                         strerror(errno), mode, (unsigned long long)offset,
101                         (unsigned long long)len);
102                 rc = errno;
103         }
104
105         return rc;
106 }
107
108 static int post_fallocate_checks(int fd, int mode, loff_t offset, loff_t len,
109                           loff_t expected_new_size)
110 {
111         struct stat st;
112         int rc = 0;
113
114         /* check the new size */
115         rc = get_stat(fd, &st);
116         if (rc != 0)
117                 goto out;
118
119         if (st.st_size != expected_new_size) {
120                 fprintf(stderr,
121                         "fallocate succeeded but size reported is wrong\n");
122                 fprintf(stderr,
123                         "mode %d, offset %llu, len %llu, new_size %llu, expected_new_size %llu\n",
124                         mode, (unsigned long long)offset,
125                         (unsigned long long)len, (unsigned long long)st.st_size,
126                         (unsigned long long)expected_new_size);
127                 rc = -1;
128         }
129 out:
130         return rc;
131 }
132
133 static int create_hole(int fd)
134 {
135         int rc;
136
137         rc = write_data_to_file(fd);
138         if (rc != 0)
139                 goto out;
140
141         lseek(fd, HOLE_BLOCKS * blksize, SEEK_CUR);
142
143         rc = write_data_to_file(fd);
144         if (rc != 0)
145                 return rc;
146 out:
147         return rc;
148 }
149
150 static int do_fallocate(int fd, int mode, loff_t offset,
151                         loff_t expected_new_size)
152 {
153         int rc;
154         loff_t len;
155
156         len = blksize;
157         rc = __do_fallocate(fd, mode, offset, len);
158         if (rc != 0)
159                 goto out;
160
161         rc = post_fallocate_checks(fd, mode, offset, len, expected_new_size);
162         if (rc != 0) {
163                 fprintf(stderr, "post_fallocate_checks failed for mode %d\n",
164                         mode);
165                 goto out;
166         }
167 out:
168         return rc;
169
170 }
171
172 static int test_prealloc_nonsparse(int fd)
173 {
174         int rc, mode;
175         loff_t offset, expected_new_size;
176         struct stat st;
177
178         lseek(fd, 0, SEEK_SET);
179         rc = write_data_to_file(fd);
180         if (rc != 0)
181                 goto out;
182
183         rc = get_stat(fd, &st);
184         if (rc != 0)
185                 goto out;
186
187         /* test default mode */
188         mode = 0;
189         offset = lseek(fd, 0, SEEK_END);
190         expected_new_size = WRITE_BLOCKS * blksize + blksize;
191         rc = do_fallocate(fd, mode, offset, expected_new_size);
192 out:
193         return rc;
194 }
195
196 static int test_prealloc_sparse(int fd)
197 {
198         int rc, mode;
199         loff_t offset, expected_new_size;
200         struct stat st;
201
202         rc = ftruncate(fd, 0);
203         if (rc != 0) {
204                 fprintf(stderr, "ftruncate error %s\n", strerror(errno));
205                 rc = errno;
206                 goto out;
207         }
208
209         lseek(fd, 0, SEEK_SET);
210         rc = create_hole(fd);
211         if (rc != 0)
212                 goto out;
213
214         rc = get_stat(fd, &st);
215         if (rc != 0)
216                 goto out;
217
218         /* test default mode */
219         mode = 0;
220         offset = lseek(fd, (WRITE_BLOCKS + HOLE_BLOCKS / 2) * blksize,
221                        SEEK_SET);
222         expected_new_size = (2 * WRITE_BLOCKS + HOLE_BLOCKS) * blksize;
223         rc = do_fallocate(fd, mode, offset, expected_new_size);
224 out:
225         return rc;
226 }
227
228 int main(int argc, char *argv[])
229 {
230         char *fname, *mount_point = NULL;
231         int rc = -EINVAL, fd;
232         struct stat st;
233         struct mntent *ent;
234         FILE *mntpt;
235
236         if (argc != 2)
237                 usage(argv[0]);
238
239         fname = argv[1];
240         if (fname[0] != '/') {
241                 fprintf(stderr, "Need absolute path of the file\n");
242                 goto out;
243         }
244
245         fd = open(fname, O_RDWR | O_CREAT, 0700);
246         if (fd < 0) {
247                 fprintf(stderr, "open file %s error: %s\n",
248                         fname, strerror(errno));
249                 rc = errno;
250                 goto out;
251         }
252
253         mntpt = setmntent("/etc/mtab", "r");
254         if (mntpt == NULL) {
255                 fprintf(stderr, "setmntent error: %s\n",
256                         strerror(errno));
257                 rc = errno;
258                 goto out_open;
259         }
260
261         while (NULL != (ent = getmntent(mntpt))) {
262                 if (llapi_is_lustre_mnttype(ent->mnt_fsname) == 0) {
263                         mount_point = ent->mnt_dir;
264                         break;
265                 }
266         }
267         endmntent(mntpt);
268
269         if (mount_point == NULL) {
270                 fprintf(stderr, "file not on lustre filesystem?\n");
271                 goto out_open;
272         }
273
274         rc = get_stat(fd, &st);
275         if (rc != 0)
276                 goto out_open;
277         blksize = st.st_blksize;
278
279         rc = test_prealloc_nonsparse(fd);
280         if (rc != 0)
281                 goto out_open;
282
283         rc = test_prealloc_sparse(fd);
284         if (rc != 0)
285                 goto out_open;
286
287 out_open:
288         close(fd);
289 out:
290         return rc;
291 }