Commit 554c577c authored by Andreas Gruenbacher's avatar Andreas Gruenbacher
Browse files

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: default avatarAndreas Gruenbacher <agruenba@redhat.com>
parent a7ac203d
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -1013,6 +1013,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct gfs2_holder *statfs_gh = NULL;
	struct gfs2_holder *statfs_gh = NULL;
	size_t prev_count = 0, window_size = 0;
	size_t prev_count = 0, window_size = 0;
	size_t orig_count = iov_iter_count(from);
	size_t read = 0;
	size_t read = 0;
	ssize_t ret;
	ssize_t ret;


@@ -1057,6 +1058,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
	if (inode == sdp->sd_rindex)
	if (inode == sdp->sd_rindex)
		gfs2_glock_dq_uninit(statfs_gh);
		gfs2_glock_dq_uninit(statfs_gh);


	from->count = orig_count - read;
	if (should_fault_in_pages(ret, from, &prev_count, &window_size)) {
	if (should_fault_in_pages(ret, from, &prev_count, &window_size)) {
		size_t leftover;
		size_t leftover;


@@ -1064,6 +1066,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
		leftover = fault_in_iov_iter_readable(from, window_size);
		leftover = fault_in_iov_iter_readable(from, window_size);
		gfs2_holder_disallow_demote(gh);
		gfs2_holder_disallow_demote(gh);
		if (leftover != window_size) {
		if (leftover != window_size) {
			from->count = min(from->count, window_size - leftover);
			if (!gfs2_holder_queued(gh)) {
			if (!gfs2_holder_queued(gh)) {
				if (read)
				if (read)
					goto out_uninit;
					goto out_uninit;