Whamcloud - gitweb
LU-9219 tests: add missing mgs reformat to conf-sanity/56
[fs/lustre-release.git] / lustre / tests / sendfile_grouplock.c
1 /*
2  * GPL HEADDER 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 /*
24  * Copyright 2015 Cray Inc, all rights reserved.
25  * Author: Frank Zago.
26  *
27  * A few portions are extracted from llapi_layout_test.c
28  */
29
30 /*
31  * The CRC32 implementation is from RFC 1952, which bears the
32  * following notice:
33  *
34  * Copyright (c) 1996 L. Peter Deutsch
35  *
36  * Permission is granted to copy and distribute this document for any
37  * purpose and without charge, including translations into other
38  * languages and incorporation into compilations, provided that the
39  * copyright notice and this notice are preserved, and that any
40  * substantive changes or deletions from the original are clearly
41  * marked.
42  */
43
44 /*
45  * The purpose of this test is to exert the group lock ioctls in
46  * conjunction with sendfile. Some bugs were found when both were used
47  * at the same time. See LU-6368 and LU-6371.
48  *
49  * The program will exit as soon as a non zero error code is returned.
50  *
51  * It can be called like this:
52  *
53  * dd if=/dev/zero of=/mnt/lustre/foo1 bs=1M count=40
54  * ./sendfile_grouplock /mnt/lustre/foo1
55  */
56
57 #include <stdlib.h>
58 #include <errno.h>
59 #include <getopt.h>
60 #include <fcntl.h>
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <time.h>
64 #include <unistd.h>
65 #include <poll.h>
66 #include <sys/sendfile.h>
67
68 #include <lustre/lustreapi.h>
69
70 #define ERROR(fmt, ...)                                                 \
71         fprintf(stderr, "%s: %s:%d: %s: " fmt "\n",                     \
72                 program_invocation_short_name, __FILE__, __LINE__,      \
73                 __func__, ## __VA_ARGS__);
74
75 #define DIE(fmt, ...)                           \
76         do {                                    \
77                 ERROR(fmt, ## __VA_ARGS__);     \
78                 exit(EXIT_FAILURE);             \
79         } while (0)
80
81 #define ASSERTF(cond, fmt, ...)                                         \
82         do {                                                            \
83                 if (!(cond))                                            \
84                         DIE("assertion '%s' failed: "fmt,               \
85                             #cond, ## __VA_ARGS__);                     \
86         } while (0)
87
88 #define PERFORM(testfn) \
89         do {                                                            \
90                 fprintf(stderr, "Starting test " #testfn " at %lld\n",  \
91                         (unsigned long long)time(NULL));                \
92                 testfn();                                               \
93                 fprintf(stderr, "Finishing test " #testfn " at %lld\n", \
94                         (unsigned long long)time(NULL));                \
95         } while (0)
96
97 /* This test will copy from source_file to dest_file */
98 static const char *source_file;
99 static char *dest_file;
100 static unsigned long source_crc; /* CRC32 of original file */
101
102 /*
103  * A small CRC32 implementation, from RFC 1952
104  */
105
106 /* Table of CRCs of all 8-bit messages. */
107 static unsigned long crc_table[256];
108
109 /* Flag: has the table been computed? Initially false. */
110 static int crc_table_computed;
111
112 /* Make the table for a fast CRC. */
113 static void make_crc_table(void)
114 {
115         unsigned long c;
116
117         int n, k;
118         for (n = 0; n < 256; n++) {
119                 c = (unsigned long) n;
120                 for (k = 0; k < 8; k++) {
121                         if (c & 1)
122                                 c = 0xedb88320L ^ (c >> 1);
123                         else
124                                 c = c >> 1;
125                 }
126                 crc_table[n] = c;
127         }
128         crc_table_computed = 1;
129 }
130
131 /*
132  * Update a running crc with the bytes buf[0..len-1] and return the
133  * updated crc. The crc should be initialized to zero. Pre- and
134  * post-conditioning (one's complement) is performed within this
135  * function so it shouldn't be done by the caller. Usage example:
136  *
137  *      unsigned long crc = 0L;
138  *
139  *      while (read_buffer(buffer, length) != EOF) {
140  *              crc = update_crc(crc, buffer, length);
141  *      }
142  *      if (crc != original_crc) error();
143  */
144 static unsigned long update_crc(unsigned long crc,
145                                 unsigned char *buf, int len)
146 {
147         unsigned long c = crc ^ 0xffffffffL;
148         int n;
149
150         if (!crc_table_computed)
151                 make_crc_table();
152         for (n = 0; n < len; n++)
153                 c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
154
155         return c ^ 0xffffffffL;
156 }
157
158 /* Cleanup our test file. */
159 static void cleanup(void)
160 {
161         unlink(dest_file);
162 }
163
164 /* Compute the CRC32 of a file */
165 static unsigned long compute_crc(const char *fname)
166 {
167         unsigned char buf[1024*1024];
168         unsigned long crc = 0L;
169         struct stat stbuf;
170         int fd;
171         int rc;
172         size_t filesize;
173
174         fd = open(fname, O_RDONLY);
175         ASSERTF(fd >= 0, "open failed for '%s': %s",
176                 fname, strerror(errno));
177
178         rc = fstat(fd, &stbuf);
179         ASSERTF(rc == 0, "fstat of '%s' failed: %s", fname, strerror(errno));
180         filesize = stbuf.st_size;
181
182         while (filesize != 0) {
183                 size_t to_read = sizeof(buf);
184                 ssize_t sret;
185
186                 if (to_read > filesize)
187                         to_read = filesize;
188
189                 sret = read(fd, buf, to_read);
190                 ASSERTF(sret >= 0, "read of %zu bytes from '%s' failed: %s",
191                         to_read, fname, strerror(errno));
192                 ASSERTF(sret > 0, "unexpected EOF for '%s'",
193                         fname);
194
195                 filesize -= sret;
196                 crc = update_crc(crc, buf, sret);
197         }
198
199         close(fd);
200
201         return crc;
202 }
203
204 /* Helper. Copy a file with sendfile. The destination will be
205  * created. If a group lock is 0, it means do not take one. */
206 static int sendfile_copy(const char *source, int source_gid,
207                          const char *dest, int dest_gid)
208 {
209         int rc;
210         struct stat stbuf;
211         size_t filesize;
212         int fd_in;
213         int fd_out;
214
215         fd_in = open(source, O_RDONLY);
216         ASSERTF(fd_in >= 0, "open failed for '%s': %s",
217                 source, strerror(errno));
218
219         rc = fstat(fd_in, &stbuf);
220         ASSERTF(rc == 0, "fstat of '%s' failed: %s", source, strerror(errno));
221         filesize = stbuf.st_size;
222
223         if (source_gid != 0) {
224                 rc = llapi_group_lock(fd_in, source_gid);
225                 ASSERTF(rc == 0, "cannot set group lock %d for '%s': %s",
226                         source_gid, source, strerror(-rc));
227         }
228
229         fd_out = open(dest, O_WRONLY | O_TRUNC | O_CREAT, 0644);
230         ASSERTF(fd_out >= 0, "creation failed for '%s': %s",
231                 dest, strerror(errno));
232
233         if (dest_gid != 0) {
234                 rc = llapi_group_lock(fd_out, dest_gid);
235                 ASSERTF(rc == 0, "cannot set group lock %d for '%s': %s",
236                         dest_gid, dest, strerror(-rc));
237         }
238
239         /* Transfer by 10M blocks */
240         while (filesize != 0) {
241                 size_t to_copy = 10*1024*1024;
242                 ssize_t sret;
243
244                 if (to_copy > filesize)
245                         to_copy = filesize;
246
247                 sret = sendfile(fd_out, fd_in, NULL, to_copy);
248                 rc = errno;
249
250                 /* Although senfile can return less than requested,
251                  * that should not happen under present conditions. At
252                  * the very least, make sure that a decent size was
253                  * copied. See LU-6371. */
254
255                 ASSERTF(sret != 0, "sendfile read 0 bytes");
256                 ASSERTF(sret > 0, "sendfile failed: %s", strerror(rc));
257                 ASSERTF(sret > 100*1024,
258                         "sendfile read too little data: %zd bytes", sret);
259
260                 if (sret != to_copy)
261                         fprintf(stderr,
262                                "Warning: sendfile returned %zd bytes instead of %zu requested\n",
263                                sret, to_copy);
264
265                 filesize -= sret;
266
267         }
268
269         if (dest_gid != 0) {
270                 rc = llapi_group_unlock(fd_out, dest_gid);
271                 ASSERTF(rc == 0, "cannot clear group lock %d for '%s': %s",
272                         dest_gid, dest, strerror(-rc));
273         }
274         if (source_gid != 0) {
275                 rc = llapi_group_unlock(fd_in, source_gid);
276                 ASSERTF(rc == 0, "cannot clear group lock %d for '%s': %s",
277                         source_gid, source, strerror(-rc));
278         }
279
280         close(fd_out);
281         close(fd_in);
282
283         return 0;
284 }
285
286 /* Basic sendfile, without lock taken */
287 static void test10(void)
288 {
289         unsigned long crc;
290
291         cleanup();
292         sendfile_copy(source_file, 0, dest_file, 0);
293         sync();
294
295         crc = compute_crc(dest_file);
296         ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
297 }
298
299 /* sendfile, source locked */
300 static void test11(void)
301 {
302         unsigned long crc;
303
304         cleanup();
305         sendfile_copy(source_file, 85543, dest_file, 0);
306         sync();
307
308         crc = compute_crc(dest_file);
309         ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
310 }
311
312 /* sendfile, destination locked */
313 static void test12(void)
314 {
315         unsigned long crc;
316
317         cleanup();
318         sendfile_copy(source_file, 0, dest_file, 98765);
319         sync();
320
321         crc = compute_crc(dest_file);
322         ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
323 }
324
325 /* sendfile, source and destination locked, with same lock number */
326 static void test13(void)
327 {
328         const int gid = 8765;
329         unsigned long crc;
330
331         cleanup();
332         sendfile_copy(source_file, gid, dest_file, gid);
333         sync();
334
335         crc = compute_crc(dest_file);
336         ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
337 }
338
339 /* sendfile, source and destination locked, with different lock number */
340 static void test14(void)
341 {
342         unsigned long crc;
343
344         cleanup();
345         sendfile_copy(source_file, 98765, dest_file, 34543);
346         sync();
347
348         crc = compute_crc(dest_file);
349         ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
350 }
351
352 /* Basic sendfile, without lock taken, to /dev/null */
353 static void test15(void)
354 {
355         sendfile_copy(source_file, 0, "/dev/null", 0);
356         sync();
357 }
358
359 /* sendfile, source locked, to /dev/null */
360 static void test16(void)
361 {
362         sendfile_copy(source_file, 85543, "/dev/null", 0);
363         sync();
364 }
365
366 int main(int argc, char *argv[])
367 {
368         int rc;
369
370         if (argc != 2 || argv[1][0] != '/') {
371                 fprintf(stderr,
372                         "Argument must be an absolute path to a Lustre file\n");
373                 return EXIT_FAILURE;
374         }
375
376         source_file = argv[1];
377         rc = asprintf(&dest_file, "%s-dest", source_file);
378         if (rc == -1) {
379                 fprintf(stderr, "Allocation failure\n");
380                 return EXIT_FAILURE;
381         }
382
383         /* Play nice with Lustre test scripts. Non-line buffered output
384          * stream under I/O redirection may appear incorrectly. */
385         setvbuf(stdout, NULL, _IOLBF, 0);
386
387         cleanup();
388         atexit(cleanup);
389
390         /* Compute crc of original file */
391         source_crc = compute_crc(source_file);
392
393         PERFORM(test10);
394         PERFORM(test11);
395         PERFORM(test12);
396         PERFORM(test13);
397         PERFORM(test14);
398         PERFORM(test15);
399         PERFORM(test16);
400
401         return EXIT_SUCCESS;
402 }