[Hardy][PATCH 1/1] splice: fix infinite loop in generic_file_splice_read()

Leann Ogasawara leann.ogasawara at canonical.com
Tue Aug 23 19:27:31 UTC 2011


BugLink: http://bugs.launchpad.net/bugs/790557

SRU Justification:

Impact: Without the fix, users can experience "sporadic kernel lockups
on a Ubuntu Hardy LTS fileserver which produces serious downtimes."

Fix: upstream commit 8191ecd1d14c6914c660dfa007154860a7908857

User has built their own Hardy kernel with the above patch applied.
They can confirm they no longer experience the sporadic lockups on their
production system.  This is a clean cherry-pick from upstream.  Please
consider for Hardy SRU.

Thanks,
Leann

>From 8cd7c215bccee7dcd8b8d70fa335657013a65df1 Mon Sep 17 00:00:00 2001
From: Jens Axboe <jens.axboe at oracle.com>
Date: Thu, 10 Apr 2008 08:24:25 +0200
Subject: [PATCH] splice: fix infinite loop in generic_file_splice_read()

BugLink: http://bugs.launchpad.net/bugs/790557

There's a quirky loop in generic_file_splice_read() that could go
on indefinitely, if the file splice returns 0 permanently (and not
just as a temporary condition). Get rid of the loop and pass
back -EAGAIN correctly from __generic_file_splice_read(), so we
handle that condition properly as well.

Signed-off-by: Jens Axboe <jens.axboe at oracle.com>
(cherry picked from commit 8191ecd1d14c6914c660dfa007154860a7908857)

Signed-off-by: Leann Ogasawara <leann.ogasawara at canonical.com>
---
 fs/splice.c |   31 ++++++-------------------------
 1 files changed, 6 insertions(+), 25 deletions(-)

diff --git a/fs/splice.c b/fs/splice.c
index ef9fc8f..b2872d7 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -364,8 +364,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
 			 * for an in-flight io page
 			 */
 			if (flags & SPLICE_F_NONBLOCK) {
-				if (TestSetPageLocked(page))
+				if (TestSetPageLocked(page)) {
+					error = -EAGAIN;
 					break;
+				}
 			} else
 				lock_page(page);
 
@@ -473,9 +475,8 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
 				 struct pipe_inode_info *pipe, size_t len,
 				 unsigned int flags)
 {
-	ssize_t spliced;
-	int ret;
 	loff_t isize, left;
+	int ret;
 
 	isize = i_size_read(in->f_mapping->host);
 	if (unlikely(*ppos >= isize))
@@ -485,29 +486,9 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
 	if (unlikely(left < len))
 		len = left;
 
-	ret = 0;
-	spliced = 0;
-	while (len && !spliced) {
-		ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
-
-		if (ret < 0)
-			break;
-		else if (!ret) {
-			if (spliced)
-				break;
-			if (flags & SPLICE_F_NONBLOCK) {
-				ret = -EAGAIN;
-				break;
-			}
-		}
-
+	ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
+	if (ret > 0)
 		*ppos += ret;
-		len -= ret;
-		spliced += ret;
-	}
-
-	if (spliced)
-		return spliced;
 
 	return ret;
 }
-- 
1.7.5.4







More information about the kernel-team mailing list