xref: /freebsd/sys/contrib/openzfs/cmd/zstream/zstream_util.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 
13 /*
14  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
15  * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
16  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
17  * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
18  * All rights reserved
19  * Copyright (c) 2013 Steven Hartland. All rights reserved.
20  * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
21  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
22  * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
23  * Copyright (c) 2019 Datto Inc.
24  * Copyright (c) 2024, Klara, Inc.
25  */
26 
27 #include <assert.h>
28 #include <err.h>
29 #include <errno.h>
30 #include <pthread.h>
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <sys/abd.h>
35 #include <sys/fs/zfs.h>
36 #include <sys/stdtypes.h>
37 #include <sys/sysmacros.h>
38 #include <sys/zfs_ioctl.h>
39 #include <sys/zio.h>
40 #include <sys/zio_compress.h>
41 #include <unistd.h>
42 
43 #include "zstream_util.h"
44 
45 void *
safe_malloc(size_t size)46 safe_malloc(size_t size)
47 {
48 	void *rv = malloc(size);
49 	if (rv == NULL) {
50 		errx(1, "failed to allocate %zu bytes, aborting...", size);
51 	}
52 	return (rv);
53 }
54 
55 void *
safe_calloc(size_t size)56 safe_calloc(size_t size)
57 {
58 	void *rv = calloc(1, size);
59 	if (rv == NULL) {
60 		errx(1, "failed to allocate %zu bytes, aborting...", size);
61 	}
62 	return (rv);
63 }
64 
65 void
safe_pthread_sigmask(int how,const sigset_t * set,sigset_t * oldset)66 safe_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
67 {
68 	int error = pthread_sigmask(how, set, oldset);
69 	if (error != 0) {
70 		errno = error;
71 		err(1, "pthread_sigmask failed");
72 	}
73 }
74 
75 pthread_t
safe_create_thread(thread_f * body,void * body_arg,const char * name,boolean_t detach)76 safe_create_thread(thread_f *body, void *body_arg, const char *name,
77     boolean_t detach)
78 {
79 	pthread_t tid;
80 	int ret;
81 	int name_attempts = 3;
82 
83 	ret = pthread_create(&tid, NULL, body, body_arg);
84 	if (ret != 0) {
85 		errno = ret;
86 		err(1, "pthread_create for %s failed", name);
87 	}
88 	/*
89 	 * pthread_setname_np() fails randomly on some Debian systems
90 	 * because of difficulty reading /proc/self/task. The characteristic
91 	 * error is "No such file or directory." The name is just a
92 	 * debugging aid, so we can ignore the error, but we'll make three
93 	 * attempts to set it. This code previously printed a warning
94 	 * message, but that interferes with zstream dump output comparisons
95 	 * in ZTS.
96 	 */
97 	while (name_attempts-- > 0) {
98 		ret = pthread_setname_np(tid, name);
99 		if (ret == 0)
100 			break;
101 		usleep(100);
102 	}
103 	if (detach) {
104 		ret = pthread_detach(tid);
105 		if (ret != 0) {
106 			errno = ret;
107 			err(1, "failed to detach %s thread", name);
108 		}
109 	}
110 	return (tid);
111 }
112 
113 char *
checksum_str(zio_cksum_t * cksum,char * buff,size_t buff_size)114 checksum_str(zio_cksum_t *cksum, char *buff, size_t buff_size)
115 {
116 	snprintf(buff, buff_size, "%.16llx / %.16llx / %.16llx / %.16llx",
117 	    (long long unsigned int) cksum->zc_word[0],
118 	    (long long unsigned int) cksum->zc_word[1],
119 	    (long long unsigned int) cksum->zc_word[2],
120 	    (long long unsigned int) cksum->zc_word[3]);
121 	return (buff);
122 }
123 
124 boolean_t
validate_checksum(zio_cksum_t * expected,zio_cksum_t * actual,boolean_t swap,const char * where,off_t stream_offset)125 validate_checksum(zio_cksum_t *expected, zio_cksum_t *actual,
126     boolean_t swap, const char *where, off_t stream_offset)
127 {
128 	static char buff[128];
129 	zio_cksum_t swapped_actual;
130 
131 	if (swap) {
132 		swapped_actual = *actual;
133 		actual = &swapped_actual;
134 		ZIO_CHECKSUM_BSWAP(actual);
135 	}
136 	/* cppcheck-suppress uninitvar */
137 	if (ZIO_CHECKSUM_EQUAL(*expected, *actual)) {
138 		return (B_TRUE);
139 	}
140 	fflush(stdout);
141 	fprintf(stderr, "Incorrect checksum %s (stream offset %lld)\n", where,
142 	    (longlong_t)stream_offset);
143 	fprintf(stderr, "Expected = %s\n", checksum_str(expected, buff,
144 	    sizeof (buff)));
145 	fprintf(stderr, "  Actual = %s\n", checksum_str(actual, buff,
146 	    sizeof (buff)));
147 	return (B_FALSE);
148 }
149 
150 boolean_t
write_is_encrypted(struct drr_write * drrw)151 write_is_encrypted(struct drr_write *drrw)
152 {
153 	for (int i = 0; i < ZIO_DATA_SALT_LEN; i++) {
154 		if (drrw->drr_salt[i] != 0) {
155 			return (B_TRUE);
156 		}
157 	}
158 	return (B_FALSE);
159 }
160 
161 /*
162  * The specified compress_type must reflect the buffer's actual compression.
163  * Returns an allocated buffer if decompression was successful, NULL
164  * otherwise.
165  */
166 uint8_t *
decompress_buffer(uint8_t * inbuff,size_t inbuff_size,size_t logical_size,enum zio_compress compress_type)167 decompress_buffer(uint8_t *inbuff, size_t inbuff_size, size_t logical_size,
168     enum zio_compress compress_type)
169 {
170 	uint8_t *outbuff = safe_malloc(logical_size);
171 	abd_t sabd, dabd;
172 	int ret;
173 
174 	VERIFY3B(ctype_is_uncompressed(compress_type), ==, B_FALSE);
175 
176 	abd_get_from_buf_struct(&sabd, inbuff, inbuff_size);
177 	abd_get_from_buf_struct(&dabd, outbuff, logical_size);
178 	ret = zio_decompress_data(compress_type, &sabd, &dabd,
179 	    inbuff_size, abd_get_size(&dabd), NULL);
180 
181 	abd_free(&dabd);
182 	abd_free(&sabd);
183 
184 	if (ret != 0) {
185 		free(outbuff);
186 		return (NULL);
187 	}
188 
189 	return (outbuff);
190 }
191 
192 /*
193  * Returns an allocated buffer if compression was successful, NULL
194  * otherwise.
195  */
196 uint8_t *
compress_buffer(uint8_t * inbuff,size_t inbuff_size,compression_spec_t compress_type,size_t * compressed_size)197 compress_buffer(uint8_t *inbuff, size_t inbuff_size,
198     compression_spec_t compress_type, size_t *compressed_size)
199 {
200 	uint8_t *outbuff = safe_malloc(inbuff_size);
201 	abd_t	sabd, dabd;
202 	size_t	csize, rounded;
203 
204 	VERIFY3B(ctype_is_uncompressed(compress_type.cs_type), ==, B_FALSE);
205 
206 	abd_t *pabd = abd_get_from_buf_struct(&dabd, outbuff, inbuff_size);
207 	abd_get_from_buf_struct(&sabd, inbuff, inbuff_size);
208 	csize = zio_compress_data(compress_type.cs_type, &sabd,
209 	    &pabd, inbuff_size, inbuff_size, compress_type.cs_level);
210 
211 	rounded = P2ROUNDUP(csize, SPA_MINBLOCKSIZE);
212 	if (rounded < inbuff_size) {
213 		abd_zero_off(pabd, csize, rounded - csize);
214 		*compressed_size = rounded;
215 	} else {
216 		free(outbuff);
217 		outbuff = NULL;
218 	}
219 
220 	abd_free(&sabd);
221 	abd_free(&dabd);
222 
223 	return (outbuff);
224 }
225