xref: /freebsd/sys/fs/tarfs/tarfs_io.c (revision 91e03758ded5dbaf7a5a6247c3eb61a07c95494d)
169d94f4cSDag-Erling Smørgrav /*-
269d94f4cSDag-Erling Smørgrav  * SPDX-License-Identifier: BSD-2-Clause
369d94f4cSDag-Erling Smørgrav  *
469d94f4cSDag-Erling Smørgrav  * Copyright (c) 2013 Juniper Networks, Inc.
569d94f4cSDag-Erling Smørgrav  * Copyright (c) 2022-2023 Klara, Inc.
669d94f4cSDag-Erling Smørgrav  *
769d94f4cSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
869d94f4cSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
969d94f4cSDag-Erling Smørgrav  * are met:
1069d94f4cSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
1169d94f4cSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
1269d94f4cSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1369d94f4cSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1469d94f4cSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1569d94f4cSDag-Erling Smørgrav  *
1669d94f4cSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1769d94f4cSDag-Erling Smørgrav  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1869d94f4cSDag-Erling Smørgrav  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1969d94f4cSDag-Erling Smørgrav  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2069d94f4cSDag-Erling Smørgrav  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2169d94f4cSDag-Erling Smørgrav  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2269d94f4cSDag-Erling Smørgrav  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2369d94f4cSDag-Erling Smørgrav  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2469d94f4cSDag-Erling Smørgrav  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2569d94f4cSDag-Erling Smørgrav  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2669d94f4cSDag-Erling Smørgrav  * SUCH DAMAGE.
2769d94f4cSDag-Erling Smørgrav  */
2869d94f4cSDag-Erling Smørgrav 
2969d94f4cSDag-Erling Smørgrav #include "opt_tarfs.h"
3069d94f4cSDag-Erling Smørgrav #include "opt_zstdio.h"
3169d94f4cSDag-Erling Smørgrav 
3269d94f4cSDag-Erling Smørgrav #include <sys/param.h>
3369d94f4cSDag-Erling Smørgrav #include <sys/systm.h>
3469d94f4cSDag-Erling Smørgrav #include <sys/counter.h>
3569d94f4cSDag-Erling Smørgrav #include <sys/bio.h>
3669d94f4cSDag-Erling Smørgrav #include <sys/buf.h>
3769d94f4cSDag-Erling Smørgrav #include <sys/malloc.h>
3869d94f4cSDag-Erling Smørgrav #include <sys/mount.h>
3969d94f4cSDag-Erling Smørgrav #include <sys/sysctl.h>
4069d94f4cSDag-Erling Smørgrav #include <sys/uio.h>
4169d94f4cSDag-Erling Smørgrav #include <sys/vnode.h>
4269d94f4cSDag-Erling Smørgrav 
43146d9da6SDag-Erling Smørgrav #if defined(ZSTDIO)
44146d9da6SDag-Erling Smørgrav #define TARFS_ZIO 1
45146d9da6SDag-Erling Smørgrav #else
46146d9da6SDag-Erling Smørgrav #undef TARFS_ZIO
47146d9da6SDag-Erling Smørgrav #endif
48146d9da6SDag-Erling Smørgrav 
4969d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO
5069d94f4cSDag-Erling Smørgrav #define ZSTD_STATIC_LINKING_ONLY
5169d94f4cSDag-Erling Smørgrav #include <contrib/zstd/lib/zstd.h>
5269d94f4cSDag-Erling Smørgrav #endif
5369d94f4cSDag-Erling Smørgrav 
5469d94f4cSDag-Erling Smørgrav #include <fs/tarfs/tarfs.h>
5569d94f4cSDag-Erling Smørgrav #include <fs/tarfs/tarfs_dbg.h>
5669d94f4cSDag-Erling Smørgrav 
5769d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG
5869d94f4cSDag-Erling Smørgrav SYSCTL_NODE(_vfs_tarfs, OID_AUTO, zio, CTLFLAG_RD, 0,
5969d94f4cSDag-Erling Smørgrav     "Tar filesystem decompression layer");
6069d94f4cSDag-Erling Smørgrav COUNTER_U64_DEFINE_EARLY(tarfs_zio_inflated);
6169d94f4cSDag-Erling Smørgrav SYSCTL_COUNTER_U64(_vfs_tarfs_zio, OID_AUTO, inflated, CTLFLAG_RD,
6269d94f4cSDag-Erling Smørgrav     &tarfs_zio_inflated, "Amount of compressed data inflated.");
6369d94f4cSDag-Erling Smørgrav COUNTER_U64_DEFINE_EARLY(tarfs_zio_consumed);
6469d94f4cSDag-Erling Smørgrav SYSCTL_COUNTER_U64(_vfs_tarfs_zio, OID_AUTO, consumed, CTLFLAG_RD,
6569d94f4cSDag-Erling Smørgrav     &tarfs_zio_consumed, "Amount of compressed data consumed.");
6669d94f4cSDag-Erling Smørgrav COUNTER_U64_DEFINE_EARLY(tarfs_zio_bounced);
6769d94f4cSDag-Erling Smørgrav SYSCTL_COUNTER_U64(_vfs_tarfs_zio, OID_AUTO, bounced, CTLFLAG_RD,
6869d94f4cSDag-Erling Smørgrav     &tarfs_zio_bounced, "Amount of decompressed data bounced.");
6969d94f4cSDag-Erling Smørgrav 
7069d94f4cSDag-Erling Smørgrav static int
tarfs_sysctl_handle_zio_reset(SYSCTL_HANDLER_ARGS)7169d94f4cSDag-Erling Smørgrav tarfs_sysctl_handle_zio_reset(SYSCTL_HANDLER_ARGS)
7269d94f4cSDag-Erling Smørgrav {
7369d94f4cSDag-Erling Smørgrav 	unsigned int tmp;
7469d94f4cSDag-Erling Smørgrav 	int error;
7569d94f4cSDag-Erling Smørgrav 
7669d94f4cSDag-Erling Smørgrav 	tmp = 0;
7769d94f4cSDag-Erling Smørgrav 	if ((error = SYSCTL_OUT(req, &tmp, sizeof(tmp))) != 0)
7869d94f4cSDag-Erling Smørgrav 		return (error);
7969d94f4cSDag-Erling Smørgrav 	if (req->newptr != NULL) {
8069d94f4cSDag-Erling Smørgrav 		if ((error = SYSCTL_IN(req, &tmp, sizeof(tmp))) != 0)
8169d94f4cSDag-Erling Smørgrav 			return (error);
8269d94f4cSDag-Erling Smørgrav 		counter_u64_zero(tarfs_zio_inflated);
8369d94f4cSDag-Erling Smørgrav 		counter_u64_zero(tarfs_zio_consumed);
8469d94f4cSDag-Erling Smørgrav 		counter_u64_zero(tarfs_zio_bounced);
8569d94f4cSDag-Erling Smørgrav 	}
8669d94f4cSDag-Erling Smørgrav 	return (0);
8769d94f4cSDag-Erling Smørgrav }
8869d94f4cSDag-Erling Smørgrav 
8969d94f4cSDag-Erling Smørgrav SYSCTL_PROC(_vfs_tarfs_zio, OID_AUTO, reset,
9069d94f4cSDag-Erling Smørgrav     CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW,
9169d94f4cSDag-Erling Smørgrav     NULL, 0, tarfs_sysctl_handle_zio_reset, "IU",
9269d94f4cSDag-Erling Smørgrav     "Reset compression counters.");
9369d94f4cSDag-Erling Smørgrav #endif
9469d94f4cSDag-Erling Smørgrav 
9569d94f4cSDag-Erling Smørgrav MALLOC_DEFINE(M_TARFSZSTATE, "tarfs zstate", "tarfs decompression state");
9669d94f4cSDag-Erling Smørgrav MALLOC_DEFINE(M_TARFSZBUF, "tarfs zbuf", "tarfs decompression buffers");
9769d94f4cSDag-Erling Smørgrav 
9869d94f4cSDag-Erling Smørgrav #define XZ_MAGIC		(uint8_t[]){ 0xfd, 0x37, 0x7a, 0x58, 0x5a }
9969d94f4cSDag-Erling Smørgrav #define ZLIB_MAGIC		(uint8_t[]){ 0x1f, 0x8b, 0x08 }
10069d94f4cSDag-Erling Smørgrav #define ZSTD_MAGIC		(uint8_t[]){ 0x28, 0xb5, 0x2f, 0xfd }
10169d94f4cSDag-Erling Smørgrav 
10269d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO
10369d94f4cSDag-Erling Smørgrav struct tarfs_zstd {
10469d94f4cSDag-Erling Smørgrav 	ZSTD_DStream *zds;
10569d94f4cSDag-Erling Smørgrav };
10669d94f4cSDag-Erling Smørgrav #endif
10769d94f4cSDag-Erling Smørgrav 
10869d94f4cSDag-Erling Smørgrav /* XXX review use of curthread / uio_td / td_cred */
10969d94f4cSDag-Erling Smørgrav 
11069d94f4cSDag-Erling Smørgrav /*
11169d94f4cSDag-Erling Smørgrav  * Reads from the tar file according to the provided uio.  If the archive
11269d94f4cSDag-Erling Smørgrav  * is compressed and raw is false, reads the decompressed stream;
11369d94f4cSDag-Erling Smørgrav  * otherwise, reads directly from the original file.  Returns 0 on success
11469d94f4cSDag-Erling Smørgrav  * and a positive errno value on failure.
11569d94f4cSDag-Erling Smørgrav  */
11669d94f4cSDag-Erling Smørgrav int
tarfs_io_read(struct tarfs_mount * tmp,bool raw,struct uio * uiop)11769d94f4cSDag-Erling Smørgrav tarfs_io_read(struct tarfs_mount *tmp, bool raw, struct uio *uiop)
11869d94f4cSDag-Erling Smørgrav {
11969d94f4cSDag-Erling Smørgrav 	void *rl = NULL;
12069d94f4cSDag-Erling Smørgrav 	off_t off = uiop->uio_offset;
12169d94f4cSDag-Erling Smørgrav 	size_t len = uiop->uio_resid;
12269d94f4cSDag-Erling Smørgrav 	int error;
12369d94f4cSDag-Erling Smørgrav 
12469d94f4cSDag-Erling Smørgrav 	if (raw || tmp->znode == NULL) {
12569d94f4cSDag-Erling Smørgrav 		rl = vn_rangelock_rlock(tmp->vp, off, off + len);
12669d94f4cSDag-Erling Smørgrav 		error = vn_lock(tmp->vp, LK_SHARED);
12769d94f4cSDag-Erling Smørgrav 		if (error == 0) {
128*91e03758SDag-Erling Smørgrav 			error = VOP_READ(tmp->vp, uiop, IO_NODELOCKED,
12969d94f4cSDag-Erling Smørgrav 			    uiop->uio_td->td_ucred);
13069d94f4cSDag-Erling Smørgrav 			VOP_UNLOCK(tmp->vp);
13169d94f4cSDag-Erling Smørgrav 		}
13269d94f4cSDag-Erling Smørgrav 		vn_rangelock_unlock(tmp->vp, rl);
13369d94f4cSDag-Erling Smørgrav 	} else {
13469d94f4cSDag-Erling Smørgrav 		error = vn_lock(tmp->znode, LK_EXCLUSIVE);
13569d94f4cSDag-Erling Smørgrav 		if (error == 0) {
13669d94f4cSDag-Erling Smørgrav 			error = VOP_READ(tmp->znode, uiop,
13769d94f4cSDag-Erling Smørgrav 			    IO_DIRECT | IO_NODELOCKED,
13869d94f4cSDag-Erling Smørgrav 			    uiop->uio_td->td_ucred);
13969d94f4cSDag-Erling Smørgrav 			VOP_UNLOCK(tmp->znode);
14069d94f4cSDag-Erling Smørgrav 		}
14169d94f4cSDag-Erling Smørgrav 	}
14269d94f4cSDag-Erling Smørgrav 	TARFS_DPF(IO, "%s(%zu, %zu) = %d (resid %zd)\n", __func__,
14369d94f4cSDag-Erling Smørgrav 	    (size_t)off, len, error, uiop->uio_resid);
14469d94f4cSDag-Erling Smørgrav 	return (error);
14569d94f4cSDag-Erling Smørgrav }
14669d94f4cSDag-Erling Smørgrav 
14769d94f4cSDag-Erling Smørgrav /*
14869d94f4cSDag-Erling Smørgrav  * Reads from the tar file into the provided buffer.  If the archive is
14969d94f4cSDag-Erling Smørgrav  * compressed and raw is false, reads the decompressed stream; otherwise,
15069d94f4cSDag-Erling Smørgrav  * reads directly from the original file.  Returns the number of bytes
15169d94f4cSDag-Erling Smørgrav  * read on success, 0 on EOF, and a negative errno value on failure.
15269d94f4cSDag-Erling Smørgrav  */
15369d94f4cSDag-Erling Smørgrav ssize_t
tarfs_io_read_buf(struct tarfs_mount * tmp,bool raw,void * buf,off_t off,size_t len)15469d94f4cSDag-Erling Smørgrav tarfs_io_read_buf(struct tarfs_mount *tmp, bool raw,
15569d94f4cSDag-Erling Smørgrav     void *buf, off_t off, size_t len)
15669d94f4cSDag-Erling Smørgrav {
15769d94f4cSDag-Erling Smørgrav 	struct uio auio;
15869d94f4cSDag-Erling Smørgrav 	struct iovec aiov;
15969d94f4cSDag-Erling Smørgrav 	ssize_t res;
16069d94f4cSDag-Erling Smørgrav 	int error;
16169d94f4cSDag-Erling Smørgrav 
16269d94f4cSDag-Erling Smørgrav 	if (len == 0) {
16369d94f4cSDag-Erling Smørgrav 		TARFS_DPF(IO, "%s(%zu, %zu) null\n", __func__,
16469d94f4cSDag-Erling Smørgrav 		    (size_t)off, len);
16569d94f4cSDag-Erling Smørgrav 		return (0);
16669d94f4cSDag-Erling Smørgrav 	}
16769d94f4cSDag-Erling Smørgrav 	aiov.iov_base = buf;
16869d94f4cSDag-Erling Smørgrav 	aiov.iov_len = len;
16969d94f4cSDag-Erling Smørgrav 	auio.uio_iov = &aiov;
17069d94f4cSDag-Erling Smørgrav 	auio.uio_iovcnt = 1;
17169d94f4cSDag-Erling Smørgrav 	auio.uio_offset = off;
17269d94f4cSDag-Erling Smørgrav 	auio.uio_segflg = UIO_SYSSPACE;
17369d94f4cSDag-Erling Smørgrav 	auio.uio_rw = UIO_READ;
17469d94f4cSDag-Erling Smørgrav 	auio.uio_resid = len;
17569d94f4cSDag-Erling Smørgrav 	auio.uio_td = curthread;
17669d94f4cSDag-Erling Smørgrav 	error = tarfs_io_read(tmp, raw, &auio);
17769d94f4cSDag-Erling Smørgrav 	if (error != 0) {
17869d94f4cSDag-Erling Smørgrav 		TARFS_DPF(IO, "%s(%zu, %zu) error %d\n", __func__,
17969d94f4cSDag-Erling Smørgrav 		    (size_t)off, len, error);
18069d94f4cSDag-Erling Smørgrav 		return (-error);
18169d94f4cSDag-Erling Smørgrav 	}
18269d94f4cSDag-Erling Smørgrav 	res = len - auio.uio_resid;
18369d94f4cSDag-Erling Smørgrav 	if (res == 0 && len != 0) {
18469d94f4cSDag-Erling Smørgrav 		TARFS_DPF(IO, "%s(%zu, %zu) eof\n", __func__,
18569d94f4cSDag-Erling Smørgrav 		    (size_t)off, len);
18669d94f4cSDag-Erling Smørgrav 	} else {
18769d94f4cSDag-Erling Smørgrav 		TARFS_DPF(IO, "%s(%zu, %zu) read %zd | %*D\n", __func__,
18869d94f4cSDag-Erling Smørgrav 		    (size_t)off, len, res,
18969d94f4cSDag-Erling Smørgrav 		    (int)(res > 8 ? 8 : res), (uint8_t *)buf, " ");
19069d94f4cSDag-Erling Smørgrav 	}
19169d94f4cSDag-Erling Smørgrav 	return (res);
19269d94f4cSDag-Erling Smørgrav }
19369d94f4cSDag-Erling Smørgrav 
19469d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO
19569d94f4cSDag-Erling Smørgrav static void *
tarfs_zstate_alloc(void * opaque,size_t size)19669d94f4cSDag-Erling Smørgrav tarfs_zstate_alloc(void *opaque, size_t size)
19769d94f4cSDag-Erling Smørgrav {
19869d94f4cSDag-Erling Smørgrav 
19969d94f4cSDag-Erling Smørgrav 	(void)opaque;
20069d94f4cSDag-Erling Smørgrav 	return (malloc(size, M_TARFSZSTATE, M_WAITOK));
20169d94f4cSDag-Erling Smørgrav }
20269d94f4cSDag-Erling Smørgrav #endif
20369d94f4cSDag-Erling Smørgrav 
20469d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO
20569d94f4cSDag-Erling Smørgrav static void
tarfs_zstate_free(void * opaque,void * address)20669d94f4cSDag-Erling Smørgrav tarfs_zstate_free(void *opaque, void *address)
20769d94f4cSDag-Erling Smørgrav {
20869d94f4cSDag-Erling Smørgrav 
20969d94f4cSDag-Erling Smørgrav 	(void)opaque;
21069d94f4cSDag-Erling Smørgrav 	free(address, M_TARFSZSTATE);
21169d94f4cSDag-Erling Smørgrav }
21269d94f4cSDag-Erling Smørgrav #endif
21369d94f4cSDag-Erling Smørgrav 
21469d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO
21569d94f4cSDag-Erling Smørgrav static ZSTD_customMem tarfs_zstd_mem = {
21669d94f4cSDag-Erling Smørgrav 	tarfs_zstate_alloc,
21769d94f4cSDag-Erling Smørgrav 	tarfs_zstate_free,
21869d94f4cSDag-Erling Smørgrav 	NULL,
21969d94f4cSDag-Erling Smørgrav };
22069d94f4cSDag-Erling Smørgrav #endif
22169d94f4cSDag-Erling Smørgrav 
222146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO
22369d94f4cSDag-Erling Smørgrav /*
22469d94f4cSDag-Erling Smørgrav  * Updates the decompression frame index, recording the current input and
22569d94f4cSDag-Erling Smørgrav  * output offsets in a new index entry, and growing the index if
22669d94f4cSDag-Erling Smørgrav  * necessary.
22769d94f4cSDag-Erling Smørgrav  */
22869d94f4cSDag-Erling Smørgrav static void
tarfs_zio_update_index(struct tarfs_zio * zio,off_t i,off_t o)22969d94f4cSDag-Erling Smørgrav tarfs_zio_update_index(struct tarfs_zio *zio, off_t i, off_t o)
23069d94f4cSDag-Erling Smørgrav {
23169d94f4cSDag-Erling Smørgrav 
23269d94f4cSDag-Erling Smørgrav 	if (++zio->curidx >= zio->nidx) {
23369d94f4cSDag-Erling Smørgrav 		if (++zio->nidx > zio->szidx) {
23469d94f4cSDag-Erling Smørgrav 			zio->szidx *= 2;
23569d94f4cSDag-Erling Smørgrav 			zio->idx = realloc(zio->idx,
23669d94f4cSDag-Erling Smørgrav 			    zio->szidx * sizeof(*zio->idx),
23769d94f4cSDag-Erling Smørgrav 			    M_TARFSZSTATE, M_ZERO | M_WAITOK);
23869d94f4cSDag-Erling Smørgrav 			TARFS_DPF(ALLOC, "%s: resized zio index\n", __func__);
23969d94f4cSDag-Erling Smørgrav 		}
24069d94f4cSDag-Erling Smørgrav 		zio->idx[zio->curidx].i = i;
24169d94f4cSDag-Erling Smørgrav 		zio->idx[zio->curidx].o = o;
24269d94f4cSDag-Erling Smørgrav 		TARFS_DPF(ZIDX, "%s: index %u = i %zu o %zu\n", __func__,
24369d94f4cSDag-Erling Smørgrav 		    zio->curidx, (size_t)zio->idx[zio->curidx].i,
24469d94f4cSDag-Erling Smørgrav 		    (size_t)zio->idx[zio->curidx].o);
24569d94f4cSDag-Erling Smørgrav 	}
24669d94f4cSDag-Erling Smørgrav 	MPASS(zio->idx[zio->curidx].i == i);
24769d94f4cSDag-Erling Smørgrav 	MPASS(zio->idx[zio->curidx].o == o);
24869d94f4cSDag-Erling Smørgrav }
249146d9da6SDag-Erling Smørgrav #endif
25069d94f4cSDag-Erling Smørgrav 
25169d94f4cSDag-Erling Smørgrav /*
25269d94f4cSDag-Erling Smørgrav  * VOP_ACCESS for zio node.
25369d94f4cSDag-Erling Smørgrav  */
25469d94f4cSDag-Erling Smørgrav static int
tarfs_zaccess(struct vop_access_args * ap)25569d94f4cSDag-Erling Smørgrav tarfs_zaccess(struct vop_access_args *ap)
25669d94f4cSDag-Erling Smørgrav {
25769d94f4cSDag-Erling Smørgrav 	struct vnode *vp = ap->a_vp;
25869d94f4cSDag-Erling Smørgrav 	struct tarfs_zio *zio = vp->v_data;
25969d94f4cSDag-Erling Smørgrav 	struct tarfs_mount *tmp = zio->tmp;
26069d94f4cSDag-Erling Smørgrav 	accmode_t accmode = ap->a_accmode;
26169d94f4cSDag-Erling Smørgrav 	int error = EPERM;
26269d94f4cSDag-Erling Smørgrav 
26369d94f4cSDag-Erling Smørgrav 	if (accmode == VREAD) {
26469d94f4cSDag-Erling Smørgrav 		error = vn_lock(tmp->vp, LK_SHARED);
26569d94f4cSDag-Erling Smørgrav 		if (error == 0) {
26669d94f4cSDag-Erling Smørgrav 			error = VOP_ACCESS(tmp->vp, accmode, ap->a_cred, ap->a_td);
26769d94f4cSDag-Erling Smørgrav 			VOP_UNLOCK(tmp->vp);
26869d94f4cSDag-Erling Smørgrav 		}
26969d94f4cSDag-Erling Smørgrav 	}
27069d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ZIO, "%s(%d) = %d\n", __func__, accmode, error);
27169d94f4cSDag-Erling Smørgrav 	return (error);
27269d94f4cSDag-Erling Smørgrav }
27369d94f4cSDag-Erling Smørgrav 
27469d94f4cSDag-Erling Smørgrav /*
27569d94f4cSDag-Erling Smørgrav  * VOP_GETATTR for zio node.
27669d94f4cSDag-Erling Smørgrav  */
27769d94f4cSDag-Erling Smørgrav static int
tarfs_zgetattr(struct vop_getattr_args * ap)27869d94f4cSDag-Erling Smørgrav tarfs_zgetattr(struct vop_getattr_args *ap)
27969d94f4cSDag-Erling Smørgrav {
28069d94f4cSDag-Erling Smørgrav 	struct vattr va;
28169d94f4cSDag-Erling Smørgrav 	struct vnode *vp = ap->a_vp;
28269d94f4cSDag-Erling Smørgrav 	struct tarfs_zio *zio = vp->v_data;
28369d94f4cSDag-Erling Smørgrav 	struct tarfs_mount *tmp = zio->tmp;
28469d94f4cSDag-Erling Smørgrav 	struct vattr *vap = ap->a_vap;
28569d94f4cSDag-Erling Smørgrav 	int error = 0;
28669d94f4cSDag-Erling Smørgrav 
28769d94f4cSDag-Erling Smørgrav 	VATTR_NULL(vap);
28869d94f4cSDag-Erling Smørgrav 	error = vn_lock(tmp->vp, LK_SHARED);
28969d94f4cSDag-Erling Smørgrav 	if (error == 0) {
29069d94f4cSDag-Erling Smørgrav 		error = VOP_GETATTR(tmp->vp, &va, ap->a_cred);
29169d94f4cSDag-Erling Smørgrav 		VOP_UNLOCK(tmp->vp);
29269d94f4cSDag-Erling Smørgrav 		if (error == 0) {
29369d94f4cSDag-Erling Smørgrav 			vap->va_type = VREG;
29469d94f4cSDag-Erling Smørgrav 			vap->va_mode = va.va_mode;
29569d94f4cSDag-Erling Smørgrav 			vap->va_nlink = 1;
29669d94f4cSDag-Erling Smørgrav 			vap->va_gid = va.va_gid;
29769d94f4cSDag-Erling Smørgrav 			vap->va_uid = va.va_uid;
29869d94f4cSDag-Erling Smørgrav 			vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
29969d94f4cSDag-Erling Smørgrav 			vap->va_fileid = TARFS_ZIOINO;
30069d94f4cSDag-Erling Smørgrav 			vap->va_size = zio->idx[zio->nidx - 1].o;
30169d94f4cSDag-Erling Smørgrav 			vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
30269d94f4cSDag-Erling Smørgrav 			vap->va_atime = va.va_atime;
30369d94f4cSDag-Erling Smørgrav 			vap->va_ctime = va.va_ctime;
30469d94f4cSDag-Erling Smørgrav 			vap->va_mtime = va.va_mtime;
30569d94f4cSDag-Erling Smørgrav 			vap->va_birthtime = tmp->root->birthtime;
30669d94f4cSDag-Erling Smørgrav 			vap->va_bytes = va.va_bytes;
30769d94f4cSDag-Erling Smørgrav 		}
30869d94f4cSDag-Erling Smørgrav 	}
30969d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ZIO, "%s() = %d\n", __func__, error);
31069d94f4cSDag-Erling Smørgrav 	return (error);
31169d94f4cSDag-Erling Smørgrav }
31269d94f4cSDag-Erling Smørgrav 
31369d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO
31469d94f4cSDag-Erling Smørgrav /*
31569d94f4cSDag-Erling Smørgrav  * VOP_READ for zio node, zstd edition.
31669d94f4cSDag-Erling Smørgrav  */
31769d94f4cSDag-Erling Smørgrav static int
tarfs_zread_zstd(struct tarfs_zio * zio,struct uio * uiop)31869d94f4cSDag-Erling Smørgrav tarfs_zread_zstd(struct tarfs_zio *zio, struct uio *uiop)
31969d94f4cSDag-Erling Smørgrav {
32069d94f4cSDag-Erling Smørgrav 	void *ibuf = NULL, *obuf = NULL, *rl = NULL;
32169d94f4cSDag-Erling Smørgrav 	struct uio auio;
32269d94f4cSDag-Erling Smørgrav 	struct iovec aiov;
32369d94f4cSDag-Erling Smørgrav 	struct tarfs_mount *tmp = zio->tmp;
32469d94f4cSDag-Erling Smørgrav 	struct tarfs_zstd *zstd = zio->zstd;
32569d94f4cSDag-Erling Smørgrav 	struct thread *td = curthread;
32669d94f4cSDag-Erling Smørgrav 	ZSTD_inBuffer zib;
32769d94f4cSDag-Erling Smørgrav 	ZSTD_outBuffer zob;
32869d94f4cSDag-Erling Smørgrav 	off_t zsize;
32969d94f4cSDag-Erling Smørgrav 	off_t ipos, opos;
33069d94f4cSDag-Erling Smørgrav 	size_t ilen, olen;
33169d94f4cSDag-Erling Smørgrav 	size_t zerror;
33269d94f4cSDag-Erling Smørgrav 	off_t off = uiop->uio_offset;
33369d94f4cSDag-Erling Smørgrav 	size_t len = uiop->uio_resid;
33469d94f4cSDag-Erling Smørgrav 	size_t resid = uiop->uio_resid;
33569d94f4cSDag-Erling Smørgrav 	size_t bsize;
33669d94f4cSDag-Erling Smørgrav 	int error;
33769d94f4cSDag-Erling Smørgrav 	bool reset = false;
33869d94f4cSDag-Erling Smørgrav 
33969d94f4cSDag-Erling Smørgrav 	/* do we have to rewind? */
34069d94f4cSDag-Erling Smørgrav 	if (off < zio->opos) {
34169d94f4cSDag-Erling Smørgrav 		while (zio->curidx > 0 && off < zio->idx[zio->curidx].o)
34269d94f4cSDag-Erling Smørgrav 			zio->curidx--;
34369d94f4cSDag-Erling Smørgrav 		reset = true;
34469d94f4cSDag-Erling Smørgrav 	}
34569d94f4cSDag-Erling Smørgrav 	/* advance to the nearest index entry */
34669d94f4cSDag-Erling Smørgrav 	if (off > zio->opos) {
34769d94f4cSDag-Erling Smørgrav 		// XXX maybe do a binary search instead
34869d94f4cSDag-Erling Smørgrav 		while (zio->curidx < zio->nidx - 1 &&
34969d94f4cSDag-Erling Smørgrav 		    off >= zio->idx[zio->curidx + 1].o) {
35069d94f4cSDag-Erling Smørgrav 			zio->curidx++;
35169d94f4cSDag-Erling Smørgrav 			reset = true;
35269d94f4cSDag-Erling Smørgrav 		}
35369d94f4cSDag-Erling Smørgrav 	}
35469d94f4cSDag-Erling Smørgrav 	/* reset the decompression stream if needed */
35569d94f4cSDag-Erling Smørgrav 	if (reset) {
35669d94f4cSDag-Erling Smørgrav 		zio->ipos = zio->idx[zio->curidx].i;
35769d94f4cSDag-Erling Smørgrav 		zio->opos = zio->idx[zio->curidx].o;
35869d94f4cSDag-Erling Smørgrav 		ZSTD_resetDStream(zstd->zds);
35969d94f4cSDag-Erling Smørgrav 		TARFS_DPF(ZIDX, "%s: skipping to index %u = i %zu o %zu\n", __func__,
36069d94f4cSDag-Erling Smørgrav 		    zio->curidx, (size_t)zio->ipos, (size_t)zio->opos);
36169d94f4cSDag-Erling Smørgrav 	} else {
36269d94f4cSDag-Erling Smørgrav 		TARFS_DPF(ZIDX, "%s: continuing at i %zu o %zu\n", __func__,
36369d94f4cSDag-Erling Smørgrav 		    (size_t)zio->ipos, (size_t)zio->opos);
36469d94f4cSDag-Erling Smørgrav 	}
36569d94f4cSDag-Erling Smørgrav 
36669d94f4cSDag-Erling Smørgrav 	/*
36769d94f4cSDag-Erling Smørgrav 	 * Set up a temporary buffer for compressed data.  Use the size
36869d94f4cSDag-Erling Smørgrav 	 * recommended by the zstd library; this is usually 128 kB, but
36969d94f4cSDag-Erling Smørgrav 	 * just in case, make sure it's a multiple of the page size and no
37069d94f4cSDag-Erling Smørgrav 	 * larger than MAXBSIZE.
37169d94f4cSDag-Erling Smørgrav 	 */
37269d94f4cSDag-Erling Smørgrav 	bsize = roundup(ZSTD_CStreamOutSize(), PAGE_SIZE);
37369d94f4cSDag-Erling Smørgrav 	if (bsize > MAXBSIZE)
37469d94f4cSDag-Erling Smørgrav 		bsize = MAXBSIZE;
37569d94f4cSDag-Erling Smørgrav 	ibuf = malloc(bsize, M_TEMP, M_WAITOK);
37669d94f4cSDag-Erling Smørgrav 	zib.src = NULL;
37769d94f4cSDag-Erling Smørgrav 	zib.size = 0;
37869d94f4cSDag-Erling Smørgrav 	zib.pos = 0;
37969d94f4cSDag-Erling Smørgrav 
38069d94f4cSDag-Erling Smørgrav 	/*
38169d94f4cSDag-Erling Smørgrav 	 * Set up the decompression buffer.  If the target is not in
38269d94f4cSDag-Erling Smørgrav 	 * kernel space, we will have to set up a bounce buffer.
38369d94f4cSDag-Erling Smørgrav 	 *
38469d94f4cSDag-Erling Smørgrav 	 * TODO: to avoid using a bounce buffer, map destination pages
38569d94f4cSDag-Erling Smørgrav 	 * using vm_fault_quick_hold_pages().
38669d94f4cSDag-Erling Smørgrav 	 */
38769d94f4cSDag-Erling Smørgrav 	MPASS(zio->opos <= off);
38869d94f4cSDag-Erling Smørgrav 	MPASS(uiop->uio_iovcnt == 1);
38969d94f4cSDag-Erling Smørgrav 	MPASS(uiop->uio_iov->iov_len >= len);
39069d94f4cSDag-Erling Smørgrav 	if (uiop->uio_segflg == UIO_SYSSPACE) {
39169d94f4cSDag-Erling Smørgrav 		zob.dst = uiop->uio_iov->iov_base;
39269d94f4cSDag-Erling Smørgrav 	} else {
393bf84156bSDag-Erling Smørgrav 		TARFS_DPF(BOUNCE, "%s: allocating %zu-byte bounce buffer\n",
39469d94f4cSDag-Erling Smørgrav 		    __func__, len);
39569d94f4cSDag-Erling Smørgrav 		zob.dst = obuf = malloc(len, M_TEMP, M_WAITOK);
39669d94f4cSDag-Erling Smørgrav 	}
39769d94f4cSDag-Erling Smørgrav 	zob.size = len;
39869d94f4cSDag-Erling Smørgrav 	zob.pos = 0;
39969d94f4cSDag-Erling Smørgrav 
40069d94f4cSDag-Erling Smørgrav 	/* lock tarball */
40169d94f4cSDag-Erling Smørgrav 	rl = vn_rangelock_rlock(tmp->vp, zio->ipos, OFF_MAX);
40269d94f4cSDag-Erling Smørgrav 	error = vn_lock(tmp->vp, LK_SHARED);
40369d94f4cSDag-Erling Smørgrav 	if (error != 0) {
40469d94f4cSDag-Erling Smørgrav 		goto fail_unlocked;
40569d94f4cSDag-Erling Smørgrav 	}
40669d94f4cSDag-Erling Smørgrav 	/* check size */
40769d94f4cSDag-Erling Smørgrav 	error = vn_getsize_locked(tmp->vp, &zsize, td->td_ucred);
40869d94f4cSDag-Erling Smørgrav 	if (error != 0) {
40969d94f4cSDag-Erling Smørgrav 		goto fail;
41069d94f4cSDag-Erling Smørgrav 	}
41169d94f4cSDag-Erling Smørgrav 	if (zio->ipos >= zsize) {
41269d94f4cSDag-Erling Smørgrav 		/* beyond EOF */
41369d94f4cSDag-Erling Smørgrav 		goto fail;
41469d94f4cSDag-Erling Smørgrav 	}
41569d94f4cSDag-Erling Smørgrav 
41669d94f4cSDag-Erling Smørgrav 	while (resid > 0) {
41769d94f4cSDag-Erling Smørgrav 		if (zib.pos == zib.size) {
41869d94f4cSDag-Erling Smørgrav 			/* request data from the underlying file */
41969d94f4cSDag-Erling Smørgrav 			aiov.iov_base = ibuf;
42069d94f4cSDag-Erling Smørgrav 			aiov.iov_len = bsize;
42169d94f4cSDag-Erling Smørgrav 			auio.uio_iov = &aiov;
42269d94f4cSDag-Erling Smørgrav 			auio.uio_iovcnt = 1;
42369d94f4cSDag-Erling Smørgrav 			auio.uio_offset = zio->ipos;
42469d94f4cSDag-Erling Smørgrav 			auio.uio_segflg = UIO_SYSSPACE;
42569d94f4cSDag-Erling Smørgrav 			auio.uio_rw = UIO_READ;
42669d94f4cSDag-Erling Smørgrav 			auio.uio_resid = aiov.iov_len;
42769d94f4cSDag-Erling Smørgrav 			auio.uio_td = td;
428*91e03758SDag-Erling Smørgrav 			error = VOP_READ(tmp->vp, &auio, IO_NODELOCKED,
42969d94f4cSDag-Erling Smørgrav 			    td->td_ucred);
43069d94f4cSDag-Erling Smørgrav 			if (error != 0)
43169d94f4cSDag-Erling Smørgrav 				goto fail;
43269d94f4cSDag-Erling Smørgrav 			TARFS_DPF(ZIO, "%s: req %zu+%zu got %zu+%zu\n", __func__,
43369d94f4cSDag-Erling Smørgrav 			    (size_t)zio->ipos, bsize,
43469d94f4cSDag-Erling Smørgrav 			    (size_t)zio->ipos, bsize - auio.uio_resid);
43569d94f4cSDag-Erling Smørgrav 			zib.src = ibuf;
43669d94f4cSDag-Erling Smørgrav 			zib.size = bsize - auio.uio_resid;
43769d94f4cSDag-Erling Smørgrav 			zib.pos = 0;
43869d94f4cSDag-Erling Smørgrav 		}
43969d94f4cSDag-Erling Smørgrav 		MPASS(zib.pos <= zib.size);
44069d94f4cSDag-Erling Smørgrav 		if (zib.pos == zib.size) {
44169d94f4cSDag-Erling Smørgrav 			TARFS_DPF(ZIO, "%s: end of file after i %zu o %zu\n", __func__,
44269d94f4cSDag-Erling Smørgrav 			    (size_t)zio->ipos, (size_t)zio->opos);
44369d94f4cSDag-Erling Smørgrav 			goto fail;
44469d94f4cSDag-Erling Smørgrav 		}
44569d94f4cSDag-Erling Smørgrav 		if (zio->opos < off) {
44669d94f4cSDag-Erling Smørgrav 			/* to be discarded */
44769d94f4cSDag-Erling Smørgrav 			zob.size = min(off - zio->opos, len);
44869d94f4cSDag-Erling Smørgrav 			zob.pos = 0;
44969d94f4cSDag-Erling Smørgrav 		} else {
45069d94f4cSDag-Erling Smørgrav 			zob.size = len;
45169d94f4cSDag-Erling Smørgrav 			zob.pos = zio->opos - off;
45269d94f4cSDag-Erling Smørgrav 		}
45369d94f4cSDag-Erling Smørgrav 		ipos = zib.pos;
45469d94f4cSDag-Erling Smørgrav 		opos = zob.pos;
45569d94f4cSDag-Erling Smørgrav 		/* decompress as much as possible */
45669d94f4cSDag-Erling Smørgrav 		zerror = ZSTD_decompressStream(zstd->zds, &zob, &zib);
45769d94f4cSDag-Erling Smørgrav 		zio->ipos += ilen = zib.pos - ipos;
45869d94f4cSDag-Erling Smørgrav 		zio->opos += olen = zob.pos - opos;
45969d94f4cSDag-Erling Smørgrav 		if (zio->opos > off)
46069d94f4cSDag-Erling Smørgrav 			resid -= olen;
46169d94f4cSDag-Erling Smørgrav 		if (ZSTD_isError(zerror)) {
46269d94f4cSDag-Erling Smørgrav 			TARFS_DPF(ZIO, "%s: inflate failed after i %zu o %zu: %s\n", __func__,
46369d94f4cSDag-Erling Smørgrav 			    (size_t)zio->ipos, (size_t)zio->opos, ZSTD_getErrorName(zerror));
46469d94f4cSDag-Erling Smørgrav 			error = EIO;
46569d94f4cSDag-Erling Smørgrav 			goto fail;
46669d94f4cSDag-Erling Smørgrav 		}
46769d94f4cSDag-Erling Smørgrav 		if (zerror == 0 && olen == 0) {
46869d94f4cSDag-Erling Smørgrav 			TARFS_DPF(ZIO, "%s: end of stream after i %zu o %zu\n", __func__,
46969d94f4cSDag-Erling Smørgrav 			    (size_t)zio->ipos, (size_t)zio->opos);
47069d94f4cSDag-Erling Smørgrav 			break;
47169d94f4cSDag-Erling Smørgrav 		}
47269d94f4cSDag-Erling Smørgrav 		if (zerror == 0) {
47369d94f4cSDag-Erling Smørgrav 			TARFS_DPF(ZIO, "%s: end of frame after i %zu o %zu\n", __func__,
47469d94f4cSDag-Erling Smørgrav 			    (size_t)zio->ipos, (size_t)zio->opos);
47569d94f4cSDag-Erling Smørgrav 			tarfs_zio_update_index(zio, zio->ipos, zio->opos);
47669d94f4cSDag-Erling Smørgrav 		}
47769d94f4cSDag-Erling Smørgrav 		TARFS_DPF(ZIO, "%s: inflated %zu\n", __func__, olen);
47869d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG
47969d94f4cSDag-Erling Smørgrav 		counter_u64_add(tarfs_zio_inflated, olen);
48069d94f4cSDag-Erling Smørgrav #endif
48169d94f4cSDag-Erling Smørgrav 	}
48269d94f4cSDag-Erling Smørgrav fail:
48369d94f4cSDag-Erling Smørgrav 	VOP_UNLOCK(tmp->vp);
48469d94f4cSDag-Erling Smørgrav fail_unlocked:
48569d94f4cSDag-Erling Smørgrav 	if (error == 0) {
48669d94f4cSDag-Erling Smørgrav 		if (uiop->uio_segflg == UIO_SYSSPACE) {
48769d94f4cSDag-Erling Smørgrav 			uiop->uio_resid = resid;
48869d94f4cSDag-Erling Smørgrav 		} else if (len > resid) {
489bf84156bSDag-Erling Smørgrav 			TARFS_DPF(BOUNCE, "%s: bounced %zu bytes\n", __func__,
49069d94f4cSDag-Erling Smørgrav 			    len - resid);
49169d94f4cSDag-Erling Smørgrav 			error = uiomove(obuf, len - resid, uiop);
49269d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG
49369d94f4cSDag-Erling Smørgrav 			counter_u64_add(tarfs_zio_bounced, len - resid);
49469d94f4cSDag-Erling Smørgrav #endif
49569d94f4cSDag-Erling Smørgrav 		}
49669d94f4cSDag-Erling Smørgrav 	}
49769d94f4cSDag-Erling Smørgrav 	if (obuf != NULL) {
498bf84156bSDag-Erling Smørgrav 		TARFS_DPF(BOUNCE, "%s: freeing bounce buffer\n", __func__);
49969d94f4cSDag-Erling Smørgrav 		free(obuf, M_TEMP);
50069d94f4cSDag-Erling Smørgrav 	}
50169d94f4cSDag-Erling Smørgrav 	if (rl != NULL)
50269d94f4cSDag-Erling Smørgrav 		vn_rangelock_unlock(tmp->vp, rl);
50369d94f4cSDag-Erling Smørgrav 	if (ibuf != NULL)
50469d94f4cSDag-Erling Smørgrav 		free(ibuf, M_TEMP);
50569d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ZIO, "%s(%zu, %zu) = %d (resid %zd)\n", __func__,
50669d94f4cSDag-Erling Smørgrav 	    (size_t)off, len, error, uiop->uio_resid);
50769d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG
50869d94f4cSDag-Erling Smørgrav 	counter_u64_add(tarfs_zio_consumed, len - uiop->uio_resid);
50969d94f4cSDag-Erling Smørgrav #endif
51069d94f4cSDag-Erling Smørgrav 	if (error != 0) {
51169d94f4cSDag-Erling Smørgrav 		zio->curidx = 0;
51269d94f4cSDag-Erling Smørgrav 		zio->ipos = zio->idx[0].i;
51369d94f4cSDag-Erling Smørgrav 		zio->opos = zio->idx[0].o;
51469d94f4cSDag-Erling Smørgrav 		ZSTD_resetDStream(zstd->zds);
51569d94f4cSDag-Erling Smørgrav 	}
51669d94f4cSDag-Erling Smørgrav 	return (error);
51769d94f4cSDag-Erling Smørgrav }
51869d94f4cSDag-Erling Smørgrav #endif
51969d94f4cSDag-Erling Smørgrav 
52069d94f4cSDag-Erling Smørgrav /*
52169d94f4cSDag-Erling Smørgrav  * VOP_READ for zio node.
52269d94f4cSDag-Erling Smørgrav  */
52369d94f4cSDag-Erling Smørgrav static int
tarfs_zread(struct vop_read_args * ap)52469d94f4cSDag-Erling Smørgrav tarfs_zread(struct vop_read_args *ap)
52569d94f4cSDag-Erling Smørgrav {
526cf93505eSDag-Erling Smørgrav #if defined(TARFS_DEBUG) || defined(ZSTDIO)
52769d94f4cSDag-Erling Smørgrav 	struct vnode *vp = ap->a_vp;
52869d94f4cSDag-Erling Smørgrav 	struct tarfs_zio *zio = vp->v_data;
52969d94f4cSDag-Erling Smørgrav 	struct uio *uiop = ap->a_uio;
530cf93505eSDag-Erling Smørgrav #endif
53169d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG
53269d94f4cSDag-Erling Smørgrav 	off_t off = uiop->uio_offset;
53369d94f4cSDag-Erling Smørgrav 	size_t len = uiop->uio_resid;
53469d94f4cSDag-Erling Smørgrav #endif
53569d94f4cSDag-Erling Smørgrav 	int error;
53669d94f4cSDag-Erling Smørgrav 
53769d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ZIO, "%s(%zu, %zu)\n", __func__,
53869d94f4cSDag-Erling Smørgrav 	    (size_t)off, len);
53969d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO
54069d94f4cSDag-Erling Smørgrav 	if (zio->zstd != NULL) {
54169d94f4cSDag-Erling Smørgrav 		error = tarfs_zread_zstd(zio, uiop);
54269d94f4cSDag-Erling Smørgrav 	} else
54369d94f4cSDag-Erling Smørgrav #endif
54469d94f4cSDag-Erling Smørgrav 		error = EFTYPE;
54569d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ZIO, "%s(%zu, %zu) = %d (resid %zd)\n", __func__,
54669d94f4cSDag-Erling Smørgrav 	    (size_t)off, len, error, uiop->uio_resid);
54769d94f4cSDag-Erling Smørgrav 	return (error);
54869d94f4cSDag-Erling Smørgrav }
54969d94f4cSDag-Erling Smørgrav 
55069d94f4cSDag-Erling Smørgrav /*
55169d94f4cSDag-Erling Smørgrav  * VOP_RECLAIM for zio node.
55269d94f4cSDag-Erling Smørgrav  */
55369d94f4cSDag-Erling Smørgrav static int
tarfs_zreclaim(struct vop_reclaim_args * ap)55469d94f4cSDag-Erling Smørgrav tarfs_zreclaim(struct vop_reclaim_args *ap)
55569d94f4cSDag-Erling Smørgrav {
55669d94f4cSDag-Erling Smørgrav 	struct vnode *vp = ap->a_vp;
55769d94f4cSDag-Erling Smørgrav 
55869d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ZIO, "%s(%p)\n", __func__, vp);
55969d94f4cSDag-Erling Smørgrav 	vp->v_data = NULL;
56069d94f4cSDag-Erling Smørgrav 	return (0);
56169d94f4cSDag-Erling Smørgrav }
56269d94f4cSDag-Erling Smørgrav 
56369d94f4cSDag-Erling Smørgrav /*
56469d94f4cSDag-Erling Smørgrav  * VOP_STRATEGY for zio node.
56569d94f4cSDag-Erling Smørgrav  */
56669d94f4cSDag-Erling Smørgrav static int
tarfs_zstrategy(struct vop_strategy_args * ap)56769d94f4cSDag-Erling Smørgrav tarfs_zstrategy(struct vop_strategy_args *ap)
56869d94f4cSDag-Erling Smørgrav {
56969d94f4cSDag-Erling Smørgrav 	struct uio auio;
57069d94f4cSDag-Erling Smørgrav 	struct iovec iov;
57169d94f4cSDag-Erling Smørgrav 	struct vnode *vp = ap->a_vp;
57269d94f4cSDag-Erling Smørgrav 	struct buf *bp = ap->a_bp;
57369d94f4cSDag-Erling Smørgrav 	off_t off;
57469d94f4cSDag-Erling Smørgrav 	size_t len;
57569d94f4cSDag-Erling Smørgrav 	int error;
57669d94f4cSDag-Erling Smørgrav 
57769d94f4cSDag-Erling Smørgrav 	iov.iov_base = bp->b_data;
57869d94f4cSDag-Erling Smørgrav 	iov.iov_len = bp->b_bcount;
57969d94f4cSDag-Erling Smørgrav 	off = bp->b_iooffset;
58069d94f4cSDag-Erling Smørgrav 	len = bp->b_bcount;
58169d94f4cSDag-Erling Smørgrav 	bp->b_resid = len;
58269d94f4cSDag-Erling Smørgrav 	auio.uio_iov = &iov;
58369d94f4cSDag-Erling Smørgrav 	auio.uio_iovcnt = 1;
58469d94f4cSDag-Erling Smørgrav 	auio.uio_offset = off;
58569d94f4cSDag-Erling Smørgrav 	auio.uio_resid = len;
58669d94f4cSDag-Erling Smørgrav 	auio.uio_segflg = UIO_SYSSPACE;
58769d94f4cSDag-Erling Smørgrav 	auio.uio_rw = UIO_READ;
58869d94f4cSDag-Erling Smørgrav 	auio.uio_td = curthread;
58969d94f4cSDag-Erling Smørgrav 	error = VOP_READ(vp, &auio, IO_DIRECT | IO_NODELOCKED, bp->b_rcred);
59069d94f4cSDag-Erling Smørgrav 	bp->b_flags |= B_DONE;
59169d94f4cSDag-Erling Smørgrav 	if (error != 0) {
59269d94f4cSDag-Erling Smørgrav 		bp->b_ioflags |= BIO_ERROR;
59369d94f4cSDag-Erling Smørgrav 		bp->b_error = error;
59469d94f4cSDag-Erling Smørgrav 	}
59569d94f4cSDag-Erling Smørgrav 	return (0);
59669d94f4cSDag-Erling Smørgrav }
59769d94f4cSDag-Erling Smørgrav 
59869d94f4cSDag-Erling Smørgrav static struct vop_vector tarfs_znodeops = {
59969d94f4cSDag-Erling Smørgrav 	.vop_default =		&default_vnodeops,
60069d94f4cSDag-Erling Smørgrav 
60169d94f4cSDag-Erling Smørgrav 	.vop_access =		tarfs_zaccess,
60269d94f4cSDag-Erling Smørgrav 	.vop_getattr =		tarfs_zgetattr,
60369d94f4cSDag-Erling Smørgrav 	.vop_read =		tarfs_zread,
60469d94f4cSDag-Erling Smørgrav 	.vop_reclaim =		tarfs_zreclaim,
60569d94f4cSDag-Erling Smørgrav 	.vop_strategy =		tarfs_zstrategy,
60669d94f4cSDag-Erling Smørgrav };
60769d94f4cSDag-Erling Smørgrav VFS_VOP_VECTOR_REGISTER(tarfs_znodeops);
60869d94f4cSDag-Erling Smørgrav 
609146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO
61069d94f4cSDag-Erling Smørgrav /*
61169d94f4cSDag-Erling Smørgrav  * Initializes the decompression layer.
61269d94f4cSDag-Erling Smørgrav  */
61369d94f4cSDag-Erling Smørgrav static struct tarfs_zio *
tarfs_zio_init(struct tarfs_mount * tmp,off_t i,off_t o)61469d94f4cSDag-Erling Smørgrav tarfs_zio_init(struct tarfs_mount *tmp, off_t i, off_t o)
61569d94f4cSDag-Erling Smørgrav {
61669d94f4cSDag-Erling Smørgrav 	struct tarfs_zio *zio;
61769d94f4cSDag-Erling Smørgrav 	struct vnode *zvp;
61869d94f4cSDag-Erling Smørgrav 
61969d94f4cSDag-Erling Smørgrav 	zio = malloc(sizeof(*zio), M_TARFSZSTATE, M_ZERO | M_WAITOK);
62069d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ALLOC, "%s: allocated zio\n", __func__);
62169d94f4cSDag-Erling Smørgrav 	zio->tmp = tmp;
62269d94f4cSDag-Erling Smørgrav 	zio->szidx = 128;
62369d94f4cSDag-Erling Smørgrav 	zio->idx = malloc(zio->szidx * sizeof(*zio->idx), M_TARFSZSTATE,
62469d94f4cSDag-Erling Smørgrav 	    M_ZERO | M_WAITOK);
62569d94f4cSDag-Erling Smørgrav 	zio->curidx = 0;
62669d94f4cSDag-Erling Smørgrav 	zio->nidx = 1;
62769d94f4cSDag-Erling Smørgrav 	zio->idx[zio->curidx].i = zio->ipos = i;
62869d94f4cSDag-Erling Smørgrav 	zio->idx[zio->curidx].o = zio->opos = o;
62969d94f4cSDag-Erling Smørgrav 	tmp->zio = zio;
63069d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ALLOC, "%s: allocated zio index\n", __func__);
631ce6a0c77SDag-Erling Smørgrav 	(void)getnewvnode("tarfsz", tmp->vfs, &tarfs_znodeops, &zvp);
63269d94f4cSDag-Erling Smørgrav 	zvp->v_data = zio;
63369d94f4cSDag-Erling Smørgrav 	zvp->v_type = VREG;
63469d94f4cSDag-Erling Smørgrav 	zvp->v_mount = tmp->vfs;
63569d94f4cSDag-Erling Smørgrav 	vn_set_state(zvp, VSTATE_CONSTRUCTED);
63669d94f4cSDag-Erling Smørgrav 	tmp->znode = zvp;
63769d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ZIO, "%s: created zio node\n", __func__);
63869d94f4cSDag-Erling Smørgrav 	return (zio);
63969d94f4cSDag-Erling Smørgrav }
640146d9da6SDag-Erling Smørgrav #endif
64169d94f4cSDag-Erling Smørgrav 
64269d94f4cSDag-Erling Smørgrav /*
64369d94f4cSDag-Erling Smørgrav  * Initializes the I/O layer, including decompression if the signature of
64469d94f4cSDag-Erling Smørgrav  * a supported compression format is detected.  Returns 0 on success and a
64569d94f4cSDag-Erling Smørgrav  * positive errno value on failure.
64669d94f4cSDag-Erling Smørgrav  */
64769d94f4cSDag-Erling Smørgrav int
tarfs_io_init(struct tarfs_mount * tmp)64869d94f4cSDag-Erling Smørgrav tarfs_io_init(struct tarfs_mount *tmp)
64969d94f4cSDag-Erling Smørgrav {
65069d94f4cSDag-Erling Smørgrav 	uint8_t *block;
651146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO
65269d94f4cSDag-Erling Smørgrav 	struct tarfs_zio *zio = NULL;
653cf93505eSDag-Erling Smørgrav #endif
65469d94f4cSDag-Erling Smørgrav 	ssize_t res;
65569d94f4cSDag-Erling Smørgrav 	int error = 0;
65669d94f4cSDag-Erling Smørgrav 
65769d94f4cSDag-Erling Smørgrav 	block = malloc(tmp->iosize, M_TEMP, M_ZERO | M_WAITOK);
65869d94f4cSDag-Erling Smørgrav 	res = tarfs_io_read_buf(tmp, true, block, 0, tmp->iosize);
65969d94f4cSDag-Erling Smørgrav 	if (res < 0) {
66069d94f4cSDag-Erling Smørgrav 		return (-res);
66169d94f4cSDag-Erling Smørgrav 	}
66269d94f4cSDag-Erling Smørgrav 	if (memcmp(block, XZ_MAGIC, sizeof(XZ_MAGIC)) == 0) {
66369d94f4cSDag-Erling Smørgrav 		printf("xz compression not supported\n");
66469d94f4cSDag-Erling Smørgrav 		error = EOPNOTSUPP;
66569d94f4cSDag-Erling Smørgrav 		goto bad;
66669d94f4cSDag-Erling Smørgrav 	} else if (memcmp(block, ZLIB_MAGIC, sizeof(ZLIB_MAGIC)) == 0) {
66769d94f4cSDag-Erling Smørgrav 		printf("zlib compression not supported\n");
66869d94f4cSDag-Erling Smørgrav 		error = EOPNOTSUPP;
66969d94f4cSDag-Erling Smørgrav 		goto bad;
67069d94f4cSDag-Erling Smørgrav 	} else if (memcmp(block, ZSTD_MAGIC, sizeof(ZSTD_MAGIC)) == 0) {
67169d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO
67269d94f4cSDag-Erling Smørgrav 		zio = tarfs_zio_init(tmp, 0, 0);
67369d94f4cSDag-Erling Smørgrav 		zio->zstd = malloc(sizeof(*zio->zstd), M_TARFSZSTATE, M_WAITOK);
67469d94f4cSDag-Erling Smørgrav 		zio->zstd->zds = ZSTD_createDStream_advanced(tarfs_zstd_mem);
67569d94f4cSDag-Erling Smørgrav 		(void)ZSTD_initDStream(zio->zstd->zds);
67669d94f4cSDag-Erling Smørgrav #else
67769d94f4cSDag-Erling Smørgrav 		printf("zstd compression not supported\n");
67869d94f4cSDag-Erling Smørgrav 		error = EOPNOTSUPP;
67969d94f4cSDag-Erling Smørgrav 		goto bad;
68069d94f4cSDag-Erling Smørgrav #endif
68169d94f4cSDag-Erling Smørgrav 	}
68269d94f4cSDag-Erling Smørgrav bad:
68369d94f4cSDag-Erling Smørgrav 	free(block, M_TEMP);
68469d94f4cSDag-Erling Smørgrav 	return (error);
68569d94f4cSDag-Erling Smørgrav }
68669d94f4cSDag-Erling Smørgrav 
687146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO
68869d94f4cSDag-Erling Smørgrav /*
68969d94f4cSDag-Erling Smørgrav  * Tears down the decompression layer.
69069d94f4cSDag-Erling Smørgrav  */
69169d94f4cSDag-Erling Smørgrav static int
tarfs_zio_fini(struct tarfs_mount * tmp)69269d94f4cSDag-Erling Smørgrav tarfs_zio_fini(struct tarfs_mount *tmp)
69369d94f4cSDag-Erling Smørgrav {
69469d94f4cSDag-Erling Smørgrav 	struct tarfs_zio *zio = tmp->zio;
69569d94f4cSDag-Erling Smørgrav 	int error = 0;
69669d94f4cSDag-Erling Smørgrav 
69769d94f4cSDag-Erling Smørgrav 	if (tmp->znode != NULL) {
69869d94f4cSDag-Erling Smørgrav 		error = vn_lock(tmp->znode, LK_EXCLUSIVE);
69969d94f4cSDag-Erling Smørgrav 		if (error != 0) {
70069d94f4cSDag-Erling Smørgrav 			TARFS_DPF(ALLOC, "%s: failed to lock znode", __func__);
70169d94f4cSDag-Erling Smørgrav 			return (error);
70269d94f4cSDag-Erling Smørgrav 		}
70369d94f4cSDag-Erling Smørgrav 		tmp->znode->v_mount = NULL;
70469d94f4cSDag-Erling Smørgrav 		vgone(tmp->znode);
70569d94f4cSDag-Erling Smørgrav 		vput(tmp->znode);
70669d94f4cSDag-Erling Smørgrav 		tmp->znode = NULL;
70769d94f4cSDag-Erling Smørgrav 	}
70869d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO
70969d94f4cSDag-Erling Smørgrav 	if (zio->zstd != NULL) {
71069d94f4cSDag-Erling Smørgrav 		TARFS_DPF(ALLOC, "%s: freeing zstd state\n", __func__);
71169d94f4cSDag-Erling Smørgrav 		ZSTD_freeDStream(zio->zstd->zds);
71269d94f4cSDag-Erling Smørgrav 		free(zio->zstd, M_TARFSZSTATE);
71369d94f4cSDag-Erling Smørgrav 	}
71469d94f4cSDag-Erling Smørgrav #endif
71569d94f4cSDag-Erling Smørgrav 	if (zio->idx != NULL) {
71669d94f4cSDag-Erling Smørgrav 		TARFS_DPF(ALLOC, "%s: freeing index\n", __func__);
71769d94f4cSDag-Erling Smørgrav 		free(zio->idx, M_TARFSZSTATE);
71869d94f4cSDag-Erling Smørgrav 	}
71969d94f4cSDag-Erling Smørgrav 	TARFS_DPF(ALLOC, "%s: freeing zio\n", __func__);
72069d94f4cSDag-Erling Smørgrav 	free(zio, M_TARFSZSTATE);
72169d94f4cSDag-Erling Smørgrav 	tmp->zio = NULL;
72269d94f4cSDag-Erling Smørgrav 	return (error);
72369d94f4cSDag-Erling Smørgrav }
724146d9da6SDag-Erling Smørgrav #endif
72569d94f4cSDag-Erling Smørgrav 
72669d94f4cSDag-Erling Smørgrav /*
72769d94f4cSDag-Erling Smørgrav  * Tears down the I/O layer, including the decompression layer if
72869d94f4cSDag-Erling Smørgrav  * applicable.
72969d94f4cSDag-Erling Smørgrav  */
73069d94f4cSDag-Erling Smørgrav int
tarfs_io_fini(struct tarfs_mount * tmp)73169d94f4cSDag-Erling Smørgrav tarfs_io_fini(struct tarfs_mount *tmp)
73269d94f4cSDag-Erling Smørgrav {
73369d94f4cSDag-Erling Smørgrav 	int error = 0;
73469d94f4cSDag-Erling Smørgrav 
735146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO
73669d94f4cSDag-Erling Smørgrav 	if (tmp->zio != NULL) {
73769d94f4cSDag-Erling Smørgrav 		error = tarfs_zio_fini(tmp);
73869d94f4cSDag-Erling Smørgrav 	}
739146d9da6SDag-Erling Smørgrav #endif
74069d94f4cSDag-Erling Smørgrav 	return (error);
74169d94f4cSDag-Erling Smørgrav }
742