Fix fuse to use DIRECT_IO when required.

When a file is opened write-only and a partial block was written,
buffered I/O would try and read the whole block in. This would
result in a hung thread, since there was no open (fuse filehandle)
that allowed reading. This patch avoids the problem by forcing
DIRECT_IO for this case.
It also sets DIRECT_IO when the file system specifies the FN_DIRECTIO
flag in its reply to the open.

Tested by:	nishida@asusa.net, freebsd@moosefs.com
PR:		194293, 206238
MFC after:	2 weeks
This commit is contained in:
rmacklem 2016-05-14 20:03:22 +00:00
parent ccfee76778
commit 8d3f87b2b7
2 changed files with 23 additions and 2 deletions

View File

@ -141,7 +141,17 @@ fuse_filehandle_open(struct vnode *vp,
foo = fdi.answ;
fuse_filehandle_init(vp, fufh_type, fufhp, foo->fh);
fuse_vnode_open(vp, foo->open_flags, td);
/*
* For WRONLY opens, force DIRECT_IO. This is necessary
* since writing a partial block through the buffer cache
* will result in a read of the block and that read won't
* be allowed by the WRONLY open.
*/
if (fufh_type == FUFH_WRONLY)
fuse_vnode_open(vp, foo->open_flags | FOPEN_DIRECT_IO, td);
else
fuse_vnode_open(vp, foo->open_flags, td);
out:
fdisp_destroy(&fdi);

View File

@ -1125,6 +1125,7 @@ fuse_vnop_open(struct vop_open_args *ap)
struct fuse_vnode_data *fvdat;
int error, isdir = 0;
int32_t fuse_open_flags;
FS_DEBUG2G("inode=%ju mode=0x%x\n", (uintmax_t)VTOI(vp), mode);
@ -1136,14 +1137,24 @@ fuse_vnop_open(struct vop_open_args *ap)
if (vnode_isdir(vp)) {
isdir = 1;
}
fuse_open_flags = 0;
if (isdir) {
fufh_type = FUFH_RDONLY;
} else {
fufh_type = fuse_filehandle_xlate_from_fflags(mode);
/*
* For WRONLY opens, force DIRECT_IO. This is necessary
* since writing a partial block through the buffer cache
* will result in a read of the block and that read won't
* be allowed by the WRONLY open.
*/
if (fufh_type == FUFH_WRONLY ||
(fvdat->flag & FN_DIRECTIO) != 0)
fuse_open_flags = FOPEN_DIRECT_IO;
}
if (fuse_filehandle_valid(vp, fufh_type)) {
fuse_vnode_open(vp, 0, td);
fuse_vnode_open(vp, fuse_open_flags, td);
return 0;
}
error = fuse_filehandle_open(vp, fufh_type, NULL, td, cred);