Skip to content

Commit fa58cc8

Browse files
author
Andreas Gruenbacher
committed
gfs2: Don't get stuck writing page onto itself under direct I/O
When a direct I/O write is performed, iomap_dio_rw() invalidates the part of the page cache which the write is going to before carrying out the write. In the odd case, the direct I/O write will be reading from the same page it is writing to. gfs2 carries out writes with page faults disabled, so it should have been obvious that this page invalidation can cause iomap_dio_rw() to never make any progress. Currently, gfs2 will end up in an endless retry loop in gfs2_file_direct_write() instead, though. Break this endless loop by limiting the number of retries and falling back to buffered I/O after that. Also simplify should_fault_in_pages() sightly and add a comment to make the above case easier to understand. Reported-by: Jan Kara <[email protected]> Signed-off-by: Andreas Gruenbacher <[email protected]>
1 parent 48b1320 commit fa58cc8

File tree

1 file changed

+14
-3
lines changed

1 file changed

+14
-3
lines changed

fs/gfs2/file.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -784,9 +784,13 @@ static inline bool should_fault_in_pages(struct iov_iter *i,
784784
if (!user_backed_iter(i))
785785
return false;
786786

787+
/*
788+
* Try to fault in multiple pages initially. When that doesn't result
789+
* in any progress, fall back to a single page.
790+
*/
787791
size = PAGE_SIZE;
788792
offs = offset_in_page(iocb->ki_pos);
789-
if (*prev_count != count || !*window_size) {
793+
if (*prev_count != count) {
790794
size_t nr_dirtied;
791795

792796
nr_dirtied = max(current->nr_dirtied_pause -
@@ -870,6 +874,7 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
870874
struct gfs2_inode *ip = GFS2_I(inode);
871875
size_t prev_count = 0, window_size = 0;
872876
size_t written = 0;
877+
bool enough_retries;
873878
ssize_t ret;
874879

875880
/*
@@ -913,11 +918,17 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
913918
if (ret > 0)
914919
written = ret;
915920

921+
enough_retries = prev_count == iov_iter_count(from) &&
922+
window_size <= PAGE_SIZE;
916923
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
917924
gfs2_glock_dq(gh);
918925
window_size -= fault_in_iov_iter_readable(from, window_size);
919-
if (window_size)
920-
goto retry;
926+
if (window_size) {
927+
if (!enough_retries)
928+
goto retry;
929+
/* fall back to buffered I/O */
930+
ret = 0;
931+
}
921932
}
922933
out_unlock:
923934
if (gfs2_holder_queued(gh))

0 commit comments

Comments
 (0)