--- /dev/null
+From stable-bounces@linux.kernel.org Sun Apr 1 23:50:55 2007
+From: Brian Pomerantz <bapper@piratehaven.org>
+Date: Sun, 01 Apr 2007 23:49:41 -0700
+Subject: fix page leak during core dump
+To: torvalds@linux-foundation.org
+Cc: nickpiggin@yahoo.com.au, bapper@mvista.com, bapper@piratehaven.org, dhowells@redhat.com, hugh@veritas.com, akpm@linux-foundation.org, stable@kernel.org
+Message-ID: <200704020649.l326nfGZ026528@shell0.pdx.osdl.net>
+
+
+From: Brian Pomerantz <bapper@piratehaven.org>
+
+When the dump cannot occur most likely because of a full file system and
+the page to be written is the zero page, the call to page_cache_release()
+is missed.
+
+Signed-off-by: Brian Pomerantz <bapper@mvista.com>
+Cc: Hugh Dickins <hugh@veritas.com>
+Cc: Nick Piggin <nickpiggin@yahoo.com.au>
+Cc: David Howells <dhowells@redhat.com>
+Cc: <stable@kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/binfmt_elf.c | 5 ++++-
+ fs/binfmt_elf_fdpic.c | 2 +-
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+--- a/fs/binfmt_elf.c
++++ b/fs/binfmt_elf.c
+@@ -1704,7 +1704,10 @@ static int elf_core_dump(long signr, str
+ DUMP_SEEK(PAGE_SIZE);
+ } else {
+ if (page == ZERO_PAGE(addr)) {
+- DUMP_SEEK(PAGE_SIZE);
++ if (!dump_seek(file, PAGE_SIZE)) {
++ page_cache_release(page);
++ goto end_coredump;
++ }
+ } else {
+ void *kaddr;
+ flush_cache_page(vma, addr,
+--- a/fs/binfmt_elf_fdpic.c
++++ b/fs/binfmt_elf_fdpic.c
+@@ -1473,8 +1473,8 @@ static int elf_fdpic_dump_segments(struc
+ DUMP_SEEK(file->f_pos + PAGE_SIZE);
+ }
+ else if (page == ZERO_PAGE(addr)) {
+- DUMP_SEEK(file->f_pos + PAGE_SIZE);
+ page_cache_release(page);
++ DUMP_SEEK(file->f_pos + PAGE_SIZE);
+ }
+ else {
+ void *kaddr;
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Apr 1 23:51:13 2007
+From: Andrew Morton <akpm@linux-foundation.org>
+Date: Sun, 01 Apr 2007 23:49:43 -0700
+Subject: revert "retries in ext3_prepare_write() violate ordering requirements"
+To: torvalds@linux-foundation.org
+Cc: dev@openvz.org, stable@kernel.org, kenneth.w.chen@intel.com, saw@sw.ru, dmonakhov@openvz.org, akpm@linux-foundation.org, linux-ext4@vger.kernel.org, mingo@elte.hu
+Message-ID: <200704020649.l326nhD1026534@shell0.pdx.osdl.net>
+
+
+From: Andrew Morton <akpm@linux-foundation.org>
+
+Revert e92a4d595b464c4aae64be39ca61a9ffe9c8b278.
+
+Dmitry points out
+
+"When we block_prepare_write() failed while ext3_prepare_write() we jump to
+ "failure" label and call ext3_prepare_failure() witch search last mapped bh
+ and invoke commit_write untill it. This is wrong!! because some bh from
+ begining to the last mapped bh may be not uptodate. As a result we commit to
+ disk not uptodate page content witch contains garbage from previous usage."
+
+and
+
+"Unexpected file size increasing."
+
+ Call trace the same as it was in first issue but result is different.
+ For example we have file with i_size is zero. we want write two blocks ,
+ but fs has only one free block.
+
+ ->ext3_prepare_write(...from == 0, to == 2048)
+ retry:
+ ->block_prepare_write() == -ENOSPC# we failed but allocated one block here.
+ ->ext3_prepare_failure()
+ ->commit_write( from == 0, to == 1024) # after this i_size becomes 1024 :)
+ if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+
+ Finally when all retries will be spended ext3_prepare_failure return
+ -ENOSPC, but i_size was increased and later block trimm procedures can't
+ help here.
+
+We don't appear to have the horsepower to fix these issues, so let's put
+things back the way they were for now.
+
+Cc: Kirill Korotaev <dev@openvz.org>
+Cc: Ingo Molnar <mingo@elte.hu>
+Cc: Ken Chen <kenneth.w.chen@intel.com>
+Cc: Andrey Savochkin <saw@sw.ru>
+Cc: <linux-ext4@vger.kernel.org>
+Cc: Dmitriy Monakhov <dmonakhov@openvz.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ fs/ext3/inode.c | 85 ++++++--------------------------------------------------
+ 1 file changed, 10 insertions(+), 75 deletions(-)
+
+--- a/fs/ext3/inode.c
++++ b/fs/ext3/inode.c
+@@ -1148,102 +1148,37 @@ static int do_journal_get_write_access(h
+ return ext3_journal_get_write_access(handle, bh);
+ }
+
+-/*
+- * The idea of this helper function is following:
+- * if prepare_write has allocated some blocks, but not all of them, the
+- * transaction must include the content of the newly allocated blocks.
+- * This content is expected to be set to zeroes by block_prepare_write().
+- * 2006/10/14 SAW
+- */
+-static int ext3_prepare_failure(struct file *file, struct page *page,
+- unsigned from, unsigned to)
+-{
+- struct address_space *mapping;
+- struct buffer_head *bh, *head, *next;
+- unsigned block_start, block_end;
+- unsigned blocksize;
+- int ret;
+- handle_t *handle = ext3_journal_current_handle();
+-
+- mapping = page->mapping;
+- if (ext3_should_writeback_data(mapping->host)) {
+- /* optimization: no constraints about data */
+-skip:
+- return ext3_journal_stop(handle);
+- }
+-
+- head = page_buffers(page);
+- blocksize = head->b_size;
+- for ( bh = head, block_start = 0;
+- bh != head || !block_start;
+- block_start = block_end, bh = next)
+- {
+- next = bh->b_this_page;
+- block_end = block_start + blocksize;
+- if (block_end <= from)
+- continue;
+- if (block_start >= to) {
+- block_start = to;
+- break;
+- }
+- if (!buffer_mapped(bh))
+- /* prepare_write failed on this bh */
+- break;
+- if (ext3_should_journal_data(mapping->host)) {
+- ret = do_journal_get_write_access(handle, bh);
+- if (ret) {
+- ext3_journal_stop(handle);
+- return ret;
+- }
+- }
+- /*
+- * block_start here becomes the first block where the current iteration
+- * of prepare_write failed.
+- */
+- }
+- if (block_start <= from)
+- goto skip;
+-
+- /* commit allocated and zeroed buffers */
+- return mapping->a_ops->commit_write(file, page, from, block_start);
+-}
+-
+ static int ext3_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+ {
+ struct inode *inode = page->mapping->host;
+- int ret, ret2;
+- int needed_blocks = ext3_writepage_trans_blocks(inode);
++ int ret, needed_blocks = ext3_writepage_trans_blocks(inode);
+ handle_t *handle;
+ int retries = 0;
+
+ retry:
+ handle = ext3_journal_start(inode, needed_blocks);
+- if (IS_ERR(handle))
+- return PTR_ERR(handle);
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ goto out;
++ }
+ if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode))
+ ret = nobh_prepare_write(page, from, to, ext3_get_block);
+ else
+ ret = block_prepare_write(page, from, to, ext3_get_block);
+ if (ret)
+- goto failure;
++ goto prepare_write_failed;
+
+ if (ext3_should_journal_data(inode)) {
+ ret = walk_page_buffers(handle, page_buffers(page),
+ from, to, NULL, do_journal_get_write_access);
+- if (ret)
+- /* fatal error, just put the handle and return */
+- journal_stop(handle);
+ }
+- return ret;
+-
+-failure:
+- ret2 = ext3_prepare_failure(file, page, from, to);
+- if (ret2 < 0)
+- return ret2;
++prepare_write_failed:
++ if (ret)
++ ext3_journal_stop(handle);
+ if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+- /* retry number exceeded, or other error like -EDQUOT */
++out:
+ return ret;
+ }
+
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Apr 1 23:51:19 2007
+From: Andrew Morton <akpm@linux-foundation.org>
+Date: Sun, 01 Apr 2007 23:49:44 -0700
+Subject: revert "retries in ext4_prepare_write() violate ordering requirements"
+To: torvalds@linux-foundation.org
+Cc: dev@openvz.org, stable@kernel.org, kenneth.w.chen@intel.com, saw@sw.ru, dmonakhov@openvz.org, akpm@linux-foundation.org, linux-ext4@vger.kernel.org, mingo@elte.hu
+Message-ID: <200704020649.l326niVR026539@shell0.pdx.osdl.net>
+
+
+From: Andrew Morton <akpm@linux-foundation.org>
+
+Revert b46be05004abb419e303e66e143eed9f8a6e9f3f. Same reasoning as for ext3.
+
+Cc: Kirill Korotaev <dev@openvz.org>
+Cc: Ingo Molnar <mingo@elte.hu>
+Cc: Ken Chen <kenneth.w.chen@intel.com>
+Cc: Andrey Savochkin <saw@sw.ru>
+Cc: <linux-ext4@vger.kernel.org>
+Cc: Dmitriy Monakhov <dmonakhov@openvz.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ fs/ext4/inode.c | 85 ++++++--------------------------------------------------
+ 1 file changed, 10 insertions(+), 75 deletions(-)
+
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -1147,102 +1147,37 @@ static int do_journal_get_write_access(h
+ return ext4_journal_get_write_access(handle, bh);
+ }
+
+-/*
+- * The idea of this helper function is following:
+- * if prepare_write has allocated some blocks, but not all of them, the
+- * transaction must include the content of the newly allocated blocks.
+- * This content is expected to be set to zeroes by block_prepare_write().
+- * 2006/10/14 SAW
+- */
+-static int ext4_prepare_failure(struct file *file, struct page *page,
+- unsigned from, unsigned to)
+-{
+- struct address_space *mapping;
+- struct buffer_head *bh, *head, *next;
+- unsigned block_start, block_end;
+- unsigned blocksize;
+- int ret;
+- handle_t *handle = ext4_journal_current_handle();
+-
+- mapping = page->mapping;
+- if (ext4_should_writeback_data(mapping->host)) {
+- /* optimization: no constraints about data */
+-skip:
+- return ext4_journal_stop(handle);
+- }
+-
+- head = page_buffers(page);
+- blocksize = head->b_size;
+- for ( bh = head, block_start = 0;
+- bh != head || !block_start;
+- block_start = block_end, bh = next)
+- {
+- next = bh->b_this_page;
+- block_end = block_start + blocksize;
+- if (block_end <= from)
+- continue;
+- if (block_start >= to) {
+- block_start = to;
+- break;
+- }
+- if (!buffer_mapped(bh))
+- /* prepare_write failed on this bh */
+- break;
+- if (ext4_should_journal_data(mapping->host)) {
+- ret = do_journal_get_write_access(handle, bh);
+- if (ret) {
+- ext4_journal_stop(handle);
+- return ret;
+- }
+- }
+- /*
+- * block_start here becomes the first block where the current iteration
+- * of prepare_write failed.
+- */
+- }
+- if (block_start <= from)
+- goto skip;
+-
+- /* commit allocated and zeroed buffers */
+- return mapping->a_ops->commit_write(file, page, from, block_start);
+-}
+-
+ static int ext4_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+ {
+ struct inode *inode = page->mapping->host;
+- int ret, ret2;
+- int needed_blocks = ext4_writepage_trans_blocks(inode);
++ int ret, needed_blocks = ext4_writepage_trans_blocks(inode);
+ handle_t *handle;
+ int retries = 0;
+
+ retry:
+ handle = ext4_journal_start(inode, needed_blocks);
+- if (IS_ERR(handle))
+- return PTR_ERR(handle);
++ if (IS_ERR(handle)) {
++ ret = PTR_ERR(handle);
++ goto out;
++ }
+ if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
+ ret = nobh_prepare_write(page, from, to, ext4_get_block);
+ else
+ ret = block_prepare_write(page, from, to, ext4_get_block);
+ if (ret)
+- goto failure;
++ goto prepare_write_failed;
+
+ if (ext4_should_journal_data(inode)) {
+ ret = walk_page_buffers(handle, page_buffers(page),
+ from, to, NULL, do_journal_get_write_access);
+- if (ret)
+- /* fatal error, just put the handle and return */
+- ext4_journal_stop(handle);
+ }
+- return ret;
+-
+-failure:
+- ret2 = ext4_prepare_failure(file, page, from, to);
+- if (ret2 < 0)
+- return ret2;
++prepare_write_failed:
++ if (ret)
++ ext4_journal_stop(handle);
+ if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+- /* retry number exceeded, or other error like -EDQUOT */
++out:
+ return ret;
+ }
+
ahci.c-walkaround-for-sb600-sata-internal-error-issue.patch
fix-lba48-bug-in-libata-fill_result_tf.patch
libata-clear-tf-before-doing-request-sense.patch
+revert-retries-in-ext3_prepare_write-violate-ordering-requirements.patch
+revert-retries-in-ext4_prepare_write-violate-ordering-requirements.patch
+fix-page-leak-during-core-dump.patch