From: Greg KH <gregkh@suse.de>
To: linux-kernel@vger.kernel.org, stable@kernel.org
Cc: Justin Forbes <jmforbes@linuxtx.org>,
Zwane Mwaikambo <zwane@arm.linux.org.uk>,
"Theodore Ts'o" <tytso@mit.edu>,
Randy Dunlap <rdunlap@xenotime.net>,
Dave Jones <davej@redhat.com>,
Chuck Wolber <chuckw@quantumlinux.com>,
Chris Wedgwood <reviews@ml.cw.f00f.org>,
torvalds@osdl.org, akpm@osdl.org, alan@lxorguk.ukuu.org.uk,
Jens Axboe <axboe@suse.de>, Greg Kroah-Hartman <gregkh@suse.de>
Subject: [patch 25/45] splice: fix problems with sys_tee()
Date: Mon, 17 Jul 2006 09:27:55 -0700 [thread overview]
Message-ID: <20060717162755.GZ4829@kroah.com> (raw)
In-Reply-To: <20060717162452.GA4829@kroah.com>
[-- Attachment #1: splice-fix-problems-with-sys_tee.patch --]
[-- Type: text/plain, Size: 7743 bytes --]
-stable review patch. If anyone has any objections, please let us know.
------------------
Several issues noticed/fixed:
- We cannot reliably block in link_pipe() while holding both input and output
mutexes. So do preparatory checks before locking down both mutexes and doing
the link.
- The ipipe->nrbufs vs i check was bad, because we could have dropped the
ipipe lock in-between. This causes us to potentially look at unknown
buffers if we were racing with someone else reading this pipe.
Signed-off-by: Jens Axboe <axboe@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
fs/splice.c | 230 +++++++++++++++++++++++++++++++++---------------------------
1 file changed, 129 insertions(+), 101 deletions(-)
--- linux-2.6.17.6.orig/fs/splice.c
+++ linux-2.6.17.6/fs/splice.c
@@ -1295,6 +1295,85 @@ asmlinkage long sys_splice(int fd_in, lo
}
/*
+ * Make sure there's data to read. Wait for input if we can, otherwise
+ * return an appropriate error.
+ */
+static int link_ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
+{
+ int ret;
+
+ /*
+ * Check ->nrbufs without the inode lock first. This function
+ * is speculative anyways, so missing one is ok.
+ */
+ if (pipe->nrbufs)
+ return 0;
+
+ ret = 0;
+ mutex_lock(&pipe->inode->i_mutex);
+
+ while (!pipe->nrbufs) {
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ if (!pipe->writers)
+ break;
+ if (!pipe->waiting_writers) {
+ if (flags & SPLICE_F_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+ }
+ pipe_wait(pipe);
+ }
+
+ mutex_unlock(&pipe->inode->i_mutex);
+ return ret;
+}
+
+/*
+ * Make sure there's writeable room. Wait for room if we can, otherwise
+ * return an appropriate error.
+ */
+static int link_opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
+{
+ int ret;
+
+ /*
+ * Check ->nrbufs without the inode lock first. This function
+ * is speculative anyways, so missing one is ok.
+ */
+ if (pipe->nrbufs < PIPE_BUFFERS)
+ return 0;
+
+ ret = 0;
+ mutex_lock(&pipe->inode->i_mutex);
+
+ while (pipe->nrbufs >= PIPE_BUFFERS) {
+ if (!pipe->readers) {
+ send_sig(SIGPIPE, current, 0);
+ ret = -EPIPE;
+ break;
+ }
+ if (flags & SPLICE_F_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ pipe->waiting_writers++;
+ pipe_wait(pipe);
+ pipe->waiting_writers--;
+ }
+
+ mutex_unlock(&pipe->inode->i_mutex);
+ return ret;
+}
+
+/*
* Link contents of ipipe to opipe.
*/
static int link_pipe(struct pipe_inode_info *ipipe,
@@ -1302,9 +1381,7 @@ static int link_pipe(struct pipe_inode_i
size_t len, unsigned int flags)
{
struct pipe_buffer *ibuf, *obuf;
- int ret, do_wakeup, i, ipipe_first;
-
- ret = do_wakeup = ipipe_first = 0;
+ int ret = 0, i = 0, nbuf;
/*
* Potential ABBA deadlock, work around it by ordering lock
@@ -1312,7 +1389,6 @@ static int link_pipe(struct pipe_inode_i
* could deadlock (one doing tee from A -> B, the other from B -> A).
*/
if (ipipe->inode < opipe->inode) {
- ipipe_first = 1;
mutex_lock(&ipipe->inode->i_mutex);
mutex_lock(&opipe->inode->i_mutex);
} else {
@@ -1320,118 +1396,55 @@ static int link_pipe(struct pipe_inode_i
mutex_lock(&ipipe->inode->i_mutex);
}
- for (i = 0;; i++) {
+ do {
if (!opipe->readers) {
send_sig(SIGPIPE, current, 0);
if (!ret)
ret = -EPIPE;
break;
}
- if (ipipe->nrbufs - i) {
- ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1));
- /*
- * If we have room, fill this buffer
- */
- if (opipe->nrbufs < PIPE_BUFFERS) {
- int nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1);
-
- /*
- * Get a reference to this pipe buffer,
- * so we can copy the contents over.
- */
- ibuf->ops->get(ipipe, ibuf);
-
- obuf = opipe->bufs + nbuf;
- *obuf = *ibuf;
-
- /*
- * Don't inherit the gift flag, we need to
- * prevent multiple steals of this page.
- */
- obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
-
- if (obuf->len > len)
- obuf->len = len;
-
- opipe->nrbufs++;
- do_wakeup = 1;
- ret += obuf->len;
- len -= obuf->len;
-
- if (!len)
- break;
- if (opipe->nrbufs < PIPE_BUFFERS)
- continue;
- }
-
- /*
- * We have input available, but no output room.
- * If we already copied data, return that. If we
- * need to drop the opipe lock, it must be ordered
- * last to avoid deadlocks.
- */
- if ((flags & SPLICE_F_NONBLOCK) || !ipipe_first) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- if (do_wakeup) {
- smp_mb();
- if (waitqueue_active(&opipe->wait))
- wake_up_interruptible(&opipe->wait);
- kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
- do_wakeup = 0;
- }
+ /*
+ * If we have iterated all input buffers or ran out of
+ * output room, break.
+ */
+ if (i >= ipipe->nrbufs || opipe->nrbufs >= PIPE_BUFFERS)
+ break;
- opipe->waiting_writers++;
- pipe_wait(opipe);
- opipe->waiting_writers--;
- continue;
- }
+ ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1));
+ nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1);
/*
- * No input buffers, do the usual checks for available
- * writers and blocking and wait if necessary
+ * Get a reference to this pipe buffer,
+ * so we can copy the contents over.
*/
- if (!ipipe->writers)
- break;
- if (!ipipe->waiting_writers) {
- if (ret)
- break;
- }
+ ibuf->ops->get(ipipe, ibuf);
+
+ obuf = opipe->bufs + nbuf;
+ *obuf = *ibuf;
+
/*
- * pipe_wait() drops the ipipe mutex. To avoid deadlocks
- * with another process, we can only safely do that if
- * the ipipe lock is ordered last.
+ * Don't inherit the gift flag, we need to
+ * prevent multiple steals of this page.
*/
- if ((flags & SPLICE_F_NONBLOCK) || ipipe_first) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
+ obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
- if (waitqueue_active(&ipipe->wait))
- wake_up_interruptible_sync(&ipipe->wait);
- kill_fasync(&ipipe->fasync_writers, SIGIO, POLL_OUT);
+ if (obuf->len > len)
+ obuf->len = len;
- pipe_wait(ipipe);
- }
+ opipe->nrbufs++;
+ ret += obuf->len;
+ len -= obuf->len;
+ i++;
+ } while (len);
mutex_unlock(&ipipe->inode->i_mutex);
mutex_unlock(&opipe->inode->i_mutex);
- if (do_wakeup) {
+ /*
+ * If we put data in the output pipe, wakeup any potential readers.
+ */
+ if (ret > 0) {
smp_mb();
if (waitqueue_active(&opipe->wait))
wake_up_interruptible(&opipe->wait);
@@ -1452,14 +1465,29 @@ static long do_tee(struct file *in, stru
{
struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe;
struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe;
+ int ret = -EINVAL;
/*
- * Link ipipe to the two output pipes, consuming as we go along.
+ * Duplicate the contents of ipipe to opipe without actually
+ * copying the data.
*/
- if (ipipe && opipe)
- return link_pipe(ipipe, opipe, len, flags);
+ if (ipipe && opipe && ipipe != opipe) {
+ /*
+ * Keep going, unless we encounter an error. The ipipe/opipe
+ * ordering doesn't really matter.
+ */
+ ret = link_ipipe_prep(ipipe, flags);
+ if (!ret) {
+ ret = link_opipe_prep(opipe, flags);
+ if (!ret) {
+ ret = link_pipe(ipipe, opipe, len, flags);
+ if (!ret && (flags & SPLICE_F_NONBLOCK))
+ ret = -EAGAIN;
+ }
+ }
+ }
- return -EINVAL;
+ return ret;
}
asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags)
--
next prev parent reply other threads:[~2006-07-17 16:44 UTC|newest]
Thread overview: 64+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20060717160652.408007000@blue.kroah.org>
2006-07-17 16:24 ` [patch 00/45] 2.6.17.y -stable review Greg KH
2006-07-17 16:25 ` [patch 01/45] XFS: corruption fix Greg KH
2006-07-17 19:10 ` Chris Wedgwood
2006-07-18 13:27 ` Jan Engelhardt
2006-07-18 22:24 ` Nathan Scott
2006-07-17 16:25 ` [patch 02/45] IB/mthca: restore missing PCI registers after reset Greg KH
2006-07-26 10:29 ` Michael S. Tsirkin
2006-07-26 16:20 ` Greg KH
2006-07-26 16:32 ` Michael S. Tsirkin
2006-07-26 16:42 ` Greg KH
2006-08-21 13:22 ` Michael S. Tsirkin
2006-07-17 16:25 ` [patch 03/45] x86_64: Fix modular pc speaker Greg KH
2006-07-17 18:02 ` Dmitry Torokhov
2006-07-17 16:25 ` [patch 04/45] BLOCK: Fix bounce limit address check Greg KH
2006-07-17 16:25 ` [patch 05/45] memory hotplug: solve config broken: undefined reference to `online_page Greg KH
2006-07-17 16:26 ` [patch 06/45] v4l/dvb: Fix budget-av frontend detection Greg KH
2006-07-17 16:26 ` [patch 07/45] v4l/dvb: Fix CI on old KNC1 DVBC cards Greg KH
2006-07-25 13:01 ` Edgar Hucek
2006-07-25 15:15 ` Michael Krufky
2006-07-25 15:22 ` Edgar Hucek
2006-07-25 17:10 ` Greg KH
2006-08-01 23:23 ` Michael Krufky
2006-07-17 16:26 ` [patch 08/45] v4l/dvb: Fix CI interface on PRO KNC1 cards Greg KH
2006-07-17 16:26 ` [patch 09/45] pnp: suppress request_irq() warning Greg KH
2006-07-17 16:26 ` [patch 10/45] Reduce ACPI verbosity on null handle condition Greg KH
2006-07-17 16:26 ` [patch 11/45] via-velocity: the link is not correctly detected when the device starts Greg KH
2006-07-17 16:26 ` [patch 12/45] 2 oopses in ethtool Greg KH
2006-07-17 20:51 ` Matthew Wilcox
2006-07-17 16:26 ` [patch 13/45] v4l/dvb: Kconfig: fix description and dependencies for saa7115 module Greg KH
2006-07-17 16:26 ` [patch 14/45] PKT_SCHED: Fix illegal memory dereferences when dumping actions Greg KH
2006-07-17 16:27 ` [patch 15/45] PKT_SCHED: Return ENOENT if action module is unavailable Greg KH
2006-07-17 16:27 ` [patch 16/45] PKT_SCHED: Fix error handling while dumping actions Greg KH
2006-07-17 16:27 ` [patch 17/45] v4l/dvb: Backport fix to artec USB DVB devices Greg KH
2006-07-17 16:27 ` [patch 18/45] v4l/dvb: Backport the DISEQC regression fix to 2.6.17.x Greg KH
2006-07-17 16:27 ` [patch 19/45] v4l/dvb: Backport the budget driver DISEQC instability fix Greg KH
2006-07-17 16:27 ` [patch 20/45] v4l/dvb: stradis: dont export MODULE_DEVICE_TABLE Greg KH
2006-07-17 16:27 ` [patch 21/45] dvb-bt8xx: fix frontend detection for DViCO FusionHDTV DVB-T Lite rev 1.2 Greg KH
2006-07-17 16:27 ` [patch 22/45] Make powernow-k7 work on SMP kernels Greg KH
2006-07-17 16:27 ` [patch 23/45] Fix powernow-k8 SMP kernel on UP hardware bug Greg KH
2006-07-17 16:27 ` [patch 24/45] cdrom: fix bad cgc.buflen assignment Greg KH
2006-07-17 16:27 ` Greg KH [this message]
2006-07-17 16:28 ` [patch 26/45] USB serial ftdi_sio: Prevent userspace DoS (CVE-2006-2936) Greg KH
2006-07-17 16:28 ` [patch 27/45] tpm: interrupt clear fix Greg KH
2006-07-17 16:56 ` Kylene Jo Hall
2006-07-17 17:52 ` [stable] " Greg KH
2006-07-17 16:28 ` [patch 28/45] pdflush: handle resume wakeups Greg KH
2006-07-17 16:28 ` [patch 29/45] ieee80211: TKIP requires CRC32 Greg KH
2006-07-17 16:28 ` [patch 30/45] : Fix IPv4/DECnet routing rule dumping Greg KH
2006-07-17 16:28 ` [patch 31/45] : Add missing UFO initialisations Greg KH
2006-07-17 16:28 ` [patch 32/45] ALSA: Suppress irq handler mismatch messages in ALSA ISA drivers Greg KH
2006-07-17 16:28 ` [patch 33/45] ALSA: RME HDSP - fixed proc interface (missing {}) Greg KH
2006-07-17 16:28 ` [patch 34/45] ALSA: hda-intel - Fix race in remove Greg KH
2006-07-17 16:28 ` [patch 35/45] ALSA: Fix workaround for AD1988A rev2 codec Greg KH
2006-07-17 16:28 ` [patch 36/45] ALSA: Fix undefined (missing) references in ISA MIRO sound driver Greg KH
2006-07-17 16:28 ` [patch 37/45] ALSA: fix the SND_FM801_TEA575X dependencies Greg KH
2006-07-17 16:29 ` [patch 38/45] ALSA: Fix mute switch on VAIO laptops with STAC7661 Greg KH
2006-07-17 16:29 ` [patch 39/45] ALSA: Fix model for HP dc7600 Greg KH
2006-07-17 16:29 ` [patch 40/45] ALSA: Fix missing array terminators in AD1988 codec support Greg KH
2006-07-17 16:29 ` [patch 41/45] ALSA: Fix a deadlock in snd-rtctimer Greg KH
2006-07-17 16:29 ` [patch 42/45] ALSA: au88x0 - Fix 64bit address of MPU401 MMIO port Greg KH
2006-07-17 16:29 ` [patch 43/45] struct file leakage Greg KH
2006-07-17 16:29 ` [patch 44/45] serial 8250: sysrq deadlock fix Greg KH
2006-07-17 16:29 ` [patch 45/45] fix fdset leakage Greg KH
2006-07-18 13:24 ` [patch 00/45] 2.6.17.y -stable review akrout70
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=20060717162755.GZ4829@kroah.com \
--to=gregkh@suse.de \
--cc=akpm@osdl.org \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=axboe@suse.de \
--cc=chuckw@quantumlinux.com \
--cc=davej@redhat.com \
--cc=jmforbes@linuxtx.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rdunlap@xenotime.net \
--cc=reviews@ml.cw.f00f.org \
--cc=stable@kernel.org \
--cc=torvalds@osdl.org \
--cc=tytso@mit.edu \
--cc=zwane@arm.linux.org.uk \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.