summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2021-11-09 13:57:17 +0100
committerAndreas Gruenbacher <agruenba@redhat.com>2021-11-10 18:22:37 +0100
commit554c577cee95bdc1d03d9f457e57dc96eb791845 (patch)
treef1398c44f51ab046d63f0ba2b7a5459203a693ff /fs
parentgfs2: Fix "Introduce flag for glock holder auto-demotion" (diff)
downloadlinux-554c577cee95bdc1d03d9f457e57dc96eb791845.tar.xz
linux-554c577cee95bdc1d03d9f457e57dc96eb791845.zip
gfs2: Prevent endless loops in gfs2_file_buffered_write
Currently, instead of performing a short write, iomap_file_buffered_write will fail when part of its iov iterator cannot be read. In contrast, gfs2_file_buffered_write will loop around if it can read part of the iov iterator, so we can end up in an endless loop. This should be fixed in iomap_file_buffered_write (and also generic_perform_write), but this comes a bit late in the 5.16 development cycle, so work around it in the filesystem by trimming the iov iterator to the known-good size for now. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/file.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index c486b702e00f..3e718cfc19a7 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -1013,6 +1013,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
struct gfs2_sbd *sdp = GFS2_SB(inode);
struct gfs2_holder *statfs_gh = NULL;
size_t prev_count = 0, window_size = 0;
+ size_t orig_count = iov_iter_count(from);
size_t read = 0;
ssize_t ret;
@@ -1057,6 +1058,7 @@ retry_under_glock:
if (inode == sdp->sd_rindex)
gfs2_glock_dq_uninit(statfs_gh);
+ from->count = orig_count - read;
if (should_fault_in_pages(ret, from, &prev_count, &window_size)) {
size_t leftover;
@@ -1064,6 +1066,7 @@ retry_under_glock:
leftover = fault_in_iov_iter_readable(from, window_size);
gfs2_holder_disallow_demote(gh);
if (leftover != window_size) {
+ from->count = min(from->count, window_size - leftover);
if (!gfs2_holder_queued(gh)) {
if (read)
goto out_uninit;