aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAshish Sangwan <ashishsangwan2@gmail.com>2016-04-07 07:48:11 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-06-30 07:14:10 -0400
commit7879c4e58b7c884ee62b9306721dd1106e624b52 (patch)
tree37ee42323b17d0ad5b47dd331d5992f58caf5f13
parent5c672ab3f0ee0f78f7acad183f34db0f8781a200 (diff)
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: Ashish Sangwan <ashishsangwan2@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/fuse/file.c21
-rw-r--r--fs/fuse/fuse_i.h1
2 files changed, 10 insertions, 12 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 9154f8679024..7270e89880b5 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -562,7 +562,6 @@ static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io)
562 */ 562 */
563static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) 563static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
564{ 564{
565 bool is_sync = is_sync_kiocb(io->iocb);
566 int left; 565 int left;
567 566
568 spin_lock(&io->lock); 567 spin_lock(&io->lock);
@@ -572,11 +571,11 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
572 io->bytes = pos; 571 io->bytes = pos;
573 572
574 left = --io->reqs; 573 left = --io->reqs;
575 if (!left && is_sync) 574 if (!left && io->blocking)
576 complete(io->done); 575 complete(io->done);
577 spin_unlock(&io->lock); 576 spin_unlock(&io->lock);
578 577
579 if (!left && !is_sync) { 578 if (!left && !io->blocking) {
580 ssize_t res = fuse_get_res_by_io(io); 579 ssize_t res = fuse_get_res_by_io(io);
581 580
582 if (res >= 0) { 581 if (res >= 0) {
@@ -2850,7 +2849,6 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
2850 size_t count = iov_iter_count(iter); 2849 size_t count = iov_iter_count(iter);
2851 loff_t offset = iocb->ki_pos; 2850 loff_t offset = iocb->ki_pos;
2852 struct fuse_io_priv *io; 2851 struct fuse_io_priv *io;
2853 bool is_sync = is_sync_kiocb(iocb);
2854 2852
2855 pos = offset; 2853 pos = offset;
2856 inode = file->f_mapping->host; 2854 inode = file->f_mapping->host;
@@ -2885,17 +2883,16 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
2885 */ 2883 */
2886 io->async = async_dio; 2884 io->async = async_dio;
2887 io->iocb = iocb; 2885 io->iocb = iocb;
2886 io->blocking = is_sync_kiocb(iocb);
2888 2887
2889 /* 2888 /*
2890 * We cannot asynchronously extend the size of a file. We have no method 2889 * We cannot asynchronously extend the size of a file.
2891 * to wait on real async I/O requests, so we must submit this request 2890 * In such case the aio will behave exactly like sync io.
2892 * synchronously.
2893 */ 2891 */
2894 if (!is_sync && (offset + count > i_size) && 2892 if ((offset + count > i_size) && iov_iter_rw(iter) == WRITE)
2895 iov_iter_rw(iter) == WRITE) 2893 io->blocking = true;
2896 io->async = false;
2897 2894
2898 if (io->async && is_sync) { 2895 if (io->async && io->blocking) {
2899 /* 2896 /*
2900 * Additional reference to keep io around after 2897 * Additional reference to keep io around after
2901 * calling fuse_aio_complete() 2898 * calling fuse_aio_complete()
@@ -2915,7 +2912,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
2915 fuse_aio_complete(io, ret < 0 ? ret : 0, -1); 2912 fuse_aio_complete(io, ret < 0 ? ret : 0, -1);
2916 2913
2917 /* we have a non-extending, async request, so return */ 2914 /* we have a non-extending, async request, so return */
2918 if (!is_sync) 2915 if (!io->blocking)
2919 return -EIOCBQUEUED; 2916 return -EIOCBQUEUED;
2920 2917
2921 wait_for_completion(&wait); 2918 wait_for_completion(&wait);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 929c383432b0..5db5d24f91a5 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -259,6 +259,7 @@ struct fuse_io_priv {
259 struct kiocb *iocb; 259 struct kiocb *iocb;
260 struct file *file; 260 struct file *file;
261 struct completion *done; 261 struct completion *done;
262 bool blocking;
262}; 263};
263 264
264#define FUSE_IO_PRIV_SYNC(f) \ 265#define FUSE_IO_PRIV_SYNC(f) \