Don't ignore the return value from generic_write_sync for the direct to buffered I/O callback case when written is non-zero. Also don't bother to call generic_write_sync for the pure direct I/O case, as iomap_dio_rw already takes care of that. Signed-off-by: Christoph Hellwig <hch@xxxxxx> --- fs/gfs2/file.c | 51 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 21d032c4b077..86c0e61407b6 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -847,7 +847,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) 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 = 0; ret = gfs2_rsqa_alloc(ip); if (ret) @@ -882,52 +882,51 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) loff_t pos, endbyte; ssize_t buffered; - 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; 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)) { + if (buffered < 0) + ret = buffered; 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 - */ - } + if (ret) + goto out_unlock; + + invalidate_mapping_pages(mapping, pos >> PAGE_SHIFT, + endbyte >> PAGE_SHIFT); + ret += buffered; } 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)) - iocb->ki_pos += ret; + if (unlikely(ret <= 0)) + goto out_unlock; } + iocb->ki_pos += ret; + inode_unlock(inode); + return 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, -- 2.24.1