diff --git a/include/os/linux/spl/sys/vnode.h b/include/os/linux/spl/sys/vnode.h index 7bd278e4e13b..39e984b4e7d3 100644 --- a/include/os/linux/spl/sys/vnode.h +++ b/include/os/linux/spl/sys/vnode.h @@ -183,6 +183,12 @@ extern file_t *vn_getf(int fd); extern void vn_releasef(int fd); extern void vn_areleasef(int fd, uf_info_t *fip); +extern ssize_t spl_kernel_write(struct file *file, const void *buf, + size_t count, loff_t *pos); +extern ssize_t spl_kernel_read(struct file *file, void *buf, + size_t count, loff_t *pos); + + int spl_vn_init(void); void spl_vn_fini(void); diff --git a/include/sys/Makefile.am b/include/sys/Makefile.am index 21e85431cb67..75f7d93e7ca8 100644 --- a/include/sys/Makefile.am +++ b/include/sys/Makefile.am @@ -104,6 +104,7 @@ COMMON_H = \ $(top_srcdir)/include/sys/zfs_context.h \ $(top_srcdir)/include/sys/zfs_debug.h \ $(top_srcdir)/include/sys/zfs_delay.h \ + $(top_srcdir)/include/sys/zfs_file.h \ $(top_srcdir)/include/sys/zfs_fuid.h \ $(top_srcdir)/include/sys/zfs_project.h \ $(top_srcdir)/include/sys/zfs_ratelimit.h \ diff --git a/include/sys/dmu.h b/include/sys/dmu.h index 44889bb10b84..2c8ad4ed2714 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -1071,7 +1071,7 @@ void dmu_traverse_objset(objset_t *os, uint64_t txg_start, dmu_traverse_cb_t cb, void *arg); int dmu_diff(const char *tosnap_name, const char *fromsnap_name, - struct vnode *vp, offset_t *offp); + file_t *fp, offset_t *offp); /* CRC64 table */ #define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */ diff --git a/include/sys/dmu_recv.h b/include/sys/dmu_recv.h index 1a7347d66e8f..6ef91f1d67b8 100644 --- a/include/sys/dmu_recv.h +++ b/include/sys/dmu_recv.h @@ -62,7 +62,7 @@ typedef struct dmu_recv_cookie { nvlist_t *drc_begin_nvl; objset_t *drc_os; - vnode_t *drc_vp; /* The vnode to read the stream from */ + file_t *drc_fp; /* The file to read the stream from */ uint64_t drc_voff; /* The current offset in the stream */ uint64_t drc_bytes_read; /* @@ -82,10 +82,11 @@ typedef struct dmu_recv_cookie { int dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin, boolean_t force, boolean_t resumable, nvlist_t *localprops, nvlist_t *hidden_args, char *origin, dmu_recv_cookie_t *drc, - vnode_t *vp, offset_t *voffp); + file_t *fp, offset_t *voffp); int dmu_recv_stream(dmu_recv_cookie_t *drc, int cleanup_fd, uint64_t *action_handlep, offset_t *voffp); int dmu_recv_end(dmu_recv_cookie_t *drc, void *owner); boolean_t dmu_objset_is_receiving(objset_t *os); + #endif /* _DMU_RECV_H */ diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 59846b1c8da5..e0477f2f01fa 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -524,6 +524,10 @@ typedef struct vnode { int v_dump_fd; } vnode_t; +typedef struct file { + vnode_t *f_vnode; +} file_t; + extern char *vn_dumpdir; #define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */ @@ -620,6 +624,12 @@ extern int vn_openat(char *path, int x1, int oflags, int mode, vnode_t **vpp, extern int vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset, int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp); extern void vn_close(vnode_t *vp); +extern ssize_t spl_kernel_write(file_t *fp, const void *buf, + size_t count, loff_t *pos); +extern ssize_t spl_kernel_read(file_t *fp, void *buf, + size_t count, loff_t *pos); + +loff_t vfs_llseek(file_t *fp, loff_t offset, int whence); #define vn_remove(path, x1, x2) remove(path) #define vn_rename(from, to, seg) rename((from), (to)) diff --git a/include/sys/zfs_file.h b/include/sys/zfs_file.h new file mode 100644 index 000000000000..611d696f32b7 --- /dev/null +++ b/include/sys/zfs_file.h @@ -0,0 +1,29 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +#ifndef _SYS_ZFS_FILE_H +#define _SYS_ZFS_FILE_H + +int zfs_file_write(file_t *, const void *, size_t, loff_t *, ssize_t *); +int zfs_file_read(file_t *, void *, size_t, loff_t *, ssize_t *); +int zfs_file_seek(file_t *, loff_t *, int); + +#endif /* _SYS_ZFS_FILE_H */ diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index 9c097ce79dd0..43214d73a7c6 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -144,6 +144,7 @@ KERNEL_C = \ zfeature.c \ zfs_byteswap.c \ zfs_debug.c \ + zfs_file_os.c \ zfs_fm.c \ zfs_fuid.c \ zfs_sa.c \ diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index c14468cb2510..51797163e4a1 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -636,6 +636,39 @@ vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset, return (0); } +ssize_t +spl_kernel_write(file_t *fp, const void *buf, + size_t count, loff_t *pos) +{ + ssize_t rc; + + rc = pwrite64(fp->f_vnode->v_fd, buf, count, *pos); + if (rc < 0) + return (-errno); + *pos += rc; + return (rc); +} + +ssize_t +spl_kernel_read(file_t *fp, void *buf, + size_t count, loff_t *pos) +{ + ssize_t rc; + + rc = pread64(fp->f_vnode->v_fd, buf, count, *pos); + if (rc < 0) + return (-errno); + *pos += rc; + return (rc); +} + +loff_t +vfs_llseek(file_t *fp, loff_t offset, int whence) +{ + + return (lseek(fp->f_vnode->v_fd, offset, whence)); +} + void vn_close(vnode_t *vp) { diff --git a/module/os/linux/spl/spl-vnode.c b/module/os/linux/spl/spl-vnode.c index d9056c964e5a..44f49dd3eea9 100644 --- a/module/os/linux/spl/spl-vnode.c +++ b/module/os/linux/spl/spl-vnode.c @@ -73,7 +73,7 @@ spl_filp_fsync(struct file *fp, int sync) #endif /* HAVE_2ARGS_VFS_FSYNC */ } -static ssize_t +ssize_t spl_kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) { #if defined(HAVE_KERNEL_WRITE_PPOS) @@ -92,8 +92,9 @@ spl_kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) return (ret); #endif } +EXPORT_SYMBOL(spl_kernel_write); -static ssize_t +ssize_t spl_kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) { #if defined(HAVE_KERNEL_READ_PPOS) @@ -112,6 +113,7 @@ spl_kernel_read(struct file *file, void *buf, size_t count, loff_t *pos) return (ret); #endif } +EXPORT_SYMBOL(spl_kernel_read); vtype_t vn_mode_to_vtype(mode_t mode) diff --git a/module/os/linux/zfs/Makefile.in b/module/os/linux/zfs/Makefile.in index 1532773782ae..60d92182f388 100644 --- a/module/os/linux/zfs/Makefile.in +++ b/module/os/linux/zfs/Makefile.in @@ -26,6 +26,7 @@ $(MODULE)-objs += ../os/linux/zfs/zfs_acl.o $(MODULE)-objs += ../os/linux/zfs/zfs_ctldir.o $(MODULE)-objs += ../os/linux/zfs/zfs_debug.o $(MODULE)-objs += ../os/linux/zfs/zfs_dir.o +$(MODULE)-objs += ../os/linux/zfs/zfs_file_os.o $(MODULE)-objs += ../os/linux/zfs/zfs_ioctl_os.o $(MODULE)-objs += ../os/linux/zfs/zfs_onexit_os.o $(MODULE)-objs += ../os/linux/zfs/zfs_sysfs.o diff --git a/module/os/linux/zfs/zfs_file_os.c b/module/os/linux/zfs/zfs_file_os.c new file mode 100644 index 000000000000..7f9d522cc90d --- /dev/null +++ b/module/os/linux/zfs/zfs_file_os.c @@ -0,0 +1,103 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * zfs_file_open -> filp_open + * zfs_file_close -> filp_close + * zfs_file_seek -> vfs_llseek + * zfs_file_sync -> spl_filp_fsync + * zfs_file_pwrite -> spl_kernel_write + * zfs_file_pread -> spl_kernel_read + * zfs_file_stat -> vfs_getattr + * zfs_file_unlink -> vfs_unlink + * zfs_file_get -> fget + * zfs_file_put -> fput + */ + +#ifdef _KERNEL +#define FILE2FP(file) ((file)->f_file) +#else +#define FILE2FP(file) (file) +#endif + +int +zfs_file_write(file_t *file, const void *buf, size_t count, loff_t *offp, + ssize_t *resid) +{ + ssize_t rc; + struct file *fp; + + fp = FILE2FP(file); + rc = spl_kernel_write(fp, buf, count, offp); + if (rc < 0) + return ((int)-rc); + *resid = rc; + return (0); +} + +int +zfs_file_read(file_t *file, void *buf, size_t count, loff_t *offp, + ssize_t *resid) +{ + ssize_t rc; + struct file *fp; + + fp = FILE2FP(file); + rc = spl_kernel_read(fp, buf, count, offp); + if (rc < 0) + return ((int)-rc); + *resid = rc; + return (0); +} + +int +zfs_file_seek(file_t *file, loff_t *offp, int whence) +{ + struct file *fp; + loff_t rc; + + fp = FILE2FP(file); + rc = vfs_llseek(fp, *offp, whence); + if (rc < 0) + return (-rc); + + *offp = rc; + return (0); +} diff --git a/module/zfs/dmu_diff.c b/module/zfs/dmu_diff.c index c40ed57f243d..e16ca2d2631a 100644 --- a/module/zfs/dmu_diff.c +++ b/module/zfs/dmu_diff.c @@ -40,17 +40,21 @@ #include #include #include +#include -struct diffarg { - struct vnode *da_vp; /* file to which we are reporting */ + +typedef struct dmu_diffarg { + file_t *da_fp; /* file to which we are reporting */ offset_t *da_offp; int da_err; /* error that stopped diff search */ dmu_diff_record_t da_ddr; -}; +} dmu_diffarg_t; -static int -write_record(struct diffarg *da) +int +write_record(dmu_diffarg_t *da) { + file_t *fp; + loff_t off; ssize_t resid; /* have to get resid to get detailed errno */ if (da->da_ddr.ddr_type == DDR_NONE) { @@ -58,15 +62,19 @@ write_record(struct diffarg *da) return (0); } - da->da_err = vn_rdwr(UIO_WRITE, da->da_vp, (caddr_t)&da->da_ddr, - sizeof (da->da_ddr), 0, UIO_SYSSPACE, FAPPEND, - RLIM64_INFINITY, CRED(), &resid); + fp = da->da_fp; + off = (loff_t)0; + da->da_err = zfs_file_seek(fp, &off, SEEK_END); + if (da->da_err && da->da_err != ESPIPE) + return (da->da_err); + da->da_err = zfs_file_write(fp, (caddr_t)&da->da_ddr, + sizeof (da->da_ddr), &off, &resid); *da->da_offp += sizeof (da->da_ddr); return (da->da_err); } static int -report_free_dnode_range(struct diffarg *da, uint64_t first, uint64_t last) +report_free_dnode_range(dmu_diffarg_t *da, uint64_t first, uint64_t last) { ASSERT(first <= last); if (da->da_ddr.ddr_type != DDR_FREE || @@ -83,7 +91,7 @@ report_free_dnode_range(struct diffarg *da, uint64_t first, uint64_t last) } static int -report_dnode(struct diffarg *da, uint64_t object, dnode_phys_t *dnp) +report_dnode(dmu_diffarg_t *da, uint64_t object, dnode_phys_t *dnp) { ASSERT(dnp != NULL); if (dnp->dn_type == DMU_OT_NONE) @@ -110,7 +118,7 @@ static int diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg) { - struct diffarg *da = arg; + dmu_diffarg_t *da = arg; int err = 0; if (issig(JUSTLOOKING) && issig(FORREAL)) @@ -162,9 +170,9 @@ diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, int dmu_diff(const char *tosnap_name, const char *fromsnap_name, - struct vnode *vp, offset_t *offp) + file_t *fp, offset_t *offp) { - struct diffarg da; + dmu_diffarg_t da; dsl_dataset_t *fromsnap; dsl_dataset_t *tosnap; dsl_pool_t *dp; @@ -205,7 +213,7 @@ dmu_diff(const char *tosnap_name, const char *fromsnap_name, dsl_dataset_long_hold(tosnap, FTAG); dsl_pool_rele(dp, FTAG); - da.da_vp = vp; + da.da_fp = fp; da.da_offp = offp; da.da_ddr.ddr_type = DDR_NONE; da.da_ddr.ddr_first = da.da_ddr.ddr_last = 0; diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c index 48c3705c65a6..4dda8e9b73cb 100644 --- a/module/zfs/dmu_recv.c +++ b/module/zfs/dmu_recv.c @@ -61,6 +61,7 @@ #ifdef _KERNEL #include #endif +#include int zfs_recv_queue_length = SPA_MAXBLOCKSIZE; int zfs_recv_queue_ff = 20; @@ -1103,7 +1104,7 @@ dmu_recv_resume_begin_sync(void *arg, dmu_tx_t *tx) int dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin, boolean_t force, boolean_t resumable, nvlist_t *localprops, - nvlist_t *hidden_args, char *origin, dmu_recv_cookie_t *drc, vnode_t *vp, + nvlist_t *hidden_args, char *origin, dmu_recv_cookie_t *drc, file_t *fp, offset_t *voffp) { dmu_recv_begin_arg_t drba = { 0 }; @@ -1131,7 +1132,7 @@ dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin, return (SET_ERROR(EINVAL)); } - drc->drc_vp = vp; + drc->drc_fp = fp; drc->drc_voff = *voffp; drc->drc_featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo); @@ -1248,12 +1249,13 @@ receive_read(dmu_recv_cookie_t *drc, int len, void *buf) while (done < len) { ssize_t resid; + file_t *fp; + loff_t off; - drc->drc_err = vn_rdwr(UIO_READ, drc->drc_vp, - (char *)buf + done, len - done, - drc->drc_voff, UIO_SYSSPACE, FAPPEND, - RLIM64_INFINITY, CRED(), &resid); - + fp = drc->drc_fp; + off = drc->drc_voff; + drc->drc_err = zfs_file_read(fp, (char *)buf + done, + len - done, &off, &resid); if (resid == len - done) { /* * Note: ECKSUM indicates that the receive diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 25863c8e434c..2bd2b18ad849 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -192,6 +192,7 @@ #include #include #include +#include #include #include @@ -4727,7 +4728,7 @@ zfs_ioc_recv_impl(char *tofs, char *tosnap, char *origin, nvlist_t *recvprops, off = input_fp->f_offset; error = dmu_recv_begin(tofs, tosnap, begin_record, force, - resumable, localprops, hidden_args, origin, &drc, input_fp->f_vnode, + resumable, localprops, hidden_args, origin, &drc, input_fp, &off); if (error != 0) goto out; @@ -5221,8 +5222,8 @@ zfs_ioc_recv_new(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl) } typedef struct dump_bytes_io { - vnode_t *dbi_vp; - void *dbi_buf; + file_t *dbi_fp; + caddr_t dbi_buf; int dbi_len; int dbi_err; } dump_bytes_io_t; @@ -5231,11 +5232,19 @@ static void dump_bytes_cb(void *arg) { dump_bytes_io_t *dbi = (dump_bytes_io_t *)arg; - ssize_t resid; /* have to get resid to get detailed errno */ + file_t *fp; + loff_t off; + size_t resid; + caddr_t buf; + + fp = dbi->dbi_fp; + buf = dbi->dbi_buf; + off = (loff_t)0; + dbi->dbi_err = zfs_file_seek(fp, &off, SEEK_END); + if (dbi->dbi_err && dbi->dbi_err != ESPIPE) + return; - dbi->dbi_err = vn_rdwr(UIO_WRITE, dbi->dbi_vp, - (caddr_t)dbi->dbi_buf, dbi->dbi_len, - 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); + dbi->dbi_err = zfs_file_write(fp, buf, dbi->dbi_len, &off, &resid); } static int @@ -5243,7 +5252,7 @@ dump_bytes(objset_t *os, void *buf, int len, void *arg) { dump_bytes_io_t dbi; - dbi.dbi_vp = arg; + dbi.dbi_fp = arg; dbi.dbi_buf = buf; dbi.dbi_len = len; @@ -5353,7 +5362,7 @@ zfs_ioc_send(zfs_cmd_t *zc) off = fp->f_offset; dmu_send_outparams_t out = {0}; out.dso_outfunc = dump_bytes; - out.dso_arg = fp->f_vnode; + out.dso_arg = fp; out.dso_dryrun = B_FALSE; error = dmu_send_obj(zc->zc_name, zc->zc_sendobj, zc->zc_fromobj, embedok, large_block_ok, compressok, rawok, @@ -5934,7 +5943,7 @@ zfs_ioc_diff(zfs_cmd_t *zc) off = fp->f_offset; - error = dmu_diff(zc->zc_name, zc->zc_value, fp->f_vnode, &off); + error = dmu_diff(zc->zc_name, zc->zc_value, fp, &off); if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) fp->f_offset = off; @@ -6307,7 +6316,7 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl) off = fp->f_offset; dmu_send_outparams_t out = {0}; out.dso_outfunc = dump_bytes; - out.dso_arg = fp->f_vnode; + out.dso_arg = fp; out.dso_dryrun = B_FALSE; error = dmu_send(snapname, fromname, embedok, largeblockok, compressok, rawok, resumeobj, resumeoff, redactbook, fd, &off, &out);