xref: /freebsd/sys/fs/tarfs/tarfs_io.c (revision 4d3fc8b0)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013 Juniper Networks, Inc.
5  * Copyright (c) 2022-2023 Klara, Inc.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include "opt_tarfs.h"
30 #include "opt_zstdio.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/counter.h>
35 #include <sys/bio.h>
36 #include <sys/buf.h>
37 #include <sys/malloc.h>
38 #include <sys/mount.h>
39 #include <sys/sysctl.h>
40 #include <sys/uio.h>
41 #include <sys/vnode.h>
42 
43 #if defined(ZSTDIO)
44 #define TARFS_ZIO 1
45 #else
46 #undef TARFS_ZIO
47 #endif
48 
49 #ifdef ZSTDIO
50 #define ZSTD_STATIC_LINKING_ONLY
51 #include <contrib/zstd/lib/zstd.h>
52 #endif
53 
54 #include <fs/tarfs/tarfs.h>
55 #include <fs/tarfs/tarfs_dbg.h>
56 
57 #ifdef TARFS_DEBUG
58 SYSCTL_NODE(_vfs_tarfs, OID_AUTO, zio, CTLFLAG_RD, 0,
59     "Tar filesystem decompression layer");
60 COUNTER_U64_DEFINE_EARLY(tarfs_zio_inflated);
61 SYSCTL_COUNTER_U64(_vfs_tarfs_zio, OID_AUTO, inflated, CTLFLAG_RD,
62     &tarfs_zio_inflated, "Amount of compressed data inflated.");
63 COUNTER_U64_DEFINE_EARLY(tarfs_zio_consumed);
64 SYSCTL_COUNTER_U64(_vfs_tarfs_zio, OID_AUTO, consumed, CTLFLAG_RD,
65     &tarfs_zio_consumed, "Amount of compressed data consumed.");
66 COUNTER_U64_DEFINE_EARLY(tarfs_zio_bounced);
67 SYSCTL_COUNTER_U64(_vfs_tarfs_zio, OID_AUTO, bounced, CTLFLAG_RD,
68     &tarfs_zio_bounced, "Amount of decompressed data bounced.");
69 
70 static int
71 tarfs_sysctl_handle_zio_reset(SYSCTL_HANDLER_ARGS)
72 {
73 	unsigned int tmp;
74 	int error;
75 
76 	tmp = 0;
77 	if ((error = SYSCTL_OUT(req, &tmp, sizeof(tmp))) != 0)
78 		return (error);
79 	if (req->newptr != NULL) {
80 		if ((error = SYSCTL_IN(req, &tmp, sizeof(tmp))) != 0)
81 			return (error);
82 		counter_u64_zero(tarfs_zio_inflated);
83 		counter_u64_zero(tarfs_zio_consumed);
84 		counter_u64_zero(tarfs_zio_bounced);
85 	}
86 	return (0);
87 }
88 
89 SYSCTL_PROC(_vfs_tarfs_zio, OID_AUTO, reset,
90     CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW,
91     NULL, 0, tarfs_sysctl_handle_zio_reset, "IU",
92     "Reset compression counters.");
93 #endif
94 
95 MALLOC_DEFINE(M_TARFSZSTATE, "tarfs zstate", "tarfs decompression state");
96 MALLOC_DEFINE(M_TARFSZBUF, "tarfs zbuf", "tarfs decompression buffers");
97 
98 #define XZ_MAGIC		(uint8_t[]){ 0xfd, 0x37, 0x7a, 0x58, 0x5a }
99 #define ZLIB_MAGIC		(uint8_t[]){ 0x1f, 0x8b, 0x08 }
100 #define ZSTD_MAGIC		(uint8_t[]){ 0x28, 0xb5, 0x2f, 0xfd }
101 
102 #ifdef ZSTDIO
103 struct tarfs_zstd {
104 	ZSTD_DStream *zds;
105 };
106 #endif
107 
108 /* XXX review use of curthread / uio_td / td_cred */
109 
110 /*
111  * Reads from the tar file according to the provided uio.  If the archive
112  * is compressed and raw is false, reads the decompressed stream;
113  * otherwise, reads directly from the original file.  Returns 0 on success
114  * and a positive errno value on failure.
115  */
116 int
117 tarfs_io_read(struct tarfs_mount *tmp, bool raw, struct uio *uiop)
118 {
119 	void *rl = NULL;
120 	off_t off = uiop->uio_offset;
121 	size_t len = uiop->uio_resid;
122 	int error;
123 
124 	if (raw || tmp->znode == NULL) {
125 		rl = vn_rangelock_rlock(tmp->vp, off, off + len);
126 		error = vn_lock(tmp->vp, LK_SHARED);
127 		if (error == 0) {
128 			error = VOP_READ(tmp->vp, uiop,
129 			    IO_DIRECT|IO_NODELOCKED,
130 			    uiop->uio_td->td_ucred);
131 			VOP_UNLOCK(tmp->vp);
132 		}
133 		vn_rangelock_unlock(tmp->vp, rl);
134 	} else {
135 		error = vn_lock(tmp->znode, LK_EXCLUSIVE);
136 		if (error == 0) {
137 			error = VOP_READ(tmp->znode, uiop,
138 			    IO_DIRECT | IO_NODELOCKED,
139 			    uiop->uio_td->td_ucred);
140 			VOP_UNLOCK(tmp->znode);
141 		}
142 	}
143 	TARFS_DPF(IO, "%s(%zu, %zu) = %d (resid %zd)\n", __func__,
144 	    (size_t)off, len, error, uiop->uio_resid);
145 	return (error);
146 }
147 
148 /*
149  * Reads from the tar file into the provided buffer.  If the archive is
150  * compressed and raw is false, reads the decompressed stream; otherwise,
151  * reads directly from the original file.  Returns the number of bytes
152  * read on success, 0 on EOF, and a negative errno value on failure.
153  */
154 ssize_t
155 tarfs_io_read_buf(struct tarfs_mount *tmp, bool raw,
156     void *buf, off_t off, size_t len)
157 {
158 	struct uio auio;
159 	struct iovec aiov;
160 	ssize_t res;
161 	int error;
162 
163 	if (len == 0) {
164 		TARFS_DPF(IO, "%s(%zu, %zu) null\n", __func__,
165 		    (size_t)off, len);
166 		return (0);
167 	}
168 	aiov.iov_base = buf;
169 	aiov.iov_len = len;
170 	auio.uio_iov = &aiov;
171 	auio.uio_iovcnt = 1;
172 	auio.uio_offset = off;
173 	auio.uio_segflg = UIO_SYSSPACE;
174 	auio.uio_rw = UIO_READ;
175 	auio.uio_resid = len;
176 	auio.uio_td = curthread;
177 	error = tarfs_io_read(tmp, raw, &auio);
178 	if (error != 0) {
179 		TARFS_DPF(IO, "%s(%zu, %zu) error %d\n", __func__,
180 		    (size_t)off, len, error);
181 		return (-error);
182 	}
183 	res = len - auio.uio_resid;
184 	if (res == 0 && len != 0) {
185 		TARFS_DPF(IO, "%s(%zu, %zu) eof\n", __func__,
186 		    (size_t)off, len);
187 	} else {
188 		TARFS_DPF(IO, "%s(%zu, %zu) read %zd | %*D\n", __func__,
189 		    (size_t)off, len, res,
190 		    (int)(res > 8 ? 8 : res), (uint8_t *)buf, " ");
191 	}
192 	return (res);
193 }
194 
195 #ifdef ZSTDIO
196 static void *
197 tarfs_zstate_alloc(void *opaque, size_t size)
198 {
199 
200 	(void)opaque;
201 	return (malloc(size, M_TARFSZSTATE, M_WAITOK));
202 }
203 #endif
204 
205 #ifdef ZSTDIO
206 static void
207 tarfs_zstate_free(void *opaque, void *address)
208 {
209 
210 	(void)opaque;
211 	free(address, M_TARFSZSTATE);
212 }
213 #endif
214 
215 #ifdef ZSTDIO
216 static ZSTD_customMem tarfs_zstd_mem = {
217 	tarfs_zstate_alloc,
218 	tarfs_zstate_free,
219 	NULL,
220 };
221 #endif
222 
223 #ifdef TARFS_ZIO
224 /*
225  * Updates the decompression frame index, recording the current input and
226  * output offsets in a new index entry, and growing the index if
227  * necessary.
228  */
229 static void
230 tarfs_zio_update_index(struct tarfs_zio *zio, off_t i, off_t o)
231 {
232 
233 	if (++zio->curidx >= zio->nidx) {
234 		if (++zio->nidx > zio->szidx) {
235 			zio->szidx *= 2;
236 			zio->idx = realloc(zio->idx,
237 			    zio->szidx * sizeof(*zio->idx),
238 			    M_TARFSZSTATE, M_ZERO | M_WAITOK);
239 			TARFS_DPF(ALLOC, "%s: resized zio index\n", __func__);
240 		}
241 		zio->idx[zio->curidx].i = i;
242 		zio->idx[zio->curidx].o = o;
243 		TARFS_DPF(ZIDX, "%s: index %u = i %zu o %zu\n", __func__,
244 		    zio->curidx, (size_t)zio->idx[zio->curidx].i,
245 		    (size_t)zio->idx[zio->curidx].o);
246 	}
247 	MPASS(zio->idx[zio->curidx].i == i);
248 	MPASS(zio->idx[zio->curidx].o == o);
249 }
250 #endif
251 
252 /*
253  * VOP_ACCESS for zio node.
254  */
255 static int
256 tarfs_zaccess(struct vop_access_args *ap)
257 {
258 	struct vnode *vp = ap->a_vp;
259 	struct tarfs_zio *zio = vp->v_data;
260 	struct tarfs_mount *tmp = zio->tmp;
261 	accmode_t accmode = ap->a_accmode;
262 	int error = EPERM;
263 
264 	if (accmode == VREAD) {
265 		error = vn_lock(tmp->vp, LK_SHARED);
266 		if (error == 0) {
267 			error = VOP_ACCESS(tmp->vp, accmode, ap->a_cred, ap->a_td);
268 			VOP_UNLOCK(tmp->vp);
269 		}
270 	}
271 	TARFS_DPF(ZIO, "%s(%d) = %d\n", __func__, accmode, error);
272 	return (error);
273 }
274 
275 /*
276  * VOP_GETATTR for zio node.
277  */
278 static int
279 tarfs_zgetattr(struct vop_getattr_args *ap)
280 {
281 	struct vattr va;
282 	struct vnode *vp = ap->a_vp;
283 	struct tarfs_zio *zio = vp->v_data;
284 	struct tarfs_mount *tmp = zio->tmp;
285 	struct vattr *vap = ap->a_vap;
286 	int error = 0;
287 
288 	VATTR_NULL(vap);
289 	error = vn_lock(tmp->vp, LK_SHARED);
290 	if (error == 0) {
291 		error = VOP_GETATTR(tmp->vp, &va, ap->a_cred);
292 		VOP_UNLOCK(tmp->vp);
293 		if (error == 0) {
294 			vap->va_type = VREG;
295 			vap->va_mode = va.va_mode;
296 			vap->va_nlink = 1;
297 			vap->va_gid = va.va_gid;
298 			vap->va_uid = va.va_uid;
299 			vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
300 			vap->va_fileid = TARFS_ZIOINO;
301 			vap->va_size = zio->idx[zio->nidx - 1].o;
302 			vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
303 			vap->va_atime = va.va_atime;
304 			vap->va_ctime = va.va_ctime;
305 			vap->va_mtime = va.va_mtime;
306 			vap->va_birthtime = tmp->root->birthtime;
307 			vap->va_bytes = va.va_bytes;
308 		}
309 	}
310 	TARFS_DPF(ZIO, "%s() = %d\n", __func__, error);
311 	return (error);
312 }
313 
314 #ifdef ZSTDIO
315 /*
316  * VOP_READ for zio node, zstd edition.
317  */
318 static int
319 tarfs_zread_zstd(struct tarfs_zio *zio, struct uio *uiop)
320 {
321 	void *ibuf = NULL, *obuf = NULL, *rl = NULL;
322 	struct uio auio;
323 	struct iovec aiov;
324 	struct tarfs_mount *tmp = zio->tmp;
325 	struct tarfs_zstd *zstd = zio->zstd;
326 	struct thread *td = curthread;
327 	ZSTD_inBuffer zib;
328 	ZSTD_outBuffer zob;
329 	off_t zsize;
330 	off_t ipos, opos;
331 	size_t ilen, olen;
332 	size_t zerror;
333 	off_t off = uiop->uio_offset;
334 	size_t len = uiop->uio_resid;
335 	size_t resid = uiop->uio_resid;
336 	size_t bsize;
337 	int error;
338 	bool reset = false;
339 
340 	/* do we have to rewind? */
341 	if (off < zio->opos) {
342 		while (zio->curidx > 0 && off < zio->idx[zio->curidx].o)
343 			zio->curidx--;
344 		reset = true;
345 	}
346 	/* advance to the nearest index entry */
347 	if (off > zio->opos) {
348 		// XXX maybe do a binary search instead
349 		while (zio->curidx < zio->nidx - 1 &&
350 		    off >= zio->idx[zio->curidx + 1].o) {
351 			zio->curidx++;
352 			reset = true;
353 		}
354 	}
355 	/* reset the decompression stream if needed */
356 	if (reset) {
357 		zio->ipos = zio->idx[zio->curidx].i;
358 		zio->opos = zio->idx[zio->curidx].o;
359 		ZSTD_resetDStream(zstd->zds);
360 		TARFS_DPF(ZIDX, "%s: skipping to index %u = i %zu o %zu\n", __func__,
361 		    zio->curidx, (size_t)zio->ipos, (size_t)zio->opos);
362 	} else {
363 		TARFS_DPF(ZIDX, "%s: continuing at i %zu o %zu\n", __func__,
364 		    (size_t)zio->ipos, (size_t)zio->opos);
365 	}
366 
367 	/*
368 	 * Set up a temporary buffer for compressed data.  Use the size
369 	 * recommended by the zstd library; this is usually 128 kB, but
370 	 * just in case, make sure it's a multiple of the page size and no
371 	 * larger than MAXBSIZE.
372 	 */
373 	bsize = roundup(ZSTD_CStreamOutSize(), PAGE_SIZE);
374 	if (bsize > MAXBSIZE)
375 		bsize = MAXBSIZE;
376 	ibuf = malloc(bsize, M_TEMP, M_WAITOK);
377 	zib.src = NULL;
378 	zib.size = 0;
379 	zib.pos = 0;
380 
381 	/*
382 	 * Set up the decompression buffer.  If the target is not in
383 	 * kernel space, we will have to set up a bounce buffer.
384 	 *
385 	 * TODO: to avoid using a bounce buffer, map destination pages
386 	 * using vm_fault_quick_hold_pages().
387 	 */
388 	MPASS(zio->opos <= off);
389 	MPASS(uiop->uio_iovcnt == 1);
390 	MPASS(uiop->uio_iov->iov_len >= len);
391 	if (uiop->uio_segflg == UIO_SYSSPACE) {
392 		zob.dst = uiop->uio_iov->iov_base;
393 	} else {
394 		TARFS_DPF(BOUNCE, "%s: allocating %zu-byte bounce buffer\n",
395 		    __func__, len);
396 		zob.dst = obuf = malloc(len, M_TEMP, M_WAITOK);
397 	}
398 	zob.size = len;
399 	zob.pos = 0;
400 
401 	/* lock tarball */
402 	rl = vn_rangelock_rlock(tmp->vp, zio->ipos, OFF_MAX);
403 	error = vn_lock(tmp->vp, LK_SHARED);
404 	if (error != 0) {
405 		goto fail_unlocked;
406 	}
407 	/* check size */
408 	error = vn_getsize_locked(tmp->vp, &zsize, td->td_ucred);
409 	if (error != 0) {
410 		goto fail;
411 	}
412 	if (zio->ipos >= zsize) {
413 		/* beyond EOF */
414 		goto fail;
415 	}
416 
417 	while (resid > 0) {
418 		if (zib.pos == zib.size) {
419 			/* request data from the underlying file */
420 			aiov.iov_base = ibuf;
421 			aiov.iov_len = bsize;
422 			auio.uio_iov = &aiov;
423 			auio.uio_iovcnt = 1;
424 			auio.uio_offset = zio->ipos;
425 			auio.uio_segflg = UIO_SYSSPACE;
426 			auio.uio_rw = UIO_READ;
427 			auio.uio_resid = aiov.iov_len;
428 			auio.uio_td = td;
429 			error = VOP_READ(tmp->vp, &auio,
430 			    IO_DIRECT | IO_NODELOCKED,
431 			    td->td_ucred);
432 			if (error != 0)
433 				goto fail;
434 			TARFS_DPF(ZIO, "%s: req %zu+%zu got %zu+%zu\n", __func__,
435 			    (size_t)zio->ipos, bsize,
436 			    (size_t)zio->ipos, bsize - auio.uio_resid);
437 			zib.src = ibuf;
438 			zib.size = bsize - auio.uio_resid;
439 			zib.pos = 0;
440 		}
441 		MPASS(zib.pos <= zib.size);
442 		if (zib.pos == zib.size) {
443 			TARFS_DPF(ZIO, "%s: end of file after i %zu o %zu\n", __func__,
444 			    (size_t)zio->ipos, (size_t)zio->opos);
445 			goto fail;
446 		}
447 		if (zio->opos < off) {
448 			/* to be discarded */
449 			zob.size = min(off - zio->opos, len);
450 			zob.pos = 0;
451 		} else {
452 			zob.size = len;
453 			zob.pos = zio->opos - off;
454 		}
455 		ipos = zib.pos;
456 		opos = zob.pos;
457 		/* decompress as much as possible */
458 		zerror = ZSTD_decompressStream(zstd->zds, &zob, &zib);
459 		zio->ipos += ilen = zib.pos - ipos;
460 		zio->opos += olen = zob.pos - opos;
461 		if (zio->opos > off)
462 			resid -= olen;
463 		if (ZSTD_isError(zerror)) {
464 			TARFS_DPF(ZIO, "%s: inflate failed after i %zu o %zu: %s\n", __func__,
465 			    (size_t)zio->ipos, (size_t)zio->opos, ZSTD_getErrorName(zerror));
466 			error = EIO;
467 			goto fail;
468 		}
469 		if (zerror == 0 && olen == 0) {
470 			TARFS_DPF(ZIO, "%s: end of stream after i %zu o %zu\n", __func__,
471 			    (size_t)zio->ipos, (size_t)zio->opos);
472 			break;
473 		}
474 		if (zerror == 0) {
475 			TARFS_DPF(ZIO, "%s: end of frame after i %zu o %zu\n", __func__,
476 			    (size_t)zio->ipos, (size_t)zio->opos);
477 			tarfs_zio_update_index(zio, zio->ipos, zio->opos);
478 		}
479 		TARFS_DPF(ZIO, "%s: inflated %zu\n", __func__, olen);
480 #ifdef TARFS_DEBUG
481 		counter_u64_add(tarfs_zio_inflated, olen);
482 #endif
483 	}
484 fail:
485 	VOP_UNLOCK(tmp->vp);
486 fail_unlocked:
487 	if (error == 0) {
488 		if (uiop->uio_segflg == UIO_SYSSPACE) {
489 			uiop->uio_resid = resid;
490 		} else if (len > resid) {
491 			TARFS_DPF(BOUNCE, "%s: bounced %zu bytes\n", __func__,
492 			    len - resid);
493 			error = uiomove(obuf, len - resid, uiop);
494 #ifdef TARFS_DEBUG
495 			counter_u64_add(tarfs_zio_bounced, len - resid);
496 #endif
497 		}
498 	}
499 	if (obuf != NULL) {
500 		TARFS_DPF(BOUNCE, "%s: freeing bounce buffer\n", __func__);
501 		free(obuf, M_TEMP);
502 	}
503 	if (rl != NULL)
504 		vn_rangelock_unlock(tmp->vp, rl);
505 	if (ibuf != NULL)
506 		free(ibuf, M_TEMP);
507 	TARFS_DPF(ZIO, "%s(%zu, %zu) = %d (resid %zd)\n", __func__,
508 	    (size_t)off, len, error, uiop->uio_resid);
509 #ifdef TARFS_DEBUG
510 	counter_u64_add(tarfs_zio_consumed, len - uiop->uio_resid);
511 #endif
512 	if (error != 0) {
513 		zio->curidx = 0;
514 		zio->ipos = zio->idx[0].i;
515 		zio->opos = zio->idx[0].o;
516 		ZSTD_resetDStream(zstd->zds);
517 	}
518 	return (error);
519 }
520 #endif
521 
522 /*
523  * VOP_READ for zio node.
524  */
525 static int
526 tarfs_zread(struct vop_read_args *ap)
527 {
528 #if defined(TARFS_DEBUG) || defined(ZSTDIO)
529 	struct vnode *vp = ap->a_vp;
530 	struct tarfs_zio *zio = vp->v_data;
531 	struct uio *uiop = ap->a_uio;
532 #endif
533 #ifdef TARFS_DEBUG
534 	off_t off = uiop->uio_offset;
535 	size_t len = uiop->uio_resid;
536 #endif
537 	int error;
538 
539 	TARFS_DPF(ZIO, "%s(%zu, %zu)\n", __func__,
540 	    (size_t)off, len);
541 #ifdef ZSTDIO
542 	if (zio->zstd != NULL) {
543 		error = tarfs_zread_zstd(zio, uiop);
544 	} else
545 #endif
546 		error = EFTYPE;
547 	TARFS_DPF(ZIO, "%s(%zu, %zu) = %d (resid %zd)\n", __func__,
548 	    (size_t)off, len, error, uiop->uio_resid);
549 	return (error);
550 }
551 
552 /*
553  * VOP_RECLAIM for zio node.
554  */
555 static int
556 tarfs_zreclaim(struct vop_reclaim_args *ap)
557 {
558 	struct vnode *vp = ap->a_vp;
559 
560 	TARFS_DPF(ZIO, "%s(%p)\n", __func__, vp);
561 	vp->v_data = NULL;
562 	return (0);
563 }
564 
565 /*
566  * VOP_STRATEGY for zio node.
567  */
568 static int
569 tarfs_zstrategy(struct vop_strategy_args *ap)
570 {
571 	struct uio auio;
572 	struct iovec iov;
573 	struct vnode *vp = ap->a_vp;
574 	struct buf *bp = ap->a_bp;
575 	off_t off;
576 	size_t len;
577 	int error;
578 
579 	iov.iov_base = bp->b_data;
580 	iov.iov_len = bp->b_bcount;
581 	off = bp->b_iooffset;
582 	len = bp->b_bcount;
583 	bp->b_resid = len;
584 	auio.uio_iov = &iov;
585 	auio.uio_iovcnt = 1;
586 	auio.uio_offset = off;
587 	auio.uio_resid = len;
588 	auio.uio_segflg = UIO_SYSSPACE;
589 	auio.uio_rw = UIO_READ;
590 	auio.uio_td = curthread;
591 	error = VOP_READ(vp, &auio, IO_DIRECT | IO_NODELOCKED, bp->b_rcred);
592 	bp->b_flags |= B_DONE;
593 	if (error != 0) {
594 		bp->b_ioflags |= BIO_ERROR;
595 		bp->b_error = error;
596 	}
597 	return (0);
598 }
599 
600 static struct vop_vector tarfs_znodeops = {
601 	.vop_default =		&default_vnodeops,
602 
603 	.vop_access =		tarfs_zaccess,
604 	.vop_getattr =		tarfs_zgetattr,
605 	.vop_read =		tarfs_zread,
606 	.vop_reclaim =		tarfs_zreclaim,
607 	.vop_strategy =		tarfs_zstrategy,
608 };
609 VFS_VOP_VECTOR_REGISTER(tarfs_znodeops);
610 
611 #ifdef TARFS_ZIO
612 /*
613  * Initializes the decompression layer.
614  */
615 static struct tarfs_zio *
616 tarfs_zio_init(struct tarfs_mount *tmp, off_t i, off_t o)
617 {
618 	struct tarfs_zio *zio;
619 	struct vnode *zvp;
620 
621 	zio = malloc(sizeof(*zio), M_TARFSZSTATE, M_ZERO | M_WAITOK);
622 	TARFS_DPF(ALLOC, "%s: allocated zio\n", __func__);
623 	zio->tmp = tmp;
624 	zio->szidx = 128;
625 	zio->idx = malloc(zio->szidx * sizeof(*zio->idx), M_TARFSZSTATE,
626 	    M_ZERO | M_WAITOK);
627 	zio->curidx = 0;
628 	zio->nidx = 1;
629 	zio->idx[zio->curidx].i = zio->ipos = i;
630 	zio->idx[zio->curidx].o = zio->opos = o;
631 	tmp->zio = zio;
632 	TARFS_DPF(ALLOC, "%s: allocated zio index\n", __func__);
633 	(void)getnewvnode("tarfsz", tmp->vfs, &tarfs_znodeops, &zvp);
634 	zvp->v_data = zio;
635 	zvp->v_type = VREG;
636 	zvp->v_mount = tmp->vfs;
637 	vn_set_state(zvp, VSTATE_CONSTRUCTED);
638 	tmp->znode = zvp;
639 	TARFS_DPF(ZIO, "%s: created zio node\n", __func__);
640 	return (zio);
641 }
642 #endif
643 
644 /*
645  * Initializes the I/O layer, including decompression if the signature of
646  * a supported compression format is detected.  Returns 0 on success and a
647  * positive errno value on failure.
648  */
649 int
650 tarfs_io_init(struct tarfs_mount *tmp)
651 {
652 	uint8_t *block;
653 #ifdef TARFS_ZIO
654 	struct tarfs_zio *zio = NULL;
655 #endif
656 	ssize_t res;
657 	int error = 0;
658 
659 	block = malloc(tmp->iosize, M_TEMP, M_ZERO | M_WAITOK);
660 	res = tarfs_io_read_buf(tmp, true, block, 0, tmp->iosize);
661 	if (res < 0) {
662 		return (-res);
663 	}
664 	if (memcmp(block, XZ_MAGIC, sizeof(XZ_MAGIC)) == 0) {
665 		printf("xz compression not supported\n");
666 		error = EOPNOTSUPP;
667 		goto bad;
668 	} else if (memcmp(block, ZLIB_MAGIC, sizeof(ZLIB_MAGIC)) == 0) {
669 		printf("zlib compression not supported\n");
670 		error = EOPNOTSUPP;
671 		goto bad;
672 	} else if (memcmp(block, ZSTD_MAGIC, sizeof(ZSTD_MAGIC)) == 0) {
673 #ifdef ZSTDIO
674 		zio = tarfs_zio_init(tmp, 0, 0);
675 		zio->zstd = malloc(sizeof(*zio->zstd), M_TARFSZSTATE, M_WAITOK);
676 		zio->zstd->zds = ZSTD_createDStream_advanced(tarfs_zstd_mem);
677 		(void)ZSTD_initDStream(zio->zstd->zds);
678 #else
679 		printf("zstd compression not supported\n");
680 		error = EOPNOTSUPP;
681 		goto bad;
682 #endif
683 	}
684 bad:
685 	free(block, M_TEMP);
686 	return (error);
687 }
688 
689 #ifdef TARFS_ZIO
690 /*
691  * Tears down the decompression layer.
692  */
693 static int
694 tarfs_zio_fini(struct tarfs_mount *tmp)
695 {
696 	struct tarfs_zio *zio = tmp->zio;
697 	int error = 0;
698 
699 	if (tmp->znode != NULL) {
700 		error = vn_lock(tmp->znode, LK_EXCLUSIVE);
701 		if (error != 0) {
702 			TARFS_DPF(ALLOC, "%s: failed to lock znode", __func__);
703 			return (error);
704 		}
705 		tmp->znode->v_mount = NULL;
706 		vgone(tmp->znode);
707 		vput(tmp->znode);
708 		tmp->znode = NULL;
709 	}
710 #ifdef ZSTDIO
711 	if (zio->zstd != NULL) {
712 		TARFS_DPF(ALLOC, "%s: freeing zstd state\n", __func__);
713 		ZSTD_freeDStream(zio->zstd->zds);
714 		free(zio->zstd, M_TARFSZSTATE);
715 	}
716 #endif
717 	if (zio->idx != NULL) {
718 		TARFS_DPF(ALLOC, "%s: freeing index\n", __func__);
719 		free(zio->idx, M_TARFSZSTATE);
720 	}
721 	TARFS_DPF(ALLOC, "%s: freeing zio\n", __func__);
722 	free(zio, M_TARFSZSTATE);
723 	tmp->zio = NULL;
724 	return (error);
725 }
726 #endif
727 
728 /*
729  * Tears down the I/O layer, including the decompression layer if
730  * applicable.
731  */
732 int
733 tarfs_io_fini(struct tarfs_mount *tmp)
734 {
735 	int error = 0;
736 
737 #ifdef TARFS_ZIO
738 	if (tmp->zio != NULL) {
739 		error = tarfs_zio_fini(tmp);
740 	}
741 #endif
742 	return (error);
743 }
744