From: Chris Wright Date: Tue, 27 Jun 2006 19:14:58 +0000 (-0700) Subject: generic_file_buffered_write deadlock fix fwd, from akpm X-Git-Tag: v2.6.17.2~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1d80b68d4359b7947f3e4b9eccab6d641253f6e7;p=thirdparty%2Fkernel%2Fstable-queue.git generic_file_buffered_write deadlock fix fwd, from akpm --- diff --git a/queue-2.6.17/generic_file_buffered_write-deadlock-on-vectored-write.patch b/queue-2.6.17/generic_file_buffered_write-deadlock-on-vectored-write.patch new file mode 100644 index 00000000000..eeabb112bb4 --- /dev/null +++ b/queue-2.6.17/generic_file_buffered_write-deadlock-on-vectored-write.patch @@ -0,0 +1,71 @@ +From stable-bounces@linux.kernel.org Tue Jun 27 02:54:58 2006 +Date: Tue, 27 Jun 2006 02:53:57 -0700 +From: akpm@osdl.org +To: torvalds@osdl.org +Cc: neilb@suse.de, schwidefsky@de.ibm.com, vs@namesys.com, stable@kernel.org +Subject: [stable] [patch 037/112] generic_file_buffered_write(): deadlock on vectored write + +From: "Vladimir V. Saveliev" + +generic_file_buffered_write() prefaults in user pages in order to avoid +deadlock on copying from the same page as write goes to. + +However, it looks like there is a problem when write is vectored: +fault_in_pages_readable brings in current segment or its part (maxlen). +OTOH, filemap_copy_from_user_iovec is called to copy number of bytes +(bytes) which may exceed current segment, so filemap_copy_from_user_iovec +switches to the next segment which is not brought in yet. Pagefault is +generated. That causes the deadlock if pagefault is for the same page +write goes to: page being written is locked and not uptodate, pagefault +will deadlock trying to lock locked page. + +[akpm@osdl.org: somewhat rewritten] +Cc: Neil Brown +Cc: Martin Schwidefsky +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Chris Wright +--- + + mm/filemap.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +--- linux-2.6.17.1.orig/mm/filemap.c ++++ linux-2.6.17.1/mm/filemap.c +@@ -2004,14 +2004,21 @@ generic_file_buffered_write(struct kiocb + do { + unsigned long index; + unsigned long offset; +- unsigned long maxlen; + size_t copied; + + offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ + index = pos >> PAGE_CACHE_SHIFT; + bytes = PAGE_CACHE_SIZE - offset; +- if (bytes > count) +- bytes = count; ++ ++ /* Limit the size of the copy to the caller's write size */ ++ bytes = min(bytes, count); ++ ++ /* ++ * Limit the size of the copy to that of the current segment, ++ * because fault_in_pages_readable() doesn't know how to walk ++ * segments. ++ */ ++ bytes = min(bytes, cur_iov->iov_len - iov_base); + + /* + * Bring in the user page that we will copy from _first_. +@@ -2019,10 +2026,7 @@ generic_file_buffered_write(struct kiocb + * same page as we're writing to, without it being marked + * up-to-date. + */ +- maxlen = cur_iov->iov_len - iov_base; +- if (maxlen > bytes) +- maxlen = bytes; +- fault_in_pages_readable(buf, maxlen); ++ fault_in_pages_readable(buf, bytes); + + page = __grab_cache_page(mapping,index,&cached_page,&lru_pvec); + if (!page) { diff --git a/queue-2.6.17/series b/queue-2.6.17/series index 5102cfc7acd..2a5a4e77352 100644 --- a/queue-2.6.17/series +++ b/queue-2.6.17/series @@ -22,3 +22,4 @@ kbuild-fix-100-initramfs-bloat-in-2.6.17-versus-2.6.16.patch link-error-when-futexes-are-disabled-on-64bit-architectures.patch idr-fix-race-in-idr-code.patch input-return-correct-size-when-reading-modalias-attribute.patch +generic_file_buffered_write-deadlock-on-vectored-write.patch