Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/clone_after_trunc.c
289328 views
// SPDX-License-Identifier: CDDL-1.012#include <errno.h>3#include <fcntl.h>4#include <limits.h>5#include <pthread.h>6#include <string.h>7#include <stdio.h>8#include <stdlib.h>9#include <unistd.h>10#include <sys/stat.h>1112#if defined(_GNU_SOURCE) && defined(__linux__)13_Static_assert(sizeof (loff_t) == sizeof (off_t),14"loff_t and off_t must be the same size");15#endif1617ssize_t18copy_file_range(int, off_t *, int, off_t *, size_t, unsigned int)19__attribute__((weak));2021#define FILE_SIZE (1024 * 1024)22#define RECORD_SIZE (128 * 1024)23#define NUM_THREADS 642425const char *dir;26volatile int failed;2728static void *29run_test(void *arg)30{31int thread_id = (int)(long)arg;3233char src_path[PATH_MAX], dst_path[PATH_MAX];34snprintf(src_path, PATH_MAX, "%s/src-%d", dir, thread_id);35snprintf(dst_path, PATH_MAX, "%s/dst-%d", dir, thread_id);3637unsigned char *write_buf = malloc(FILE_SIZE);38unsigned char *read_buf = malloc(FILE_SIZE);3940// Write out expected data.41memset(write_buf, 0xAA, FILE_SIZE);42int src = open(src_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);43if (write(src, write_buf, FILE_SIZE) != FILE_SIZE)44perror("write");45close(src);4647// Create destination file so we exercise O_TRUNC.48int dst = open(dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);49if (write(dst, write_buf, FILE_SIZE) != FILE_SIZE)50perror("write");51fsync(dst);52close(dst);5354// Open file with O_TRUNC and perform copy.55src = open(src_path, O_RDONLY);56dst = open(dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);5758off_t off_in = 0, off_out = 0;59ssize_t ret =60copy_file_range(src, &off_in, dst, &off_out, FILE_SIZE, 0);61if (ret != FILE_SIZE)62perror("copy_file_range");63close(src);64close(dst);6566// Read back67dst = open(dst_path, O_RDONLY);68if (read(dst, read_buf, FILE_SIZE) != FILE_SIZE)69perror("read");70close(dst);7172// Bug check73if (memcmp(write_buf, read_buf, FILE_SIZE) != 0) {74failed = 1;75fprintf(stderr, "[%d]: FAIL\n", thread_id);7677int all_zeros = 1;78for (int i = 0; i < RECORD_SIZE; i++) {79if (read_buf[i] != 0) {80all_zeros = 0;81break;82}83}8485if (all_zeros) {86fprintf(stderr, "[%d]: ALL ZERO\n", thread_id);87}88}8990unlink(src_path);91unlink(dst_path);92free(write_buf);93free(read_buf);94return (NULL);95}9697int98main(int argc, const char **argv)99{100if (argc < 2) {101fprintf(stderr, "usage: %s <dir>\n", argv[0]);102return (1);103}104dir = argv[1];105106pthread_t threads[NUM_THREADS];107108for (int i = 0; i < NUM_THREADS; i++) {109pthread_create(&threads[i], NULL, run_test, (void *)(long)i);110}111for (int i = 0; i < NUM_THREADS; i++) {112pthread_join(threads[i], NULL);113}114115return (failed);116}117118119