Whamcloud - gitweb
LU-17038 tests: remove mlink utility
[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, "fallocate failed, error %s, mode %d, "
99                         "offset %llu, len %llu\n", strerror(errno), mode,
100                         (unsigned long long)offset, (unsigned long long)len);
101                 rc = errno;
102         }
103
104         return rc;
105 }
106
107 static int post_fallocate_checks(int fd, int mode, loff_t offset, loff_t len,
108                           loff_t expected_new_size)
109 {
110         struct stat st;
111         int rc = 0;
112
113         /* check the new size */
114         rc = get_stat(fd, &st);
115         if (rc != 0)
116                 goto out;
117
118         if (st.st_size != expected_new_size) {
119                 fprintf(stderr, "fallocate succeeded but size reported "
120                         "is wrong\n");
121                 fprintf(stderr, "mode %d, offset %llu, len %llu, "
122                         "new_size %llu, expected_new_size %llu\n", mode,
123                         (unsigned long long)offset, (unsigned long long)len,
124                         (unsigned long long)st.st_size,
125                         (unsigned long long)expected_new_size);
126                 rc = -1;
127         }
128 out:
129         return rc;
130 }
131
132 static int create_hole(int fd)
133 {
134         int rc;
135
136         rc = write_data_to_file(fd);
137         if (rc != 0)
138                 goto out;
139
140         lseek(fd, HOLE_BLOCKS * blksize, SEEK_CUR);
141
142         rc = write_data_to_file(fd);
143         if (rc != 0)
144                 return rc;
145 out:
146         return rc;
147 }
148
149 static int do_fallocate(int fd, int mode, loff_t offset,
150                         loff_t expected_new_size)
151 {
152         int rc;
153         loff_t len;
154
155         len = blksize;
156         rc = __do_fallocate(fd, mode, offset, len);
157         if (rc != 0)
158                 goto out;
159
160         rc = post_fallocate_checks(fd, mode, offset, len, expected_new_size);
161         if (rc != 0) {
162                 fprintf(stderr, "post_fallocate_checks failed for mode %d\n",
163                         mode);
164                 goto out;
165         }
166 out:
167         return rc;
168
169 }
170
171 static int test_prealloc_nonsparse(int fd)
172 {
173         int rc, mode;
174         loff_t offset, expected_new_size;
175         struct stat st;
176
177         lseek(fd, 0, SEEK_SET);
178         rc = write_data_to_file(fd);
179         if (rc != 0)
180                 goto out;
181
182         rc = get_stat(fd, &st);
183         if (rc != 0)
184                 goto out;
185
186         /* test default mode */
187         mode = 0;
188         offset = lseek(fd, 0, SEEK_END);
189         expected_new_size = WRITE_BLOCKS * blksize + blksize;
190         rc = do_fallocate(fd, mode, offset, expected_new_size);
191 out:
192         return rc;
193 }
194
195 static int test_prealloc_sparse(int fd)
196 {
197         int rc, mode;
198         loff_t offset, expected_new_size;
199         struct stat st;
200
201         rc = ftruncate(fd, 0);
202         if (rc != 0) {
203                 fprintf(stderr, "ftruncate error %s\n", strerror(errno));
204                 rc = errno;
205                 goto out;
206         }
207
208         lseek(fd, 0, SEEK_SET);
209         rc = create_hole(fd);
210         if (rc != 0)
211                 goto out;
212
213         rc = get_stat(fd, &st);
214         if (rc != 0)
215                 goto out;
216
217         /* test default mode */
218         mode = 0;
219         offset = lseek(fd, (WRITE_BLOCKS + HOLE_BLOCKS / 2) * blksize,
220                        SEEK_SET);
221         expected_new_size = (2 * WRITE_BLOCKS + HOLE_BLOCKS) * blksize;
222         rc = do_fallocate(fd, mode, offset, expected_new_size);
223 out:
224         return rc;
225 }
226
227 int main(int argc, char *argv[])
228 {
229         char *fname, *mount_point = NULL;
230         int rc = -EINVAL, fd;
231         struct stat st;
232         struct mntent *ent;
233         FILE *mntpt;
234
235         if (argc != 2)
236                 usage(argv[0]);
237
238         fname = argv[1];
239         if (fname[0] != '/') {
240                 fprintf(stderr, "Need absolute path of the file\n");
241                 goto out;
242         }
243
244         fd = open(fname, O_RDWR | O_CREAT, 0700);
245         if (fd < 0) {
246                 fprintf(stderr, "open file %s error: %s\n",
247                         fname, strerror(errno));
248                 rc = errno;
249                 goto out;
250         }
251
252         mntpt = setmntent("/etc/mtab", "r");
253         if (mntpt == NULL) {
254                 fprintf(stderr, "setmntent error: %s\n",
255                         strerror(errno));
256                 rc = errno;
257                 goto out_open;
258         }
259
260         while (NULL != (ent = getmntent(mntpt))) {
261                 if (llapi_is_lustre_mnttype(ent->mnt_fsname) == 0) {
262                         mount_point = ent->mnt_dir;
263                         break;
264                 }
265         }
266         endmntent(mntpt);
267
268         if (mount_point == NULL) {
269                 fprintf(stderr, "file not on lustre filesystem?\n");
270                 goto out_open;
271         }
272
273         rc = get_stat(fd, &st);
274         if (rc != 0)
275                 goto out_open;
276         blksize = st.st_blksize;
277
278         rc = test_prealloc_nonsparse(fd);
279         if (rc != 0)
280                 goto out_open;
281
282         rc = test_prealloc_sparse(fd);
283         if (rc != 0)
284                 goto out_open;
285
286 out_open:
287         close(fd);
288 out:
289         return rc;
290 }