mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-20 00:33:57 +00:00
fusefs: inline fuse_io_dispatch
This function was always confusing, because it created an H-shaped callgraph: two functions called in and left via different paths based on which which called. MFC after: 2 weeks
This commit is contained in:
parent
25927e068f
commit
dc433e1530
|
@ -119,184 +119,11 @@ SDT_PROVIDER_DECLARE(fusefs);
|
|||
*/
|
||||
SDT_PROBE_DEFINE2(fusefs, , io, trace, "int", "char*");
|
||||
|
||||
static int
|
||||
fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end);
|
||||
static int
|
||||
fuse_read_directbackend(struct vnode *vp, struct uio *uio,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh);
|
||||
static int
|
||||
fuse_read_biobackend(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid);
|
||||
static int
|
||||
fuse_write_directbackend(struct vnode *vp, struct uio *uio,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize,
|
||||
int ioflag, bool pages);
|
||||
static int
|
||||
fuse_write_biobackend(struct vnode *vp, struct uio *uio,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid);
|
||||
|
||||
/* Invalidate a range of cached data, whether dirty of not */
|
||||
static int
|
||||
fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end)
|
||||
{
|
||||
struct buf *bp;
|
||||
daddr_t left_lbn, end_lbn, right_lbn;
|
||||
off_t new_filesize;
|
||||
int iosize, left_on, right_on, right_blksize;
|
||||
|
||||
iosize = fuse_iosize(vp);
|
||||
left_lbn = start / iosize;
|
||||
end_lbn = howmany(end, iosize);
|
||||
left_on = start & (iosize - 1);
|
||||
if (left_on != 0) {
|
||||
bp = getblk(vp, left_lbn, iosize, PCATCH, 0, 0);
|
||||
if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyend >= left_on) {
|
||||
/*
|
||||
* Flush the dirty buffer, because we don't have a
|
||||
* byte-granular way to record which parts of the
|
||||
* buffer are valid.
|
||||
*/
|
||||
bwrite(bp);
|
||||
if (bp->b_error)
|
||||
return (bp->b_error);
|
||||
} else {
|
||||
brelse(bp);
|
||||
}
|
||||
}
|
||||
right_on = end & (iosize - 1);
|
||||
if (right_on != 0) {
|
||||
right_lbn = end / iosize;
|
||||
new_filesize = MAX(filesize, end);
|
||||
right_blksize = MIN(iosize, new_filesize - iosize * right_lbn);
|
||||
bp = getblk(vp, right_lbn, right_blksize, PCATCH, 0, 0);
|
||||
if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyoff < right_on) {
|
||||
/*
|
||||
* Flush the dirty buffer, because we don't have a
|
||||
* byte-granular way to record which parts of the
|
||||
* buffer are valid.
|
||||
*/
|
||||
bwrite(bp);
|
||||
if (bp->b_error)
|
||||
return (bp->b_error);
|
||||
} else {
|
||||
brelse(bp);
|
||||
}
|
||||
}
|
||||
|
||||
v_inval_buf_range(vp, left_lbn, end_lbn, iosize);
|
||||
return (0);
|
||||
}
|
||||
|
||||
SDT_PROBE_DEFINE5(fusefs, , io, io_dispatch, "struct vnode*", "struct uio*",
|
||||
"int", "struct ucred*", "struct fuse_filehandle*");
|
||||
SDT_PROBE_DEFINE4(fusefs, , io, io_dispatch_filehandles_closed, "struct vnode*",
|
||||
"struct uio*", "int", "struct ucred*");
|
||||
int
|
||||
fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
struct ucred *cred, pid_t pid)
|
||||
{
|
||||
struct fuse_filehandle *fufh;
|
||||
int err, directio;
|
||||
int fflag;
|
||||
bool closefufh = false;
|
||||
|
||||
MPASS(vp->v_type == VREG || vp->v_type == VDIR);
|
||||
|
||||
fflag = (uio->uio_rw == UIO_READ) ? FREAD : FWRITE;
|
||||
err = fuse_filehandle_getrw(vp, fflag, &fufh, cred, pid);
|
||||
if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
|
||||
/*
|
||||
* nfsd will do I/O without first doing VOP_OPEN. We
|
||||
* must implicitly open the file here
|
||||
*/
|
||||
err = fuse_filehandle_open(vp, fflag, &fufh, curthread, cred);
|
||||
closefufh = true;
|
||||
}
|
||||
else if (err) {
|
||||
SDT_PROBE4(fusefs, , io, io_dispatch_filehandles_closed,
|
||||
vp, uio, ioflag, cred);
|
||||
printf("FUSE: io dispatch: filehandles are closed\n");
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
goto out;
|
||||
SDT_PROBE5(fusefs, , io, io_dispatch, vp, uio, ioflag, cred, fufh);
|
||||
|
||||
/*
|
||||
* Ideally, when the daemon asks for direct io at open time, the
|
||||
* standard file flag should be set according to this, so that would
|
||||
* just change the default mode, which later on could be changed via
|
||||
* fcntl(2).
|
||||
* But this doesn't work, the O_DIRECT flag gets cleared at some point
|
||||
* (don't know where). So to make any use of the Fuse direct_io option,
|
||||
* we hardwire it into the file's private data (similarly to Linux,
|
||||
* btw.).
|
||||
*/
|
||||
directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp));
|
||||
|
||||
switch (uio->uio_rw) {
|
||||
case UIO_READ:
|
||||
fuse_vnode_update(vp, FN_ATIMECHANGE);
|
||||
if (directio) {
|
||||
SDT_PROBE2(fusefs, , io, trace, 1,
|
||||
"direct read of vnode");
|
||||
err = fuse_read_directbackend(vp, uio, cred, fufh);
|
||||
} else {
|
||||
SDT_PROBE2(fusefs, , io, trace, 1,
|
||||
"buffered read of vnode");
|
||||
err = fuse_read_biobackend(vp, uio, ioflag, cred, fufh,
|
||||
pid);
|
||||
}
|
||||
break;
|
||||
case UIO_WRITE:
|
||||
fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
|
||||
if (directio) {
|
||||
off_t start, end, filesize;
|
||||
bool pages = (ioflag & IO_VMIO) != 0;
|
||||
|
||||
SDT_PROBE2(fusefs, , io, trace, 1,
|
||||
"direct write of vnode");
|
||||
|
||||
err = fuse_vnode_size(vp, &filesize, cred, curthread);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
start = uio->uio_offset;
|
||||
end = start + uio->uio_resid;
|
||||
if (!pages) {
|
||||
err = fuse_inval_buf_range(vp, filesize, start,
|
||||
end);
|
||||
if (err)
|
||||
return (err);
|
||||
}
|
||||
err = fuse_write_directbackend(vp, uio, cred, fufh,
|
||||
filesize, ioflag, pages);
|
||||
} else {
|
||||
SDT_PROBE2(fusefs, , io, trace, 1,
|
||||
"buffered write of vnode");
|
||||
if (!fsess_opt_writeback(vnode_mount(vp)))
|
||||
ioflag |= IO_SYNC;
|
||||
err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag,
|
||||
pid);
|
||||
}
|
||||
fuse_internal_clear_suid_on_write(vp, cred, uio->uio_td);
|
||||
break;
|
||||
default:
|
||||
panic("uninterpreted mode passed to fuse_io_dispatch");
|
||||
}
|
||||
|
||||
out:
|
||||
if (closefufh)
|
||||
fuse_filehandle_close(vp, fufh, curthread, cred);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
SDT_PROBE_DEFINE4(fusefs, , io, read_bio_backend_start, "int", "int", "int", "int");
|
||||
SDT_PROBE_DEFINE2(fusefs, , io, read_bio_backend_feed, "int", "struct buf*");
|
||||
SDT_PROBE_DEFINE4(fusefs, , io, read_bio_backend_end, "int", "ssize_t", "int",
|
||||
"struct buf*");
|
||||
static int
|
||||
int
|
||||
fuse_read_biobackend(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid)
|
||||
{
|
||||
|
@ -402,7 +229,7 @@ SDT_PROBE_DEFINE1(fusefs, , io, read_directbackend_start,
|
|||
SDT_PROBE_DEFINE3(fusefs, , io, read_directbackend_complete,
|
||||
"struct fuse_dispatcher*", "struct fuse_read_in*", "struct uio*");
|
||||
|
||||
static int
|
||||
int
|
||||
fuse_read_directbackend(struct vnode *vp, struct uio *uio,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh)
|
||||
{
|
||||
|
@ -464,7 +291,7 @@ fuse_read_directbackend(struct vnode *vp, struct uio *uio,
|
|||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
fuse_write_directbackend(struct vnode *vp, struct uio *uio,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize,
|
||||
int ioflag, bool pages)
|
||||
|
@ -627,7 +454,7 @@ SDT_PROBE_DEFINE6(fusefs, , io, write_biobackend_start, "int64_t", "int", "int",
|
|||
SDT_PROBE_DEFINE2(fusefs, , io, write_biobackend_append_race, "long", "int");
|
||||
SDT_PROBE_DEFINE2(fusefs, , io, write_biobackend_issue, "int", "struct buf*");
|
||||
|
||||
static int
|
||||
int
|
||||
fuse_write_biobackend(struct vnode *vp, struct uio *uio,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid)
|
||||
{
|
||||
|
|
|
@ -65,10 +65,17 @@
|
|||
#ifndef _FUSE_IO_H_
|
||||
#define _FUSE_IO_H_
|
||||
|
||||
int fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
struct ucred *cred, pid_t pid);
|
||||
int fuse_io_strategy(struct vnode *vp, struct buf *bp);
|
||||
int fuse_io_flushbuf(struct vnode *vp, int waitfor, struct thread *td);
|
||||
int fuse_io_invalbuf(struct vnode *vp, struct thread *td);
|
||||
int fuse_read_directbackend(struct vnode *vp, struct uio *uio,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh);
|
||||
int fuse_read_biobackend(struct vnode *vp, struct uio *uio, int ioflag,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, pid_t pid);
|
||||
int fuse_write_directbackend(struct vnode *vp, struct uio *uio,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, off_t filesize,
|
||||
int ioflag, bool pages);
|
||||
int fuse_write_biobackend(struct vnode *vp, struct uio *uio,
|
||||
struct ucred *cred, struct fuse_filehandle *fufh, int ioflag, pid_t pid);
|
||||
|
||||
#endif /* _FUSE_IO_H_ */
|
||||
|
|
|
@ -318,6 +318,59 @@ fuse_fifo_close(struct vop_close_args *ap)
|
|||
return (fifo_specops.vop_close(ap));
|
||||
}
|
||||
|
||||
/* Invalidate a range of cached data, whether dirty of not */
|
||||
static int
|
||||
fuse_inval_buf_range(struct vnode *vp, off_t filesize, off_t start, off_t end)
|
||||
{
|
||||
struct buf *bp;
|
||||
daddr_t left_lbn, end_lbn, right_lbn;
|
||||
off_t new_filesize;
|
||||
int iosize, left_on, right_on, right_blksize;
|
||||
|
||||
iosize = fuse_iosize(vp);
|
||||
left_lbn = start / iosize;
|
||||
end_lbn = howmany(end, iosize);
|
||||
left_on = start & (iosize - 1);
|
||||
if (left_on != 0) {
|
||||
bp = getblk(vp, left_lbn, iosize, PCATCH, 0, 0);
|
||||
if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyend >= left_on) {
|
||||
/*
|
||||
* Flush the dirty buffer, because we don't have a
|
||||
* byte-granular way to record which parts of the
|
||||
* buffer are valid.
|
||||
*/
|
||||
bwrite(bp);
|
||||
if (bp->b_error)
|
||||
return (bp->b_error);
|
||||
} else {
|
||||
brelse(bp);
|
||||
}
|
||||
}
|
||||
right_on = end & (iosize - 1);
|
||||
if (right_on != 0) {
|
||||
right_lbn = end / iosize;
|
||||
new_filesize = MAX(filesize, end);
|
||||
right_blksize = MIN(iosize, new_filesize - iosize * right_lbn);
|
||||
bp = getblk(vp, right_lbn, right_blksize, PCATCH, 0, 0);
|
||||
if ((bp->b_flags & B_CACHE) != 0 && bp->b_dirtyoff < right_on) {
|
||||
/*
|
||||
* Flush the dirty buffer, because we don't have a
|
||||
* byte-granular way to record which parts of the
|
||||
* buffer are valid.
|
||||
*/
|
||||
bwrite(bp);
|
||||
if (bp->b_error)
|
||||
return (bp->b_error);
|
||||
} else {
|
||||
brelse(bp);
|
||||
}
|
||||
}
|
||||
|
||||
v_inval_buf_range(vp, left_lbn, end_lbn, iosize);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* Send FUSE_LSEEK for this node */
|
||||
static int
|
||||
fuse_vnop_do_lseek(struct vnode *vp, struct thread *td, struct ucred *cred,
|
||||
|
@ -1587,6 +1640,8 @@ fuse_vnop_pathconf(struct vop_pathconf_args *ap)
|
|||
}
|
||||
}
|
||||
|
||||
SDT_PROBE_DEFINE3(fusefs, , vnops, filehandles_closed, "struct vnode*",
|
||||
"struct uio*", "struct ucred*");
|
||||
/*
|
||||
struct vnop_read_args {
|
||||
struct vnode *a_vp;
|
||||
|
@ -1603,6 +1658,11 @@ fuse_vnop_read(struct vop_read_args *ap)
|
|||
int ioflag = ap->a_ioflag;
|
||||
struct ucred *cred = ap->a_cred;
|
||||
pid_t pid = curthread->td_proc->p_pid;
|
||||
struct fuse_filehandle *fufh;
|
||||
int err;
|
||||
bool closefufh = false, directio;
|
||||
|
||||
MPASS(vp->v_type == VREG || vp->v_type == VDIR);
|
||||
|
||||
if (fuse_isdeadfs(vp)) {
|
||||
return ENXIO;
|
||||
|
@ -1612,7 +1672,45 @@ fuse_vnop_read(struct vop_read_args *ap)
|
|||
ioflag |= IO_DIRECT;
|
||||
}
|
||||
|
||||
return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
|
||||
err = fuse_filehandle_getrw(vp, FREAD, &fufh, cred, pid);
|
||||
if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
|
||||
/*
|
||||
* nfsd will do I/O without first doing VOP_OPEN. We
|
||||
* must implicitly open the file here
|
||||
*/
|
||||
err = fuse_filehandle_open(vp, FREAD, &fufh, curthread, cred);
|
||||
closefufh = true;
|
||||
}
|
||||
if (err) {
|
||||
SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally, when the daemon asks for direct io at open time, the
|
||||
* standard file flag should be set according to this, so that would
|
||||
* just change the default mode, which later on could be changed via
|
||||
* fcntl(2).
|
||||
* But this doesn't work, the O_DIRECT flag gets cleared at some point
|
||||
* (don't know where). So to make any use of the Fuse direct_io option,
|
||||
* we hardwire it into the file's private data (similarly to Linux,
|
||||
* btw.).
|
||||
*/
|
||||
directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp));
|
||||
|
||||
fuse_vnode_update(vp, FN_ATIMECHANGE);
|
||||
if (directio) {
|
||||
SDT_PROBE2(fusefs, , vnops, trace, 1, "direct read of vnode");
|
||||
err = fuse_read_directbackend(vp, uio, cred, fufh);
|
||||
} else {
|
||||
SDT_PROBE2(fusefs, , vnops, trace, 1, "buffered read of vnode");
|
||||
err = fuse_read_biobackend(vp, uio, ioflag, cred, fufh, pid);
|
||||
}
|
||||
|
||||
if (closefufh)
|
||||
fuse_filehandle_close(vp, fufh, curthread, cred);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2165,6 +2263,11 @@ fuse_vnop_write(struct vop_write_args *ap)
|
|||
int ioflag = ap->a_ioflag;
|
||||
struct ucred *cred = ap->a_cred;
|
||||
pid_t pid = curthread->td_proc->p_pid;
|
||||
struct fuse_filehandle *fufh;
|
||||
int err;
|
||||
bool closefufh = false, directio;
|
||||
|
||||
MPASS(vp->v_type == VREG || vp->v_type == VDIR);
|
||||
|
||||
if (fuse_isdeadfs(vp)) {
|
||||
return ENXIO;
|
||||
|
@ -2174,7 +2277,67 @@ fuse_vnop_write(struct vop_write_args *ap)
|
|||
ioflag |= IO_DIRECT;
|
||||
}
|
||||
|
||||
return fuse_io_dispatch(vp, uio, ioflag, cred, pid);
|
||||
err = fuse_filehandle_getrw(vp, FWRITE, &fufh, cred, pid);
|
||||
if (err == EBADF && vnode_mount(vp)->mnt_flag & MNT_EXPORTED) {
|
||||
/*
|
||||
* nfsd will do I/O without first doing VOP_OPEN. We
|
||||
* must implicitly open the file here
|
||||
*/
|
||||
err = fuse_filehandle_open(vp, FWRITE, &fufh, curthread, cred);
|
||||
closefufh = true;
|
||||
}
|
||||
if (err) {
|
||||
SDT_PROBE3(fusefs, , vnops, filehandles_closed, vp, uio, cred);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally, when the daemon asks for direct io at open time, the
|
||||
* standard file flag should be set according to this, so that would
|
||||
* just change the default mode, which later on could be changed via
|
||||
* fcntl(2).
|
||||
* But this doesn't work, the O_DIRECT flag gets cleared at some point
|
||||
* (don't know where). So to make any use of the Fuse direct_io option,
|
||||
* we hardwire it into the file's private data (similarly to Linux,
|
||||
* btw.).
|
||||
*/
|
||||
directio = (ioflag & IO_DIRECT) || !fsess_opt_datacache(vnode_mount(vp));
|
||||
|
||||
fuse_vnode_update(vp, FN_MTIMECHANGE | FN_CTIMECHANGE);
|
||||
if (directio) {
|
||||
off_t start, end, filesize;
|
||||
bool pages = (ioflag & IO_VMIO) != 0;
|
||||
|
||||
SDT_PROBE2(fusefs, , vnops, trace, 1, "direct write of vnode");
|
||||
|
||||
err = fuse_vnode_size(vp, &filesize, cred, curthread);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
start = uio->uio_offset;
|
||||
end = start + uio->uio_resid;
|
||||
if (!pages) {
|
||||
err = fuse_inval_buf_range(vp, filesize, start,
|
||||
end);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
err = fuse_write_directbackend(vp, uio, cred, fufh,
|
||||
filesize, ioflag, pages);
|
||||
} else {
|
||||
SDT_PROBE2(fusefs, , vnops, trace, 1,
|
||||
"buffered write of vnode");
|
||||
if (!fsess_opt_writeback(vnode_mount(vp)))
|
||||
ioflag |= IO_SYNC;
|
||||
err = fuse_write_biobackend(vp, uio, cred, fufh, ioflag, pid);
|
||||
}
|
||||
fuse_internal_clear_suid_on_write(vp, cred, uio->uio_td);
|
||||
|
||||
out:
|
||||
if (closefufh)
|
||||
fuse_filehandle_close(vp, fufh, curthread, cred);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static daddr_t
|
||||
|
|
Loading…
Reference in a new issue