In case of synchronous DIO request (i.e. read(2) or write(2) for a file opened with O_DIRECT), the patch submits fuse requests asynchronously, but waits for their completions before return from fuse_direct_IO().
In case of asynchronous DIO request (i.e. libaio io_submit() or a file opened with O_DIRECT), the patch submits fuse requests asynchronously and return -EIOCBQUEUED immediately. The only special case is async DIO extending file. Here the patch falls back to old behaviour because we can't return -EIOCBQUEUED and update i_size later, without i_mutex hold. Signed-off-by: Maxim Patlasov <mpatla...@parallels.com> --- fs/fuse/file.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 42 insertions(+), 2 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c585158..ef6d3de 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2348,14 +2348,54 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, ssize_t ret = 0; struct file *file = NULL; loff_t pos = 0; + struct inode *inode; + loff_t i_size; + size_t count = iov_length(iov, nr_segs); + struct kiocb *async_cb = NULL; file = iocb->ki_filp; pos = offset; + inode = file->f_mapping->host; + i_size = i_size_read(inode); + + /* cannot write beyond eof asynchronously */ + if (is_sync_kiocb(iocb) || (offset + count <= i_size) || rw != WRITE) { + struct fuse_io_priv *io; + + io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); + if (!io) + return -ENOMEM; + + spin_lock_init(&io->lock); + io->reqs = 1; + io->bytes = -1; + io->size = 0; + io->offset = offset; + io->write = (rw == WRITE); + io->err = 0; + io->iocb = iocb; + iocb->private = io; + + async_cb = iocb; + } if (rw == WRITE) - ret = __fuse_direct_write(file, iov, nr_segs, &pos, NULL); + ret = __fuse_direct_write(file, iov, nr_segs, &pos, async_cb); else - ret = __fuse_direct_read(file, iov, nr_segs, &pos, NULL); + ret = __fuse_direct_read(file, iov, nr_segs, &pos, async_cb); + + if (async_cb) { + fuse_aio_complete(async_cb->private, ret == count ? 0 : -EIO, + -1); + + if (!is_sync_kiocb(iocb)) + return -EIOCBQUEUED; + + ret = wait_on_sync_kiocb(iocb); + + if (rw == WRITE && ret > 0) + fuse_write_update_size(inode, pos); + } return ret; } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/