Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/fuse/fuse_vnops.c
Show First 20 Lines • Show All 654 Lines • ▼ Show 20 Lines | if (fsess_not_impl(mp, FUSE_COPY_FILE_RANGE)) | ||||
goto fallback; | goto fallback; | ||||
if (ap->a_fsizetd == NULL) | if (ap->a_fsizetd == NULL) | ||||
td = curthread; | td = curthread; | ||||
else | else | ||||
td = ap->a_fsizetd; | td = ap->a_fsizetd; | ||||
pid = td->td_proc->p_pid; | pid = td->td_proc->p_pid; | ||||
err = fuse_filehandle_getrw(invp, FREAD, &infufh, incred, pid); | |||||
if (err) | |||||
return (err); | |||||
err = fuse_filehandle_getrw(outvp, FWRITE, &outfufh, outcred, pid); | |||||
if (err) | |||||
return (err); | |||||
/* Lock both vnodes, avoiding risk of deadlock. */ | /* Lock both vnodes, avoiding risk of deadlock. */ | ||||
do { | do { | ||||
err = vn_lock(outvp, LK_EXCLUSIVE); | err = vn_lock(outvp, LK_EXCLUSIVE); | ||||
if (invp == outvp) | if (invp == outvp) | ||||
break; | break; | ||||
if (err == 0) { | if (err == 0) { | ||||
err = vn_lock(invp, LK_SHARED | LK_NOWAIT); | err = vn_lock(invp, LK_SHARED | LK_NOWAIT); | ||||
if (err == 0) | if (err == 0) | ||||
break; | break; | ||||
VOP_UNLOCK(outvp); | VOP_UNLOCK(outvp); | ||||
err = vn_lock(invp, LK_SHARED); | err = vn_lock(invp, LK_SHARED); | ||||
if (err == 0) | if (err == 0) | ||||
VOP_UNLOCK(invp); | VOP_UNLOCK(invp); | ||||
} | } | ||||
} while (err == 0); | } while (err == 0); | ||||
if (err != 0) | if (err != 0) | ||||
return (err); | |||||
err = fuse_filehandle_getrw(invp, FREAD, &infufh, incred, pid); | |||||
if (err) | |||||
return (err); | |||||
err = fuse_filehandle_getrw(outvp, FWRITE, &outfufh, outcred, pid); | |||||
if (err) | |||||
return (err); | return (err); | ||||
if (ap->a_fsizetd) { | if (ap->a_fsizetd) { | ||||
io.uio_offset = *ap->a_outoffp; | io.uio_offset = *ap->a_outoffp; | ||||
io.uio_resid = *ap->a_lenp; | io.uio_resid = *ap->a_lenp; | ||||
err = vn_rlimit_fsize(outvp, &io, ap->a_fsizetd); | err = vn_rlimit_fsize(outvp, &io, ap->a_fsizetd); | ||||
if (err) | if (err) | ||||
goto unlock; | goto unlock; | ||||
} | } | ||||
fdisp_init(&fdi, sizeof(*fcfri)); | fdisp_init(&fdi, sizeof(*fcfri)); | ||||
fdisp_make_vp(&fdi, FUSE_COPY_FILE_RANGE, invp, td, incred); | fdisp_make_vp(&fdi, FUSE_COPY_FILE_RANGE, invp, td, incred); | ||||
fcfri = fdi.indata; | fcfri = fdi.indata; | ||||
fcfri->fh_in = infufh->fh_id; | fcfri->fh_in = infufh->fh_id; | ||||
fcfri->off_in = *ap->a_inoffp; | fcfri->off_in = *ap->a_inoffp; | ||||
fcfri->nodeid_out = VTOI(outvp); | fcfri->nodeid_out = VTOI(outvp); | ||||
fcfri->fh_out = outfufh->fh_id; | fcfri->fh_out = outfufh->fh_id; | ||||
fcfri->off_out = *ap->a_outoffp; | fcfri->off_out = *ap->a_outoffp; | ||||
fcfri->len = *ap->a_lenp; | fcfri->len = *ap->a_lenp; | ||||
fcfri->flags = 0; | fcfri->flags = 0; | ||||
err = fdisp_wait_answ(&fdi); | err = fdisp_wait_answ(&fdi); | ||||
if (err == 0) { | if (err == 0) { | ||||
fwo = fdi.answ; | fwo = fdi.answ; | ||||
*ap->a_lenp = fwo->size; | *ap->a_lenp = fwo->size; | ||||
*ap->a_inoffp += fwo->size; | *ap->a_inoffp += fwo->size; | ||||
*ap->a_outoffp += fwo->size; | *ap->a_outoffp += fwo->size; | ||||
fuse_internal_clear_suid_on_write(outvp, outcred, td); | fuse_internal_clear_suid_on_write(outvp, outcred, td); | ||||
} | } | ||||
fdisp_destroy(&fdi); | fdisp_destroy(&fdi); | ||||
unlock: | unlock: | ||||
if (invp != outvp) | if (invp != outvp) | ||||
VOP_UNLOCK(invp); | VOP_UNLOCK(invp); | ||||
VOP_UNLOCK(outvp); | VOP_UNLOCK(outvp); | ||||
cem: Need `goto unlock` instead of `return (err);` to avoid leaking the locks, I think. | |||||
if (err == ENOSYS) { | if (err == ENOSYS) { | ||||
fsess_set_notimpl(mp, FUSE_COPY_FILE_RANGE); | fsess_set_notimpl(mp, FUSE_COPY_FILE_RANGE); | ||||
fallback: | fallback: | ||||
err = vn_generic_copy_file_range(ap->a_invp, ap->a_inoffp, | err = vn_generic_copy_file_range(ap->a_invp, ap->a_inoffp, | ||||
ap->a_outvp, ap->a_outoffp, ap->a_lenp, ap->a_flags, | ap->a_outvp, ap->a_outoffp, ap->a_lenp, ap->a_flags, | ||||
ap->a_incred, ap->a_outcred, ap->a_fsizetd); | ap->a_incred, ap->a_outcred, ap->a_fsizetd); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,015 Lines • Show Last 20 Lines |
Need goto unlock instead of return (err); to avoid leaking the locks, I think.