| From 6e5e41e2dc4e4413296d5a4af54ac92d7cd52317 Mon Sep 17 00:00:00 2001 |
| From: Andreas Gruenbacher <agruenba@redhat.com> |
| Date: Tue, 14 Jan 2020 17:12:18 +0100 |
| Subject: gfs2: fix O_SYNC write handling |
| |
| From: Andreas Gruenbacher <agruenba@redhat.com> |
| |
| commit 6e5e41e2dc4e4413296d5a4af54ac92d7cd52317 upstream. |
| |
| In gfs2_file_write_iter, for direct writes, the error checking in the buffered |
| write fallback case is incomplete. This can cause inode write errors to go |
| undetected. Fix and clean up gfs2_file_write_iter along the way. |
| |
| Based on a proposed fix by Christoph Hellwig <hch@lst.de>. |
| |
| Fixes: 967bcc91b044 ("gfs2: iomap direct I/O support") |
| Cc: stable@vger.kernel.org # v4.19+ |
| Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/gfs2/file.c | 51 +++++++++++++++++++++------------------------------ |
| 1 file changed, 21 insertions(+), 30 deletions(-) |
| |
| --- a/fs/gfs2/file.c |
| +++ b/fs/gfs2/file.c |
| @@ -780,7 +780,7 @@ static ssize_t gfs2_file_write_iter(stru |
| struct file *file = iocb->ki_filp; |
| struct inode *inode = file_inode(file); |
| struct gfs2_inode *ip = GFS2_I(inode); |
| - ssize_t written = 0, ret; |
| + ssize_t ret; |
| |
| ret = gfs2_rsqa_alloc(ip); |
| if (ret) |
| @@ -812,55 +812,46 @@ static ssize_t gfs2_file_write_iter(stru |
| |
| if (iocb->ki_flags & IOCB_DIRECT) { |
| struct address_space *mapping = file->f_mapping; |
| - loff_t pos, endbyte; |
| - ssize_t buffered; |
| + ssize_t buffered, ret2; |
| |
| - written = gfs2_file_direct_write(iocb, from); |
| - if (written < 0 || !iov_iter_count(from)) |
| + ret = gfs2_file_direct_write(iocb, from); |
| + if (ret < 0 || !iov_iter_count(from)) |
| goto out_unlock; |
| |
| + iocb->ki_flags |= IOCB_DSYNC; |
| current->backing_dev_info = inode_to_bdi(inode); |
| - ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops); |
| + buffered = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops); |
| current->backing_dev_info = NULL; |
| - if (unlikely(ret < 0)) |
| + if (unlikely(buffered <= 0)) |
| goto out_unlock; |
| - buffered = ret; |
| |
| /* |
| * We need to ensure that the page cache pages are written to |
| * disk and invalidated to preserve the expected O_DIRECT |
| - * semantics. |
| + * semantics. If the writeback or invalidate fails, only report |
| + * the direct I/O range as we don't know if the buffered pages |
| + * made it to disk. |
| */ |
| - pos = iocb->ki_pos; |
| - endbyte = pos + buffered - 1; |
| - ret = filemap_write_and_wait_range(mapping, pos, endbyte); |
| - if (!ret) { |
| - iocb->ki_pos += buffered; |
| - written += buffered; |
| - invalidate_mapping_pages(mapping, |
| - pos >> PAGE_SHIFT, |
| - endbyte >> PAGE_SHIFT); |
| - } else { |
| - /* |
| - * We don't know how much we wrote, so just return |
| - * the number of bytes which were direct-written |
| - */ |
| - } |
| + iocb->ki_pos += buffered; |
| + ret2 = generic_write_sync(iocb, buffered); |
| + invalidate_mapping_pages(mapping, |
| + (iocb->ki_pos - buffered) >> PAGE_SHIFT, |
| + (iocb->ki_pos - 1) >> PAGE_SHIFT); |
| + if (!ret || ret2 > 0) |
| + ret += ret2; |
| } else { |
| current->backing_dev_info = inode_to_bdi(inode); |
| ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops); |
| current->backing_dev_info = NULL; |
| - if (likely(ret > 0)) |
| + if (likely(ret > 0)) { |
| iocb->ki_pos += ret; |
| + ret = generic_write_sync(iocb, ret); |
| + } |
| } |
| |
| out_unlock: |
| inode_unlock(inode); |
| - if (likely(ret > 0)) { |
| - /* Handle various SYNC-type writes */ |
| - ret = generic_write_sync(iocb, ret); |
| - } |
| - return written ? written : ret; |
| + return ret; |
| } |
| |
| static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, |