Change dmu_diff() back to use a "file" instead of a "vnode".
Command "zfs diff" calls it with a pipe, not a plain file. Fixes PR kern/54541: kernel panic using "zfs diff"
This commit is contained in:
parent
97755cb245
commit
239a7f3a3b
|
@ -43,16 +43,13 @@
|
|||
struct diffarg {
|
||||
#ifdef __FreeBSD__
|
||||
kthread_t *da_td;
|
||||
struct file *da_fp; /* file to which we are reporting */
|
||||
#else
|
||||
struct vnode *da_vp; /* file to which we are reporting */
|
||||
#endif
|
||||
struct file *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;
|
||||
};
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
static int
|
||||
write_bytes(struct diffarg *da)
|
||||
{
|
||||
|
@ -66,18 +63,30 @@ write_bytes(struct diffarg *da)
|
|||
auio.uio_resid = aiov.iov_len;
|
||||
auio.uio_rw = UIO_WRITE;
|
||||
auio.uio_offset = (off_t)-1;
|
||||
#ifdef __FreeBSD__
|
||||
auio.uio_segflg = UIO_SYSSPACE;
|
||||
auio.uio_td = da->da_td;
|
||||
#else
|
||||
auio.uio_vmspace = vmspace_kernel();
|
||||
#endif /* __FreeBSD__ */
|
||||
#ifdef _KERNEL
|
||||
#ifdef __FreeBSD__
|
||||
if (da->da_fp->f_type == DTYPE_VNODE)
|
||||
bwillwrite();
|
||||
return (fo_write(da->da_fp, &auio, da->da_td->td_ucred, 0, da->da_td));
|
||||
#else
|
||||
int flags = 0;
|
||||
|
||||
if (da->da_fp->f_type == DTYPE_VNODE)
|
||||
flags |= FOF_UPDATE_OFFSET;
|
||||
return (*da->da_fp->f_ops->fo_write)(da->da_fp, &da->da_fp->f_offset,
|
||||
&auio, da->da_fp->f_cred, flags);
|
||||
#endif /* __FreeBSD__ */
|
||||
#else
|
||||
fprintf(stderr, "%s: returning EOPNOTSUPP\n", __func__);
|
||||
return (EOPNOTSUPP);
|
||||
#endif
|
||||
}
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
static int
|
||||
write_record(struct diffarg *da)
|
||||
|
@ -89,13 +98,7 @@ write_record(struct diffarg *da)
|
|||
return (0);
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
da->da_err = write_bytes(da);
|
||||
#else
|
||||
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);
|
||||
#endif
|
||||
*da->da_offp += sizeof (da->da_ddr);
|
||||
return (da->da_err);
|
||||
}
|
||||
|
@ -193,11 +196,7 @@ diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
|
|||
|
||||
int
|
||||
dmu_diff(const char *tosnap_name, const char *fromsnap_name,
|
||||
#ifdef __FreeBSD__
|
||||
struct file *fp, offset_t *offp)
|
||||
#else
|
||||
struct vnode *vp, offset_t *offp)
|
||||
#endif
|
||||
{
|
||||
struct diffarg da;
|
||||
dsl_dataset_t *fromsnap;
|
||||
|
@ -242,10 +241,8 @@ dmu_diff(const char *tosnap_name, const char *fromsnap_name,
|
|||
|
||||
#ifdef __FreeBSD__
|
||||
da.da_td = curthread;
|
||||
da.da_fp = fp;
|
||||
#else
|
||||
da.da_vp = vp;
|
||||
#endif
|
||||
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;
|
||||
|
|
|
@ -957,13 +957,8 @@ typedef void (*dmu_traverse_cb_t)(objset_t *os, void *arg, struct blkptr *bp,
|
|||
void dmu_traverse_objset(objset_t *os, uint64_t txg_start,
|
||||
dmu_traverse_cb_t cb, void *arg);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
int dmu_diff(const char *tosnap_name, const char *fromsnap_name,
|
||||
struct file *fp, offset_t *offp);
|
||||
#else
|
||||
int dmu_diff(const char *tosnap_name, const char *fromsnap_name,
|
||||
struct vnode *vp, offset_t *offp);
|
||||
#endif
|
||||
|
||||
/* CRC64 table */
|
||||
#define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */
|
||||
|
|
|
@ -5296,11 +5296,7 @@ zfs_ioc_diff(zfs_cmd_t *zc)
|
|||
|
||||
off = fp->f_offset;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
error = dmu_diff(zc->zc_name, zc->zc_value, fp, &off);
|
||||
#else
|
||||
error = dmu_diff(zc->zc_name, zc->zc_value, fp->f_vnode, &off);
|
||||
#endif
|
||||
|
||||
if (off >= 0 && off <= MAXOFFSET_T)
|
||||
fp->f_offset = off;
|
||||
|
|
Loading…
Reference in New Issue