Whamcloud - gitweb
LU-17705 ptlrpc: replace synchronize_rcu() with rcu_barrier()
[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 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 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 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 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 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 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 int do_fallocate(int fd, int mode, loff_t offset, loff_t expected_new_size)
150 {
151         int rc;
152         loff_t len;
153
154         len = blksize;
155         rc = __do_fallocate(fd, mode, offset, len);
156         if (rc != 0)
157                 goto out;
158
159         rc = post_fallocate_checks(fd, mode, offset, len, expected_new_size);
160         if (rc != 0) {
161                 fprintf(stderr, "post_fallocate_checks failed for mode %d\n",
162                         mode);
163                 goto out;
164         }
165 out:
166         return rc;
167
168 }
169
170 int test_prealloc_nonsparse(int fd)
171 {
172         int rc, mode;
173         loff_t offset, expected_new_size;
174         struct stat st;
175
176         lseek(fd, 0, SEEK_SET);
177         rc = write_data_to_file(fd);
178         if (rc != 0)
179                 goto out;
180
181         rc = get_stat(fd, &st);
182         if (rc != 0)
183                 goto out;
184
185         /* test default mode */
186         mode = 0;
187         offset = lseek(fd, 0, SEEK_END);
188         expected_new_size = WRITE_BLOCKS * blksize + blksize;
189         rc = do_fallocate(fd, mode, offset, expected_new_size);
190 out:
191         return rc;
192 }
193
194 int test_prealloc_sparse(int fd)
195 {
196         int rc, mode;
197         loff_t offset, expected_new_size;
198         struct stat st;
199
200         rc = ftruncate(fd, 0);
201         if (rc != 0) {
202                 fprintf(stderr, "ftruncate error %s\n", strerror(errno));
203                 rc = errno;
204                 goto out;
205         }
206
207         lseek(fd, 0, SEEK_SET);
208         rc = create_hole(fd);
209         if (rc != 0)
210                 goto out;
211
212         rc = get_stat(fd, &st);
213         if (rc != 0)
214                 goto out;
215
216         /* test default mode */
217         mode = 0;
218         offset = lseek(fd, (WRITE_BLOCKS + HOLE_BLOCKS / 2) * blksize,
219                        SEEK_SET);
220         expected_new_size = (2 * WRITE_BLOCKS + HOLE_BLOCKS) * blksize;
221         rc = do_fallocate(fd, mode, offset, expected_new_size);
222 out:
223         return rc;
224 }
225
226 int main(int argc, char *argv[])
227 {
228         char *fname, *mount_point = NULL;
229         int rc = -EINVAL, fd;
230         struct stat st;
231         struct mntent *ent;
232         FILE *mntpt;
233
234         if (argc != 2)
235                 usage(argv[0]);
236
237         fname = argv[1];
238         if (fname[0] != '/') {
239                 fprintf(stderr, "Need absolute path of the file\n");
240                 goto out;
241         }
242
243         fd = open(fname, O_RDWR | O_CREAT, 0700);
244         if (fd < 0) {
245                 fprintf(stderr, "open file %s error: %s\n",
246                         fname, strerror(errno));
247                 rc = errno;
248                 goto out;
249         }
250
251         mntpt = setmntent("/etc/mtab", "r");
252         if (mntpt == NULL) {
253                 fprintf(stderr, "setmntent error: %s\n",
254                         strerror(errno));
255                 rc = errno;
256                 goto out_open;
257         }
258
259         while (NULL != (ent = getmntent(mntpt))) {
260                 if (llapi_is_lustre_mnttype(ent->mnt_fsname) == 0) {
261                         mount_point = ent->mnt_dir;
262                         break;
263                 }
264         }
265         endmntent(mntpt);
266
267         if (mount_point == NULL) {
268                 fprintf(stderr, "file not on lustre filesystem?\n");
269                 goto out_open;
270         }
271
272         rc = get_stat(fd, &st);
273         if (rc != 0)
274                 goto out_open;
275         blksize = st.st_blksize;
276
277         rc = test_prealloc_nonsparse(fd);
278         if (rc != 0)
279                 goto out_open;
280
281         rc = test_prealloc_sparse(fd);
282         if (rc != 0)
283                 goto out_open;
284
285 out_open:
286         close(fd);
287 out:
288         return rc;
289 }