Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/mmap_seek.c
48529 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright (c) 2021 by Lawrence Livermore National Security, LLC.24*/2526#include <unistd.h>27#include <fcntl.h>28#include <stdio.h>29#include <stdlib.h>30#include <string.h>31#include <sys/mman.h>32#include <sys/sysmacros.h>33#include <errno.h>34#ifdef __linux__35#include <linux/fs.h>36#endif3738/* some older uClibc's lack the defines, so we'll manually define them */39#ifdef __UCLIBC__40#ifndef SEEK_DATA41#define SEEK_DATA 342#endif43#ifndef SEEK_HOLE44#define SEEK_HOLE 445#endif46#endif4748static void49seek_expect(int fd, off_t offset, int whence, off_t expect_offset)50{51errno = 0;52off_t seek_offset = lseek(fd, offset, whence);53if (seek_offset == expect_offset)54return;5556int err = errno;57fprintf(stderr, "lseek(fd, %ld, SEEK_%s) = %ld (expected %ld)",58offset, (whence == SEEK_DATA ? "DATA" : "HOLE"),59seek_offset, expect_offset);60if (err != 0)61fprintf(stderr, " (errno %d [%s])\n", err, strerror(err));62else63fputc('\n', stderr);64exit(2);65}6667static inline void68seek_data(int fd, off_t offset, off_t expected)69{70seek_expect(fd, offset, SEEK_DATA, expected);71}7273static inline void74seek_hole(int fd, off_t offset, off_t expected)75{76seek_expect(fd, offset, SEEK_HOLE, expected);77}7879int80main(int argc, char **argv)81{82char *execname = argv[0];83char *file_path = argv[1];84char *buf = NULL;85int err;8687if (argc != 4) {88(void) printf("usage: %s <file name> <file size> "89"<block size>\n", argv[0]);90exit(1);91}9293int fd = open(file_path, O_RDWR | O_CREAT, 0666);94if (fd == -1) {95(void) fprintf(stderr, "%s: %s: ", execname, file_path);96perror("open");97exit(2);98}99100off_t file_size = atoi(argv[2]);101off_t block_size = atoi(argv[3]);102103if (block_size * 2 > file_size) {104(void) fprintf(stderr, "file size must be at least "105"double the block size\n");106exit(2);107}108109err = ftruncate(fd, file_size);110if (err == -1) {111perror("ftruncate");112exit(2);113}114115if ((buf = mmap(NULL, file_size, PROT_READ | PROT_WRITE,116MAP_SHARED, fd, 0)) == MAP_FAILED) {117perror("mmap");118exit(2);119}120121/* Verify the file is sparse and reports no data. */122seek_data(fd, 0, -1);123124/* Verify the file is reported as a hole. */125seek_hole(fd, 0, 0);126127/* Verify search beyond end of file is an error. */128seek_data(fd, 2 * file_size, -1);129seek_hole(fd, 2 * file_size, -1);130131/* Dirty the first byte. */132memset(buf, 'a', 1);133seek_data(fd, 0, 0);134seek_data(fd, block_size, -1);135seek_hole(fd, 0, block_size);136seek_hole(fd, block_size, block_size);137138/* Dirty the first half of the file. */139memset(buf, 'b', file_size / 2);140seek_data(fd, 0, 0);141seek_data(fd, block_size, block_size);142seek_hole(fd, 0, P2ROUNDUP(file_size / 2, block_size));143seek_hole(fd, block_size, P2ROUNDUP(file_size / 2, block_size));144145/* Dirty the whole file. */146memset(buf, 'c', file_size);147seek_data(fd, 0, 0);148seek_data(fd, file_size * 3 / 4,149P2ROUNDUP(file_size * 3 / 4, block_size));150seek_hole(fd, 0, file_size);151seek_hole(fd, file_size / 2, file_size);152153/* Punch a hole (required compression be enabled). */154memset(buf + block_size, 0, block_size);155seek_data(fd, 0, 0);156seek_data(fd, block_size, 2 * block_size);157seek_hole(fd, 0, block_size);158seek_hole(fd, block_size, block_size);159seek_hole(fd, 2 * block_size, file_size);160161err = munmap(buf, file_size);162if (err == -1) {163perror("munmap");164exit(2);165}166167close(fd);168169return (0);170}171172173