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