diff --git a/mm/filemap.c b/mm/filemap.c
index 89ce6fe5f8be152e71218085af5396dcb72d315c..76bea88cbebcb6201d87574890f476ff0051caee 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1750,7 +1750,11 @@ static void __iov_iter_advance_iov(struct iov_iter *i, size_t bytes)
 		const struct iovec *iov = i->iov;
 		size_t base = i->iov_offset;
 
-		while (bytes) {
+		/*
+		 * The !iov->iov_len check ensures we skip over unlikely
+		 * zero-length segments.
+		 */
+		while (bytes || !iov->iov_len) {
 			int copy = min(bytes, iov->iov_len - base);
 
 			bytes -= copy;
@@ -2268,6 +2272,7 @@ static ssize_t generic_perform_write(struct file *file,
 
 		cond_resched();
 
+		iov_iter_advance(i, copied);
 		if (unlikely(copied == 0)) {
 			/*
 			 * If we were unable to copy any data at all, we must
@@ -2281,7 +2286,6 @@ static ssize_t generic_perform_write(struct file *file,
 						iov_iter_single_seg_count(i));
 			goto again;
 		}
-		iov_iter_advance(i, copied);
 		pos += copied;
 		written += copied;