4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
24 * Copyright 2015 Cray Inc, all rights reserved.
26 * Copyright (c) 2017, Intel Corporation.
30 * A few portions are extracted from llapi_layout_test.c
34 * The CRC32 implementation is from RFC 1952, which bears the
37 * Copyright (c) 1996 L. Peter Deutsch
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
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.
52 * The program will exit as soon as a non zero error code is returned.
54 * It can be called like this:
56 * dd if=/dev/zero of=/mnt/lustre/foo1 bs=1M count=40
57 * ./sendfile_grouplock /mnt/lustre/foo1
64 #include <sys/types.h>
69 #include <sys/sendfile.h>
71 #include <lustre/lustreapi.h>
73 #define ERROR(fmt, ...) \
74 fprintf(stderr, "%s: %s:%d: %s: " fmt "\n", \
75 program_invocation_short_name, __FILE__, __LINE__, \
76 __func__, ## __VA_ARGS__);
78 #define DIE(fmt, ...) \
80 ERROR(fmt, ## __VA_ARGS__); \
84 #define ASSERTF(cond, fmt, ...) \
87 DIE("assertion '%s' failed: "fmt, \
88 #cond, ## __VA_ARGS__); \
91 #define PERFORM(testfn) \
93 fprintf(stderr, "Starting test " #testfn " at %lld\n", \
94 (unsigned long long)time(NULL)); \
96 fprintf(stderr, "Finishing test " #testfn " at %lld\n", \
97 (unsigned long long)time(NULL)); \
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 */
106 * A small CRC32 implementation, from RFC 1952
109 /* Table of CRCs of all 8-bit messages. */
110 static unsigned long crc_table[256];
112 /* Flag: has the table been computed? Initially false. */
113 static int crc_table_computed;
115 /* Make the table for a fast CRC. */
116 static void make_crc_table(void)
121 for (n = 0; n < 256; n++) {
122 c = (unsigned long) n;
123 for (k = 0; k < 8; k++) {
125 c = 0xedb88320L ^ (c >> 1);
131 crc_table_computed = 1;
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:
140 * unsigned long crc = 0L;
142 * while (read_buffer(buffer, length) != EOF) {
143 * crc = update_crc(crc, buffer, length);
145 * if (crc != original_crc) error();
147 static unsigned long update_crc(unsigned long crc,
148 unsigned char *buf, int len)
150 unsigned long c = crc ^ 0xffffffffL;
153 if (!crc_table_computed)
155 for (n = 0; n < len; n++)
156 c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
158 return c ^ 0xffffffffL;
161 /* Cleanup our test file. */
162 static void cleanup(void)
167 /* Compute the CRC32 of a file */
168 static unsigned long compute_crc(const char *fname)
170 unsigned char buf[1024*1024];
171 unsigned long crc = 0L;
177 fd = open(fname, O_RDONLY);
178 ASSERTF(fd >= 0, "open failed for '%s': %s",
179 fname, strerror(errno));
181 rc = fstat(fd, &stbuf);
182 ASSERTF(rc == 0, "fstat of '%s' failed: %s", fname, strerror(errno));
183 filesize = stbuf.st_size;
185 while (filesize != 0) {
186 size_t to_read = sizeof(buf);
189 if (to_read > filesize)
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'",
199 crc = update_crc(crc, buf, sret);
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 static int sendfile_copy(const char *source, int source_gid,
210 const char *dest, int dest_gid)
218 fd_in = open(source, O_RDONLY);
219 ASSERTF(fd_in >= 0, "open failed for '%s': %s",
220 source, strerror(errno));
222 rc = fstat(fd_in, &stbuf);
223 ASSERTF(rc == 0, "fstat of '%s' failed: %s", source, strerror(errno));
224 filesize = stbuf.st_size;
226 if (source_gid != 0) {
227 rc = llapi_group_lock(fd_in, source_gid);
228 ASSERTF(rc == 0, "cannot set group lock %d for '%s': %s",
229 source_gid, source, strerror(-rc));
232 fd_out = open(dest, O_WRONLY | O_TRUNC | O_CREAT, 0644);
233 ASSERTF(fd_out >= 0, "creation failed for '%s': %s",
234 dest, strerror(errno));
237 rc = llapi_group_lock(fd_out, dest_gid);
238 ASSERTF(rc == 0, "cannot set group lock %d for '%s': %s",
239 dest_gid, dest, strerror(-rc));
242 /* Transfer by 10M blocks */
243 while (filesize != 0) {
244 size_t to_copy = 10*1024*1024;
247 if (to_copy > filesize)
250 sret = sendfile(fd_out, fd_in, NULL, to_copy);
253 /* Although senfile can return less than requested,
254 * that should not happen under present conditions. At
255 * the very least, make sure that a decent size was
256 * copied. See LU-6371. */
258 ASSERTF(sret != 0, "sendfile read 0 bytes");
259 ASSERTF(sret > 0, "sendfile failed: %s", strerror(rc));
260 ASSERTF(sret > 100*1024,
261 "sendfile read too little data: %zd bytes", sret);
265 "Warning: sendfile returned %zd bytes instead of %zu requested\n",
273 rc = llapi_group_unlock(fd_out, dest_gid);
274 ASSERTF(rc == 0, "cannot clear group lock %d for '%s': %s",
275 dest_gid, dest, strerror(-rc));
277 if (source_gid != 0) {
278 rc = llapi_group_unlock(fd_in, source_gid);
279 ASSERTF(rc == 0, "cannot clear group lock %d for '%s': %s",
280 source_gid, source, strerror(-rc));
289 /* Basic sendfile, without lock taken */
290 static void test10(void)
295 sendfile_copy(source_file, 0, dest_file, 0);
298 crc = compute_crc(dest_file);
299 ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
302 /* sendfile, source locked */
303 static void test11(void)
308 sendfile_copy(source_file, 85543, dest_file, 0);
311 crc = compute_crc(dest_file);
312 ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
315 /* sendfile, destination locked */
316 static void test12(void)
321 sendfile_copy(source_file, 0, dest_file, 98765);
324 crc = compute_crc(dest_file);
325 ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
328 /* sendfile, source and destination locked, with same lock number */
329 static void test13(void)
331 const int gid = 8765;
335 sendfile_copy(source_file, gid, dest_file, gid);
338 crc = compute_crc(dest_file);
339 ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
342 /* sendfile, source and destination locked, with different lock number */
343 static void test14(void)
348 sendfile_copy(source_file, 98765, dest_file, 34543);
351 crc = compute_crc(dest_file);
352 ASSERTF(source_crc == crc, "CRC differs: %lu and %lu", source_crc, crc);
355 /* Basic sendfile, without lock taken, to /dev/null */
356 static void test15(void)
358 sendfile_copy(source_file, 0, "/dev/null", 0);
362 /* sendfile, source locked, to /dev/null */
363 static void test16(void)
365 sendfile_copy(source_file, 85543, "/dev/null", 0);
369 int main(int argc, char *argv[])
373 if (argc != 2 || argv[1][0] != '/') {
375 "Argument must be an absolute path to a Lustre file\n");
379 source_file = argv[1];
380 rc = asprintf(&dest_file, "%s-dest", source_file);
382 fprintf(stderr, "Allocation failure\n");
386 /* Play nice with Lustre test scripts. Non-line buffered output
387 * stream under I/O redirection may appear incorrectly. */
388 setvbuf(stdout, NULL, _IOLBF, 0);
393 /* Compute crc of original file */
394 source_crc = compute_crc(source_file);