Skip to content

Commit 6e5e41e

Browse files
author
Andreas Gruenbacher
committed
gfs2: fix O_SYNC write handling
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 <[email protected]>. Fixes: 967bcc9 ("gfs2: iomap direct I/O support") Cc: [email protected] # v4.19+ Signed-off-by: Andreas Gruenbacher <[email protected]>
1 parent 4c0e8dd commit 6e5e41e

File tree

1 file changed

+21
-30
lines changed

1 file changed

+21
-30
lines changed

fs/gfs2/file.c

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
847847
struct file *file = iocb->ki_filp;
848848
struct inode *inode = file_inode(file);
849849
struct gfs2_inode *ip = GFS2_I(inode);
850-
ssize_t written = 0, ret;
850+
ssize_t ret;
851851

852852
ret = gfs2_rsqa_alloc(ip);
853853
if (ret)
@@ -879,55 +879,46 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
879879

880880
if (iocb->ki_flags & IOCB_DIRECT) {
881881
struct address_space *mapping = file->f_mapping;
882-
loff_t pos, endbyte;
883-
ssize_t buffered;
882+
ssize_t buffered, ret2;
884883

885-
written = gfs2_file_direct_write(iocb, from);
886-
if (written < 0 || !iov_iter_count(from))
884+
ret = gfs2_file_direct_write(iocb, from);
885+
if (ret < 0 || !iov_iter_count(from))
887886
goto out_unlock;
888887

888+
iocb->ki_flags |= IOCB_DSYNC;
889889
current->backing_dev_info = inode_to_bdi(inode);
890-
ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops);
890+
buffered = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops);
891891
current->backing_dev_info = NULL;
892-
if (unlikely(ret < 0))
892+
if (unlikely(buffered <= 0))
893893
goto out_unlock;
894-
buffered = ret;
895894

896895
/*
897896
* We need to ensure that the page cache pages are written to
898897
* disk and invalidated to preserve the expected O_DIRECT
899-
* semantics.
898+
* semantics. If the writeback or invalidate fails, only report
899+
* the direct I/O range as we don't know if the buffered pages
900+
* made it to disk.
900901
*/
901-
pos = iocb->ki_pos;
902-
endbyte = pos + buffered - 1;
903-
ret = filemap_write_and_wait_range(mapping, pos, endbyte);
904-
if (!ret) {
905-
iocb->ki_pos += buffered;
906-
written += buffered;
907-
invalidate_mapping_pages(mapping,
908-
pos >> PAGE_SHIFT,
909-
endbyte >> PAGE_SHIFT);
910-
} else {
911-
/*
912-
* We don't know how much we wrote, so just return
913-
* the number of bytes which were direct-written
914-
*/
915-
}
902+
iocb->ki_pos += buffered;
903+
ret2 = generic_write_sync(iocb, buffered);
904+
invalidate_mapping_pages(mapping,
905+
(iocb->ki_pos - buffered) >> PAGE_SHIFT,
906+
(iocb->ki_pos - 1) >> PAGE_SHIFT);
907+
if (!ret || ret2 > 0)
908+
ret += ret2;
916909
} else {
917910
current->backing_dev_info = inode_to_bdi(inode);
918911
ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops);
919912
current->backing_dev_info = NULL;
920-
if (likely(ret > 0))
913+
if (likely(ret > 0)) {
921914
iocb->ki_pos += ret;
915+
ret = generic_write_sync(iocb, ret);
916+
}
922917
}
923918

924919
out_unlock:
925920
inode_unlock(inode);
926-
if (likely(ret > 0)) {
927-
/* Handle various SYNC-type writes */
928-
ret = generic_write_sync(iocb, ret);
929-
}
930-
return written ? written : ret;
921+
return ret;
931922
}
932923

933924
static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,

0 commit comments

Comments
 (0)