[Devel] [PATCH] Fix restoring pipes with full buffers

Dan Smith danms at us.ibm.com
Fri Jan 28 10:45:11 PST 2011


While this fixes restoring pipes that were completely full, it actually
corrects a potential issue with restoring any pipe buffers.  By using
splice() to do this work when we are reading the image from another pipe,
we depend on userspace setting up the buffers in the pipe perfectly
such that the data to be restored is oriented in the pipe in the same
way as it is expected (or required) to be in the restored pipe.  The
"full" case is the hardest to get right, but userspace could break things
if it loaded up the inbound pipe with lots of small buffers which would
cause splice() to hit the PIPE_BUFFERS limit before having read the
requested amount of data.

Instead, drop the optimization and just read() and write() data into
the pipe.

Signed-off-by: Dan Smith <danms at us.ibm.com>
---
 fs/pipe.c |   49 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/fs/pipe.c b/fs/pipe.c
index 9664e4f..0da1e3a 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -926,17 +926,60 @@ static int pipe_file_checkpoint(struct ckpt_ctx *ctx, struct file *file)
 	return ret;
 }
 
+static int restore_pipe_buffer(struct ckpt_ctx *ctx,
+			       struct file *dest,
+			       int len)
+{
+	char *buf;
+	int ret;
+	int nread;
+	int nwrote;
+	int nleft = len;
+
+	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (nleft = len; nleft > 0; nleft -= nread) {
+		int size = nleft < PAGE_SIZE ? nleft : PAGE_SIZE;
+		loff_t pos;
+
+		pos = file_pos_read(ctx->file);
+		nread = kernel_read(ctx->file, pos, buf, size);
+		if (nread < 0) {
+			ret = nread;
+			goto out;
+		}
+		file_pos_write(ctx->file, pos + nread);
+
+		pos = file_pos_read(dest);
+		nwrote = kernel_write(dest, pos, buf, nread);
+		if (nwrote < 0) {
+			ret = nwrote;
+			goto out;
+		}
+		file_pos_write(dest, pos + nwrote);
+
+		if (nwrote != nread) {
+			ret = -EPIPE;
+			goto out;
+		}
+	}
+	ret = len;
+ out:
+	kfree(buf);
+	return ret;
+}
+
 static int restore_pipe(struct ckpt_ctx *ctx, struct file *file)
 {
-	struct pipe_inode_info *pipe;
 	int len, ret;
 
 	len = _ckpt_read_obj_type(ctx, NULL, 0, CKPT_HDR_PIPE_BUF);
 	if (len <= 0)
 		return len;
 
-	pipe = file->f_dentry->d_inode->i_pipe;
-	ret = do_splice_to(ctx->file, &ctx->file->f_pos, pipe, len, 0);
+	ret = restore_pipe_buffer(ctx, file, len);
 
 	if (ret >= 0 && ret != len)
 		ret = -EPIPE;  /* can occur due to an error in source file */
-- 
1.7.2.2

_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers




More information about the Devel mailing list