From: Greg Kroah-Hartman Date: Wed, 11 Apr 2007 21:41:18 +0000 (-0700) Subject: more patches queued up X-Git-Tag: v2.6.20.7~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d5c92242f8bbede569feb17f910b59f05d7fac8e;p=thirdparty%2Fkernel%2Fstable-queue.git more patches queued up --- diff --git a/queue-2.6.20/fix-page-leak-during-core-dump.patch b/queue-2.6.20/fix-page-leak-during-core-dump.patch new file mode 100644 index 00000000000..e6d553b2df6 --- /dev/null +++ b/queue-2.6.20/fix-page-leak-during-core-dump.patch @@ -0,0 +1,54 @@ +From stable-bounces@linux.kernel.org Sun Apr 1 23:50:55 2007 +From: Brian Pomerantz +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 + +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 +Cc: Hugh Dickins +Cc: Nick Piggin +Cc: David Howells +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman + +--- + 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; diff --git a/queue-2.6.20/revert-retries-in-ext3_prepare_write-violate-ordering-requirements.patch b/queue-2.6.20/revert-retries-in-ext3_prepare_write-violate-ordering-requirements.patch new file mode 100644 index 00000000000..e5dfdb27f85 --- /dev/null +++ b/queue-2.6.20/revert-retries-in-ext3_prepare_write-violate-ordering-requirements.patch @@ -0,0 +1,173 @@ +From stable-bounces@linux.kernel.org Sun Apr 1 23:51:13 2007 +From: Andrew Morton +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 + +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 +Cc: Ingo Molnar +Cc: Ken Chen +Cc: Andrey Savochkin +Cc: +Cc: Dmitriy Monakhov +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman + + +--- + 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; + } + diff --git a/queue-2.6.20/revert-retries-in-ext4_prepare_write-violate-ordering-requirements.patch b/queue-2.6.20/revert-retries-in-ext4_prepare_write-violate-ordering-requirements.patch new file mode 100644 index 00000000000..c83cf993da4 --- /dev/null +++ b/queue-2.6.20/revert-retries-in-ext4_prepare_write-violate-ordering-requirements.patch @@ -0,0 +1,141 @@ +From stable-bounces@linux.kernel.org Sun Apr 1 23:51:19 2007 +From: Andrew Morton +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 + +Revert b46be05004abb419e303e66e143eed9f8a6e9f3f. Same reasoning as for ext3. + +Cc: Kirill Korotaev +Cc: Ingo Molnar +Cc: Ken Chen +Cc: Andrey Savochkin +Cc: +Cc: Dmitriy Monakhov +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + } + diff --git a/queue-2.6.20/series b/queue-2.6.20/series index b1eb0c3881d..e44a4a501d5 100644 --- a/queue-2.6.20/series +++ b/queue-2.6.20/series @@ -25,3 +25,6 @@ libata-bugfix-preserve-lba-bit-for-hdio_drive_task.patch 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