[CRIU] [PATCH 3/5] pipes: dump of pipe with O_DIRECT support

Stanislav Kinsburskiy skinsbursky at virtuozzo.com
Tue Dec 15 02:57:57 PST 2015


Pipe with O_DIRECT is working in so called "packetized" mode.
In this mode all writes are individual and not merged.
Thus splice can be used to write all the pipe contents to the image file.
Simple write is used instead and each packet is prepended by pipe_data entry.

Signed-off-by: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>
---
 pipes.c |  118 +++++++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 88 insertions(+), 30 deletions(-)

diff --git a/pipes.c b/pipes.c
index 532ff7e..cc13946 100644
--- a/pipes.c
+++ b/pipes.c
@@ -417,13 +417,98 @@ int collect_pipes(void)
 	return collect_pipe_data(CR_FD_PIPES_DATA, pd_hash_pipes);
 }
 
+static int write_pipe_data_entry(struct cr_img *img, u32 pipe_id,
+				 u32 bytes, u32 pipe_size)
+{
+	PipeDataEntry pde = PIPE_DATA_ENTRY__INIT;
+
+	pde.pipe_id	= pipe_id;
+	pde.bytes	= bytes;
+	pde.has_size	= true;
+	pde.size	= pipe_size;
+
+	return pb_write_one(img, &pde, PB_PIPE_DATA);
+}
+
+static int splice_one_pipe_data_entry(struct cr_img *img, int pipe_fd,
+				      u32 pipe_id, u32 bytes, u32 pipe_size)
+{
+	if (write_pipe_data_entry(img, pipe_id, bytes, pipe_size) < 0)
+		return -1;
+
+	if (bytes) {
+		int wrote;
+
+		wrote = splice(pipe_fd, NULL, img_raw_fd(img), NULL, bytes, 0);
+		if (wrote < 0) {
+			pr_perror("Can't push pipe data");
+			return -1;
+		} else if (wrote != bytes) {
+			pr_err("%#x: Wanted to write %d bytes, but wrote %d\n",
+					pipe_id, bytes, wrote);
+			return -1;
+		}
+	}
+	return bytes;
+}
+
+static int write_one_pipe_data_entry(struct cr_img *img, int pipe_fd,
+				     u32 pipe_id, u32 bytes, u32 pipe_size)
+{
+	char buffer[PIPE_BUF];
+
+	/* FIXME: should we care about signals? */
+	bytes = read(pipe_fd, buffer, PIPE_BUF);
+	if (bytes < 0) {
+		pr_perror("Failed to read from pipe");
+		return -1;
+	}
+
+	if (write_pipe_data_entry(img, pipe_id, bytes, pipe_size) < 0)
+		return -1;
+
+	if (write(img_raw_fd(img), buffer, bytes) != bytes) {
+		pr_perror("Failed to write pipe data");
+		return -1;
+	}
+
+	return bytes;
+}
+
+static int write_one_pipe_data(struct cr_img *img, int pipe_fd,
+			       const struct fd_parms *p,
+			       u32 bytes, u32 pipe_size)
+{
+	int (*write_pipe_data)(struct cr_img *img, int pipe_fd,
+			       u32 pipe_id, u32 bytes, u32 pipe_size);
+	int wrote;
+
+	if (p->flags & O_DIRECT)
+		write_pipe_data = write_one_pipe_data_entry;
+	else
+		write_pipe_data = splice_one_pipe_data_entry;
+
+	/* The cycle below is required for O_DIRECT pipes only, because we have
+	 * to write one PipeDataEntry object per each packet in the pipe.
+	 * Cycle will contain only one iteration in case of ordinary pipe. */
+	do {
+		wrote = write_pipe_data(img, pipe_fd, pipe_id(p),
+					bytes, pipe_size);
+		if (wrote < 0)
+			return -1;
+		bytes -= wrote;
+		BUG_ON(bytes < 0);
+	} while (bytes);
+
+	return 0;
+}
+
 int dump_one_pipe_data(struct pipe_data_dump *pd, int lfd, const struct fd_parms *p)
 {
 	struct cr_img *img;
 	int pipe_size, i, bytes;
 	int steal_pipe[2];
 	int ret = -1;
-	PipeDataEntry pde = PIPE_DATA_ENTRY__INIT;
 
 	if (p->flags & O_WRONLY)
 		return 0;
@@ -450,7 +535,7 @@ int dump_one_pipe_data(struct pipe_data_dump *pd, int lfd, const struct fd_parms
 		goto err;
 	}
 
-	if (pipe(steal_pipe) < 0) {
+	if (pipe2(steal_pipe, p->flags & O_DIRECT) < 0) {
 		pr_perror("Can't create pipe for stealing data");
 		goto err;
 	}
@@ -465,29 +550,7 @@ int dump_one_pipe_data(struct pipe_data_dump *pd, int lfd, const struct fd_parms
 		bytes = 0;
 	}
 
-	pde.pipe_id	= pipe_id(p);
-	pde.bytes	= bytes;
-	pde.has_size	= true;
-	pde.size	= pipe_size;
-
-	if (pb_write_one(img, &pde, PB_PIPE_DATA))
-		goto err_close;
-
-	if (bytes) {
-		int wrote;
-
-		wrote = splice(steal_pipe[0], NULL, img_raw_fd(img), NULL, bytes, 0);
-		if (wrote < 0) {
-			pr_perror("Can't push pipe data");
-			goto err_close;
-		} else if (wrote != bytes) {
-			pr_err("%#x: Wanted to write %d bytes, but wrote %d\n",
-					pipe_id(p), bytes, wrote);
-			goto err_close;
-		}
-	}
-
-	ret = 0;
+	ret = write_one_pipe_data(img, steal_pipe[0], p, bytes, pipe_size);
 
 err_close:
 	close(steal_pipe[0]);
@@ -505,11 +568,6 @@ static int dump_one_pipe(int lfd, u32 id, const struct fd_parms *p)
 	pr_info("Dumping pipe %d with id %#x pipe_id %#x\n",
 			lfd, id, pipe_id(p));
 
-	if (p->flags & O_DIRECT) {
-		pr_err("The packetized mode for pipes is not supported yet\n");
-		return -1;
-	}
-
 	pe.id		= id;
 	pe.pipe_id	= pipe_id(p);
 	pe.flags	= p->flags;



More information about the CRIU mailing list