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 43*146d9da6SDag-Erling Smørgrav #if defined(ZSTDIO) 44*146d9da6SDag-Erling Smørgrav #define TARFS_ZIO 1 45*146d9da6SDag-Erling Smørgrav #else 46*146d9da6SDag-Erling Smørgrav #undef TARFS_ZIO 47*146d9da6SDag-Erling Smørgrav #endif 48*146d9da6SDag-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 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 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) { 12869d94f4cSDag-Erling Smørgrav error = VOP_READ(tmp->vp, uiop, 12969d94f4cSDag-Erling Smørgrav IO_DIRECT|IO_NODELOCKED, 13069d94f4cSDag-Erling Smørgrav uiop->uio_td->td_ucred); 13169d94f4cSDag-Erling Smørgrav VOP_UNLOCK(tmp->vp); 13269d94f4cSDag-Erling Smørgrav } 13369d94f4cSDag-Erling Smørgrav vn_rangelock_unlock(tmp->vp, rl); 13469d94f4cSDag-Erling Smørgrav } else { 13569d94f4cSDag-Erling Smørgrav error = vn_lock(tmp->znode, LK_EXCLUSIVE); 13669d94f4cSDag-Erling Smørgrav if (error == 0) { 13769d94f4cSDag-Erling Smørgrav error = VOP_READ(tmp->znode, uiop, 13869d94f4cSDag-Erling Smørgrav IO_DIRECT | IO_NODELOCKED, 13969d94f4cSDag-Erling Smørgrav uiop->uio_td->td_ucred); 14069d94f4cSDag-Erling Smørgrav VOP_UNLOCK(tmp->znode); 14169d94f4cSDag-Erling Smørgrav } 14269d94f4cSDag-Erling Smørgrav } 14369d94f4cSDag-Erling Smørgrav TARFS_DPF(IO, "%s(%zu, %zu) = %d (resid %zd)\n", __func__, 14469d94f4cSDag-Erling Smørgrav (size_t)off, len, error, uiop->uio_resid); 14569d94f4cSDag-Erling Smørgrav return (error); 14669d94f4cSDag-Erling Smørgrav } 14769d94f4cSDag-Erling Smørgrav 14869d94f4cSDag-Erling Smørgrav /* 14969d94f4cSDag-Erling Smørgrav * Reads from the tar file into the provided buffer. If the archive is 15069d94f4cSDag-Erling Smørgrav * compressed and raw is false, reads the decompressed stream; otherwise, 15169d94f4cSDag-Erling Smørgrav * reads directly from the original file. Returns the number of bytes 15269d94f4cSDag-Erling Smørgrav * read on success, 0 on EOF, and a negative errno value on failure. 15369d94f4cSDag-Erling Smørgrav */ 15469d94f4cSDag-Erling Smørgrav ssize_t 15569d94f4cSDag-Erling Smørgrav tarfs_io_read_buf(struct tarfs_mount *tmp, bool raw, 15669d94f4cSDag-Erling Smørgrav void *buf, off_t off, size_t len) 15769d94f4cSDag-Erling Smørgrav { 15869d94f4cSDag-Erling Smørgrav struct uio auio; 15969d94f4cSDag-Erling Smørgrav struct iovec aiov; 16069d94f4cSDag-Erling Smørgrav ssize_t res; 16169d94f4cSDag-Erling Smørgrav int error; 16269d94f4cSDag-Erling Smørgrav 16369d94f4cSDag-Erling Smørgrav if (len == 0) { 16469d94f4cSDag-Erling Smørgrav TARFS_DPF(IO, "%s(%zu, %zu) null\n", __func__, 16569d94f4cSDag-Erling Smørgrav (size_t)off, len); 16669d94f4cSDag-Erling Smørgrav return (0); 16769d94f4cSDag-Erling Smørgrav } 16869d94f4cSDag-Erling Smørgrav aiov.iov_base = buf; 16969d94f4cSDag-Erling Smørgrav aiov.iov_len = len; 17069d94f4cSDag-Erling Smørgrav auio.uio_iov = &aiov; 17169d94f4cSDag-Erling Smørgrav auio.uio_iovcnt = 1; 17269d94f4cSDag-Erling Smørgrav auio.uio_offset = off; 17369d94f4cSDag-Erling Smørgrav auio.uio_segflg = UIO_SYSSPACE; 17469d94f4cSDag-Erling Smørgrav auio.uio_rw = UIO_READ; 17569d94f4cSDag-Erling Smørgrav auio.uio_resid = len; 17669d94f4cSDag-Erling Smørgrav auio.uio_td = curthread; 17769d94f4cSDag-Erling Smørgrav error = tarfs_io_read(tmp, raw, &auio); 17869d94f4cSDag-Erling Smørgrav if (error != 0) { 17969d94f4cSDag-Erling Smørgrav TARFS_DPF(IO, "%s(%zu, %zu) error %d\n", __func__, 18069d94f4cSDag-Erling Smørgrav (size_t)off, len, error); 18169d94f4cSDag-Erling Smørgrav return (-error); 18269d94f4cSDag-Erling Smørgrav } 18369d94f4cSDag-Erling Smørgrav res = len - auio.uio_resid; 18469d94f4cSDag-Erling Smørgrav if (res == 0 && len != 0) { 18569d94f4cSDag-Erling Smørgrav TARFS_DPF(IO, "%s(%zu, %zu) eof\n", __func__, 18669d94f4cSDag-Erling Smørgrav (size_t)off, len); 18769d94f4cSDag-Erling Smørgrav } else { 18869d94f4cSDag-Erling Smørgrav TARFS_DPF(IO, "%s(%zu, %zu) read %zd | %*D\n", __func__, 18969d94f4cSDag-Erling Smørgrav (size_t)off, len, res, 19069d94f4cSDag-Erling Smørgrav (int)(res > 8 ? 8 : res), (uint8_t *)buf, " "); 19169d94f4cSDag-Erling Smørgrav } 19269d94f4cSDag-Erling Smørgrav return (res); 19369d94f4cSDag-Erling Smørgrav } 19469d94f4cSDag-Erling Smørgrav 19569d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO 19669d94f4cSDag-Erling Smørgrav static void * 19769d94f4cSDag-Erling Smørgrav tarfs_zstate_alloc(void *opaque, size_t size) 19869d94f4cSDag-Erling Smørgrav { 19969d94f4cSDag-Erling Smørgrav 20069d94f4cSDag-Erling Smørgrav (void)opaque; 20169d94f4cSDag-Erling Smørgrav return (malloc(size, M_TARFSZSTATE, M_WAITOK)); 20269d94f4cSDag-Erling Smørgrav } 20369d94f4cSDag-Erling Smørgrav #endif 20469d94f4cSDag-Erling Smørgrav 20569d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO 20669d94f4cSDag-Erling Smørgrav static void 20769d94f4cSDag-Erling Smørgrav tarfs_zstate_free(void *opaque, void *address) 20869d94f4cSDag-Erling Smørgrav { 20969d94f4cSDag-Erling Smørgrav 21069d94f4cSDag-Erling Smørgrav (void)opaque; 21169d94f4cSDag-Erling Smørgrav free(address, M_TARFSZSTATE); 21269d94f4cSDag-Erling Smørgrav } 21369d94f4cSDag-Erling Smørgrav #endif 21469d94f4cSDag-Erling Smørgrav 21569d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO 21669d94f4cSDag-Erling Smørgrav static ZSTD_customMem tarfs_zstd_mem = { 21769d94f4cSDag-Erling Smørgrav tarfs_zstate_alloc, 21869d94f4cSDag-Erling Smørgrav tarfs_zstate_free, 21969d94f4cSDag-Erling Smørgrav NULL, 22069d94f4cSDag-Erling Smørgrav }; 22169d94f4cSDag-Erling Smørgrav #endif 22269d94f4cSDag-Erling Smørgrav 223*146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO 22469d94f4cSDag-Erling Smørgrav /* 22569d94f4cSDag-Erling Smørgrav * Updates the decompression frame index, recording the current input and 22669d94f4cSDag-Erling Smørgrav * output offsets in a new index entry, and growing the index if 22769d94f4cSDag-Erling Smørgrav * necessary. 22869d94f4cSDag-Erling Smørgrav */ 22969d94f4cSDag-Erling Smørgrav static void 23069d94f4cSDag-Erling Smørgrav tarfs_zio_update_index(struct tarfs_zio *zio, off_t i, off_t o) 23169d94f4cSDag-Erling Smørgrav { 23269d94f4cSDag-Erling Smørgrav 23369d94f4cSDag-Erling Smørgrav if (++zio->curidx >= zio->nidx) { 23469d94f4cSDag-Erling Smørgrav if (++zio->nidx > zio->szidx) { 23569d94f4cSDag-Erling Smørgrav zio->szidx *= 2; 23669d94f4cSDag-Erling Smørgrav zio->idx = realloc(zio->idx, 23769d94f4cSDag-Erling Smørgrav zio->szidx * sizeof(*zio->idx), 23869d94f4cSDag-Erling Smørgrav M_TARFSZSTATE, M_ZERO | M_WAITOK); 23969d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: resized zio index\n", __func__); 24069d94f4cSDag-Erling Smørgrav } 24169d94f4cSDag-Erling Smørgrav zio->idx[zio->curidx].i = i; 24269d94f4cSDag-Erling Smørgrav zio->idx[zio->curidx].o = o; 24369d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIDX, "%s: index %u = i %zu o %zu\n", __func__, 24469d94f4cSDag-Erling Smørgrav zio->curidx, (size_t)zio->idx[zio->curidx].i, 24569d94f4cSDag-Erling Smørgrav (size_t)zio->idx[zio->curidx].o); 24669d94f4cSDag-Erling Smørgrav } 24769d94f4cSDag-Erling Smørgrav MPASS(zio->idx[zio->curidx].i == i); 24869d94f4cSDag-Erling Smørgrav MPASS(zio->idx[zio->curidx].o == o); 24969d94f4cSDag-Erling Smørgrav } 250*146d9da6SDag-Erling Smørgrav #endif 25169d94f4cSDag-Erling Smørgrav 25269d94f4cSDag-Erling Smørgrav /* 25369d94f4cSDag-Erling Smørgrav * VOP_ACCESS for zio node. 25469d94f4cSDag-Erling Smørgrav */ 25569d94f4cSDag-Erling Smørgrav static int 25669d94f4cSDag-Erling Smørgrav tarfs_zaccess(struct vop_access_args *ap) 25769d94f4cSDag-Erling Smørgrav { 25869d94f4cSDag-Erling Smørgrav struct vnode *vp = ap->a_vp; 25969d94f4cSDag-Erling Smørgrav struct tarfs_zio *zio = vp->v_data; 26069d94f4cSDag-Erling Smørgrav struct tarfs_mount *tmp = zio->tmp; 26169d94f4cSDag-Erling Smørgrav accmode_t accmode = ap->a_accmode; 26269d94f4cSDag-Erling Smørgrav int error = EPERM; 26369d94f4cSDag-Erling Smørgrav 26469d94f4cSDag-Erling Smørgrav if (accmode == VREAD) { 26569d94f4cSDag-Erling Smørgrav error = vn_lock(tmp->vp, LK_SHARED); 26669d94f4cSDag-Erling Smørgrav if (error == 0) { 26769d94f4cSDag-Erling Smørgrav error = VOP_ACCESS(tmp->vp, accmode, ap->a_cred, ap->a_td); 26869d94f4cSDag-Erling Smørgrav VOP_UNLOCK(tmp->vp); 26969d94f4cSDag-Erling Smørgrav } 27069d94f4cSDag-Erling Smørgrav } 27169d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s(%d) = %d\n", __func__, accmode, error); 27269d94f4cSDag-Erling Smørgrav return (error); 27369d94f4cSDag-Erling Smørgrav } 27469d94f4cSDag-Erling Smørgrav 27569d94f4cSDag-Erling Smørgrav /* 27669d94f4cSDag-Erling Smørgrav * VOP_GETATTR for zio node. 27769d94f4cSDag-Erling Smørgrav */ 27869d94f4cSDag-Erling Smørgrav static int 27969d94f4cSDag-Erling Smørgrav tarfs_zgetattr(struct vop_getattr_args *ap) 28069d94f4cSDag-Erling Smørgrav { 28169d94f4cSDag-Erling Smørgrav struct vattr va; 28269d94f4cSDag-Erling Smørgrav struct vnode *vp = ap->a_vp; 28369d94f4cSDag-Erling Smørgrav struct tarfs_zio *zio = vp->v_data; 28469d94f4cSDag-Erling Smørgrav struct tarfs_mount *tmp = zio->tmp; 28569d94f4cSDag-Erling Smørgrav struct vattr *vap = ap->a_vap; 28669d94f4cSDag-Erling Smørgrav int error = 0; 28769d94f4cSDag-Erling Smørgrav 28869d94f4cSDag-Erling Smørgrav VATTR_NULL(vap); 28969d94f4cSDag-Erling Smørgrav error = vn_lock(tmp->vp, LK_SHARED); 29069d94f4cSDag-Erling Smørgrav if (error == 0) { 29169d94f4cSDag-Erling Smørgrav error = VOP_GETATTR(tmp->vp, &va, ap->a_cred); 29269d94f4cSDag-Erling Smørgrav VOP_UNLOCK(tmp->vp); 29369d94f4cSDag-Erling Smørgrav if (error == 0) { 29469d94f4cSDag-Erling Smørgrav vap->va_type = VREG; 29569d94f4cSDag-Erling Smørgrav vap->va_mode = va.va_mode; 29669d94f4cSDag-Erling Smørgrav vap->va_nlink = 1; 29769d94f4cSDag-Erling Smørgrav vap->va_gid = va.va_gid; 29869d94f4cSDag-Erling Smørgrav vap->va_uid = va.va_uid; 29969d94f4cSDag-Erling Smørgrav vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 30069d94f4cSDag-Erling Smørgrav vap->va_fileid = TARFS_ZIOINO; 30169d94f4cSDag-Erling Smørgrav vap->va_size = zio->idx[zio->nidx - 1].o; 30269d94f4cSDag-Erling Smørgrav vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; 30369d94f4cSDag-Erling Smørgrav vap->va_atime = va.va_atime; 30469d94f4cSDag-Erling Smørgrav vap->va_ctime = va.va_ctime; 30569d94f4cSDag-Erling Smørgrav vap->va_mtime = va.va_mtime; 30669d94f4cSDag-Erling Smørgrav vap->va_birthtime = tmp->root->birthtime; 30769d94f4cSDag-Erling Smørgrav vap->va_bytes = va.va_bytes; 30869d94f4cSDag-Erling Smørgrav } 30969d94f4cSDag-Erling Smørgrav } 31069d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s() = %d\n", __func__, error); 31169d94f4cSDag-Erling Smørgrav return (error); 31269d94f4cSDag-Erling Smørgrav } 31369d94f4cSDag-Erling Smørgrav 31469d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO 31569d94f4cSDag-Erling Smørgrav /* 31669d94f4cSDag-Erling Smørgrav * VOP_READ for zio node, zstd edition. 31769d94f4cSDag-Erling Smørgrav */ 31869d94f4cSDag-Erling Smørgrav static int 31969d94f4cSDag-Erling Smørgrav tarfs_zread_zstd(struct tarfs_zio *zio, struct uio *uiop) 32069d94f4cSDag-Erling Smørgrav { 32169d94f4cSDag-Erling Smørgrav void *ibuf = NULL, *obuf = NULL, *rl = NULL; 32269d94f4cSDag-Erling Smørgrav struct uio auio; 32369d94f4cSDag-Erling Smørgrav struct iovec aiov; 32469d94f4cSDag-Erling Smørgrav struct tarfs_mount *tmp = zio->tmp; 32569d94f4cSDag-Erling Smørgrav struct tarfs_zstd *zstd = zio->zstd; 32669d94f4cSDag-Erling Smørgrav struct thread *td = curthread; 32769d94f4cSDag-Erling Smørgrav ZSTD_inBuffer zib; 32869d94f4cSDag-Erling Smørgrav ZSTD_outBuffer zob; 32969d94f4cSDag-Erling Smørgrav off_t zsize; 33069d94f4cSDag-Erling Smørgrav off_t ipos, opos; 33169d94f4cSDag-Erling Smørgrav size_t ilen, olen; 33269d94f4cSDag-Erling Smørgrav size_t zerror; 33369d94f4cSDag-Erling Smørgrav off_t off = uiop->uio_offset; 33469d94f4cSDag-Erling Smørgrav size_t len = uiop->uio_resid; 33569d94f4cSDag-Erling Smørgrav size_t resid = uiop->uio_resid; 33669d94f4cSDag-Erling Smørgrav size_t bsize; 33769d94f4cSDag-Erling Smørgrav int error; 33869d94f4cSDag-Erling Smørgrav bool reset = false; 33969d94f4cSDag-Erling Smørgrav 34069d94f4cSDag-Erling Smørgrav /* do we have to rewind? */ 34169d94f4cSDag-Erling Smørgrav if (off < zio->opos) { 34269d94f4cSDag-Erling Smørgrav while (zio->curidx > 0 && off < zio->idx[zio->curidx].o) 34369d94f4cSDag-Erling Smørgrav zio->curidx--; 34469d94f4cSDag-Erling Smørgrav reset = true; 34569d94f4cSDag-Erling Smørgrav } 34669d94f4cSDag-Erling Smørgrav /* advance to the nearest index entry */ 34769d94f4cSDag-Erling Smørgrav if (off > zio->opos) { 34869d94f4cSDag-Erling Smørgrav // XXX maybe do a binary search instead 34969d94f4cSDag-Erling Smørgrav while (zio->curidx < zio->nidx - 1 && 35069d94f4cSDag-Erling Smørgrav off >= zio->idx[zio->curidx + 1].o) { 35169d94f4cSDag-Erling Smørgrav zio->curidx++; 35269d94f4cSDag-Erling Smørgrav reset = true; 35369d94f4cSDag-Erling Smørgrav } 35469d94f4cSDag-Erling Smørgrav } 35569d94f4cSDag-Erling Smørgrav /* reset the decompression stream if needed */ 35669d94f4cSDag-Erling Smørgrav if (reset) { 35769d94f4cSDag-Erling Smørgrav zio->ipos = zio->idx[zio->curidx].i; 35869d94f4cSDag-Erling Smørgrav zio->opos = zio->idx[zio->curidx].o; 35969d94f4cSDag-Erling Smørgrav ZSTD_resetDStream(zstd->zds); 36069d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIDX, "%s: skipping to index %u = i %zu o %zu\n", __func__, 36169d94f4cSDag-Erling Smørgrav zio->curidx, (size_t)zio->ipos, (size_t)zio->opos); 36269d94f4cSDag-Erling Smørgrav } else { 36369d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIDX, "%s: continuing at i %zu o %zu\n", __func__, 36469d94f4cSDag-Erling Smørgrav (size_t)zio->ipos, (size_t)zio->opos); 36569d94f4cSDag-Erling Smørgrav } 36669d94f4cSDag-Erling Smørgrav 36769d94f4cSDag-Erling Smørgrav /* 36869d94f4cSDag-Erling Smørgrav * Set up a temporary buffer for compressed data. Use the size 36969d94f4cSDag-Erling Smørgrav * recommended by the zstd library; this is usually 128 kB, but 37069d94f4cSDag-Erling Smørgrav * just in case, make sure it's a multiple of the page size and no 37169d94f4cSDag-Erling Smørgrav * larger than MAXBSIZE. 37269d94f4cSDag-Erling Smørgrav */ 37369d94f4cSDag-Erling Smørgrav bsize = roundup(ZSTD_CStreamOutSize(), PAGE_SIZE); 37469d94f4cSDag-Erling Smørgrav if (bsize > MAXBSIZE) 37569d94f4cSDag-Erling Smørgrav bsize = MAXBSIZE; 37669d94f4cSDag-Erling Smørgrav ibuf = malloc(bsize, M_TEMP, M_WAITOK); 37769d94f4cSDag-Erling Smørgrav zib.src = NULL; 37869d94f4cSDag-Erling Smørgrav zib.size = 0; 37969d94f4cSDag-Erling Smørgrav zib.pos = 0; 38069d94f4cSDag-Erling Smørgrav 38169d94f4cSDag-Erling Smørgrav /* 38269d94f4cSDag-Erling Smørgrav * Set up the decompression buffer. If the target is not in 38369d94f4cSDag-Erling Smørgrav * kernel space, we will have to set up a bounce buffer. 38469d94f4cSDag-Erling Smørgrav * 38569d94f4cSDag-Erling Smørgrav * TODO: to avoid using a bounce buffer, map destination pages 38669d94f4cSDag-Erling Smørgrav * using vm_fault_quick_hold_pages(). 38769d94f4cSDag-Erling Smørgrav */ 38869d94f4cSDag-Erling Smørgrav MPASS(zio->opos <= off); 38969d94f4cSDag-Erling Smørgrav MPASS(uiop->uio_iovcnt == 1); 39069d94f4cSDag-Erling Smørgrav MPASS(uiop->uio_iov->iov_len >= len); 39169d94f4cSDag-Erling Smørgrav if (uiop->uio_segflg == UIO_SYSSPACE) { 39269d94f4cSDag-Erling Smørgrav zob.dst = uiop->uio_iov->iov_base; 39369d94f4cSDag-Erling Smørgrav } else { 39469d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: allocating %zu-byte bounce buffer\n", 39569d94f4cSDag-Erling Smørgrav __func__, len); 39669d94f4cSDag-Erling Smørgrav zob.dst = obuf = malloc(len, M_TEMP, M_WAITOK); 39769d94f4cSDag-Erling Smørgrav } 39869d94f4cSDag-Erling Smørgrav zob.size = len; 39969d94f4cSDag-Erling Smørgrav zob.pos = 0; 40069d94f4cSDag-Erling Smørgrav 40169d94f4cSDag-Erling Smørgrav /* lock tarball */ 40269d94f4cSDag-Erling Smørgrav rl = vn_rangelock_rlock(tmp->vp, zio->ipos, OFF_MAX); 40369d94f4cSDag-Erling Smørgrav error = vn_lock(tmp->vp, LK_SHARED); 40469d94f4cSDag-Erling Smørgrav if (error != 0) { 40569d94f4cSDag-Erling Smørgrav goto fail_unlocked; 40669d94f4cSDag-Erling Smørgrav } 40769d94f4cSDag-Erling Smørgrav /* check size */ 40869d94f4cSDag-Erling Smørgrav error = vn_getsize_locked(tmp->vp, &zsize, td->td_ucred); 40969d94f4cSDag-Erling Smørgrav if (error != 0) { 41069d94f4cSDag-Erling Smørgrav goto fail; 41169d94f4cSDag-Erling Smørgrav } 41269d94f4cSDag-Erling Smørgrav if (zio->ipos >= zsize) { 41369d94f4cSDag-Erling Smørgrav /* beyond EOF */ 41469d94f4cSDag-Erling Smørgrav goto fail; 41569d94f4cSDag-Erling Smørgrav } 41669d94f4cSDag-Erling Smørgrav 41769d94f4cSDag-Erling Smørgrav while (resid > 0) { 41869d94f4cSDag-Erling Smørgrav if (zib.pos == zib.size) { 41969d94f4cSDag-Erling Smørgrav /* request data from the underlying file */ 42069d94f4cSDag-Erling Smørgrav aiov.iov_base = ibuf; 42169d94f4cSDag-Erling Smørgrav aiov.iov_len = bsize; 42269d94f4cSDag-Erling Smørgrav auio.uio_iov = &aiov; 42369d94f4cSDag-Erling Smørgrav auio.uio_iovcnt = 1; 42469d94f4cSDag-Erling Smørgrav auio.uio_offset = zio->ipos; 42569d94f4cSDag-Erling Smørgrav auio.uio_segflg = UIO_SYSSPACE; 42669d94f4cSDag-Erling Smørgrav auio.uio_rw = UIO_READ; 42769d94f4cSDag-Erling Smørgrav auio.uio_resid = aiov.iov_len; 42869d94f4cSDag-Erling Smørgrav auio.uio_td = td; 42969d94f4cSDag-Erling Smørgrav error = VOP_READ(tmp->vp, &auio, 43069d94f4cSDag-Erling Smørgrav IO_DIRECT | IO_NODELOCKED, 43169d94f4cSDag-Erling Smørgrav td->td_ucred); 43269d94f4cSDag-Erling Smørgrav if (error != 0) 43369d94f4cSDag-Erling Smørgrav goto fail; 43469d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s: req %zu+%zu got %zu+%zu\n", __func__, 43569d94f4cSDag-Erling Smørgrav (size_t)zio->ipos, bsize, 43669d94f4cSDag-Erling Smørgrav (size_t)zio->ipos, bsize - auio.uio_resid); 43769d94f4cSDag-Erling Smørgrav zib.src = ibuf; 43869d94f4cSDag-Erling Smørgrav zib.size = bsize - auio.uio_resid; 43969d94f4cSDag-Erling Smørgrav zib.pos = 0; 44069d94f4cSDag-Erling Smørgrav } 44169d94f4cSDag-Erling Smørgrav MPASS(zib.pos <= zib.size); 44269d94f4cSDag-Erling Smørgrav if (zib.pos == zib.size) { 44369d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s: end of file after i %zu o %zu\n", __func__, 44469d94f4cSDag-Erling Smørgrav (size_t)zio->ipos, (size_t)zio->opos); 44569d94f4cSDag-Erling Smørgrav goto fail; 44669d94f4cSDag-Erling Smørgrav } 44769d94f4cSDag-Erling Smørgrav if (zio->opos < off) { 44869d94f4cSDag-Erling Smørgrav /* to be discarded */ 44969d94f4cSDag-Erling Smørgrav zob.size = min(off - zio->opos, len); 45069d94f4cSDag-Erling Smørgrav zob.pos = 0; 45169d94f4cSDag-Erling Smørgrav } else { 45269d94f4cSDag-Erling Smørgrav zob.size = len; 45369d94f4cSDag-Erling Smørgrav zob.pos = zio->opos - off; 45469d94f4cSDag-Erling Smørgrav } 45569d94f4cSDag-Erling Smørgrav ipos = zib.pos; 45669d94f4cSDag-Erling Smørgrav opos = zob.pos; 45769d94f4cSDag-Erling Smørgrav /* decompress as much as possible */ 45869d94f4cSDag-Erling Smørgrav zerror = ZSTD_decompressStream(zstd->zds, &zob, &zib); 45969d94f4cSDag-Erling Smørgrav zio->ipos += ilen = zib.pos - ipos; 46069d94f4cSDag-Erling Smørgrav zio->opos += olen = zob.pos - opos; 46169d94f4cSDag-Erling Smørgrav if (zio->opos > off) 46269d94f4cSDag-Erling Smørgrav resid -= olen; 46369d94f4cSDag-Erling Smørgrav if (ZSTD_isError(zerror)) { 46469d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s: inflate failed after i %zu o %zu: %s\n", __func__, 46569d94f4cSDag-Erling Smørgrav (size_t)zio->ipos, (size_t)zio->opos, ZSTD_getErrorName(zerror)); 46669d94f4cSDag-Erling Smørgrav error = EIO; 46769d94f4cSDag-Erling Smørgrav goto fail; 46869d94f4cSDag-Erling Smørgrav } 46969d94f4cSDag-Erling Smørgrav if (zerror == 0 && olen == 0) { 47069d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s: end of stream after i %zu o %zu\n", __func__, 47169d94f4cSDag-Erling Smørgrav (size_t)zio->ipos, (size_t)zio->opos); 47269d94f4cSDag-Erling Smørgrav break; 47369d94f4cSDag-Erling Smørgrav } 47469d94f4cSDag-Erling Smørgrav if (zerror == 0) { 47569d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s: end of frame after i %zu o %zu\n", __func__, 47669d94f4cSDag-Erling Smørgrav (size_t)zio->ipos, (size_t)zio->opos); 47769d94f4cSDag-Erling Smørgrav tarfs_zio_update_index(zio, zio->ipos, zio->opos); 47869d94f4cSDag-Erling Smørgrav } 47969d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s: inflated %zu\n", __func__, olen); 48069d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG 48169d94f4cSDag-Erling Smørgrav counter_u64_add(tarfs_zio_inflated, olen); 48269d94f4cSDag-Erling Smørgrav #endif 48369d94f4cSDag-Erling Smørgrav } 48469d94f4cSDag-Erling Smørgrav fail: 48569d94f4cSDag-Erling Smørgrav VOP_UNLOCK(tmp->vp); 48669d94f4cSDag-Erling Smørgrav fail_unlocked: 48769d94f4cSDag-Erling Smørgrav if (error == 0) { 48869d94f4cSDag-Erling Smørgrav if (uiop->uio_segflg == UIO_SYSSPACE) { 48969d94f4cSDag-Erling Smørgrav uiop->uio_resid = resid; 49069d94f4cSDag-Erling Smørgrav } else if (len > resid) { 49169d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: bounced %zu bytes\n", __func__, 49269d94f4cSDag-Erling Smørgrav len - resid); 49369d94f4cSDag-Erling Smørgrav error = uiomove(obuf, len - resid, uiop); 49469d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG 49569d94f4cSDag-Erling Smørgrav counter_u64_add(tarfs_zio_bounced, len - resid); 49669d94f4cSDag-Erling Smørgrav #endif 49769d94f4cSDag-Erling Smørgrav } 49869d94f4cSDag-Erling Smørgrav } 49969d94f4cSDag-Erling Smørgrav if (obuf != NULL) { 50069d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: freeing bounce buffer\n", __func__); 50169d94f4cSDag-Erling Smørgrav free(obuf, M_TEMP); 50269d94f4cSDag-Erling Smørgrav } 50369d94f4cSDag-Erling Smørgrav if (rl != NULL) 50469d94f4cSDag-Erling Smørgrav vn_rangelock_unlock(tmp->vp, rl); 50569d94f4cSDag-Erling Smørgrav if (ibuf != NULL) 50669d94f4cSDag-Erling Smørgrav free(ibuf, M_TEMP); 50769d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s(%zu, %zu) = %d (resid %zd)\n", __func__, 50869d94f4cSDag-Erling Smørgrav (size_t)off, len, error, uiop->uio_resid); 50969d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG 51069d94f4cSDag-Erling Smørgrav counter_u64_add(tarfs_zio_consumed, len - uiop->uio_resid); 51169d94f4cSDag-Erling Smørgrav #endif 51269d94f4cSDag-Erling Smørgrav if (error != 0) { 51369d94f4cSDag-Erling Smørgrav zio->curidx = 0; 51469d94f4cSDag-Erling Smørgrav zio->ipos = zio->idx[0].i; 51569d94f4cSDag-Erling Smørgrav zio->opos = zio->idx[0].o; 51669d94f4cSDag-Erling Smørgrav ZSTD_resetDStream(zstd->zds); 51769d94f4cSDag-Erling Smørgrav } 51869d94f4cSDag-Erling Smørgrav return (error); 51969d94f4cSDag-Erling Smørgrav } 52069d94f4cSDag-Erling Smørgrav #endif 52169d94f4cSDag-Erling Smørgrav 52269d94f4cSDag-Erling Smørgrav /* 52369d94f4cSDag-Erling Smørgrav * VOP_READ for zio node. 52469d94f4cSDag-Erling Smørgrav */ 52569d94f4cSDag-Erling Smørgrav static int 52669d94f4cSDag-Erling Smørgrav tarfs_zread(struct vop_read_args *ap) 52769d94f4cSDag-Erling Smørgrav { 528cf93505eSDag-Erling Smørgrav #if defined(TARFS_DEBUG) || defined(ZSTDIO) 52969d94f4cSDag-Erling Smørgrav struct vnode *vp = ap->a_vp; 53069d94f4cSDag-Erling Smørgrav struct tarfs_zio *zio = vp->v_data; 53169d94f4cSDag-Erling Smørgrav struct uio *uiop = ap->a_uio; 532cf93505eSDag-Erling Smørgrav #endif 53369d94f4cSDag-Erling Smørgrav #ifdef TARFS_DEBUG 53469d94f4cSDag-Erling Smørgrav off_t off = uiop->uio_offset; 53569d94f4cSDag-Erling Smørgrav size_t len = uiop->uio_resid; 53669d94f4cSDag-Erling Smørgrav #endif 53769d94f4cSDag-Erling Smørgrav int error; 53869d94f4cSDag-Erling Smørgrav 53969d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s(%zu, %zu)\n", __func__, 54069d94f4cSDag-Erling Smørgrav (size_t)off, len); 54169d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO 54269d94f4cSDag-Erling Smørgrav if (zio->zstd != NULL) { 54369d94f4cSDag-Erling Smørgrav error = tarfs_zread_zstd(zio, uiop); 54469d94f4cSDag-Erling Smørgrav } else 54569d94f4cSDag-Erling Smørgrav #endif 54669d94f4cSDag-Erling Smørgrav error = EFTYPE; 54769d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s(%zu, %zu) = %d (resid %zd)\n", __func__, 54869d94f4cSDag-Erling Smørgrav (size_t)off, len, error, uiop->uio_resid); 54969d94f4cSDag-Erling Smørgrav return (error); 55069d94f4cSDag-Erling Smørgrav } 55169d94f4cSDag-Erling Smørgrav 55269d94f4cSDag-Erling Smørgrav /* 55369d94f4cSDag-Erling Smørgrav * VOP_RECLAIM for zio node. 55469d94f4cSDag-Erling Smørgrav */ 55569d94f4cSDag-Erling Smørgrav static int 55669d94f4cSDag-Erling Smørgrav tarfs_zreclaim(struct vop_reclaim_args *ap) 55769d94f4cSDag-Erling Smørgrav { 55869d94f4cSDag-Erling Smørgrav struct vnode *vp = ap->a_vp; 55969d94f4cSDag-Erling Smørgrav 56069d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s(%p)\n", __func__, vp); 56169d94f4cSDag-Erling Smørgrav vp->v_data = NULL; 56269d94f4cSDag-Erling Smørgrav return (0); 56369d94f4cSDag-Erling Smørgrav } 56469d94f4cSDag-Erling Smørgrav 56569d94f4cSDag-Erling Smørgrav /* 56669d94f4cSDag-Erling Smørgrav * VOP_STRATEGY for zio node. 56769d94f4cSDag-Erling Smørgrav */ 56869d94f4cSDag-Erling Smørgrav static int 56969d94f4cSDag-Erling Smørgrav tarfs_zstrategy(struct vop_strategy_args *ap) 57069d94f4cSDag-Erling Smørgrav { 57169d94f4cSDag-Erling Smørgrav struct uio auio; 57269d94f4cSDag-Erling Smørgrav struct iovec iov; 57369d94f4cSDag-Erling Smørgrav struct vnode *vp = ap->a_vp; 57469d94f4cSDag-Erling Smørgrav struct buf *bp = ap->a_bp; 57569d94f4cSDag-Erling Smørgrav off_t off; 57669d94f4cSDag-Erling Smørgrav size_t len; 57769d94f4cSDag-Erling Smørgrav int error; 57869d94f4cSDag-Erling Smørgrav 57969d94f4cSDag-Erling Smørgrav iov.iov_base = bp->b_data; 58069d94f4cSDag-Erling Smørgrav iov.iov_len = bp->b_bcount; 58169d94f4cSDag-Erling Smørgrav off = bp->b_iooffset; 58269d94f4cSDag-Erling Smørgrav len = bp->b_bcount; 58369d94f4cSDag-Erling Smørgrav bp->b_resid = len; 58469d94f4cSDag-Erling Smørgrav auio.uio_iov = &iov; 58569d94f4cSDag-Erling Smørgrav auio.uio_iovcnt = 1; 58669d94f4cSDag-Erling Smørgrav auio.uio_offset = off; 58769d94f4cSDag-Erling Smørgrav auio.uio_resid = len; 58869d94f4cSDag-Erling Smørgrav auio.uio_segflg = UIO_SYSSPACE; 58969d94f4cSDag-Erling Smørgrav auio.uio_rw = UIO_READ; 59069d94f4cSDag-Erling Smørgrav auio.uio_td = curthread; 59169d94f4cSDag-Erling Smørgrav error = VOP_READ(vp, &auio, IO_DIRECT | IO_NODELOCKED, bp->b_rcred); 59269d94f4cSDag-Erling Smørgrav bp->b_flags |= B_DONE; 59369d94f4cSDag-Erling Smørgrav if (error != 0) { 59469d94f4cSDag-Erling Smørgrav bp->b_ioflags |= BIO_ERROR; 59569d94f4cSDag-Erling Smørgrav bp->b_error = error; 59669d94f4cSDag-Erling Smørgrav } 59769d94f4cSDag-Erling Smørgrav return (0); 59869d94f4cSDag-Erling Smørgrav } 59969d94f4cSDag-Erling Smørgrav 60069d94f4cSDag-Erling Smørgrav static struct vop_vector tarfs_znodeops = { 60169d94f4cSDag-Erling Smørgrav .vop_default = &default_vnodeops, 60269d94f4cSDag-Erling Smørgrav 60369d94f4cSDag-Erling Smørgrav .vop_access = tarfs_zaccess, 60469d94f4cSDag-Erling Smørgrav .vop_getattr = tarfs_zgetattr, 60569d94f4cSDag-Erling Smørgrav .vop_read = tarfs_zread, 60669d94f4cSDag-Erling Smørgrav .vop_reclaim = tarfs_zreclaim, 60769d94f4cSDag-Erling Smørgrav .vop_strategy = tarfs_zstrategy, 60869d94f4cSDag-Erling Smørgrav }; 60969d94f4cSDag-Erling Smørgrav VFS_VOP_VECTOR_REGISTER(tarfs_znodeops); 61069d94f4cSDag-Erling Smørgrav 611*146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO 61269d94f4cSDag-Erling Smørgrav /* 61369d94f4cSDag-Erling Smørgrav * Initializes the decompression layer. 61469d94f4cSDag-Erling Smørgrav */ 61569d94f4cSDag-Erling Smørgrav static struct tarfs_zio * 61669d94f4cSDag-Erling Smørgrav tarfs_zio_init(struct tarfs_mount *tmp, off_t i, off_t o) 61769d94f4cSDag-Erling Smørgrav { 61869d94f4cSDag-Erling Smørgrav struct tarfs_zio *zio; 61969d94f4cSDag-Erling Smørgrav struct vnode *zvp; 62069d94f4cSDag-Erling Smørgrav 62169d94f4cSDag-Erling Smørgrav zio = malloc(sizeof(*zio), M_TARFSZSTATE, M_ZERO | M_WAITOK); 62269d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: allocated zio\n", __func__); 62369d94f4cSDag-Erling Smørgrav zio->tmp = tmp; 62469d94f4cSDag-Erling Smørgrav zio->szidx = 128; 62569d94f4cSDag-Erling Smørgrav zio->idx = malloc(zio->szidx * sizeof(*zio->idx), M_TARFSZSTATE, 62669d94f4cSDag-Erling Smørgrav M_ZERO | M_WAITOK); 62769d94f4cSDag-Erling Smørgrav zio->curidx = 0; 62869d94f4cSDag-Erling Smørgrav zio->nidx = 1; 62969d94f4cSDag-Erling Smørgrav zio->idx[zio->curidx].i = zio->ipos = i; 63069d94f4cSDag-Erling Smørgrav zio->idx[zio->curidx].o = zio->opos = o; 63169d94f4cSDag-Erling Smørgrav tmp->zio = zio; 63269d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: allocated zio index\n", __func__); 63369d94f4cSDag-Erling Smørgrav getnewvnode("tarfsz", tmp->vfs, &tarfs_znodeops, &zvp); 63469d94f4cSDag-Erling Smørgrav zvp->v_data = zio; 63569d94f4cSDag-Erling Smørgrav zvp->v_type = VREG; 63669d94f4cSDag-Erling Smørgrav zvp->v_mount = tmp->vfs; 63769d94f4cSDag-Erling Smørgrav vn_set_state(zvp, VSTATE_CONSTRUCTED); 63869d94f4cSDag-Erling Smørgrav tmp->znode = zvp; 63969d94f4cSDag-Erling Smørgrav TARFS_DPF(ZIO, "%s: created zio node\n", __func__); 64069d94f4cSDag-Erling Smørgrav return (zio); 64169d94f4cSDag-Erling Smørgrav } 642*146d9da6SDag-Erling Smørgrav #endif 64369d94f4cSDag-Erling Smørgrav 64469d94f4cSDag-Erling Smørgrav /* 64569d94f4cSDag-Erling Smørgrav * Initializes the I/O layer, including decompression if the signature of 64669d94f4cSDag-Erling Smørgrav * a supported compression format is detected. Returns 0 on success and a 64769d94f4cSDag-Erling Smørgrav * positive errno value on failure. 64869d94f4cSDag-Erling Smørgrav */ 64969d94f4cSDag-Erling Smørgrav int 65069d94f4cSDag-Erling Smørgrav tarfs_io_init(struct tarfs_mount *tmp) 65169d94f4cSDag-Erling Smørgrav { 65269d94f4cSDag-Erling Smørgrav uint8_t *block; 653*146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO 65469d94f4cSDag-Erling Smørgrav struct tarfs_zio *zio = NULL; 655cf93505eSDag-Erling Smørgrav #endif 65669d94f4cSDag-Erling Smørgrav ssize_t res; 65769d94f4cSDag-Erling Smørgrav int error = 0; 65869d94f4cSDag-Erling Smørgrav 65969d94f4cSDag-Erling Smørgrav block = malloc(tmp->iosize, M_TEMP, M_ZERO | M_WAITOK); 66069d94f4cSDag-Erling Smørgrav res = tarfs_io_read_buf(tmp, true, block, 0, tmp->iosize); 66169d94f4cSDag-Erling Smørgrav if (res < 0) { 66269d94f4cSDag-Erling Smørgrav return (-res); 66369d94f4cSDag-Erling Smørgrav } 66469d94f4cSDag-Erling Smørgrav if (memcmp(block, XZ_MAGIC, sizeof(XZ_MAGIC)) == 0) { 66569d94f4cSDag-Erling Smørgrav printf("xz compression not supported\n"); 66669d94f4cSDag-Erling Smørgrav error = EOPNOTSUPP; 66769d94f4cSDag-Erling Smørgrav goto bad; 66869d94f4cSDag-Erling Smørgrav } else if (memcmp(block, ZLIB_MAGIC, sizeof(ZLIB_MAGIC)) == 0) { 66969d94f4cSDag-Erling Smørgrav printf("zlib compression not supported\n"); 67069d94f4cSDag-Erling Smørgrav error = EOPNOTSUPP; 67169d94f4cSDag-Erling Smørgrav goto bad; 67269d94f4cSDag-Erling Smørgrav } else if (memcmp(block, ZSTD_MAGIC, sizeof(ZSTD_MAGIC)) == 0) { 67369d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO 67469d94f4cSDag-Erling Smørgrav zio = tarfs_zio_init(tmp, 0, 0); 67569d94f4cSDag-Erling Smørgrav zio->zstd = malloc(sizeof(*zio->zstd), M_TARFSZSTATE, M_WAITOK); 67669d94f4cSDag-Erling Smørgrav zio->zstd->zds = ZSTD_createDStream_advanced(tarfs_zstd_mem); 67769d94f4cSDag-Erling Smørgrav (void)ZSTD_initDStream(zio->zstd->zds); 67869d94f4cSDag-Erling Smørgrav #else 67969d94f4cSDag-Erling Smørgrav printf("zstd compression not supported\n"); 68069d94f4cSDag-Erling Smørgrav error = EOPNOTSUPP; 68169d94f4cSDag-Erling Smørgrav goto bad; 68269d94f4cSDag-Erling Smørgrav #endif 68369d94f4cSDag-Erling Smørgrav } 68469d94f4cSDag-Erling Smørgrav bad: 68569d94f4cSDag-Erling Smørgrav free(block, M_TEMP); 68669d94f4cSDag-Erling Smørgrav return (error); 68769d94f4cSDag-Erling Smørgrav } 68869d94f4cSDag-Erling Smørgrav 689*146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO 69069d94f4cSDag-Erling Smørgrav /* 69169d94f4cSDag-Erling Smørgrav * Tears down the decompression layer. 69269d94f4cSDag-Erling Smørgrav */ 69369d94f4cSDag-Erling Smørgrav static int 69469d94f4cSDag-Erling Smørgrav tarfs_zio_fini(struct tarfs_mount *tmp) 69569d94f4cSDag-Erling Smørgrav { 69669d94f4cSDag-Erling Smørgrav struct tarfs_zio *zio = tmp->zio; 69769d94f4cSDag-Erling Smørgrav int error = 0; 69869d94f4cSDag-Erling Smørgrav 69969d94f4cSDag-Erling Smørgrav if (tmp->znode != NULL) { 70069d94f4cSDag-Erling Smørgrav error = vn_lock(tmp->znode, LK_EXCLUSIVE); 70169d94f4cSDag-Erling Smørgrav if (error != 0) { 70269d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: failed to lock znode", __func__); 70369d94f4cSDag-Erling Smørgrav return (error); 70469d94f4cSDag-Erling Smørgrav } 70569d94f4cSDag-Erling Smørgrav tmp->znode->v_mount = NULL; 70669d94f4cSDag-Erling Smørgrav vgone(tmp->znode); 70769d94f4cSDag-Erling Smørgrav vput(tmp->znode); 70869d94f4cSDag-Erling Smørgrav tmp->znode = NULL; 70969d94f4cSDag-Erling Smørgrav } 71069d94f4cSDag-Erling Smørgrav #ifdef ZSTDIO 71169d94f4cSDag-Erling Smørgrav if (zio->zstd != NULL) { 71269d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: freeing zstd state\n", __func__); 71369d94f4cSDag-Erling Smørgrav ZSTD_freeDStream(zio->zstd->zds); 71469d94f4cSDag-Erling Smørgrav free(zio->zstd, M_TARFSZSTATE); 71569d94f4cSDag-Erling Smørgrav } 71669d94f4cSDag-Erling Smørgrav #endif 71769d94f4cSDag-Erling Smørgrav if (zio->idx != NULL) { 71869d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: freeing index\n", __func__); 71969d94f4cSDag-Erling Smørgrav free(zio->idx, M_TARFSZSTATE); 72069d94f4cSDag-Erling Smørgrav } 72169d94f4cSDag-Erling Smørgrav TARFS_DPF(ALLOC, "%s: freeing zio\n", __func__); 72269d94f4cSDag-Erling Smørgrav free(zio, M_TARFSZSTATE); 72369d94f4cSDag-Erling Smørgrav tmp->zio = NULL; 72469d94f4cSDag-Erling Smørgrav return (error); 72569d94f4cSDag-Erling Smørgrav } 726*146d9da6SDag-Erling Smørgrav #endif 72769d94f4cSDag-Erling Smørgrav 72869d94f4cSDag-Erling Smørgrav /* 72969d94f4cSDag-Erling Smørgrav * Tears down the I/O layer, including the decompression layer if 73069d94f4cSDag-Erling Smørgrav * applicable. 73169d94f4cSDag-Erling Smørgrav */ 73269d94f4cSDag-Erling Smørgrav int 73369d94f4cSDag-Erling Smørgrav tarfs_io_fini(struct tarfs_mount *tmp) 73469d94f4cSDag-Erling Smørgrav { 73569d94f4cSDag-Erling Smørgrav int error = 0; 73669d94f4cSDag-Erling Smørgrav 737*146d9da6SDag-Erling Smørgrav #ifdef TARFS_ZIO 73869d94f4cSDag-Erling Smørgrav if (tmp->zio != NULL) { 73969d94f4cSDag-Erling Smørgrav error = tarfs_zio_fini(tmp); 74069d94f4cSDag-Erling Smørgrav } 741*146d9da6SDag-Erling Smørgrav #endif 74269d94f4cSDag-Erling Smørgrav return (error); 74369d94f4cSDag-Erling Smørgrav } 744