xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/cmd/mmap_seek.c (revision ce4dcb97ca433b2a2f03fbae957dae0ff16f6f51)
1716fd348SMartin Matuska /*
2716fd348SMartin Matuska  * CDDL HEADER START
3716fd348SMartin Matuska  *
4716fd348SMartin Matuska  * The contents of this file are subject to the terms of the
5716fd348SMartin Matuska  * Common Development and Distribution License (the "License").
6716fd348SMartin Matuska  * You may not use this file except in compliance with the License.
7716fd348SMartin Matuska  *
8716fd348SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10716fd348SMartin Matuska  * See the License for the specific language governing permissions
11716fd348SMartin Matuska  * and limitations under the License.
12716fd348SMartin Matuska  *
13716fd348SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14716fd348SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15716fd348SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16716fd348SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17716fd348SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18716fd348SMartin Matuska  *
19716fd348SMartin Matuska  * CDDL HEADER END
20716fd348SMartin Matuska  */
21716fd348SMartin Matuska 
22716fd348SMartin Matuska /*
23716fd348SMartin Matuska  * Copyright (c) 2021 by Lawrence Livermore National Security, LLC.
24716fd348SMartin Matuska  */
25716fd348SMartin Matuska 
26716fd348SMartin Matuska #include <unistd.h>
27716fd348SMartin Matuska #include <fcntl.h>
28716fd348SMartin Matuska #include <stdio.h>
29716fd348SMartin Matuska #include <stdlib.h>
30716fd348SMartin Matuska #include <string.h>
31716fd348SMartin Matuska #include <sys/mman.h>
32716fd348SMartin Matuska #include <sys/sysmacros.h>
33716fd348SMartin Matuska #include <errno.h>
34716fd348SMartin Matuska #ifdef __linux__
35716fd348SMartin Matuska #include <linux/fs.h>
36716fd348SMartin Matuska #endif
37716fd348SMartin Matuska 
38*ce4dcb97SMartin Matuska /* some older uClibc's lack the defines, so we'll manually define them */
39*ce4dcb97SMartin Matuska #ifdef	__UCLIBC__
40*ce4dcb97SMartin Matuska #ifndef	SEEK_DATA
41*ce4dcb97SMartin Matuska #define	SEEK_DATA 3
42*ce4dcb97SMartin Matuska #endif
43*ce4dcb97SMartin Matuska #ifndef	SEEK_HOLE
44*ce4dcb97SMartin Matuska #define	SEEK_HOLE 4
45*ce4dcb97SMartin Matuska #endif
46*ce4dcb97SMartin Matuska #endif
47*ce4dcb97SMartin Matuska 
48716fd348SMartin Matuska static void
seek_data(int fd,off_t offset,off_t expected)49716fd348SMartin Matuska seek_data(int fd, off_t offset, off_t expected)
50716fd348SMartin Matuska {
51716fd348SMartin Matuska 	off_t data_offset = lseek(fd, offset, SEEK_DATA);
52716fd348SMartin Matuska 	if (data_offset != expected) {
53716fd348SMartin Matuska 		fprintf(stderr, "lseek(fd, %d, SEEK_DATA) = %d (expected %d)\n",
54716fd348SMartin Matuska 		    (int)offset, (int)data_offset, (int)expected);
55716fd348SMartin Matuska 		exit(2);
56716fd348SMartin Matuska 	}
57716fd348SMartin Matuska }
58716fd348SMartin Matuska 
59716fd348SMartin Matuska static void
seek_hole(int fd,off_t offset,off_t expected)60716fd348SMartin Matuska seek_hole(int fd, off_t offset, off_t expected)
61716fd348SMartin Matuska {
62716fd348SMartin Matuska 	off_t hole_offset = lseek(fd, offset, SEEK_HOLE);
63716fd348SMartin Matuska 	if (hole_offset != expected) {
64716fd348SMartin Matuska 		fprintf(stderr, "lseek(fd, %d, SEEK_HOLE) = %d (expected %d)\n",
65716fd348SMartin Matuska 		    (int)offset, (int)hole_offset, (int)expected);
66716fd348SMartin Matuska 		exit(2);
67716fd348SMartin Matuska 	}
68716fd348SMartin Matuska }
69716fd348SMartin Matuska 
70716fd348SMartin Matuska int
main(int argc,char ** argv)71716fd348SMartin Matuska main(int argc, char **argv)
72716fd348SMartin Matuska {
73716fd348SMartin Matuska 	char *execname = argv[0];
74716fd348SMartin Matuska 	char *file_path = argv[1];
75716fd348SMartin Matuska 	char *buf = NULL;
76716fd348SMartin Matuska 	int err;
77716fd348SMartin Matuska 
78716fd348SMartin Matuska 	if (argc != 4) {
79716fd348SMartin Matuska 		(void) printf("usage: %s <file name> <file size> "
80716fd348SMartin Matuska 		    "<block size>\n", argv[0]);
81716fd348SMartin Matuska 		exit(1);
82716fd348SMartin Matuska 	}
83716fd348SMartin Matuska 
84716fd348SMartin Matuska 	int fd = open(file_path, O_RDWR | O_CREAT, 0666);
85716fd348SMartin Matuska 	if (fd == -1) {
86716fd348SMartin Matuska 		(void) fprintf(stderr, "%s: %s: ", execname, file_path);
87716fd348SMartin Matuska 		perror("open");
88716fd348SMartin Matuska 		exit(2);
89716fd348SMartin Matuska 	}
90716fd348SMartin Matuska 
91716fd348SMartin Matuska 	off_t file_size = atoi(argv[2]);
92716fd348SMartin Matuska 	off_t block_size = atoi(argv[3]);
93716fd348SMartin Matuska 
94716fd348SMartin Matuska 	if (block_size * 2 > file_size) {
95716fd348SMartin Matuska 		(void) fprintf(stderr, "file size must be at least "
96716fd348SMartin Matuska 		    "double the block size\n");
97716fd348SMartin Matuska 		exit(2);
98716fd348SMartin Matuska 	}
99716fd348SMartin Matuska 
100716fd348SMartin Matuska 	err = ftruncate(fd, file_size);
101716fd348SMartin Matuska 	if (err == -1) {
102716fd348SMartin Matuska 		perror("ftruncate");
103716fd348SMartin Matuska 		exit(2);
104716fd348SMartin Matuska 	}
105716fd348SMartin Matuska 
106716fd348SMartin Matuska 	if ((buf = mmap(NULL, file_size, PROT_READ | PROT_WRITE,
107716fd348SMartin Matuska 	    MAP_SHARED, fd, 0)) == MAP_FAILED) {
108716fd348SMartin Matuska 		perror("mmap");
109716fd348SMartin Matuska 		exit(2);
110716fd348SMartin Matuska 	}
111716fd348SMartin Matuska 
112716fd348SMartin Matuska 	/* Verify the file is sparse and reports no data. */
113716fd348SMartin Matuska 	seek_data(fd, 0, -1);
114716fd348SMartin Matuska 
115716fd348SMartin Matuska 	/* Verify the file is reported as a hole. */
116716fd348SMartin Matuska 	seek_hole(fd, 0, 0);
117716fd348SMartin Matuska 
118716fd348SMartin Matuska 	/* Verify search beyond end of file is an error. */
119716fd348SMartin Matuska 	seek_data(fd, 2 * file_size, -1);
120716fd348SMartin Matuska 	seek_hole(fd, 2 * file_size, -1);
121716fd348SMartin Matuska 
122716fd348SMartin Matuska 	/* Dirty the first byte. */
123716fd348SMartin Matuska 	memset(buf, 'a', 1);
124716fd348SMartin Matuska 	seek_data(fd, 0, 0);
125716fd348SMartin Matuska 	seek_data(fd, block_size, -1);
126716fd348SMartin Matuska 	seek_hole(fd, 0, block_size);
127716fd348SMartin Matuska 	seek_hole(fd, block_size, block_size);
128716fd348SMartin Matuska 
129716fd348SMartin Matuska 	/* Dirty the first half of the file. */
130716fd348SMartin Matuska 	memset(buf, 'b', file_size / 2);
131716fd348SMartin Matuska 	seek_data(fd, 0, 0);
132716fd348SMartin Matuska 	seek_data(fd, block_size, block_size);
133716fd348SMartin Matuska 	seek_hole(fd, 0, P2ROUNDUP(file_size / 2, block_size));
134716fd348SMartin Matuska 	seek_hole(fd, block_size, P2ROUNDUP(file_size / 2, block_size));
135716fd348SMartin Matuska 
136716fd348SMartin Matuska 	/* Dirty the whole file. */
137716fd348SMartin Matuska 	memset(buf, 'c', file_size);
138716fd348SMartin Matuska 	seek_data(fd, 0, 0);
139716fd348SMartin Matuska 	seek_data(fd, file_size * 3 / 4,
140716fd348SMartin Matuska 	    P2ROUNDUP(file_size * 3 / 4, block_size));
141716fd348SMartin Matuska 	seek_hole(fd, 0, file_size);
142716fd348SMartin Matuska 	seek_hole(fd, file_size / 2, file_size);
143716fd348SMartin Matuska 
144716fd348SMartin Matuska 	/* Punch a hole (required compression be enabled). */
145716fd348SMartin Matuska 	memset(buf + block_size, 0, block_size);
146716fd348SMartin Matuska 	seek_data(fd, 0, 0);
147716fd348SMartin Matuska 	seek_data(fd, block_size, 2 * block_size);
148716fd348SMartin Matuska 	seek_hole(fd, 0, block_size);
149716fd348SMartin Matuska 	seek_hole(fd, block_size, block_size);
150716fd348SMartin Matuska 	seek_hole(fd, 2 * block_size, file_size);
151716fd348SMartin Matuska 
152716fd348SMartin Matuska 	err = munmap(buf, file_size);
153716fd348SMartin Matuska 	if (err == -1) {
154716fd348SMartin Matuska 		perror("munmap");
155716fd348SMartin Matuska 		exit(2);
156716fd348SMartin Matuska 	}
157716fd348SMartin Matuska 
158716fd348SMartin Matuska 	close(fd);
159716fd348SMartin Matuska 
160716fd348SMartin Matuska 	return (0);
161716fd348SMartin Matuska }
162