提交 7879c4e5 编写于 作者: A Ashish Sangwan 提交者: Miklos Szeredi

fuse: improve aio directIO write performance for size extending writes

While sending the blocking directIO in fuse, the write request is broken
into sub-requests, each of default size 128k and all the requests are sent
in non-blocking background mode if async_dio mode is supported by libfuse.
The process which issue the write wait for the completion of all the
sub-requests. Sending multiple requests parallely gives a chance to perform
parallel writes in the user space fuse implementation if it is
multi-threaded and hence improves the performance.

When there is a size extending aio dio write, we switch to blocking mode so
that we can properly update the size of the file after completion of the
writes. However, in this situation all the sub-requests are sent in
serialized manner where the next request is sent only after receiving the
reply of the current request. Hence the multi-threaded user space
implementation is not utilized properly.

This patch changes the size extending aio dio behavior to exactly follow
blocking dio. For multi threaded fuse implementation having 10 threads and
using buffer size of 64MB to perform async directIO, we are getting double
the speed.
Signed-off-by: NAshish Sangwan <ashishsangwan2@gmail.com>
Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
上级 5c672ab3
...@@ -562,7 +562,6 @@ static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io) ...@@ -562,7 +562,6 @@ static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io)
*/ */
static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
{ {
bool is_sync = is_sync_kiocb(io->iocb);
int left; int left;
spin_lock(&io->lock); spin_lock(&io->lock);
...@@ -572,11 +571,11 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) ...@@ -572,11 +571,11 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
io->bytes = pos; io->bytes = pos;
left = --io->reqs; left = --io->reqs;
if (!left && is_sync) if (!left && io->blocking)
complete(io->done); complete(io->done);
spin_unlock(&io->lock); spin_unlock(&io->lock);
if (!left && !is_sync) { if (!left && !io->blocking) {
ssize_t res = fuse_get_res_by_io(io); ssize_t res = fuse_get_res_by_io(io);
if (res >= 0) { if (res >= 0) {
...@@ -2850,7 +2849,6 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ...@@ -2850,7 +2849,6 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
size_t count = iov_iter_count(iter); size_t count = iov_iter_count(iter);
loff_t offset = iocb->ki_pos; loff_t offset = iocb->ki_pos;
struct fuse_io_priv *io; struct fuse_io_priv *io;
bool is_sync = is_sync_kiocb(iocb);
pos = offset; pos = offset;
inode = file->f_mapping->host; inode = file->f_mapping->host;
...@@ -2885,17 +2883,16 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ...@@ -2885,17 +2883,16 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
*/ */
io->async = async_dio; io->async = async_dio;
io->iocb = iocb; io->iocb = iocb;
io->blocking = is_sync_kiocb(iocb);
/* /*
* We cannot asynchronously extend the size of a file. We have no method * We cannot asynchronously extend the size of a file.
* to wait on real async I/O requests, so we must submit this request * In such case the aio will behave exactly like sync io.
* synchronously.
*/ */
if (!is_sync && (offset + count > i_size) && if ((offset + count > i_size) && iov_iter_rw(iter) == WRITE)
iov_iter_rw(iter) == WRITE) io->blocking = true;
io->async = false;
if (io->async && is_sync) { if (io->async && io->blocking) {
/* /*
* Additional reference to keep io around after * Additional reference to keep io around after
* calling fuse_aio_complete() * calling fuse_aio_complete()
...@@ -2915,7 +2912,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ...@@ -2915,7 +2912,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
fuse_aio_complete(io, ret < 0 ? ret : 0, -1); fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
/* we have a non-extending, async request, so return */ /* we have a non-extending, async request, so return */
if (!is_sync) if (!io->blocking)
return -EIOCBQUEUED; return -EIOCBQUEUED;
wait_for_completion(&wait); wait_for_completion(&wait);
......
...@@ -259,6 +259,7 @@ struct fuse_io_priv { ...@@ -259,6 +259,7 @@ struct fuse_io_priv {
struct kiocb *iocb; struct kiocb *iocb;
struct file *file; struct file *file;
struct completion *done; struct completion *done;
bool blocking;
}; };
#define FUSE_IO_PRIV_SYNC(f) \ #define FUSE_IO_PRIV_SYNC(f) \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册