mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Jeff Licquia <licquia@progeny.com>
To: linux-kernel@vger.kernel.org
Cc: torvalds@osdl.org
Subject: [PATCH] 2.6.13: POSIX violation in pipes on ia64 for kernels > 2.6.10
Date: Thu, 13 Oct 2005 14:44:35 -0500	[thread overview]
Message-ID: <1129232675.4573.18.camel@laptop1> (raw)

On architectures where PAGE_SIZE > PIPE_BUF, a read of PIPE_BUF bytes
from a full pipe does not change the pipe's write state.  This behavior
is different from kernels 2.6.9 and earlier, and it triggers failures of
the LSB tests.  

This patch fixes two parts of this problem: "short" writes are allowed
to partially succeed if the whole write won't fit on the current buffer,
and the last buffer for a full pipe is "held back" and gradually
released in PIPE_BUF blocks as reads happen.  This patch has been tested
against the LSB runtime test suite, with no kernel-related failures.

A more detailed description of the problem can be found on the
linux-ia64 list:

http://marc.theaimsgroup.com/?l=linux-ia64&m=112906384826364

Please CC me on replies, thanks.

Signed-off-by: Jeff Licquia <licquia@progeny.com>

--- linux-2.6.13-orig/fs/pipe.c	2005-10-10 13:51:38.000000000 -0500
+++ linux-2.6.13/fs/pipe.c	2005-10-12 17:45:34.000000000 -0500
@@ -15,6 +15,7 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/uio.h>
 #include <linux/highmem.h>
+#include <linux/limits.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -220,11 +221,13 @@
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct pipe_inode_info *info;
+	struct pipe_buffer *buf;
 	ssize_t ret;
 	int do_wakeup;
 	struct iovec *iov = (struct iovec *)_iov;
 	size_t total_len;
 	ssize_t chars;
+	size_t last_allowed_len;
 
 	total_len = iov_length(iov, nr_segs);
 	/* Null write succeeds. */
@@ -242,16 +245,28 @@
 		goto out;
 	}
 
+	buf = info->bufs + info->curbuf;
+	last_allowed_len = buf->offset & ~(PIPE_BUF-1);
+
 	/* We try to merge small writes */
 	chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */
 	if (info->nrbufs && chars != 0) {
 		int lastbuf = (info->curbuf + info->nrbufs - 1) & (PIPE_BUFFERS-1);
-		struct pipe_buffer *buf = info->bufs + lastbuf;
-		struct pipe_buf_operations *ops = buf->ops;
-		int offset = buf->offset + buf->len;
-		if (ops->can_merge && offset + chars <= PAGE_SIZE) {
+		struct pipe_buf_operations *ops;
+		int offset;
+		size_t max_write = PAGE_SIZE;
+
+		if (lastbuf == info->curbuf - 1 || lastbuf == (PIPE_BUFFERS-1))
+			max_write = last_allowed_len;
+		buf = info->bufs + lastbuf;
+		ops = buf->ops;
+		offset = buf->offset + buf->len;
+		if (ops->can_merge && offset < max_write) {
 			void *addr = ops->map(filp, info, buf);
-			int error = pipe_iov_copy_from_user(offset + addr, iov, chars);
+			int error;
+			if (chars > (max_write - offset))
+				chars = max_write - offset;
+			error = pipe_iov_copy_from_user(offset + addr, iov, chars);
 			ops->unmap(info, buf);
 			ret = error;
 			do_wakeup = 1;
@@ -275,10 +290,13 @@
 		bufs = info->nrbufs;
 		if (bufs < PIPE_BUFFERS) {
 			int newbuf = (info->curbuf + bufs) & (PIPE_BUFFERS-1);
-			struct pipe_buffer *buf = info->bufs + newbuf;
 			struct page *page = info->tmp_page;
 			int error;
+			size_t max_write = PAGE_SIZE;
 
+			if (newbuf == info->curbuf - 1 || newbuf == (PIPE_BUFFERS-1))
+				max_write = last_allowed_len;
+			buf = info->bufs + newbuf;
 			if (!page) {
 				page = alloc_page(GFP_HIGHUSER);
 				if (unlikely(!page)) {
@@ -293,7 +311,7 @@
 			 * FIXME! Is this really true?
 			 */
 			do_wakeup = 1;
-			chars = PAGE_SIZE;
+			chars = max_write;
 			if (chars > total_len)
 				chars = total_len;
 


             reply	other threads:[~2005-10-13 19:45 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-10-13 19:44 Jeff Licquia [this message]
2005-10-13 19:54 ` Linus Torvalds
2005-10-13 20:37   ` Jeff Licquia

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1129232675.4573.18.camel@laptop1 \
    --to=licquia@progeny.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@osdl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®