]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
more .29 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Thu, 14 May 2009 03:46:25 +0000 (20:46 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 14 May 2009 03:46:25 +0000 (20:46 -0700)
queue-2.6.29/ehea-fix-invalid-pointer-access.patch [new file with mode: 0644]
queue-2.6.29/fuse-destroy-bdi-on-error.patch [new file with mode: 0644]
queue-2.6.29/kvm-make-efer-reads-safe-when-efer-does-not-exist.patch [new file with mode: 0644]
queue-2.6.29/kvm-svm-remove-port-80-passthrough.patch [new file with mode: 0644]
queue-2.6.29/mac80211-minstrel-fix-memory-corruption.patch [deleted file]
queue-2.6.29/ocfs2-fix-i_mutex-locking-in-ocfs2_splice_to_file.patch [new file with mode: 0644]
queue-2.6.29/powerpc-5200-don-t-specify-irqf_shared-in-psc-uart-driver.patch [new file with mode: 0644]
queue-2.6.29/series
queue-2.6.29/splice-fix-i_mutex-locking-in-generic_splice_write.patch [new file with mode: 0644]
queue-2.6.29/splice-remove-i_mutex-locking-in-splice_from_pipe.patch [new file with mode: 0644]
queue-2.6.29/splice-split-up-__splice_from_pipe.patch [new file with mode: 0644]

diff --git a/queue-2.6.29/ehea-fix-invalid-pointer-access.patch b/queue-2.6.29/ehea-fix-invalid-pointer-access.patch
new file mode 100644 (file)
index 0000000..74ef9f8
--- /dev/null
@@ -0,0 +1,69 @@
+From 0b2febf38a33d7c40fb7bb4a58c113a1fa33c412 Mon Sep 17 00:00:00 2001
+From: Hannes Hering <hering2@de.ibm.com>
+Date: Mon, 4 May 2009 11:06:37 -0700
+Subject: ehea: fix invalid pointer access
+
+From: Hannes Hering <hering2@de.ibm.com>
+
+commit 0b2febf38a33d7c40fb7bb4a58c113a1fa33c412 upstream.
+
+This patch fixes an invalid pointer access in case the receive queue
+holds no pointer to the next skb when the queue is empty.
+
+Signed-off-by: Hannes Hering <hering2@de.ibm.com>
+Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/ehea/ehea_main.c |   31 ++++++++++++++++++-------------
+ 1 file changed, 18 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/ehea/ehea_main.c
++++ b/drivers/net/ehea/ehea_main.c
+@@ -529,14 +529,17 @@ static inline struct sk_buff *get_skb_by
+       x &= (arr_len - 1);
+       pref = skb_array[x];
+-      prefetchw(pref);
+-      prefetchw(pref + EHEA_CACHE_LINE);
++      if (pref) {
++              prefetchw(pref);
++              prefetchw(pref + EHEA_CACHE_LINE);
++
++              pref = (skb_array[x]->data);
++              prefetch(pref);
++              prefetch(pref + EHEA_CACHE_LINE);
++              prefetch(pref + EHEA_CACHE_LINE * 2);
++              prefetch(pref + EHEA_CACHE_LINE * 3);
++      }
+-      pref = (skb_array[x]->data);
+-      prefetch(pref);
+-      prefetch(pref + EHEA_CACHE_LINE);
+-      prefetch(pref + EHEA_CACHE_LINE * 2);
+-      prefetch(pref + EHEA_CACHE_LINE * 3);
+       skb = skb_array[skb_index];
+       skb_array[skb_index] = NULL;
+       return skb;
+@@ -553,12 +556,14 @@ static inline struct sk_buff *get_skb_by
+       x &= (arr_len - 1);
+       pref = skb_array[x];
+-      prefetchw(pref);
+-      prefetchw(pref + EHEA_CACHE_LINE);
+-
+-      pref = (skb_array[x]->data);
+-      prefetchw(pref);
+-      prefetchw(pref + EHEA_CACHE_LINE);
++      if (pref) {
++              prefetchw(pref);
++              prefetchw(pref + EHEA_CACHE_LINE);
++
++              pref = (skb_array[x]->data);
++              prefetchw(pref);
++              prefetchw(pref + EHEA_CACHE_LINE);
++      }
+       skb = skb_array[wqe_index];
+       skb_array[wqe_index] = NULL;
diff --git a/queue-2.6.29/fuse-destroy-bdi-on-error.patch b/queue-2.6.29/fuse-destroy-bdi-on-error.patch
new file mode 100644 (file)
index 0000000..7f3f629
--- /dev/null
@@ -0,0 +1,32 @@
+From fd9db7297749c05fcf5721ce5393a5a8b8772f2a Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@suse.cz>
+Date: Tue, 28 Apr 2009 16:56:35 +0200
+Subject: fuse: destroy bdi on error
+
+From: Miklos Szeredi <mszeredi@suse.cz>
+
+commit fd9db7297749c05fcf5721ce5393a5a8b8772f2a upstream.
+
+Destroy bdi on error in fuse_fill_super().
+
+This was an omission from commit 26c3679101dbccc054dcf370143941844ba70531
+"fuse: destroy bdi on umount", which moved the bdi_destroy() call from
+fuse_conn_put() to fuse_put_super().
+
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/fuse/inode.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/fs/fuse/inode.c
++++ b/fs/fuse/inode.c
+@@ -908,6 +908,7 @@ static int fuse_fill_super(struct super_
+  err_put_root:
+       dput(root_dentry);
+  err_put_conn:
++      bdi_destroy(&fc->bdi);
+       fuse_conn_put(fc);
+  err_fput:
+       fput(file);
diff --git a/queue-2.6.29/kvm-make-efer-reads-safe-when-efer-does-not-exist.patch b/queue-2.6.29/kvm-make-efer-reads-safe-when-efer-does-not-exist.patch
new file mode 100644 (file)
index 0000000..9a9ef9c
--- /dev/null
@@ -0,0 +1,33 @@
+From e286e86e6d2042d67d09244aa0e05ffef75c9d54 Mon Sep 17 00:00:00 2001
+From: Avi Kivity <avi@redhat.com>
+Date: Sun, 3 May 2009 18:50:55 +0300
+Subject: KVM: Make EFER reads safe when EFER does not exist
+
+From: Avi Kivity <avi@redhat.com>
+
+commit e286e86e6d2042d67d09244aa0e05ffef75c9d54 upstream.
+
+Some processors don't have EFER; don't oops if userspace wants us to
+read EFER when we check NX.
+
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/kvm/x86.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -1075,9 +1075,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *
+ static int is_efer_nx(void)
+ {
+-      u64 efer;
++      unsigned long long efer = 0;
+-      rdmsrl(MSR_EFER, efer);
++      rdmsrl_safe(MSR_EFER, &efer);
+       return efer & EFER_NX;
+ }
diff --git a/queue-2.6.29/kvm-svm-remove-port-80-passthrough.patch b/queue-2.6.29/kvm-svm-remove-port-80-passthrough.patch
new file mode 100644 (file)
index 0000000..dc68060
--- /dev/null
@@ -0,0 +1,37 @@
+From 99f85a28a78e96d28907fe036e1671a218fee597 Mon Sep 17 00:00:00 2001
+From: Avi Kivity <avi@redhat.com>
+Date: Mon, 11 May 2009 14:21:10 +0300
+Subject: KVM: SVM: Remove port 80 passthrough
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf-8
+Content-Transfer-Encoding: 8bit
+
+From: Avi Kivity <avi@redhat.com>
+
+commit 99f85a28a78e96d28907fe036e1671a218fee597 upstream.
+
+KVM optimizes guest port 80 accesses by passthing them through to the host.
+Some AMD machines die on port 80 writes, allowing the guest to hard-lock the
+host.
+
+Remove the port passthrough to avoid the problem.
+
+Reported-by: Piotr Jaroszyński <p.jaroszynski@gmail.com>
+Tested-by: Piotr Jaroszyński <p.jaroszynski@gmail.com>
+Signed-off-by: Avi Kivity <avi@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/kvm/svm.c |    1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/arch/x86/kvm/svm.c
++++ b/arch/x86/kvm/svm.c
+@@ -411,7 +411,6 @@ static __init int svm_hardware_setup(voi
+       iopm_va = page_address(iopm_pages);
+       memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+-      clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */
+       iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;
+       if (boot_cpu_has(X86_FEATURE_NX))
diff --git a/queue-2.6.29/mac80211-minstrel-fix-memory-corruption.patch b/queue-2.6.29/mac80211-minstrel-fix-memory-corruption.patch
deleted file mode 100644 (file)
index fd0c154..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From 8e532175277d9a5eae49768ed086555081f741a7 Mon Sep 17 00:00:00 2001
-From: Jiri Slaby <jirislaby@gmail.com>
-Date: Mon, 4 May 2009 18:04:55 +0200
-Subject: mac80211: minstrel, fix memory corruption
-
-From: Jiri Slaby <jirislaby@gmail.com>
-
-commit 8e532175277d9a5eae49768ed086555081f741a7 upstream.
-
-minstrel doesn't count max rate count in fact, since it doesn't use
-a loop variable `i' and hence allocs space only for bitrates found in
-the first band.
-
-Fix it by involving the `i' as an index so that it traverses all the
-bands now and finds the real max bitrate count.
-
-Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
-Cc: Felix Fietkau <nbd@openwrt.org>
-Signed-off-by: John W. Linville <linville@tuxdriver.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-
----
- net/mac80211/rc80211_minstrel.c |    2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/net/mac80211/rc80211_minstrel.c
-+++ b/net/mac80211/rc80211_minstrel.c
-@@ -476,7 +476,7 @@ minstrel_alloc_sta(void *priv, struct ie
-               return NULL;
-       for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
--              sband = hw->wiphy->bands[hw->conf.channel->band];
-+              sband = hw->wiphy->bands[i];
-               if (sband->n_bitrates > max_rates)
-                       max_rates = sband->n_bitrates;
-       }
diff --git a/queue-2.6.29/ocfs2-fix-i_mutex-locking-in-ocfs2_splice_to_file.patch b/queue-2.6.29/ocfs2-fix-i_mutex-locking-in-ocfs2_splice_to_file.patch
new file mode 100644 (file)
index 0000000..6e063f7
--- /dev/null
@@ -0,0 +1,179 @@
+From 328eaaba4e41a04c1dc4679d65bea3fee4349d86 Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <miklos@szeredi.hu>
+Date: Tue, 14 Apr 2009 19:48:39 +0200
+Subject: ocfs2: fix i_mutex locking in ocfs2_splice_to_file()
+
+From: Miklos Szeredi <miklos@szeredi.hu>
+
+commit 328eaaba4e41a04c1dc4679d65bea3fee4349d86 upstream.
+
+Rearrange locking of i_mutex on destination and call to
+ocfs2_rw_lock() so locks are only held while buffers are copied with
+the pipe_to_file() actor, and not while waiting for more data on the
+pipe.
+
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/ocfs2/file.c        |   96 ++++++++++++++++++++++++++++++++++++++-----------
+ fs/splice.c            |    5 +-
+ include/linux/splice.h |    2 +
+ 3 files changed, 80 insertions(+), 23 deletions(-)
+
+--- a/fs/ocfs2/file.c
++++ b/fs/ocfs2/file.c
+@@ -1912,6 +1912,22 @@ out_sems:
+       return written ? written : ret;
+ }
++static int ocfs2_splice_to_file(struct pipe_inode_info *pipe,
++                              struct file *out,
++                              struct splice_desc *sd)
++{
++      int ret;
++
++      ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, &sd->pos,
++                                          sd->total_len, 0, NULL);
++      if (ret < 0) {
++              mlog_errno(ret);
++              return ret;
++      }
++
++      return splice_from_pipe_feed(pipe, sd, pipe_to_file);
++}
++
+ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
+                                      struct file *out,
+                                      loff_t *ppos,
+@@ -1919,38 +1935,76 @@ static ssize_t ocfs2_file_splice_write(s
+                                      unsigned int flags)
+ {
+       int ret;
+-      struct inode *inode = out->f_path.dentry->d_inode;
++      struct address_space *mapping = out->f_mapping;
++      struct inode *inode = mapping->host;
++      struct splice_desc sd = {
++              .total_len = len,
++              .flags = flags,
++              .pos = *ppos,
++              .u.file = out,
++      };
+       mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", out, pipe,
+                  (unsigned int)len,
+                  out->f_path.dentry->d_name.len,
+                  out->f_path.dentry->d_name.name);
+-      mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
+-
+-      ret = ocfs2_rw_lock(inode, 1);
+-      if (ret < 0) {
+-              mlog_errno(ret);
+-              goto out;
+-      }
++      if (pipe->inode)
++              mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_PARENT);
+-      ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, ppos, len, 0,
+-                                          NULL);
+-      if (ret < 0) {
+-              mlog_errno(ret);
+-              goto out_unlock;
+-      }
++      splice_from_pipe_begin(&sd);
++      do {
++              ret = splice_from_pipe_next(pipe, &sd);
++              if (ret <= 0)
++                      break;
++
++              mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
++              ret = ocfs2_rw_lock(inode, 1);
++              if (ret < 0)
++                      mlog_errno(ret);
++              else {
++                      ret = ocfs2_splice_to_file(pipe, out, &sd);
++                      ocfs2_rw_unlock(inode, 1);
++              }
++              mutex_unlock(&inode->i_mutex);
++      } while (ret > 0);
++      splice_from_pipe_end(pipe, &sd);
+       if (pipe->inode)
+-              mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD);
+-      ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags);
+-      if (pipe->inode)
+               mutex_unlock(&pipe->inode->i_mutex);
+-out_unlock:
+-      ocfs2_rw_unlock(inode, 1);
+-out:
+-      mutex_unlock(&inode->i_mutex);
++      if (sd.num_spliced)
++              ret = sd.num_spliced;
++
++      if (ret > 0) {
++              unsigned long nr_pages;
++
++              *ppos += ret;
++              nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
++
++              /*
++               * If file or inode is SYNC and we actually wrote some data,
++               * sync it.
++               */
++              if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
++                      int err;
++
++                      mutex_lock(&inode->i_mutex);
++                      err = ocfs2_rw_lock(inode, 1);
++                      if (err < 0) {
++                              mlog_errno(err);
++                      } else {
++                              err = generic_osync_inode(inode, mapping,
++                                                OSYNC_METADATA|OSYNC_DATA);
++                              ocfs2_rw_unlock(inode, 1);
++                      }
++                      mutex_unlock(&inode->i_mutex);
++
++                      if (err)
++                              ret = err;
++              }
++              balance_dirty_pages_ratelimited_nr(mapping, nr_pages);
++      }
+       mlog_exit(ret);
+       return ret;
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -554,8 +554,8 @@ static int pipe_to_sendpage(struct pipe_
+  * SPLICE_F_MOVE isn't set, or we cannot move the page, we simply create
+  * a new page in the output file page cache and fill/dirty that.
+  */
+-static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
+-                      struct splice_desc *sd)
++int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
++               struct splice_desc *sd)
+ {
+       struct file *file = sd->u.file;
+       struct address_space *mapping = file->f_mapping;
+@@ -599,6 +599,7 @@ static int pipe_to_file(struct pipe_inod
+ out:
+       return ret;
+ }
++EXPORT_SYMBOL(pipe_to_file);
+ static void wakeup_pipe_writers(struct pipe_inode_info *pipe)
+ {
+--- a/include/linux/splice.h
++++ b/include/linux/splice.h
+@@ -75,6 +75,8 @@ extern int splice_from_pipe_next(struct 
+ extern void splice_from_pipe_begin(struct splice_desc *);
+ extern void splice_from_pipe_end(struct pipe_inode_info *,
+                                struct splice_desc *);
++extern int pipe_to_file(struct pipe_inode_info *, struct pipe_buffer *,
++                      struct splice_desc *);
+ extern ssize_t splice_to_pipe(struct pipe_inode_info *,
+                             struct splice_pipe_desc *);
diff --git a/queue-2.6.29/powerpc-5200-don-t-specify-irqf_shared-in-psc-uart-driver.patch b/queue-2.6.29/powerpc-5200-don-t-specify-irqf_shared-in-psc-uart-driver.patch
new file mode 100644 (file)
index 0000000..aa6e19b
--- /dev/null
@@ -0,0 +1,34 @@
+From d9f0c5f9bc74f16d0ea0f6c518b209e48783a796 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely@secretlab.ca>
+Date: Wed, 4 Feb 2009 11:23:56 -0700
+Subject: powerpc/5200: Don't specify IRQF_SHARED in PSC UART driver
+
+From: Grant Likely <grant.likely@secretlab.ca>
+
+commit d9f0c5f9bc74f16d0ea0f6c518b209e48783a796 upstream.
+
+The MPC5200 PSC device is wired up to a dedicated interrupt line
+which is never shared.  This patch removes the IRQF_SHARED flag
+from the request_irq() call which eliminates the "IRQF_DISABLED
+is not guaranteed on shared IRQs" warning message from the console
+output.
+
+Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
+Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/serial/mpc52xx_uart.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/serial/mpc52xx_uart.c
++++ b/drivers/serial/mpc52xx_uart.c
+@@ -522,7 +522,7 @@ mpc52xx_uart_startup(struct uart_port *p
+       /* Request IRQ */
+       ret = request_irq(port->irq, mpc52xx_uart_int,
+-              IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED,
++              IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+               "mpc52xx_psc_uart", port);
+       if (ret)
+               return ret;
index 2c0a0cabb440c465ffb6487dd1fa662502a7ec2b..81e15b944b05f837dcf68dfc9c6e4be8469d496e 100644 (file)
@@ -27,7 +27,6 @@ cifs-fix-incorrect-destination-buffer-size-in-cifs_strncpy_to_host.patch
 cifs-fix-buffer-size-in-cifs_convertucspath.patch
 cifs-fix-unicode-string-area-word-alignment-in-session-setup.patch
 mac80211-pid-fix-memory-corruption.patch
-mac80211-minstrel-fix-memory-corruption.patch
 mm-page_mkwrite-change-prototype-to-match-fault.patch
 fs-fix-page_mkwrite-error-cases-in-core-code-and-btrfs.patch
 mm-close-page_mkwrite-races.patch
@@ -41,3 +40,12 @@ nfs-fix-the-notifications-when-renaming-onto-an-existing-file.patch
 lockd-fix-list-corruption-on-lockd-restart.patch
 dmatest-fix-max-channels-handling.patch
 hid-add-noget-quirk-for-devices-from-ch-products.patch
+kvm-svm-remove-port-80-passthrough.patch
+kvm-make-efer-reads-safe-when-efer-does-not-exist.patch
+fuse-destroy-bdi-on-error.patch
+splice-split-up-__splice_from_pipe.patch
+splice-remove-i_mutex-locking-in-splice_from_pipe.patch
+splice-fix-i_mutex-locking-in-generic_splice_write.patch
+ocfs2-fix-i_mutex-locking-in-ocfs2_splice_to_file.patch
+ehea-fix-invalid-pointer-access.patch
+powerpc-5200-don-t-specify-irqf_shared-in-psc-uart-driver.patch
diff --git a/queue-2.6.29/splice-fix-i_mutex-locking-in-generic_splice_write.patch b/queue-2.6.29/splice-fix-i_mutex-locking-in-generic_splice_write.patch
new file mode 100644 (file)
index 0000000..cc1ce56
--- /dev/null
@@ -0,0 +1,64 @@
+From eb443e5a25d43996deb62b9bcee1a4ce5dea2ead Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <miklos@szeredi.hu>
+Date: Tue, 14 Apr 2009 19:48:38 +0200
+Subject: splice: fix i_mutex locking in generic_splice_write()
+
+From: Miklos Szeredi <miklos@szeredi.hu>
+
+commit eb443e5a25d43996deb62b9bcee1a4ce5dea2ead upstream.
+
+Rearrange locking of i_mutex on destination so it's only held while
+buffers are copied with the pipe_to_file() actor, and not while
+waiting for more data on the pipe.
+
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/splice.c |   34 +++++++++++++++++++++++-----------
+ 1 file changed, 23 insertions(+), 11 deletions(-)
+
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -894,17 +894,29 @@ generic_file_splice_write(struct pipe_in
+       };
+       ssize_t ret;
+-      WARN_ON(S_ISFIFO(inode->i_mode));
+-      mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
+-      ret = file_remove_suid(out);
+-      if (likely(!ret)) {
+-              if (pipe->inode)
+-                      mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD);
+-              ret = __splice_from_pipe(pipe, &sd, pipe_to_file);
+-              if (pipe->inode)
+-                      mutex_unlock(&pipe->inode->i_mutex);
+-      }
+-      mutex_unlock(&inode->i_mutex);
++      if (pipe->inode)
++              mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_PARENT);
++
++      splice_from_pipe_begin(&sd);
++      do {
++              ret = splice_from_pipe_next(pipe, &sd);
++              if (ret <= 0)
++                      break;
++
++              mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
++              ret = file_remove_suid(out);
++              if (!ret)
++                      ret = splice_from_pipe_feed(pipe, &sd, pipe_to_file);
++              mutex_unlock(&inode->i_mutex);
++      } while (ret > 0);
++      splice_from_pipe_end(pipe, &sd);
++
++      if (pipe->inode)
++              mutex_unlock(&pipe->inode->i_mutex);
++
++      if (sd.num_spliced)
++              ret = sd.num_spliced;
++
+       if (ret > 0) {
+               unsigned long nr_pages;
diff --git a/queue-2.6.29/splice-remove-i_mutex-locking-in-splice_from_pipe.patch b/queue-2.6.29/splice-remove-i_mutex-locking-in-splice_from_pipe.patch
new file mode 100644 (file)
index 0000000..ba324c7
--- /dev/null
@@ -0,0 +1,69 @@
+From 2933970b960223076d6affcf7a77e2bc546b8102 Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <miklos@szeredi.hu>
+Date: Tue, 14 Apr 2009 19:48:37 +0200
+Subject: splice: remove i_mutex locking in splice_from_pipe()
+
+From: Miklos Szeredi <miklos@szeredi.hu>
+
+commit 2933970b960223076d6affcf7a77e2bc546b8102 upstream.
+
+splice_from_pipe() is only called from two places:
+
+  - generic_splice_sendpage()
+  - splice_write_null()
+
+Neither of these require i_mutex to be taken on the destination inode.
+
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/splice.c |   18 ++----------------
+ 1 file changed, 2 insertions(+), 16 deletions(-)
+
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -783,7 +783,7 @@ EXPORT_SYMBOL(__splice_from_pipe);
+  * @actor:    handler that splices the data
+  *
+  * Description:
+- *    See __splice_from_pipe. This function locks the input and output inodes,
++ *    See __splice_from_pipe. This function locks the pipe inode,
+  *    otherwise it's identical to __splice_from_pipe().
+  *
+  */
+@@ -792,7 +792,6 @@ ssize_t splice_from_pipe(struct pipe_ino
+                        splice_actor *actor)
+ {
+       ssize_t ret;
+-      struct inode *inode = out->f_mapping->host;
+       struct splice_desc sd = {
+               .total_len = len,
+               .flags = flags,
+@@ -800,24 +799,11 @@ ssize_t splice_from_pipe(struct pipe_ino
+               .u.file = out,
+       };
+-      /*
+-       * The actor worker might be calling ->write_begin and
+-       * ->write_end. Most of the time, these expect i_mutex to
+-       * be held. Since this may result in an ABBA deadlock with
+-       * pipe->inode, we have to order lock acquiry here.
+-       *
+-       * Outer lock must be inode->i_mutex, as pipe_wait() will
+-       * release and reacquire pipe->inode->i_mutex, AND inode must
+-       * never be a pipe.
+-       */
+-      WARN_ON(S_ISFIFO(inode->i_mode));
+-      mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
+       if (pipe->inode)
+-              mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_CHILD);
++              mutex_lock(&pipe->inode->i_mutex);
+       ret = __splice_from_pipe(pipe, &sd, actor);
+       if (pipe->inode)
+               mutex_unlock(&pipe->inode->i_mutex);
+-      mutex_unlock(&inode->i_mutex);
+       return ret;
+ }
diff --git a/queue-2.6.29/splice-split-up-__splice_from_pipe.patch b/queue-2.6.29/splice-split-up-__splice_from_pipe.patch
new file mode 100644 (file)
index 0000000..56ffc1f
--- /dev/null
@@ -0,0 +1,317 @@
+From b3c2d2ddd63944ef2a1e4a43077b602288107e01 Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <miklos@szeredi.hu>
+Date: Tue, 14 Apr 2009 19:48:36 +0200
+Subject: splice: split up __splice_from_pipe()
+
+From: Miklos Szeredi <miklos@szeredi.hu>
+
+commit b3c2d2ddd63944ef2a1e4a43077b602288107e01 upstream.
+
+Split up __splice_from_pipe() into four helper functions:
+
+  splice_from_pipe_begin()
+  splice_from_pipe_next()
+  splice_from_pipe_feed()
+  splice_from_pipe_end()
+
+splice_from_pipe_next() will wait (if necessary) for more buffers to
+be added to the pipe.  splice_from_pipe_feed() will feed the buffers
+to the supplied actor and return when there's no more data available
+(or if all of the requested data has been copied).
+
+This is necessary so that implementations can do locking around the
+non-waiting splice_from_pipe_feed().
+
+This patch should not cause any change in behavior.
+
+Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
+Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/splice.c            |  223 ++++++++++++++++++++++++++++++++-----------------
+ include/linux/splice.h |   10 ++
+ 2 files changed, 156 insertions(+), 77 deletions(-)
+
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -600,107 +600,176 @@ out:
+       return ret;
+ }
++static void wakeup_pipe_writers(struct pipe_inode_info *pipe)
++{
++      smp_mb();
++      if (waitqueue_active(&pipe->wait))
++              wake_up_interruptible(&pipe->wait);
++      kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
++}
++
+ /**
+- * __splice_from_pipe - splice data from a pipe to given actor
++ * splice_from_pipe_feed - feed available data from a pipe to a file
+  * @pipe:     pipe to splice from
+  * @sd:               information to @actor
+  * @actor:    handler that splices the data
+  *
+  * Description:
+- *    This function does little more than loop over the pipe and call
+- *    @actor to do the actual moving of a single struct pipe_buffer to
+- *    the desired destination. See pipe_to_file, pipe_to_sendpage, or
+- *    pipe_to_user.
++
++ *    This function loops over the pipe and calls @actor to do the
++ *    actual moving of a single struct pipe_buffer to the desired
++ *    destination.  It returns when there's no more buffers left in
++ *    the pipe or if the requested number of bytes (@sd->total_len)
++ *    have been copied.  It returns a positive number (one) if the
++ *    pipe needs to be filled with more data, zero if the required
++ *    number of bytes have been copied and -errno on error.
+  *
++ *    This, together with splice_from_pipe_{begin,end,next}, may be
++ *    used to implement the functionality of __splice_from_pipe() when
++ *    locking is required around copying the pipe buffers to the
++ *    destination.
+  */
+-ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
+-                         splice_actor *actor)
++int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd,
++                        splice_actor *actor)
+ {
+-      int ret, do_wakeup, err;
+-
+-      ret = 0;
+-      do_wakeup = 0;
++      int ret;
+-      for (;;) {
+-              if (pipe->nrbufs) {
+-                      struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
+-                      const struct pipe_buf_operations *ops = buf->ops;
+-
+-                      sd->len = buf->len;
+-                      if (sd->len > sd->total_len)
+-                              sd->len = sd->total_len;
+-
+-                      err = actor(pipe, buf, sd);
+-                      if (err <= 0) {
+-                              if (!ret && err != -ENODATA)
+-                                      ret = err;
++      while (pipe->nrbufs) {
++              struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
++              const struct pipe_buf_operations *ops = buf->ops;
++
++              sd->len = buf->len;
++              if (sd->len > sd->total_len)
++                      sd->len = sd->total_len;
++
++              ret = actor(pipe, buf, sd);
++              if (ret <= 0) {
++                      if (ret == -ENODATA)
++                              ret = 0;
++                      return ret;
++              }
++              buf->offset += ret;
++              buf->len -= ret;
++
++              sd->num_spliced += ret;
++              sd->len -= ret;
++              sd->pos += ret;
++              sd->total_len -= ret;
+-                              break;
+-                      }
++              if (!buf->len) {
++                      buf->ops = NULL;
++                      ops->release(pipe, buf);
++                      pipe->curbuf = (pipe->curbuf + 1) & (PIPE_BUFFERS - 1);
++                      pipe->nrbufs--;
++                      if (pipe->inode)
++                              sd->need_wakeup = true;
++              }
+-                      ret += err;
+-                      buf->offset += err;
+-                      buf->len -= err;
+-
+-                      sd->len -= err;
+-                      sd->pos += err;
+-                      sd->total_len -= err;
+-                      if (sd->len)
+-                              continue;
+-
+-                      if (!buf->len) {
+-                              buf->ops = NULL;
+-                              ops->release(pipe, buf);
+-                              pipe->curbuf = (pipe->curbuf + 1) & (PIPE_BUFFERS - 1);
+-                              pipe->nrbufs--;
+-                              if (pipe->inode)
+-                                      do_wakeup = 1;
+-                      }
++              if (!sd->total_len)
++                      return 0;
++      }
+-                      if (!sd->total_len)
+-                              break;
+-              }
++      return 1;
++}
++EXPORT_SYMBOL(splice_from_pipe_feed);
+-              if (pipe->nrbufs)
+-                      continue;
++/**
++ * splice_from_pipe_next - wait for some data to splice from
++ * @pipe:     pipe to splice from
++ * @sd:               information about the splice operation
++ *
++ * Description:
++ *    This function will wait for some data and return a positive
++ *    value (one) if pipe buffers are available.  It will return zero
++ *    or -errno if no more data needs to be spliced.
++ */
++int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)
++{
++      while (!pipe->nrbufs) {
+               if (!pipe->writers)
+-                      break;
+-              if (!pipe->waiting_writers) {
+-                      if (ret)
+-                              break;
+-              }
++                      return 0;
+-              if (sd->flags & SPLICE_F_NONBLOCK) {
+-                      if (!ret)
+-                              ret = -EAGAIN;
+-                      break;
+-              }
++              if (!pipe->waiting_writers && sd->num_spliced)
++                      return 0;
+-              if (signal_pending(current)) {
+-                      if (!ret)
+-                              ret = -ERESTARTSYS;
+-                      break;
+-              }
++              if (sd->flags & SPLICE_F_NONBLOCK)
++                      return -EAGAIN;
+-              if (do_wakeup) {
+-                      smp_mb();
+-                      if (waitqueue_active(&pipe->wait))
+-                              wake_up_interruptible_sync(&pipe->wait);
+-                      kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
+-                      do_wakeup = 0;
++              if (signal_pending(current))
++                      return -ERESTARTSYS;
++
++              if (sd->need_wakeup) {
++                      wakeup_pipe_writers(pipe);
++                      sd->need_wakeup = false;
+               }
+               pipe_wait(pipe);
+       }
+-      if (do_wakeup) {
+-              smp_mb();
+-              if (waitqueue_active(&pipe->wait))
+-                      wake_up_interruptible(&pipe->wait);
+-              kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
+-      }
++      return 1;
++}
++EXPORT_SYMBOL(splice_from_pipe_next);
+-      return ret;
++/**
++ * splice_from_pipe_begin - start splicing from pipe
++ * @pipe:     pipe to splice from
++ *
++ * Description:
++ *    This function should be called before a loop containing
++ *    splice_from_pipe_next() and splice_from_pipe_feed() to
++ *    initialize the necessary fields of @sd.
++ */
++void splice_from_pipe_begin(struct splice_desc *sd)
++{
++      sd->num_spliced = 0;
++      sd->need_wakeup = false;
++}
++EXPORT_SYMBOL(splice_from_pipe_begin);
++
++/**
++ * splice_from_pipe_end - finish splicing from pipe
++ * @pipe:     pipe to splice from
++ * @sd:               information about the splice operation
++ *
++ * Description:
++ *    This function will wake up pipe writers if necessary.  It should
++ *    be called after a loop containing splice_from_pipe_next() and
++ *    splice_from_pipe_feed().
++ */
++void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd)
++{
++      if (sd->need_wakeup)
++              wakeup_pipe_writers(pipe);
++}
++EXPORT_SYMBOL(splice_from_pipe_end);
++
++/**
++ * __splice_from_pipe - splice data from a pipe to given actor
++ * @pipe:     pipe to splice from
++ * @sd:               information to @actor
++ * @actor:    handler that splices the data
++ *
++ * Description:
++ *    This function does little more than loop over the pipe and call
++ *    @actor to do the actual moving of a single struct pipe_buffer to
++ *    the desired destination. See pipe_to_file, pipe_to_sendpage, or
++ *    pipe_to_user.
++ *
++ */
++ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
++                         splice_actor *actor)
++{
++      int ret;
++
++      splice_from_pipe_begin(sd);
++      do {
++              ret = splice_from_pipe_next(pipe, sd);
++              if (ret > 0)
++                      ret = splice_from_pipe_feed(pipe, sd, actor);
++      } while (ret > 0);
++      splice_from_pipe_end(pipe, sd);
++
++      return sd->num_spliced ? sd->num_spliced : ret;
+ }
+ EXPORT_SYMBOL(__splice_from_pipe);
+--- a/include/linux/splice.h
++++ b/include/linux/splice.h
+@@ -36,6 +36,8 @@ struct splice_desc {
+               void *data;             /* cookie */
+       } u;
+       loff_t pos;                     /* file position */
++      size_t num_spliced;             /* number of bytes already spliced */
++      bool need_wakeup;               /* need to wake up writer */
+ };
+ struct partial_page {
+@@ -66,6 +68,14 @@ extern ssize_t splice_from_pipe(struct p
+                               splice_actor *);
+ extern ssize_t __splice_from_pipe(struct pipe_inode_info *,
+                                 struct splice_desc *, splice_actor *);
++extern int splice_from_pipe_feed(struct pipe_inode_info *, struct splice_desc *,
++                               splice_actor *);
++extern int splice_from_pipe_next(struct pipe_inode_info *,
++                               struct splice_desc *);
++extern void splice_from_pipe_begin(struct splice_desc *);
++extern void splice_from_pipe_end(struct pipe_inode_info *,
++                               struct splice_desc *);
++
+ extern ssize_t splice_to_pipe(struct pipe_inode_info *,
+                             struct splice_pipe_desc *);
+ extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,