From mboxrd@z Thu Jan 1 00:00:00 1970 From: Maxim Patlasov Subject: Re: [PATCH 1/5] fs: don't allow to complete sync iocbs through aio_complete Date: Fri, 30 Jan 2015 19:01:33 -0800 Message-ID: <20150131025520.12941.61643.stgit@R90AM809-1175L> References: <20150128165737.GB17313@lst.de> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Cc: linux-fsdevel@vger.kernel.org, linux-aio@kvack.org, mszeredi@suse.cz, viro@zeniv.linux.org.uk To: hch@lst.de Return-path: In-Reply-To: <20150128165737.GB17313@lst.de> Sender: owner-linux-aio@kvack.org List-Id: linux-fsdevel.vger.kernel.org On 01/28/2015 08:57 AM, Christoph Hellwig wrote: > On Wed, Jan 28, 2015 at 04:30:25PM +0100, Miklos Szeredi wrote: >> Adding Maxim Patlasov, who did the AIO mode in fuse. > > FYI, I don't think fuse should be too hard, it just needs a completion > in struct fuse_io_priv. I just didn't bother before getting some higher > level review for the concept. Yes, I agree. Here is an example implementation below. --- fs/fuse/file.c | 75 ++++++++++++++++++++++++++++++++++++++---------------- fs/fuse/fuse_i.h | 1 + 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index d2be147..b82207a 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -528,6 +528,18 @@ static void fuse_release_user_pages(struct fuse_req *req, int write) } } +static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io) +{ + if (io->err) + return io->err; + + if (io->bytes >= 0 && io->write) + return -EIO; + + return io->bytes < 0 ? io->size : io->bytes; + +} + /** * In case of short read, the caller sets 'pos' to the position of * actual end of fuse request in IO request. Otherwise, if bytes_requested @@ -547,6 +559,7 @@ static void fuse_release_user_pages(struct fuse_req *req, int write) static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) { int left; + bool is_sync = is_sync_kiocb(io->iocb); spin_lock(&io->lock); if (err) @@ -555,27 +568,25 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) io->bytes = pos; left = --io->reqs; - spin_unlock(&io->lock); - if (!left) { - long res; + if (!left && is_sync) { + if (io->waiter) + wake_up_process(io->waiter); + } - if (io->err) - res = io->err; - else if (io->bytes >= 0 && io->write) - res = -EIO; - else { - res = io->bytes < 0 ? io->size : io->bytes; + spin_unlock(&io->lock); - if (!is_sync_kiocb(io->iocb)) { - struct inode *inode = file_inode(io->iocb->ki_filp); - struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_inode *fi = get_fuse_inode(inode); + if (!left && !is_sync) { + ssize_t res = fuse_get_res_by_io(io); - spin_lock(&fc->lock); - fi->attr_version = ++fc->attr_version; - spin_unlock(&fc->lock); - } + if (res >= 0) { + struct inode *inode = file_inode(io->iocb->ki_filp); + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_inode *fi = get_fuse_inode(inode); + + spin_lock(&fc->lock); + fi->attr_version = ++fc->attr_version; + spin_unlock(&fc->lock); } io->iocb->complete(io->iocb, res); @@ -2798,6 +2809,29 @@ static inline loff_t fuse_round_up(loff_t off) return round_up(off, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); } +static ssize_t fuse_dio_wait(struct fuse_io_priv *io) +{ + ssize_t res; + + spin_lock(&io->lock); + + while (io->reqs) { + __set_current_state(TASK_UNINTERRUPTIBLE); + io->waiter = current; + spin_unlock(&io->lock); + io_schedule(); + /* wake up sets us TASK_RUNNING */ + spin_lock(&io->lock); + io->waiter = NULL; + } + + spin_unlock(&io->lock); + + res = fuse_get_res_by_io(io); + kfree(io); + return res; +} + static ssize_t fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t offset) @@ -2841,10 +2875,8 @@ fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, /* * By default, we want to optimize all I/Os with async request * submission to the client filesystem if supported. - * - * XXX: need to add back support for this mode.. */ - io->async = async_dio && !is_sync_kiocb(iocb); + io->async = async_dio; io->iocb = iocb; /* @@ -2867,8 +2899,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, if (!is_sync_kiocb(iocb)) return -EIOCBQUEUED; - // XXX: need fuse specific replacement -// ret = wait_on_sync_kiocb(iocb); + ret = fuse_dio_wait(io); } else { kfree(io); } diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 1cdfb07..8d4872b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -263,6 +263,7 @@ struct fuse_io_priv { int err; struct kiocb *iocb; struct file *file; + struct task_struct *waiter; }; /** -- To unsubscribe, send a message with 'unsubscribe linux-aio' in the body to majordomo@kvack.org. For more info on Linux AIO, see: http://www.kvack.org/aio/ Don't email: aart@kvack.org