From: Greg Kroah-Hartman Date: Thu, 14 May 2009 03:46:25 +0000 (-0700) Subject: more .29 patches X-Git-Tag: v2.6.29.4~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4fa42756d28fb7ef540aa324ba8ca72387ff014d;p=thirdparty%2Fkernel%2Fstable-queue.git more .29 patches --- 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 index 00000000000..74ef9f82f1c --- /dev/null +++ b/queue-2.6.29/ehea-fix-invalid-pointer-access.patch @@ -0,0 +1,69 @@ +From 0b2febf38a33d7c40fb7bb4a58c113a1fa33c412 Mon Sep 17 00:00:00 2001 +From: Hannes Hering +Date: Mon, 4 May 2009 11:06:37 -0700 +Subject: ehea: fix invalid pointer access + +From: Hannes Hering + +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 +Signed-off-by: Jan-Bernd Themann +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..7f3f6295b8f --- /dev/null +++ b/queue-2.6.29/fuse-destroy-bdi-on-error.patch @@ -0,0 +1,32 @@ +From fd9db7297749c05fcf5721ce5393a5a8b8772f2a Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 28 Apr 2009 16:56:35 +0200 +Subject: fuse: destroy bdi on error + +From: Miklos Szeredi + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..9a9ef9c3d5e --- /dev/null +++ b/queue-2.6.29/kvm-make-efer-reads-safe-when-efer-does-not-exist.patch @@ -0,0 +1,33 @@ +From e286e86e6d2042d67d09244aa0e05ffef75c9d54 Mon Sep 17 00:00:00 2001 +From: Avi Kivity +Date: Sun, 3 May 2009 18:50:55 +0300 +Subject: KVM: Make EFER reads safe when EFER does not exist + +From: Avi Kivity + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..dc680608c89 --- /dev/null +++ b/queue-2.6.29/kvm-svm-remove-port-80-passthrough.patch @@ -0,0 +1,37 @@ +From 99f85a28a78e96d28907fe036e1671a218fee597 Mon Sep 17 00:00:00 2001 +From: Avi Kivity +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 + +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 +Tested-by: Piotr Jaroszyński +Signed-off-by: Avi Kivity +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index fd0c154bf09..00000000000 --- a/queue-2.6.29/mac80211-minstrel-fix-memory-corruption.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 8e532175277d9a5eae49768ed086555081f741a7 Mon Sep 17 00:00:00 2001 -From: Jiri Slaby -Date: Mon, 4 May 2009 18:04:55 +0200 -Subject: mac80211: minstrel, fix memory corruption - -From: Jiri Slaby - -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 -Cc: Felix Fietkau -Signed-off-by: John W. Linville -Signed-off-by: Greg Kroah-Hartman - ---- - 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 index 00000000000..6e063f76687 --- /dev/null +++ b/queue-2.6.29/ocfs2-fix-i_mutex-locking-in-ocfs2_splice_to_file.patch @@ -0,0 +1,179 @@ +From 328eaaba4e41a04c1dc4679d65bea3fee4349d86 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 14 Apr 2009 19:48:39 +0200 +Subject: ocfs2: fix i_mutex locking in ocfs2_splice_to_file() + +From: Miklos Szeredi + +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 +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..aa6e19bf4d4 --- /dev/null +++ b/queue-2.6.29/powerpc-5200-don-t-specify-irqf_shared-in-psc-uart-driver.patch @@ -0,0 +1,34 @@ +From d9f0c5f9bc74f16d0ea0f6c518b209e48783a796 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Wed, 4 Feb 2009 11:23:56 -0700 +Subject: powerpc/5200: Don't specify IRQF_SHARED in PSC UART driver + +From: Grant Likely + +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 +Reviewed-by: Wolfram Sang +Signed-off-by: Greg Kroah-Hartman + +--- + 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; diff --git a/queue-2.6.29/series b/queue-2.6.29/series index 2c0a0cabb44..81e15b944b0 100644 --- a/queue-2.6.29/series +++ b/queue-2.6.29/series @@ -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 index 00000000000..cc1ce562a23 --- /dev/null +++ b/queue-2.6.29/splice-fix-i_mutex-locking-in-generic_splice_write.patch @@ -0,0 +1,64 @@ +From eb443e5a25d43996deb62b9bcee1a4ce5dea2ead Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 14 Apr 2009 19:48:38 +0200 +Subject: splice: fix i_mutex locking in generic_splice_write() + +From: Miklos Szeredi + +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 +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..ba324c7b729 --- /dev/null +++ b/queue-2.6.29/splice-remove-i_mutex-locking-in-splice_from_pipe.patch @@ -0,0 +1,69 @@ +From 2933970b960223076d6affcf7a77e2bc546b8102 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 14 Apr 2009 19:48:37 +0200 +Subject: splice: remove i_mutex locking in splice_from_pipe() + +From: Miklos Szeredi + +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 +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..56ffc1f543f --- /dev/null +++ b/queue-2.6.29/splice-split-up-__splice_from_pipe.patch @@ -0,0 +1,317 @@ +From b3c2d2ddd63944ef2a1e4a43077b602288107e01 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Tue, 14 Apr 2009 19:48:36 +0200 +Subject: splice: split up __splice_from_pipe() + +From: Miklos Szeredi + +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 +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + 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 *,